diff --git a/spring-cloud-alibaba-sentinel/pom.xml b/spring-cloud-alibaba-sentinel/pom.xml index b5707134..3abdf979 100644 --- a/spring-cloud-alibaba-sentinel/pom.xml +++ b/spring-cloud-alibaba-sentinel/pom.xml @@ -42,6 +42,13 @@ true + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + provided + true + + com.alibaba.csp sentinel-parameter-flow-control diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java index 1ba2c170..2cd3b53a 100644 --- a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java +++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java @@ -16,76 +16,268 @@ package org.springframework.cloud.alibaba.sentinel; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import java.util.Arrays; +import java.util.Map; + +import org.junit.Before; import org.junit.Test; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.server.LocalServerPort; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate; import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration; import org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor; -import org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor; +import org.springframework.cloud.alibaba.sentinel.endpoint.SentinelEndpoint; +import org.springframework.cloud.alibaba.sentinel.rest.SentinelClientHttpResponse; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; +import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig; +import com.alibaba.csp.sentinel.config.SentinelConfig; +import com.alibaba.csp.sentinel.log.LogBase; import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.csp.sentinel.slots.block.RuleConstant; +import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; +import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; +import com.alibaba.csp.sentinel.transport.config.TransportConfig; /** - * @author fangjian + * @author Jim * @author jiashuai.xie */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { + SentinelAutoConfigurationTests.TestConfig.class }, properties = { + "spring.cloud.sentinel.filter.order=123", + "spring.cloud.sentinel.filter.urlPatterns=/*,/test", + "spring.cloud.sentinel.metric.fileSingleSize=9999", + "spring.cloud.sentinel.metric.fileTotalCount=100", + "spring.cloud.sentinel.servlet.blockPage=/error", + "spring.cloud.sentinel.flow.coldFactor=3", + "spring.cloud.sentinel.eager=true", + "spring.cloud.sentinel.log.switchPid=true", + "spring.cloud.sentinel.transport.dashboard=http://localhost:8080", + "spring.cloud.sentinel.transport.port=9999", + "spring.cloud.sentinel.transport.clientIp=1.1.1.1", + "spring.cloud.sentinel.transport.heartbeatIntervalMs=20000" }, webEnvironment = RANDOM_PORT) public class SentinelAutoConfigurationTests { - private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(SentinelAutoConfiguration.class, - SentinelWebAutoConfiguration.class, SentinelTestConfiguration.class)) - .withPropertyValues("spring.cloud.sentinel.transport.port=8888") - .withPropertyValues("spring.cloud.sentinel.filter.order=123") - .withPropertyValues("spring.cloud.sentinel.filter.urlPatterns=/*,/test"); + @Autowired + private SentinelProperties sentinelProperties; + + @Autowired + private FilterRegistrationBean filterRegistrationBean; + + @Autowired + private SentinelBeanPostProcessor sentinelBeanPostProcessor; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private RestTemplate restTemplateWithBlockClass; + + @Autowired + private RestTemplate restTemplateWithoutBlockClass; + + @Autowired + private RestTemplate restTemplateWithFallbackClass; + + @LocalServerPort + private int port; + + private String url = "http://localhost:" + port; + + @Before + public void setUp() { + FlowRule rule = new FlowRule(); + rule.setGrade(RuleConstant.FLOW_GRADE_QPS); + rule.setCount(0); + rule.setResource(url); + rule.setLimitApp("default"); + rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); + rule.setStrategy(RuleConstant.STRATEGY_DIRECT); + FlowRuleManager.loadRules(Arrays.asList(rule)); + + DegradeRule degradeRule = new DegradeRule(); + degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT); + degradeRule.setResource(url + "/test"); + degradeRule.setCount(0); + degradeRule.setTimeWindow(60); + DegradeRuleManager.loadRules(Arrays.asList(degradeRule)); + } + + @Test + public void contextLoads() throws Exception { + assertNotNull("FilterRegistrationBean was not created", filterRegistrationBean); + assertNotNull("SentinelProperties was not created", sentinelProperties); + assertNotNull("SentinelBeanPostProcessor was not created", + sentinelBeanPostProcessor); + + checkSentinelLog(); + checkSentinelEager(); + checkSentinelTransport(); + checkSentinelColdFactor(); + checkSentinelMetric(); + checkSentinelFilter(); + checkEndpoint(); + } + + private void checkEndpoint() { + SentinelEndpoint sentinelEndpoint = new SentinelEndpoint(sentinelProperties); + Map map = sentinelEndpoint.invoke(); + assertEquals("Endpoint Sentinel log pid was wrong", true, map.get("logUsePid")); + assertEquals("Endpoint Sentinel transport console server was wrong", + "http://localhost:8080", map.get("consoleServer")); + assertEquals("Endpoint Sentinel transport port was wrong", "9999", + map.get("clientPort")); + assertEquals("Endpoint Sentinel transport heartbeatIntervalMs was wrong", 20000l, + map.get("heartbeatIntervalMs")); + assertEquals("Endpoint Sentinel transport clientIp was wrong", "1.1.1.1", + map.get("clientIp")); + assertEquals("Endpoint Sentinel metric file size was wrong", 9999l, + map.get("metricsFileSize")); + assertEquals("Endpoint Sentinel metric file count was wrong", 100, + map.get("totalMetricsFileCount")); + assertEquals("Endpoint Sentinel metric file charset was wrong", "UTF-8", + map.get("metricsFileCharset")); + assertEquals("Endpoint Sentinel block page was wrong", "/error", + map.get("blockPage")); + } + + private void checkSentinelFilter() { + assertEquals("SentinelProperties filter order was wrong", 123, + sentinelProperties.getFilter().getOrder()); + assertEquals("SentinelProperties filter url pattern size was wrong", 2, + sentinelProperties.getFilter().getUrlPatterns().size()); + assertEquals("SentinelProperties filter url pattern item was wrong", "/*", + sentinelProperties.getFilter().getUrlPatterns().get(0)); + assertEquals("SentinelProperties filter url pattern item was wrong", "/test", + sentinelProperties.getFilter().getUrlPatterns().get(1)); + } + + private void checkSentinelMetric() { + assertEquals("SentinelProperties metric charset was wrong", "UTF-8", + sentinelProperties.getMetric().getCharset()); + assertEquals("SentinelProperties metric file single size was wrong", "9999", + sentinelProperties.getMetric().getFileSingleSize()); + assertEquals("SentinelProperties metric file total count was wrong", "100", + sentinelProperties.getMetric().getFileTotalCount()); + } + + private void checkSentinelColdFactor() { + assertEquals("SentinelProperties coldFactor was wrong", "3", + sentinelProperties.getFlow().getColdFactor()); + } + + private void checkSentinelTransport() { + assertEquals("SentinelProperties transport port was wrong", "9999", + sentinelProperties.getTransport().getPort()); + assertEquals("SentinelProperties transport dashboard was wrong", + "http://localhost:8080", + sentinelProperties.getTransport().getDashboard()); + assertEquals("SentinelProperties transport clientIp was wrong", "1.1.1.1", + sentinelProperties.getTransport().getClientIp()); + assertEquals("SentinelProperties transport heartbeatIntervalMs was wrong", + "20000", sentinelProperties.getTransport().getHeartbeatIntervalMs()); + } + + private void checkSentinelEager() { + assertEquals("SentinelProperties eager was wrong", true, + sentinelProperties.isEager()); + } + + private void checkSentinelLog() { + assertEquals("SentinelProperties log file pid was wrong", true, + sentinelProperties.getLog().isSwitchPid()); + } @Test public void testFilter() { - this.contextRunner.run(context -> { - assertThat(context.getBean("servletRequestListener") - .getClass() == FilterRegistrationBean.class).isTrue(); + assertEquals("Sentinel Filter order was wrong", filterRegistrationBean.getOrder(), + 123); + assertEquals("Sentinel Filter url-pattern was wrong", + filterRegistrationBean.getUrlPatterns().size(), 2); + } + + @Test + public void testSentinelSystemProperties() { + assertEquals("Sentinel log pid was wrong", true, LogBase.isLogNameUsePid()); + assertEquals("Sentinel transport console server was wrong", + "http://localhost:8080", TransportConfig.getConsoleServer()); + assertEquals("Sentinel transport port was wrong", "9999", + TransportConfig.getPort()); + assertEquals("Sentinel transport heartbeatIntervalMs was wrong", 20000l, + TransportConfig.getHeartbeatIntervalMs().longValue()); + assertEquals("Sentinel transport clientIp was wrong", "1.1.1.1", + TransportConfig.getHeartbeatClientIp()); + assertEquals("Sentinel metric file size was wrong", 9999, + SentinelConfig.singleMetricFileSize()); + assertEquals("Sentinel metric file count was wrong", 100, + SentinelConfig.totalMetricFileCount()); + assertEquals("Sentinel metric file charset was wrong", "UTF-8", + SentinelConfig.charset()); + assertEquals("Sentinel block page was wrong", "/error", + WebServletConfig.getBlockPage()); + } + + @Test + public void testFlowRestTemplate() { + assertEquals("RestTemplate interceptors size was wrong", 2, + restTemplate.getInterceptors().size()); + assertEquals("RestTemplateWithBlockClass interceptors size was wrong", 1, + restTemplateWithBlockClass.getInterceptors().size()); + ResponseEntity responseEntityBlock = restTemplateWithBlockClass.getForEntity(url, + String.class); + assertEquals("RestTemplateWithBlockClass Sentinel Block Message was wrong", + "Oops", responseEntityBlock.getBody()); + assertEquals( + "RestTemplateWithBlockClass Sentinel Block Http Status Code was wrong", + HttpStatus.OK, responseEntityBlock.getStatusCode()); + ResponseEntity responseEntityRaw = restTemplate.getForEntity(url, String.class); + assertEquals("RestTemplate Sentinel Block Message was wrong", + "RestTemplate request block by sentinel", responseEntityRaw.getBody()); + assertEquals("RestTemplate Sentinel Block Http Status Code was wrong", + HttpStatus.OK, responseEntityRaw.getStatusCode()); + } + + @Test + public void testNormalRestTemplate() { + assertEquals("RestTemplateWithoutBlockClass interceptors size was wrong", 0, + restTemplateWithoutBlockClass.getInterceptors().size()); + assertThatExceptionOfType(RestClientException.class).isThrownBy(() -> { + restTemplateWithoutBlockClass.getForEntity(url, String.class); }); } @Test - public void testBeanPostProcessor() { - this.contextRunner.run(context -> { - assertThat(context.getBean("sentinelBeanPostProcessor") - .getClass() == SentinelBeanPostProcessor.class).isTrue(); - }); - } - - @Test - public void testProperties() { - this.contextRunner.run(context -> { - SentinelProperties sentinelProperties = context - .getBean(SentinelProperties.class); - assertThat(sentinelProperties.getTransport().getPort()).isEqualTo("8888"); - assertThat(sentinelProperties.getFilter().getUrlPatterns().size()) - .isEqualTo(2); - assertThat(sentinelProperties.getFilter().getUrlPatterns().get(0)) - .isEqualTo("/*"); - assertThat(sentinelProperties.getFilter().getUrlPatterns().get(1)) - .isEqualTo("/test"); - }); - } - - @Test - public void testRestTemplate() { - this.contextRunner.run(context -> { - assertThat(context.getBeansOfType(RestTemplate.class).size()).isEqualTo(2); - RestTemplate restTemplate = context.getBean("restTemplateWithBlockClass", - RestTemplate.class); - assertThat(restTemplate.getInterceptors().size()).isEqualTo(1); - assertThat(restTemplate.getInterceptors().get(0).getClass()) - .isEqualTo(SentinelProtectInterceptor.class); - }); + public void testFallbackRestTemplate() { + ResponseEntity responseEntity = restTemplateWithFallbackClass + .getForEntity(url + "/test", String.class); + assertEquals("RestTemplateWithFallbackClass Sentinel Message was wrong", + "Oops fallback", responseEntity.getBody()); + assertEquals("RestTemplateWithFallbackClass Sentinel Http Status Code was wrong", + HttpStatus.OK, responseEntity.getStatusCode()); } @Configuration @@ -94,7 +286,9 @@ public class SentinelAutoConfigurationTests { @Bean @SentinelRestTemplate RestTemplate restTemplate() { - return new RestTemplate(); + RestTemplate restTemplate = new RestTemplate(); + restTemplate.getInterceptors().add(mock(ClientHttpRequestInterceptor.class)); + return restTemplate; } @Bean @@ -103,12 +297,38 @@ public class SentinelAutoConfigurationTests { return new RestTemplate(); } + @Bean + @SentinelRestTemplate(fallbackClass = ExceptionUtil.class, fallback = "fallbackException") + RestTemplate restTemplateWithFallbackClass() { + return new RestTemplate(); + } + + @Bean + RestTemplate restTemplateWithoutBlockClass() { + return new RestTemplate(); + } + } - static class ExceptionUtil { - public static void handleException(BlockException ex) { + public static class ExceptionUtil { + public static SentinelClientHttpResponse handleException(HttpRequest request, + byte[] body, ClientHttpRequestExecution execution, BlockException ex) { System.out.println("Oops: " + ex.getClass().getCanonicalName()); + return new SentinelClientHttpResponse("Oops"); + } + + public static SentinelClientHttpResponse fallbackException(HttpRequest request, + byte[] body, ClientHttpRequestExecution execution, BlockException ex) { + System.out.println("Oops: " + ex.getClass().getCanonicalName()); + return new SentinelClientHttpResponse("Oops fallback"); } } + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ SentinelAutoConfiguration.class, + SentinelWebAutoConfiguration.class, SentinelTestConfiguration.class }) + public static class TestConfig { + } + } diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelBeanAutowiredTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelBeanAutowiredTests.java new file mode 100644 index 00000000..b22f17e8 --- /dev/null +++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelBeanAutowiredTests.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.sentinel; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser; +import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler; +import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner; +import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; +import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; +import com.alibaba.csp.sentinel.slots.block.BlockException; + +/** + * @author Jim + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { SentinelBeanAutowiredTests.TestConfig.class }, properties = { + "spring.cloud.sentinel.filter.order=111" }) +public class SentinelBeanAutowiredTests { + + @Autowired + private UrlCleaner urlCleaner; + + @Autowired + private UrlBlockHandler urlBlockHandler; + + @Autowired + private RequestOriginParser requestOriginParser; + + @Autowired + private SentinelProperties sentinelProperties; + + @Test + public void contextLoads() throws Exception { + assertNotNull("UrlCleaner was not created", urlCleaner); + assertNotNull("UrlBlockHandler was not created", urlBlockHandler); + assertNotNull("RequestOriginParser was not created", requestOriginParser); + assertNotNull("SentinelProperties was not created", sentinelProperties); + + checkUrlPattern(); + } + + private void checkUrlPattern() { + assertEquals("SentinelProperties filter order was wrong", 111, + sentinelProperties.getFilter().getOrder()); + assertEquals("SentinelProperties filter url pattern size was wrong", 1, + sentinelProperties.getFilter().getUrlPatterns().size()); + assertEquals("SentinelProperties filter url pattern was wrong", "/*", + sentinelProperties.getFilter().getUrlPatterns().get(0)); + } + + @Test + public void testBeanAutowired() { + assertEquals("UrlCleaner was not autowired", urlCleaner, + WebCallbackManager.getUrlCleaner()); + assertEquals("UrlBlockHandler was not autowired", urlBlockHandler, + WebCallbackManager.getUrlBlockHandler()); + assertEquals("RequestOriginParser was not autowired", requestOriginParser, + WebCallbackManager.getRequestOriginParser()); + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ SentinelAutoConfiguration.class, + SentinelWebAutoConfiguration.class }) + public static class TestConfig { + + @Bean + public UrlCleaner urlCleaner() { + return new UrlCleaner() { + @Override + public String clean(String s) { + return s; + } + }; + } + + @Bean + public RequestOriginParser requestOriginParser() { + return new RequestOriginParser() { + @Override + public String parseOrigin(HttpServletRequest httpServletRequest) { + return httpServletRequest.getRemoteAddr(); + } + }; + } + + @Bean + public UrlBlockHandler urlBlockHandler() { + return new UrlBlockHandler() { + @Override + public void blocked(HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse, BlockException e) + throws IOException { + FilterUtil.blockRequest(httpServletRequest, httpServletResponse); + } + }; + } + + } + +} diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelDataSourceTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelDataSourceTests.java new file mode 100644 index 00000000..44bebcb6 --- /dev/null +++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelDataSourceTests.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.sentinel; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration; +import org.springframework.cloud.alibaba.sentinel.datasource.RuleType; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * @author Jim + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { SentinelDataSourceTests.TestConfig.class }, properties = { + "spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json", + "spring.cloud.sentinel.datasource.ds1.file.data-type=json", + "spring.cloud.sentinel.datasource.ds1.file.rule-type=flow", + + "spring.cloud.sentinel.datasource.ds2.file.file=classpath: degraderule.json", + "spring.cloud.sentinel.datasource.ds2.file.data-type=json", + "spring.cloud.sentinel.datasource.ds2.file.rule-type=degrade", + + "spring.cloud.sentinel.datasource.ds3.file.file=classpath: authority.json", + "spring.cloud.sentinel.datasource.ds3.file.rule-type=authority", + + "spring.cloud.sentinel.datasource.ds4.file.file=classpath: system.json", + "spring.cloud.sentinel.datasource.ds4.file.rule-type=system", + + "spring.cloud.sentinel.datasource.ds5.file.file=classpath: param-flow.json", + "spring.cloud.sentinel.datasource.ds5.file.data-type=custom", + "spring.cloud.sentinel.datasource.ds5.file.converter-class=org.springframework.cloud.alibaba.sentinel.TestConverter", + "spring.cloud.sentinel.datasource.ds5.file.rule-type=param-flow" }) +public class SentinelDataSourceTests { + + @Autowired + private SentinelProperties sentinelProperties; + + @Test + public void contextLoads() throws Exception { + assertNotNull("SentinelProperties was not created", sentinelProperties); + + checkUrlPattern(); + } + + private void checkUrlPattern() { + assertEquals("SentinelProperties filter order was wrong", Integer.MIN_VALUE, + sentinelProperties.getFilter().getOrder()); + assertEquals("SentinelProperties filter url pattern size was wrong", 1, + sentinelProperties.getFilter().getUrlPatterns().size()); + assertEquals("SentinelProperties filter url pattern was wrong", "/*", + sentinelProperties.getFilter().getUrlPatterns().get(0)); + } + + @Test + public void testDataSource() { + assertEquals("DataSource size was wrong", 5, + sentinelProperties.getDatasource().size()); + assertNull("DataSource ds1 apollo is not null", + sentinelProperties.getDatasource().get("ds1").getApollo()); + assertNull("DataSource ds1 nacos is not null", + sentinelProperties.getDatasource().get("ds1").getNacos()); + assertNull("DataSource ds1 zk is not null", + sentinelProperties.getDatasource().get("ds1").getZk()); + assertNotNull("DataSource ds1 file is null", + sentinelProperties.getDatasource().get("ds1").getFile()); + + assertEquals("DataSource ds1 file dataType was wrong", "json", + sentinelProperties.getDatasource().get("ds1").getFile().getDataType()); + assertEquals("DataSource ds1 file ruleType was wrong", RuleType.FLOW, + sentinelProperties.getDatasource().get("ds1").getFile().getRuleType()); + + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ SentinelAutoConfiguration.class, + SentinelWebAutoConfiguration.class }) + @EnableFeignClients + public static class TestConfig { + + } + +} diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelFeignTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelFeignTests.java new file mode 100644 index 00000000..3f56f700 --- /dev/null +++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelFeignTests.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.sentinel; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.alibaba.sentinel.feign.SentinelFeignAutoConfiguration; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import com.alibaba.csp.sentinel.slots.block.RuleConstant; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; + +/** + * @author Jim + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { SentinelFeignTests.TestConfig.class }, properties = { + "feign.sentinel.enabled=true" }) +public class SentinelFeignTests { + + @Autowired + private EchoService echoService; + + @Autowired + private FooService fooService; + + @Autowired + private BarService barService; + + @Before + public void setUp() { + FlowRule rule1 = new FlowRule(); + rule1.setGrade(RuleConstant.FLOW_GRADE_QPS); + rule1.setCount(0); + rule1.setResource("GET:http://test-service/echo/{str}"); + rule1.setLimitApp("default"); + rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); + rule1.setStrategy(RuleConstant.STRATEGY_DIRECT); + FlowRule rule2 = new FlowRule(); + rule2.setGrade(RuleConstant.FLOW_GRADE_QPS); + rule2.setCount(0); + rule2.setResource("GET:http://foo-service/echo/{str}"); + rule2.setLimitApp("default"); + rule2.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); + rule2.setStrategy(RuleConstant.STRATEGY_DIRECT); + FlowRule rule3 = new FlowRule(); + rule3.setGrade(RuleConstant.FLOW_GRADE_QPS); + rule3.setCount(0); + rule3.setResource("GET:http://bar-service/bar"); + rule3.setLimitApp("default"); + rule3.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); + rule3.setStrategy(RuleConstant.STRATEGY_DIRECT); + FlowRuleManager.loadRules(Arrays.asList(rule1, rule2, rule3)); + } + + @Test + public void contextLoads() throws Exception { + assertNotNull("EchoService was not created", echoService); + assertNotNull("FooService was not created", fooService); + } + + @Test + public void testFeignClient() { + assertEquals("Sentinel Feign Client fallback success", "echo fallback", + echoService.echo("test")); + assertEquals("Sentinel Feign Client fallbackFactory success", "foo fallback", + fooService.echo("test")); + assertThatExceptionOfType(Exception.class).isThrownBy(() -> { + barService.bar(); + }); + + assertNotEquals("ToString method invoke was not in SentinelInvocationHandler", + echoService.toString(), fooService.toString()); + assertNotEquals("HashCode method invoke was not in SentinelInvocationHandler", + echoService.hashCode(), fooService.hashCode()); + assertFalse("Equals method invoke was not in SentinelInvocationHandler", + echoService.equals(fooService)); + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ SentinelFeignAutoConfiguration.class }) + @EnableFeignClients + public static class TestConfig { + + @Bean + public EchoServiceFallback echoServiceFallback() { + return new EchoServiceFallback(); + } + + @Bean + public CustomFallbackFactory customFallbackFactory() { + return new CustomFallbackFactory(); + } + + } + + @FeignClient(value = "test-service", fallback = EchoServiceFallback.class) + public interface EchoService { + @RequestMapping(path = "echo/{str}") + String echo(@RequestParam("str") String param); + } + + @FeignClient(value = "foo-service", fallbackFactory = CustomFallbackFactory.class) + public interface FooService { + @RequestMapping(path = "echo/{str}") + String echo(@RequestParam("str") String param); + } + + @FeignClient(value = "bar-service") + public interface BarService { + @RequestMapping(path = "bar") + String bar(); + } + + public static class EchoServiceFallback implements EchoService { + + @Override + public String echo(@RequestParam("str") String param) { + return "echo fallback"; + } + + } + + public static class FooServiceFallback implements FooService { + + @Override + public String echo(@RequestParam("str") String param) { + return "foo fallback"; + } + } + + public static class CustomFallbackFactory + implements feign.hystrix.FallbackFactory { + + private FooService fooService = new FooServiceFallback(); + + @Override + public FooService create(Throwable throwable) { + return fooService; + } + } + +} diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/TestConverter.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/TestConverter.java new file mode 100644 index 00000000..e7247a41 --- /dev/null +++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/TestConverter.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.sentinel; + +import java.io.IOException; +import java.util.List; + +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * @author Jim + */ +public class TestConverter implements Converter> { + private ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public List convert(String s) { + try { + return objectMapper.readValue(s, new TypeReference>() { + }); + } + catch (IOException e) { + e.printStackTrace(); + } + return null; + } +}