diff --git a/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/GrpcTestServer.java b/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/GrpcTestServer.java
index 48b5f48c..f46c5718 100644
--- a/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/GrpcTestServer.java
+++ b/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/GrpcTestServer.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * 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 com.alibaba.csp.sentinel.adapter.grpc;
import io.grpc.Server;
@@ -6,18 +21,18 @@ import io.grpc.ServerBuilder;
import java.io.IOException;
class GrpcTestServer {
+
private Server server;
- GrpcTestServer() {
- }
+ GrpcTestServer() {}
- void start(int port, boolean shouldintercept) throws IOException {
+ void start(int port, boolean shouldIntercept) throws IOException {
if (server != null) {
throw new IllegalStateException("Server already running!");
}
ServerBuilder> serverBuild = ServerBuilder.forPort(port)
- .addService(new FooServiceImpl());
- if (shouldintercept) {
+ .addService(new FooServiceImpl());
+ if (shouldIntercept) {
serverBuild.intercept(new SentinelGrpcServerInterceptor());
}
server = serverBuild.build();
diff --git a/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcClientInterceptorTest.java b/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcClientInterceptorTest.java
index 7c6972e6..bc1dba73 100755
--- a/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcClientInterceptorTest.java
+++ b/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcClientInterceptorTest.java
@@ -27,6 +27,8 @@ import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import io.grpc.StatusRuntimeException;
+import org.junit.After;
+import org.junit.Test;
import static org.junit.Assert.*;
@@ -41,9 +43,9 @@ public class SentinelGrpcClientInterceptorTest {
private final int threshold = 2;
private final GrpcTestServer server = new GrpcTestServer();
- private void configureFlowRule() {
+ private void configureFlowRule(int count) {
FlowRule rule = new FlowRule()
- .setCount(threshold)
+ .setCount(count)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setResource(resourceName)
.setLimitApp("default")
@@ -51,42 +53,44 @@ public class SentinelGrpcClientInterceptorTest {
FlowRuleManager.loadRules(Collections.singletonList(rule));
}
- //@Test
+ @Test
public void testGrpcClientInterceptor() throws Exception {
final int port = 19328;
- configureFlowRule();
+ configureFlowRule(threshold);
server.start(port, false);
FooServiceClient client = new FooServiceClient("localhost", port, new SentinelGrpcClientInterceptor());
- final int total = 8;
- for (int i = 0; i < total; i++) {
- sendRequest(client);
- }
+
+ assertTrue(sendRequest(client));
ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(resourceName, EntryType.OUT);
assertNotNull(clusterNode);
+ assertEquals(1, clusterNode.passQps());
- assertEquals((total - threshold) / 2, clusterNode.blockRequest());
- assertEquals(total / 2, clusterNode.totalRequest());
+ // Not allowed to pass.
+ configureFlowRule(0);
- long totalQps = clusterNode.totalQps();
- long passQps = clusterNode.passQps();
- long blockQps = clusterNode.blockQps();
- assertEquals(total, totalQps);
- assertEquals(total - threshold, blockQps);
- assertEquals(threshold, passQps);
+ // The second request will be blocked.
+ assertFalse(sendRequest(client));
+ assertEquals(1, clusterNode.blockQps());
server.stop();
}
- private void sendRequest(FooServiceClient client) {
+ private boolean sendRequest(FooServiceClient client) {
try {
FooResponse response = client.sayHello(FooRequest.newBuilder().setName("Sentinel").setId(666).build());
- System.out.println(ClusterBuilderSlot.getClusterNode(resourceName, EntryType.OUT).avgRt());
System.out.println("Response: " + response);
+ return true;
} catch (StatusRuntimeException ex) {
System.out.println("Blocked, cause: " + ex.getMessage());
+ return false;
}
}
+ @After
+ public void cleanUp() {
+ FlowRuleManager.loadRules(null);
+ ClusterBuilderSlot.getClusterNodeMap().clear();
+ }
}
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcServerInterceptorTest.java b/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcServerInterceptorTest.java
index 432a6281..da262ea3 100755
--- a/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcServerInterceptorTest.java
+++ b/sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcServerInterceptorTest.java
@@ -27,6 +27,8 @@ import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import io.grpc.StatusRuntimeException;
+import org.junit.After;
+import org.junit.Test;
import static org.junit.Assert.*;
@@ -43,9 +45,9 @@ public class SentinelGrpcServerInterceptorTest {
private FooServiceClient client;
- private void configureFlowRule() {
+ private void configureFlowRule(int count) {
FlowRule rule = new FlowRule()
- .setCount(threshold)
+ .setCount(count)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setResource(resourceName)
.setLimitApp("default")
@@ -53,41 +55,44 @@ public class SentinelGrpcServerInterceptorTest {
FlowRuleManager.loadRules(Collections.singletonList(rule));
}
- //@Test
+ @Test
public void testGrpcServerInterceptor() throws Exception {
final int port = 19329;
client = new FooServiceClient("localhost", port);
- configureFlowRule();
+ configureFlowRule(threshold);
server.start(port, true);
- final int total = 8;
- for (int i = 0; i < total; i++) {
- sendRequest();
- }
+ assertTrue(sendRequest());
ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(resourceName, EntryType.IN);
assertNotNull(clusterNode);
+ assertEquals(1, clusterNode.passQps());
- assertEquals((total - threshold) / 2, clusterNode.blockRequest());
- assertEquals(total / 2, clusterNode.totalRequest());
+ // Not allowed to pass.
+ configureFlowRule(0);
- long totalQps = clusterNode.totalQps();
- long passQps = clusterNode.passQps();
- long blockQps = clusterNode.blockQps();
- assertEquals(total, totalQps);
- assertEquals(total - threshold, blockQps);
- assertEquals(threshold, passQps);
+ // The second request will be blocked.
+ assertFalse(sendRequest());
+ assertEquals(1, clusterNode.blockQps());
server.stop();
}
- private void sendRequest() {
+ private boolean sendRequest() {
try {
FooResponse response = client.anotherHello(FooRequest.newBuilder().setName("Sentinel").setId(666).build());
System.out.println("Response: " + response);
+ return true;
} catch (StatusRuntimeException ex) {
System.out.println("Blocked, cause: " + ex.getMessage());
+ return false;
}
}
+
+ @After
+ public void cleanUp() {
+ FlowRuleManager.loadRules(null);
+ ClusterBuilderSlot.getClusterNodeMap().clear();
+ }
}
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-web-servlet/pom.xml b/sentinel-adapter/sentinel-web-servlet/pom.xml
index 335b5137..9e4310a9 100755
--- a/sentinel-adapter/sentinel-web-servlet/pom.xml
+++ b/sentinel-adapter/sentinel-web-servlet/pom.xml
@@ -28,5 +28,23 @@
${servlet.api.version}
provided
+
+
+ junit
+ junit
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ 1.5.17.RELEASE
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ 1.5.17.RELEASE
+ test
+
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/WebCallbackManager.java b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/WebCallbackManager.java
index af392e51..73231bcf 100755
--- a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/WebCallbackManager.java
+++ b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/WebCallbackManager.java
@@ -57,8 +57,7 @@ public class WebCallbackManager {
return requestOriginParser;
}
- public static void setRequestOriginParser(
- RequestOriginParser requestOriginParser) {
+ public static void setRequestOriginParser(RequestOriginParser requestOriginParser) {
WebCallbackManager.requestOriginParser = requestOriginParser;
}
}
diff --git a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/util/FilterUtil.java b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/util/FilterUtil.java
index 4dbc1bfc..626aecf1 100755
--- a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/util/FilterUtil.java
+++ b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/util/FilterUtil.java
@@ -64,7 +64,7 @@ public final class FilterUtil {
url.append("?").append(request.getQueryString());
}
- if (StringUtil.isEmpty(WebServletConfig.getBlockPage())) {
+ if (StringUtil.isBlank(WebServletConfig.getBlockPage())) {
writeDefaultBlockedPage(response);
} else {
String redirectUrl = WebServletConfig.getBlockPage() + "?http_referer=" + url.toString();
@@ -75,7 +75,7 @@ public final class FilterUtil {
private static void writeDefaultBlockedPage(HttpServletResponse response) throws IOException {
PrintWriter out = response.getWriter();
- out.println("Blocked by Sentinel (flow limiting)");
+ out.print(DEFAULT_BLOCK_MSG);
out.flush();
out.close();
}
@@ -183,5 +183,7 @@ public final class FilterUtil {
return i;
}
+ public static final String DEFAULT_BLOCK_MSG = "Blocked by Sentinel (flow limiting)";
+
private FilterUtil() {}
}
diff --git a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilterTest.java b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilterTest.java
new file mode 100644
index 00000000..2602f17d
--- /dev/null
+++ b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilterTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * 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 com.alibaba.csp.sentinel.adapter.servlet;
+
+import java.util.Collections;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.alibaba.csp.sentinel.adapter.servlet.callback.DefaultUrlCleaner;
+import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
+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.config.WebServletConfig;
+import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+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;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.junit.Assert.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+/**
+ * @author Eric Zhao
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = TestApplication.class)
+@AutoConfigureMockMvc
+public class CommonFilterTest {
+
+ private static final String HELLO_STR = "Hello!";
+
+ @Autowired
+ private MockMvc mvc;
+
+ private void configureRulesFor(String resource, int count) {
+ configureRulesFor(resource, count, "default");
+ }
+
+ private void configureRulesFor(String resource, int count, String limitApp) {
+ FlowRule rule = new FlowRule()
+ .setCount(count)
+ .setGrade(RuleConstant.FLOW_GRADE_QPS);
+ rule.setResource(resource);
+ if (StringUtil.isNotBlank(limitApp)) {
+ rule.setLimitApp(limitApp);
+ }
+ FlowRuleManager.loadRules(Collections.singletonList(rule));
+ }
+
+ @Test
+ public void testCommonFilterMiscellaneous() throws Exception {
+ String url = "/hello";
+ this.mvc.perform(get(url))
+ .andExpect(status().isOk())
+ .andExpect(content().string(HELLO_STR));
+
+ ClusterNode cn = ClusterBuilderSlot.getClusterNode(url);
+ assertNotNull(cn);
+ assertEquals(1, cn.passQps());
+
+ testCommonBlockAndRedirectBlockPage(url, cn);
+
+ // Test for url cleaner.
+ testUrlCleaner();
+
+ testCustomOriginParser();
+ }
+
+ private void testCommonBlockAndRedirectBlockPage(String url, ClusterNode cn) throws Exception {
+ configureRulesFor(url, 0);
+ // The request will be blocked and response is default block message.
+ this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN))
+ .andExpect(status().isOk())
+ .andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG));
+ assertEquals(1, cn.blockQps());
+
+ // Test for redirect.
+ String redirectUrl = "http://some-location.com";
+ WebServletConfig.setBlockPage(redirectUrl);
+ this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(header().string("Location", redirectUrl + "?http_referer=http://localhost/hello"));
+
+ FlowRuleManager.loadRules(null);
+ WebServletConfig.setBlockPage("");
+ }
+
+ private void testUrlCleaner() throws Exception {
+ final String fooPrefix = "/foo/";
+ String url1 = fooPrefix + 1;
+ String url2 = fooPrefix + 2;
+ WebCallbackManager.setUrlCleaner(new UrlCleaner() {
+ @Override
+ public String clean(String originUrl) {
+ if (originUrl.startsWith(fooPrefix)) {
+ return "/foo/*";
+ }
+ return originUrl;
+ }
+ });
+ this.mvc.perform(get(url1).accept(MediaType.TEXT_PLAIN))
+ .andExpect(status().isOk())
+ .andExpect(content().string("Hello 1"));
+ this.mvc.perform(get(url2).accept(MediaType.TEXT_PLAIN))
+ .andExpect(status().isOk())
+ .andExpect(content().string("Hello 2"));
+ ClusterNode cn = ClusterBuilderSlot.getClusterNode(fooPrefix + "*");
+ assertEquals(2, cn.passQps());
+ assertNull(ClusterBuilderSlot.getClusterNode(url1));
+ assertNull(ClusterBuilderSlot.getClusterNode(url2));
+
+ WebCallbackManager.setUrlCleaner(new DefaultUrlCleaner());
+ }
+
+ private void testCustomOriginParser() throws Exception {
+ String url = "/hello";
+ String limitOrigin = "userA";
+ final String headerName = "S-User";
+ configureRulesFor(url, 0, limitOrigin);
+
+ WebCallbackManager.setRequestOriginParser(new RequestOriginParser() {
+ @Override
+ public String parseOrigin(HttpServletRequest request) {
+ String origin = request.getHeader(headerName);
+ return origin != null ? origin : "";
+ }
+ });
+
+ this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN).header(headerName, "userB"))
+ .andExpect(status().isOk())
+ .andExpect(content().string(HELLO_STR));
+ // This will be blocked.
+ this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN).header(headerName, limitOrigin))
+ .andExpect(status().isOk())
+ .andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG));
+ this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN))
+ .andExpect(status().isOk())
+ .andExpect(content().string(HELLO_STR));
+
+ WebCallbackManager.setRequestOriginParser(null);
+ FlowRuleManager.loadRules(null);
+ }
+
+ @After
+ public void cleanUp() {
+ FlowRuleManager.loadRules(null);
+ ClusterBuilderSlot.getClusterNodeMap().clear();
+ }
+}
diff --git a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/FilterConfig.java b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/FilterConfig.java
new file mode 100644
index 00000000..119c6b9b
--- /dev/null
+++ b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/FilterConfig.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * 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 com.alibaba.csp.sentinel.adapter.servlet;
+
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author Eric Zhao
+ */
+@Configuration
+public class FilterConfig {
+
+ @Bean
+ public FilterRegistrationBean sentinelFilterRegistration() {
+ FilterRegistrationBean registration = new FilterRegistrationBean();
+ registration.setFilter(new CommonFilter());
+ registration.addUrlPatterns("/*");
+ registration.setName("sentinelFilter");
+ registration.setOrder(1);
+
+ return registration;
+ }
+}
diff --git a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/TestApplication.java b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/TestApplication.java
new file mode 100644
index 00000000..01913205
--- /dev/null
+++ b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/TestApplication.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * 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 com.alibaba.csp.sentinel.adapter.servlet;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author Eric Zhao
+ */
+@SpringBootApplication
+public class TestApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(TestApplication.class, args);
+ }
+}
diff --git a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/TestController.java b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/TestController.java
new file mode 100644
index 00000000..6221190b
--- /dev/null
+++ b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/TestController.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * 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 com.alibaba.csp.sentinel.adapter.servlet;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author Eric Zhao
+ */
+@RestController
+public class TestController {
+
+ @GetMapping("/hello")
+ public String apiHello() {
+ return "Hello!";
+ }
+
+ @GetMapping("/err")
+ public String apiError() {
+ return "Oops...";
+ }
+
+ @GetMapping("/foo/{id}")
+ public String apiFoo(@PathVariable("id") Long id) {
+ return "Hello " + id;
+ }
+}