Переглянути джерело

Update test cases for Sentinel web filter and gRPC adapter

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
master
Eric Zhao 6 роки тому
джерело
коміт
695fa9d84c
10 змінених файлів з 373 додано та 44 видалено
  1. +20
    -5
      sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/GrpcTestServer.java
  2. +22
    -18
      sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcClientInterceptorTest.java
  3. +22
    -17
      sentinel-adapter/sentinel-grpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/grpc/SentinelGrpcServerInterceptorTest.java
  4. +18
    -0
      sentinel-adapter/sentinel-web-servlet/pom.xml
  5. +1
    -2
      sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/WebCallbackManager.java
  6. +4
    -2
      sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/util/FilterUtil.java
  7. +176
    -0
      sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilterTest.java
  8. +38
    -0
      sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/FilterConfig.java
  9. +30
    -0
      sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/TestApplication.java
  10. +42
    -0
      sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/TestController.java

+ 20
- 5
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();


+ 22
- 18
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();
}
}

+ 22
- 17
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();
}
}

+ 18
- 0
sentinel-adapter/sentinel-web-servlet/pom.xml Переглянути файл

@@ -28,5 +28,23 @@
<version>${servlet.api.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.17.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.5.17.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

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

+ 4
- 2
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() {}
}

+ 176
- 0
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();
}
}

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

+ 30
- 0
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);
}
}

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

Завантаження…
Відмінити
Зберегти