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;
+ }
+}