diff --git a/.github/actions/scenarios/spring/lane/action.yml b/.github/actions/scenarios/spring/lane/action.yml index 58ffc26dd4..40802443af 100644 --- a/.github/actions/scenarios/spring/lane/action.yml +++ b/.github/actions/scenarios/spring/lane/action.yml @@ -186,6 +186,7 @@ runs: shell: bash env: SPRING_CLOUD_VERSION: ${{ matrix.springCloudVersion }} + SPRING_BOOT_VERSION: ${{ matrix.springBootVersion }} run: mvn test -Dsermant.integration.test.type=LANE --file sermant-integration-tests/spring-test/pom.xml - name: exit if: always() diff --git a/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-consumer/src/main/java/com/huaweicloud/integration/service/LaneServiceImpl.java b/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-consumer/src/main/java/com/huaweicloud/integration/service/LaneServiceImpl.java index c7bb0f796c..86f030f520 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-consumer/src/main/java/com/huaweicloud/integration/service/LaneServiceImpl.java +++ b/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-consumer/src/main/java/com/huaweicloud/integration/service/LaneServiceImpl.java @@ -63,6 +63,9 @@ public class LaneServiceImpl implements LaneService { public Map getLaneByDubbo(String name, LaneTestEntity laneTestEntity, String[] arr, List list, Map map) { RpcContext.getContext().setAttachment(Constant.TAG_KEY, Constant.TAG); + + // dubbo 2.5.0 - 2.5.3存在bug,会传递异步调用,所以需要手动设置为同步 + RpcContext.getContext().setAttachment("async", "false"); Map result = new HashMap<>(fooService.getAttachments()); result.put(applicationName, getMetadata()); return result; diff --git a/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-controller/src/main/java/com/huaweicloud/integration/controller/LaneController.java b/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-controller/src/main/java/com/huaweicloud/integration/controller/LaneController.java index ba1383ee7e..86291e4ec2 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-controller/src/main/java/com/huaweicloud/integration/controller/LaneController.java +++ b/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-controller/src/main/java/com/huaweicloud/integration/controller/LaneController.java @@ -30,6 +30,8 @@ import java.util.Collections; import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import javax.annotation.Resource; @@ -50,13 +52,17 @@ public class LaneController { * * @param entity entity * @return map + * @throws ExecutionException ExecutionException + * @throws InterruptedException InterruptedException */ @GetMapping("/getLaneByDubbo") - public Map getLaneByDubbo(TestEntity entity) { + public Map getLaneByDubbo(TestEntity entity) throws ExecutionException, InterruptedException { RpcContext.getContext().setAttachment(Constant.LANE_TEST_USER_ID, String.valueOf(entity.getId())); - return laneService.getLaneByDubbo(entity.getName(), new LaneTestEntity(entity.getLaneId(), entity.isEnabled()), + laneService.getLaneByDubbo(entity.getName(), new LaneTestEntity(entity.getLaneId(), entity.isEnabled()), new String[]{entity.getArrName()}, Collections.singletonList(entity.getListId()), Collections.singletonMap("name", entity.getMapName())); + Future> future = RpcContext.getContext().getFuture(); + return future.get(); } /** @@ -66,13 +72,18 @@ public Map getLaneByDubbo(TestEntity entity) { * @param id id * @param enabled enabled * @return map + * @throws ExecutionException ExecutionException + * @throws InterruptedException InterruptedException */ @GetMapping("/getLaneByFeign") public Map getLaneByFeign(@RequestParam(value = "name", defaultValue = "") String name, @RequestParam(value = "id", defaultValue = "0") int id, - @RequestParam(value = "enabled", defaultValue = "false") boolean enabled) { + @RequestParam(value = "enabled", defaultValue = "false") boolean enabled) + throws ExecutionException, InterruptedException { RpcContext.getContext().setAttachment(Constant.LANE_TEST_USER_ID, String.valueOf(id)); - return laneService.getLaneByFeign(name, new LaneTestEntity(id, enabled)); + laneService.getLaneByFeign(name, new LaneTestEntity(id, enabled)); + Future> future = RpcContext.getContext().getFuture(); + return future.get(); } /** @@ -82,12 +93,17 @@ public Map getLaneByFeign(@RequestParam(value = "name", defaultV * @param id id * @param enabled enabled * @return map + * @throws ExecutionException ExecutionException + * @throws InterruptedException InterruptedException */ @GetMapping("/getLaneByRest") public Map getLaneByRest(@RequestParam(value = "name", defaultValue = "") String name, @RequestParam(value = "id", defaultValue = "0") int id, - @RequestParam(value = "enabled", defaultValue = "false") boolean enabled) { + @RequestParam(value = "enabled", defaultValue = "false") boolean enabled) + throws ExecutionException, InterruptedException { RpcContext.getContext().setAttachment(Constant.LANE_TEST_USER_ID, String.valueOf(id)); - return laneService.getLaneByRest(name, new LaneTestEntity(id, enabled)); + laneService.getLaneByRest(name, new LaneTestEntity(id, enabled)); + Future> future = RpcContext.getContext().getFuture(); + return future.get(); } } \ No newline at end of file diff --git a/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-controller/src/main/resources/dubbo/consumer.xml b/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-controller/src/main/resources/dubbo/consumer.xml index b4eca0b1e5..7789f9afb2 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-controller/src/main/resources/dubbo/consumer.xml +++ b/sermant-integration-tests/dubbo-test/dubbo-2-6-integration-controller/src/main/resources/dubbo/consumer.xml @@ -20,5 +20,5 @@ interface="com.huaweicloud.integration.service.MetadataService" timeout="10000"/> + interface="com.huaweicloud.integration.service.LaneService" timeout="10000" async="true"/> diff --git a/sermant-integration-tests/dubbo-test/dubbo-2-7-integration-controller/src/main/java/com/huaweicloud/integration/controller/LaneController.java b/sermant-integration-tests/dubbo-test/dubbo-2-7-integration-controller/src/main/java/com/huaweicloud/integration/controller/LaneController.java index 82580ed6c2..9ee5b4b6e0 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-2-7-integration-controller/src/main/java/com/huaweicloud/integration/controller/LaneController.java +++ b/sermant-integration-tests/dubbo-test/dubbo-2-7-integration-controller/src/main/java/com/huaweicloud/integration/controller/LaneController.java @@ -29,6 +29,8 @@ import java.util.Collections; import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import javax.annotation.Resource; @@ -49,13 +51,17 @@ public class LaneController { * * @param entity entity * @return map + * @throws ExecutionException ExecutionException + * @throws InterruptedException InterruptedException */ @GetMapping("/getLaneByDubbo") - public Map getLaneByDubbo(TestEntity entity) { + public Map getLaneByDubbo(TestEntity entity) throws ExecutionException, InterruptedException { RpcContext.getContext().setAttachment(Constant.LANE_TEST_USER_ID, String.valueOf(entity.getId())); - return laneService.getLaneByDubbo(entity.getName(), new LaneTestEntity(entity.getLaneId(), entity.isEnabled()), + laneService.getLaneByDubbo(entity.getName(), new LaneTestEntity(entity.getLaneId(), entity.isEnabled()), new String[]{entity.getArrName()}, Collections.singletonList(entity.getListId()), Collections.singletonMap("name", entity.getMapName())); + Future> future = RpcContext.getContext().getFuture(); + return future.get(); } /** @@ -65,13 +71,18 @@ public Map getLaneByDubbo(TestEntity entity) { * @param id id * @param enabled enabled * @return map + * @throws ExecutionException ExecutionException + * @throws InterruptedException InterruptedException */ @GetMapping("/getLaneByFeign") public Map getLaneByFeign(@RequestParam(value = "name", defaultValue = "") String name, @RequestParam(value = "id", defaultValue = "0") int id, - @RequestParam(value = "enabled", defaultValue = "false") boolean enabled) { + @RequestParam(value = "enabled", defaultValue = "false") boolean enabled) + throws ExecutionException, InterruptedException { RpcContext.getContext().setAttachment(Constant.LANE_TEST_USER_ID, String.valueOf(id)); - return laneService.getLaneByFeign(name, new LaneTestEntity(id, enabled)); + laneService.getLaneByFeign(name, new LaneTestEntity(id, enabled)); + Future> future = RpcContext.getContext().getFuture(); + return future.get(); } /** @@ -81,12 +92,17 @@ public Map getLaneByFeign(@RequestParam(value = "name", defaultV * @param id id * @param enabled enabled * @return map + * @throws ExecutionException ExecutionException + * @throws InterruptedException InterruptedException */ @GetMapping("/getLaneByRest") public Map getLaneByRest(@RequestParam(value = "name", defaultValue = "") String name, @RequestParam(value = "id", defaultValue = "0") int id, - @RequestParam(value = "enabled", defaultValue = "false") boolean enabled) { + @RequestParam(value = "enabled", defaultValue = "false") boolean enabled) + throws ExecutionException, InterruptedException { RpcContext.getContext().setAttachment(Constant.LANE_TEST_USER_ID, String.valueOf(id)); - return laneService.getLaneByRest(name, new LaneTestEntity(id, enabled)); + laneService.getLaneByRest(name, new LaneTestEntity(id, enabled)); + Future> future = RpcContext.getContext().getFuture(); + return future.get(); } } \ No newline at end of file diff --git a/sermant-integration-tests/dubbo-test/dubbo-2-7-integration-controller/src/main/resources/dubbo/consumer.xml b/sermant-integration-tests/dubbo-test/dubbo-2-7-integration-controller/src/main/resources/dubbo/consumer.xml index 77fbc5b8e5..62fec4e074 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-2-7-integration-controller/src/main/resources/dubbo/consumer.xml +++ b/sermant-integration-tests/dubbo-test/dubbo-2-7-integration-controller/src/main/resources/dubbo/consumer.xml @@ -13,5 +13,5 @@ interface="com.huaweicloud.integration.service.MetadataService" timeout="10000"/> + interface="com.huaweicloud.integration.service.LaneService" timeout="10000" async="true"/> diff --git a/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/pom.xml b/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/pom.xml index eaa2d9385f..2f2ccaac03 100644 --- a/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/pom.xml +++ b/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/pom.xml @@ -66,6 +66,10 @@ 1.0.0 compile + + org.springframework.boot + spring-boot-starter-webflux + feign-consumer diff --git a/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/src/main/java/com/huaweicloud/spring/feign/consumer/FeignConsumerApplication.java b/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/src/main/java/com/huaweicloud/spring/feign/consumer/FeignConsumerApplication.java index 19b25f7c12..a1a7ebeb0e 100644 --- a/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/src/main/java/com/huaweicloud/spring/feign/consumer/FeignConsumerApplication.java +++ b/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/src/main/java/com/huaweicloud/spring/feign/consumer/FeignConsumerApplication.java @@ -21,8 +21,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; +import org.springframework.web.reactive.function.client.WebClient; /** * 启动类 @@ -31,9 +34,9 @@ * @since 2022-07-29 */ @SpringBootApplication(scanBasePackages = { - "com.huaweicloud.spring.feign.consumer.controller", - "com.huaweicloud.spring.common.loadbalancer.feign", - "com.huaweicloud.spring.feign.api.configuration" + "com.huaweicloud.spring.feign.consumer.controller", + "com.huaweicloud.spring.common.loadbalancer.feign", + "com.huaweicloud.spring.feign.api.configuration" }) @EnableFeignClients(basePackages = "com.huaweicloud.spring.feign.api") public class FeignConsumerApplication { @@ -55,4 +58,27 @@ public static void main(String[] args) { public ErrorDecoder errorDecoder() { return new FeignErrorDecoder(); } + + /** + * webclient,需要懒加载以避免spring cloud Finchley.x的bug + * + * @param builder 构造器 + * @return webclient + */ + @Bean + @Lazy + public WebClient webClient(WebClient.Builder builder) { + return builder.build(); + } + + /** + * 构造器 + * + * @return builder + */ + @Bean + @LoadBalanced + public WebClient.Builder builder() { + return WebClient.builder(); + } } diff --git a/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/src/main/java/com/huaweicloud/spring/feign/consumer/controller/RouterController.java b/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/src/main/java/com/huaweicloud/spring/feign/consumer/controller/RouterController.java index e6916c9445..80ed09af38 100644 --- a/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/src/main/java/com/huaweicloud/spring/feign/consumer/controller/RouterController.java +++ b/sermant-integration-tests/spring-test/spring-common-demos/spring-common-feign/feign-consumer/src/main/java/com/huaweicloud/spring/feign/consumer/controller/RouterController.java @@ -19,12 +19,19 @@ import com.huaweicloud.spring.feign.api.BootRegistryService; import com.huaweicloud.spring.feign.api.FeignService; +import reactor.core.publisher.Mono; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec; +import org.springframework.web.reactive.function.client.WebClient.ResponseSpec; import java.util.HashMap; import java.util.Map; @@ -38,6 +45,8 @@ @RestController @RequestMapping("/router") public class RouterController { + private static final String PROVIDER_URL = "http://feign-provider/lane"; + @Value("${spring.application.name}") private String applicationName; @@ -50,6 +59,10 @@ public class RouterController { @Autowired private FeignService feignService; + @Autowired + @Lazy + private WebClient client; + /** * 获取区域 * @@ -89,6 +102,28 @@ public Map getLaneByCloud(@RequestParam(value = "name", defaultV return result; } + /** + * 获取泳道信息 + * + * @param name name + * @param id id + * @param enabled enabled + * @return 泳道信息 + */ + @GetMapping("/cloud/getLaneByWebclient") + public Mono> getLaneByCloudWebclient( + @RequestParam(value = "name", defaultValue = "") String name, + @RequestParam(value = "id", defaultValue = "0") int id, + @RequestParam(value = "enabled", defaultValue = "false") boolean enabled) { + RequestHeadersSpec requestHeadersSpec = client.get().uri(PROVIDER_URL); + ResponseSpec spec = requestHeadersSpec.retrieve(); + return spec.bodyToMono(new ParameterizedTypeReference>() { + }).map(map -> { + map.put(applicationName, getMetadata()); + return map; + }); + } + private Map getMetadata() { Map meta = new HashMap<>(); meta.put("version", version); diff --git a/sermant-integration-tests/spring-test/spring-common-demos/spring-common-zuul/src/main/resources/application.yml b/sermant-integration-tests/spring-test/spring-common-demos/spring-common-zuul/src/main/resources/application.yml index 8d8c1e5a01..1246e8fd65 100644 --- a/sermant-integration-tests/spring-test/spring-common-demos/spring-common-zuul/src/main/resources/application.yml +++ b/sermant-integration-tests/spring-test/spring-common-demos/spring-common-zuul/src/main/resources/application.yml @@ -20,7 +20,7 @@ hystrix: execution: isolation: thread: - timeoutInMilliseconds: 10000 + timeoutInMilliseconds: 50000 ribbon: ConnectTimeout: 10000 diff --git a/sermant-integration-tests/spring-test/spring-intergration-test/src/test/java/com/huaweicloud/intergration/lane/LaneConfigTest.java b/sermant-integration-tests/spring-test/spring-intergration-test/src/test/java/com/huaweicloud/intergration/lane/LaneConfigTest.java index bd81b17fee..f21a5f4088 100644 --- a/sermant-integration-tests/spring-test/spring-intergration-test/src/test/java/com/huaweicloud/intergration/lane/LaneConfigTest.java +++ b/sermant-integration-tests/spring-test/spring-intergration-test/src/test/java/com/huaweicloud/intergration/lane/LaneConfigTest.java @@ -61,53 +61,53 @@ public LaneConfigTest() { @Test public void addGatewayConfig() { String content = "---\n" - + "- kind: route.sermant.io/lane\n" - + " description: lane\n" - + " rules:\n" - + " - precedence: 1\n" - + " match:\n" - + " method: get\n" - + " path: \"/rest/router/cloud/getLane\"\n" - + " protocol: http\n" - + " headers:\n" - + " x-user-id:\n" - + " greater: 100\n" - + " caseInsensitive: false\n" - + " parameters:\n" - + " name:\n" - + " in: [BaR]\n" - + " caseInsensitive: true\n" - + " id:\n" - + " less: 10\n" - + " enabled:\n" - + " exact: true\n" - + " route:\n" - + " - tag-inject:\n" - + " x-sermant-flag1: gray1\n" - + " x-sermant-flag2: gray2\n" - + " weight: 100\n" - + " - precedence: 2\n" - + " match:\n" - + " method: get\n" - + " path: \"/feign/router/cloud/getLane\"\n" - + " protocol: http\n" - + " headers:\n" - + " x-user-id:\n" - + " greater: 100\n" - + " caseInsensitive: false\n" - + " parameters:\n" - + " name:\n" - + " in: [BaR]\n" - + " caseInsensitive: true\n" - + " id:\n" - + " less: 10\n" - + " enabled:\n" - + " exact: true\n" - + " route:\n" - + " - tag-inject:\n" - + " x-sermant-flag3: gray3\n" - + " x-sermant-flag4: gray4\n" - + " weight: 100"; + + "- kind: route.sermant.io/lane\n" + + " description: lane\n" + + " rules:\n" + + " - precedence: 1\n" + + " match:\n" + + " method: get\n" + + " path: \"/rest/router/cloud/getLane\"\n" + + " protocol: http\n" + + " headers:\n" + + " x-user-id:\n" + + " greater: 100\n" + + " caseInsensitive: false\n" + + " parameters:\n" + + " name:\n" + + " in: [BaR]\n" + + " caseInsensitive: true\n" + + " id:\n" + + " less: 10\n" + + " enabled:\n" + + " exact: true\n" + + " route:\n" + + " - tag-inject:\n" + + " x-sermant-flag1: gray1\n" + + " x-sermant-flag2: gray2\n" + + " weight: 100\n" + + " - precedence: 2\n" + + " match:\n" + + " method: get\n" + + " path: \"^/feign/router/cloud/getLane.*\"\n" + + " protocol: http\n" + + " headers:\n" + + " x-user-id:\n" + + " greater: 100\n" + + " caseInsensitive: false\n" + + " parameters:\n" + + " name:\n" + + " in: [BaR]\n" + + " caseInsensitive: true\n" + + " id:\n" + + " less: 10\n" + + " enabled:\n" + + " exact: true\n" + + " route:\n" + + " - tag-inject:\n" + + " x-sermant-flag3: gray3\n" + + " x-sermant-flag4: gray4\n" + + " weight: 100"; Assertions.assertTrue(kieClient.publishConfig(ZUUL_KEY, content)); Assertions.assertTrue(kieClient.publishConfig(GATEWAY_KEY, content)); } @@ -118,98 +118,98 @@ public void addGatewayConfig() { @Test public void addConsumerConfig() { String restContent = "---\n" - + "- kind: route.sermant.io/lane\n" - + " description: consumer-lane\n" - + " rules:\n" - + " - precedence: 1\n" - + " match:\n" - + " method: get\n" - + " path: \"/router/cloud/getLane\"\n" - + " protocol: http\n" - + " headers:\n" - + " x-user-id:\n" - + " less: 100\n" - + " caseInsensitive: false\n" - + " parameters:\n" - + " name:\n" - + " in: [BaR]\n" - + " caseInsensitive: true\n" - + " id:\n" - + " greater: 10\n" - + " enabled:\n" - + " exact: true\n" - + " route:\n" - + " - tag-inject:\n" - + " x-sermant-flag5: gray5\n" - + " weight: 100\n" - + "- kind: routematcher.sermant.io/flow\n" - + " discription: consumer-flow\n" - + " rules:\n" - + " - precedence: 1\n" - + " match:\n" - + " headers:\n" - + " x-sermant-flag1:\n" - + " exact: gray1\n" - + " route:\n" - + " - weight: 100\n" - + " tags:\n" - + " version: 1.0.1\n" - + " - precedence: 2\n" - + " match:\n" - + " headers:\n" - + " x-sermant-flag3:\n" - + " exact: gray3\n" - + " route:\n" - + " - weight: 100\n" - + " tags:\n" - + " version: 1.0.1"; + + "- kind: route.sermant.io/lane\n" + + " description: consumer-lane\n" + + " rules:\n" + + " - precedence: 1\n" + + " match:\n" + + " method: get\n" + + " path: \"/router/cloud/getLane\"\n" + + " protocol: http\n" + + " headers:\n" + + " x-user-id:\n" + + " less: 100\n" + + " caseInsensitive: false\n" + + " parameters:\n" + + " name:\n" + + " in: [BaR]\n" + + " caseInsensitive: true\n" + + " id:\n" + + " greater: 10\n" + + " enabled:\n" + + " exact: true\n" + + " route:\n" + + " - tag-inject:\n" + + " x-sermant-flag5: gray5\n" + + " weight: 100\n" + + "- kind: routematcher.sermant.io/flow\n" + + " discription: consumer-flow\n" + + " rules:\n" + + " - precedence: 1\n" + + " match:\n" + + " headers:\n" + + " x-sermant-flag1:\n" + + " exact: gray1\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0.1\n" + + " - precedence: 2\n" + + " match:\n" + + " headers:\n" + + " x-sermant-flag3:\n" + + " exact: gray3\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0.1"; Assertions.assertTrue(kieClient.publishConfig(REST_CONSUMER_KEY, restContent)); String feignContent = "---\n" - + "- kind: route.sermant.io/lane\n" - + " description: consumer-lane\n" - + " rules:\n" - + " - precedence: 1\n" - + " match:\n" - + " method: get\n" - + " path: \"/router/cloud/getLane\"\n" - + " protocol: http\n" - + " headers:\n" - + " x-user-id:\n" - + " less: 100\n" - + " caseInsensitive: false\n" - + " parameters:\n" - + " name:\n" - + " in: [FOO]\n" - + " id:\n" - + " less: 10\n" - + " enabled:\n" - + " exact: true\n" - + " route:\n" - + " - tag-inject:\n" - + " x-sermant-flag6: gray6\n" - + " weight: 100\n" - + "- kind: routematcher.sermant.io/flow\n" - + " discription: consumer-flow\n" - + " rules:\n" - + " - precedence: 1\n" - + " match:\n" - + " headers:\n" - + " x-sermant-flag1:\n" - + " exact: gray1\n" - + " route:\n" - + " - weight: 100\n" - + " tags:\n" - + " version: 1.0.1\n" - + " - precedence: 2\n" - + " match:\n" - + " headers:\n" - + " x-sermant-flag3:\n" - + " exact: gray3\n" - + " route:\n" - + " - weight: 100\n" - + " tags:\n" - + " version: 1.0.1"; + + "- kind: route.sermant.io/lane\n" + + " description: consumer-lane\n" + + " rules:\n" + + " - precedence: 1\n" + + " match:\n" + + " method: get\n" + + " path: \"^/router/cloud/getLane.*\"\n" + + " protocol: http\n" + + " headers:\n" + + " x-user-id:\n" + + " less: 100\n" + + " caseInsensitive: false\n" + + " parameters:\n" + + " name:\n" + + " in: [FOO]\n" + + " id:\n" + + " less: 10\n" + + " enabled:\n" + + " exact: true\n" + + " route:\n" + + " - tag-inject:\n" + + " x-sermant-flag6: gray6\n" + + " weight: 100\n" + + "- kind: routematcher.sermant.io/flow\n" + + " discription: consumer-flow\n" + + " rules:\n" + + " - precedence: 1\n" + + " match:\n" + + " headers:\n" + + " x-sermant-flag1:\n" + + " exact: gray1\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0.1\n" + + " - precedence: 2\n" + + " match:\n" + + " headers:\n" + + " x-sermant-flag3:\n" + + " exact: gray3\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0.1"; Assertions.assertTrue(kieClient.publishConfig(FEIGN_CONSUMER_KEY, feignContent)); } @@ -219,33 +219,33 @@ public void addConsumerConfig() { @Test public void addProviderConfig() { String restContent = "---\n" - + "- kind: routematcher.sermant.io/flow\n" - + " discription: provider-flow\n" - + " rules:\n" - + " - precedence: 1\n" - + " match:\n" - + " headers:\n" - + " x-sermant-flag5:\n" - + " exact: gray5\n" - + " route:\n" - + " - weight: 100\n" - + " tags:\n" - + " version: 1.0.1"; + + "- kind: routematcher.sermant.io/flow\n" + + " discription: provider-flow\n" + + " rules:\n" + + " - precedence: 1\n" + + " match:\n" + + " headers:\n" + + " x-sermant-flag5:\n" + + " exact: gray5\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0.1"; Assertions.assertTrue(kieClient.publishConfig(REST_PROVIDER_KEY, restContent)); String feignContent = "---\n" - + "- kind: routematcher.sermant.io/flow\n" - + " discription: provider-flow\n" - + " rules:\n" - + " - precedence: 1\n" - + " match:\n" - + " headers:\n" - + " x-sermant-flag6:\n" - + " exact: gray6\n" - + " route:\n" - + " - weight: 100\n" - + " tags:\n" - + " version: 1.0.1"; + + "- kind: routematcher.sermant.io/flow\n" + + " discription: provider-flow\n" + + " rules:\n" + + " - precedence: 1\n" + + " match:\n" + + " headers:\n" + + " x-sermant-flag6:\n" + + " exact: gray6\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0.1"; Assertions.assertTrue(kieClient.publishConfig(FEIGN_PROVIDER_KEY, feignContent)); } } \ No newline at end of file diff --git a/sermant-integration-tests/spring-test/spring-intergration-test/src/test/java/com/huaweicloud/intergration/lane/LaneTest.java b/sermant-integration-tests/spring-test/spring-intergration-test/src/test/java/com/huaweicloud/intergration/lane/LaneTest.java index b17eb02e7d..b40444cfd3 100644 --- a/sermant-integration-tests/spring-test/spring-intergration-test/src/test/java/com/huaweicloud/intergration/lane/LaneTest.java +++ b/sermant-integration-tests/spring-test/spring-intergration-test/src/test/java/com/huaweicloud/intergration/lane/LaneTest.java @@ -57,10 +57,16 @@ public class LaneTest { private static final String ZUUL_FEIGN_CLOUD_BASE_PATH = IP + ZUUL_PORT + FEIGN_BASE_PATH + CLOUD_BASE_PATH; + private static final String ZUUL_WEBCLIENT_CLOUD_BASE_PATH = + IP + ZUUL_PORT + FEIGN_BASE_PATH + CLOUD_BASE_PATH + "ByWebclient"; + private static final String GATEWAY_REST_CLOUD_BASE_PATH = IP + GATEWAY_PORT + REST_BASE_PATH + CLOUD_BASE_PATH; private static final String GATEWAY_FEIGN_CLOUD_BASE_PATH = IP + GATEWAY_PORT + FEIGN_BASE_PATH + CLOUD_BASE_PATH; + private static final String GATEWAY_WEBCLIENT_CLOUD_BASE_PATH = + IP + GATEWAY_PORT + FEIGN_BASE_PATH + CLOUD_BASE_PATH + "ByWebclient"; + private static final int TIMES = 30; private static final String REST_PROVIDER_NAME = "rest-provider"; @@ -73,19 +79,26 @@ public class LaneTest { private static final String VERSION_KEY = "version"; - public static final List SPRING_CLOUD_VERSIONS_FOR_ZUUL = Arrays - .asList("Edgware.SR2", "Finchley.RELEASE", "Greenwich.RELEASE", "Hoxton.RELEASE"); + private static final List SPRING_CLOUD_VERSIONS_FOR_ZUUL = Arrays + .asList("Edgware.SR2", "Finchley.RELEASE", "Greenwich.RELEASE", "Hoxton.RELEASE"); - public static final List SPRING_CLOUD_VERSIONS_FOR_GATEWAY = Arrays - .asList("Finchley.RELEASE", "Greenwich.RELEASE", "Hoxton.RELEASE", "2020.0.0", "2021.0.0", "2021.0.3"); + private static final List SPRING_CLOUD_VERSIONS_FOR_GATEWAY = Arrays + .asList("Finchley.RELEASE", "Greenwich.RELEASE", "Hoxton.RELEASE", "2020.0.0", "2021.0.0", "2021.0.3"); private final String springCloudVersion; + private final boolean shouldTestWebclient; + /** * 构造方法 */ public LaneTest() { springCloudVersion = Optional.ofNullable(System.getenv("SPRING_CLOUD_VERSION")).orElse("Hoxton.RELEASE"); + String springBootVersion = Optional.ofNullable(System.getenv("SPRING_BOOT_VERSION")).orElse("2.2.0.RELEASE"); + String[] parts = springBootVersion.split("\\."); + + // spring boot版本从2.0.x才开始有webclient + shouldTestWebclient = Integer.parseInt(parts[0]) >= 2; } /** @@ -98,9 +111,8 @@ public void testByZuul() { return; } - testByGateway(ZUUL_REST_CLOUD_BASE_PATH, ZUUL_FEIGN_CLOUD_BASE_PATH); - testByWebInterceptor(ZUUL_REST_CLOUD_BASE_PATH, ZUUL_FEIGN_CLOUD_BASE_PATH); - + testByGateway(ZUUL_REST_CLOUD_BASE_PATH, ZUUL_FEIGN_CLOUD_BASE_PATH, ZUUL_WEBCLIENT_CLOUD_BASE_PATH); + testByWebInterceptor(ZUUL_REST_CLOUD_BASE_PATH, ZUUL_FEIGN_CLOUD_BASE_PATH, ZUUL_WEBCLIENT_CLOUD_BASE_PATH); } /** @@ -112,8 +124,9 @@ public void testBySpringCloudGateway() { if (!SPRING_CLOUD_VERSIONS_FOR_GATEWAY.contains(springCloudVersion)) { return; } - testByGateway(GATEWAY_REST_CLOUD_BASE_PATH, GATEWAY_FEIGN_CLOUD_BASE_PATH); - testByWebInterceptor(GATEWAY_REST_CLOUD_BASE_PATH, GATEWAY_FEIGN_CLOUD_BASE_PATH); + testByGateway(GATEWAY_REST_CLOUD_BASE_PATH, GATEWAY_FEIGN_CLOUD_BASE_PATH, GATEWAY_WEBCLIENT_CLOUD_BASE_PATH); + testByWebInterceptor(GATEWAY_REST_CLOUD_BASE_PATH, GATEWAY_FEIGN_CLOUD_BASE_PATH, + GATEWAY_WEBCLIENT_CLOUD_BASE_PATH); } /** @@ -122,7 +135,7 @@ public void testBySpringCloudGateway() { * @param restPath rest路径 * @param feignPath feign路径 */ - private void testByGateway(String restPath, String feignPath) { + private void testByGateway(String restPath, String feignPath, String webClientPath) { // 正常染色 HttpHeaders headers = new HttpHeaders(); headers.add("x-user-id", "101"); @@ -130,8 +143,8 @@ private void testByGateway(String restPath, String feignPath) { ResponseEntity exchange; for (int i = 0; i < TIMES; i++) { exchange = REST_TEMPLATE - .exchange(restPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(restPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); JSONObject json = JSONObject.parseObject(exchange.getBody()); JSONObject providerMsg = json.getJSONObject(REST_PROVIDER_NAME); JSONObject consumerMsg = json.getJSONObject(REST_CONSUMER_NAME); @@ -141,16 +154,28 @@ private void testByGateway(String restPath, String feignPath) { Assertions.assertEquals("1.0.1", consumerMsg.getString(VERSION_KEY)); exchange = REST_TEMPLATE - .exchange(feignPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(feignPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); json = JSONObject.parseObject(exchange.getBody()); - System.out.println(json); providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); Assertions.assertEquals("gray3", providerMsg.getString("x-sermant-flag3")); Assertions.assertEquals("gray4", providerMsg.getString("x-sermant-flag4")); Assertions.assertEquals("1.0.0", providerMsg.getString(VERSION_KEY)); Assertions.assertEquals("1.0.1", consumerMsg.getString(VERSION_KEY)); + + if (shouldTestWebclient) { + exchange = REST_TEMPLATE + .exchange(webClientPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); + json = JSONObject.parseObject(exchange.getBody()); + providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); + consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); + Assertions.assertEquals("gray3", providerMsg.getString("x-sermant-flag3")); + Assertions.assertEquals("gray4", providerMsg.getString("x-sermant-flag4")); + Assertions.assertEquals("1.0.0", providerMsg.getString(VERSION_KEY)); + Assertions.assertEquals("1.0.1", consumerMsg.getString(VERSION_KEY)); + } } // 测试已传入泳道标记 @@ -161,8 +186,8 @@ private void testByGateway(String restPath, String feignPath) { entity = new HttpEntity<>(null, headers); for (int i = 0; i < TIMES; i++) { exchange = REST_TEMPLATE - .exchange(restPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(restPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); JSONObject json = JSONObject.parseObject(exchange.getBody()); JSONObject providerMsg = json.getJSONObject(REST_PROVIDER_NAME); JSONObject consumerMsg = json.getJSONObject(REST_CONSUMER_NAME); @@ -173,8 +198,8 @@ private void testByGateway(String restPath, String feignPath) { Assertions.assertEquals("1.0.1", consumerMsg.getString(VERSION_KEY)); exchange = REST_TEMPLATE - .exchange(feignPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(feignPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); json = JSONObject.parseObject(exchange.getBody()); providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); @@ -183,6 +208,20 @@ private void testByGateway(String restPath, String feignPath) { Assertions.assertEquals("gray14", providerMsg.getString("x-sermant-flag4")); Assertions.assertEquals("1.0.0", providerMsg.getString(VERSION_KEY)); Assertions.assertEquals("1.0.1", consumerMsg.getString(VERSION_KEY)); + + if (shouldTestWebclient) { + exchange = REST_TEMPLATE + .exchange(webClientPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); + json = JSONObject.parseObject(exchange.getBody()); + providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); + consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); + Assertions.assertEquals("gray12", providerMsg.getString("x-sermant-flag2")); + Assertions.assertEquals("gray3", providerMsg.getString("x-sermant-flag3")); + Assertions.assertEquals("gray14", providerMsg.getString("x-sermant-flag4")); + Assertions.assertEquals("1.0.0", providerMsg.getString(VERSION_KEY)); + Assertions.assertEquals("1.0.1", consumerMsg.getString(VERSION_KEY)); + } } // 测试不满足染色条件 @@ -191,8 +230,8 @@ private void testByGateway(String restPath, String feignPath) { entity = new HttpEntity<>(null, headers); for (int i = 0; i < TIMES; i++) { exchange = REST_TEMPLATE - .exchange(restPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(restPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); JSONObject json = JSONObject.parseObject(exchange.getBody()); JSONObject providerMsg = json.getJSONObject(REST_PROVIDER_NAME); JSONObject consumerMsg = json.getJSONObject(REST_CONSUMER_NAME); @@ -204,8 +243,8 @@ private void testByGateway(String restPath, String feignPath) { Assertions.assertEquals("1.0.0", consumerMsg.getString(VERSION_KEY)); exchange = REST_TEMPLATE - .exchange(feignPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(feignPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); json = JSONObject.parseObject(exchange.getBody()); providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); @@ -215,6 +254,21 @@ private void testByGateway(String restPath, String feignPath) { Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag4")); Assertions.assertEquals("1.0.0", providerMsg.getString(VERSION_KEY)); Assertions.assertEquals("1.0.0", consumerMsg.getString(VERSION_KEY)); + + if (shouldTestWebclient) { + exchange = REST_TEMPLATE + .exchange(webClientPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); + json = JSONObject.parseObject(exchange.getBody()); + providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); + consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag1")); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag2")); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag3")); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag4")); + Assertions.assertEquals("1.0.0", providerMsg.getString(VERSION_KEY)); + Assertions.assertEquals("1.0.0", consumerMsg.getString(VERSION_KEY)); + } } } @@ -224,7 +278,7 @@ private void testByGateway(String restPath, String feignPath) { * @param restPath rest路径 * @param feignPath feign路径 */ - private void testByWebInterceptor(String restPath, String feignPath) { + private void testByWebInterceptor(String restPath, String feignPath, String webClientPath) { // 正常染色 HttpHeaders headers = new HttpHeaders(); headers.add("x-user-id", "99"); @@ -232,8 +286,8 @@ private void testByWebInterceptor(String restPath, String feignPath) { ResponseEntity exchange; for (int i = 0; i < TIMES; i++) { exchange = REST_TEMPLATE - .exchange(restPath + "?name=BaR&id=11&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(restPath + "?name=BaR&id=11&enabled=true", HttpMethod.GET, entity, + String.class); JSONObject json = JSONObject.parseObject(exchange.getBody()); JSONObject providerMsg = json.getJSONObject(REST_PROVIDER_NAME); JSONObject consumerMsg = json.getJSONObject(REST_CONSUMER_NAME); @@ -242,15 +296,26 @@ private void testByWebInterceptor(String restPath, String feignPath) { Assertions.assertEquals("1.0.0", consumerMsg.getString(VERSION_KEY)); exchange = REST_TEMPLATE - .exchange(feignPath + "?name=FoO&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(feignPath + "?name=FoO&id=9&enabled=true", HttpMethod.GET, entity, + String.class); json = JSONObject.parseObject(exchange.getBody()); - System.out.println(json); providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); Assertions.assertEquals("gray6", providerMsg.getString("x-sermant-flag6")); Assertions.assertEquals("1.0.1", providerMsg.getString(VERSION_KEY)); Assertions.assertEquals("1.0.0", consumerMsg.getString(VERSION_KEY)); + + if (shouldTestWebclient) { + exchange = REST_TEMPLATE + .exchange(webClientPath + "?name=FoO&id=9&enabled=true", HttpMethod.GET, entity, + String.class); + json = JSONObject.parseObject(exchange.getBody()); + providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); + consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); + Assertions.assertEquals("gray6", providerMsg.getString("x-sermant-flag6")); + Assertions.assertEquals("1.0.1", providerMsg.getString(VERSION_KEY)); + Assertions.assertEquals("1.0.0", consumerMsg.getString(VERSION_KEY)); + } } // 测试已传入泳道标记 @@ -260,8 +325,8 @@ private void testByWebInterceptor(String restPath, String feignPath) { entity = new HttpEntity<>(null, headers); for (int i = 0; i < TIMES; i++) { exchange = REST_TEMPLATE - .exchange(restPath + "?name=BaR&id=11&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(restPath + "?name=BaR&id=11&enabled=true", HttpMethod.GET, entity, + String.class); JSONObject json = JSONObject.parseObject(exchange.getBody()); JSONObject providerMsg = json.getJSONObject(REST_PROVIDER_NAME); JSONObject consumerMsg = json.getJSONObject(REST_CONSUMER_NAME); @@ -271,8 +336,8 @@ private void testByWebInterceptor(String restPath, String feignPath) { Assertions.assertEquals("1.0.1", consumerMsg.getString(VERSION_KEY)); exchange = REST_TEMPLATE - .exchange(feignPath + "?name=FoO&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(feignPath + "?name=FoO&id=9&enabled=true", HttpMethod.GET, entity, + String.class); json = JSONObject.parseObject(exchange.getBody()); providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); @@ -280,6 +345,19 @@ private void testByWebInterceptor(String restPath, String feignPath) { Assertions.assertEquals("gray6", providerMsg.getString("x-sermant-flag6")); Assertions.assertEquals("1.0.1", providerMsg.getString(VERSION_KEY)); Assertions.assertEquals("1.0.1", consumerMsg.getString(VERSION_KEY)); + + if (shouldTestWebclient) { + exchange = REST_TEMPLATE + .exchange(webClientPath + "?name=FoO&id=9&enabled=true", HttpMethod.GET, entity, + String.class); + json = JSONObject.parseObject(exchange.getBody()); + providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); + consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); + Assertions.assertEquals("gray1", providerMsg.getString("x-sermant-flag1")); + Assertions.assertEquals("gray6", providerMsg.getString("x-sermant-flag6")); + Assertions.assertEquals("1.0.1", providerMsg.getString(VERSION_KEY)); + Assertions.assertEquals("1.0.1", consumerMsg.getString(VERSION_KEY)); + } } // 测试不满足染色条件 @@ -288,8 +366,8 @@ private void testByWebInterceptor(String restPath, String feignPath) { entity = new HttpEntity<>(null, headers); for (int i = 0; i < TIMES; i++) { exchange = REST_TEMPLATE - .exchange(restPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(restPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); JSONObject json = JSONObject.parseObject(exchange.getBody()); JSONObject providerMsg = json.getJSONObject(REST_PROVIDER_NAME); JSONObject consumerMsg = json.getJSONObject(REST_CONSUMER_NAME); @@ -303,8 +381,8 @@ private void testByWebInterceptor(String restPath, String feignPath) { Assertions.assertEquals("1.0.0", consumerMsg.getString(VERSION_KEY)); exchange = REST_TEMPLATE - .exchange(feignPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, - String.class); + .exchange(feignPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); json = JSONObject.parseObject(exchange.getBody()); providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); @@ -316,6 +394,23 @@ private void testByWebInterceptor(String restPath, String feignPath) { Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag6")); Assertions.assertEquals("1.0.0", providerMsg.getString(VERSION_KEY)); Assertions.assertEquals("1.0.0", consumerMsg.getString(VERSION_KEY)); + + if (shouldTestWebclient) { + exchange = REST_TEMPLATE + .exchange(webClientPath + "?name=BaR&id=9&enabled=true", HttpMethod.GET, entity, + String.class); + json = JSONObject.parseObject(exchange.getBody()); + providerMsg = json.getJSONObject(FEIGN_PROVIDER_NAME); + consumerMsg = json.getJSONObject(FEIGN_CONSUMER_NAME); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag1")); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag2")); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag3")); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag4")); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag5")); + Assertions.assertFalse(providerMsg.containsKey("x-sermant-flag6")); + Assertions.assertEquals("1.0.0", providerMsg.getString(VERSION_KEY)); + Assertions.assertEquals("1.0.0", consumerMsg.getString(VERSION_KEY)); + } } } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/config/config.yaml b/sermant-plugins/sermant-router/config/config.yaml index d7c865b152..7c679feeeb 100644 --- a/sermant-plugins/sermant-router/config/config.yaml +++ b/sermant-plugins/sermant-router/config/config.yaml @@ -7,3 +7,10 @@ router.plugin: request-tags: [] # 需要解析的请求头的tag parse-header-tag: '' +transmit.plugin: + # 是否在直接new Thread时传递标签 + enabled-thread: true + # 是否在非定时线程池中传递标签 + enabled-thread-pool: true + # 是否在定时线程池的schedule/scheduleAtFixedRate/scheduleWithFixedDelay方法中传递标签 + enabled-scheduler: true diff --git a/sermant-plugins/sermant-router/dubbo-router-plugin/src/test/java/com/huaweicloud/sermant/router/dubbo/interceptor/ContextFilterInterceptorTest.java b/sermant-plugins/sermant-router/dubbo-router-plugin/src/test/java/com/huaweicloud/sermant/router/dubbo/interceptor/ContextFilterInterceptorTest.java index c12073fdf7..ba2a1384cd 100644 --- a/sermant-plugins/sermant-router/dubbo-router-plugin/src/test/java/com/huaweicloud/sermant/router/dubbo/interceptor/ContextFilterInterceptorTest.java +++ b/sermant-plugins/sermant-router/dubbo-router-plugin/src/test/java/com/huaweicloud/sermant/router/dubbo/interceptor/ContextFilterInterceptorTest.java @@ -17,7 +17,9 @@ package com.huaweicloud.sermant.router.dubbo.interceptor; import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; import com.huaweicloud.sermant.core.service.ServiceManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import com.huaweicloud.sermant.router.common.request.RequestTag; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; import com.huaweicloud.sermant.router.dubbo.TestDubboConfigService; @@ -49,6 +51,8 @@ public class ContextFilterInterceptorTest { private static MockedStatic mockServiceManager; + private static MockedStatic mockPluginConfigManager; + /** * UT执行前进行mock */ @@ -59,6 +63,10 @@ public static void before() { testDubboConfigService.setReturnEmptyWhenGetInjectTags(true); mockServiceManager.when(() -> ServiceManager.getService(DubboConfigService.class)) .thenReturn(testDubboConfigService); + + mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(new TransmitConfig()); } /** @@ -67,6 +75,7 @@ public static void before() { @AfterClass public static void after() { mockServiceManager.close(); + mockPluginConfigManager.close(); } public ContextFilterInterceptorTest() throws NoSuchMethodException { diff --git a/sermant-plugins/sermant-router/dubbo-router-service/src/test/java/com/huaweicloud/sermant/router/dubbo/service/AbstractDirectoryServiceTest.java b/sermant-plugins/sermant-router/dubbo-router-service/src/test/java/com/huaweicloud/sermant/router/dubbo/service/AbstractDirectoryServiceTest.java index 7e380f1170..8cd6050d62 100644 --- a/sermant-plugins/sermant-router/dubbo-router-service/src/test/java/com/huaweicloud/sermant/router/dubbo/service/AbstractDirectoryServiceTest.java +++ b/sermant-plugins/sermant-router/dubbo-router-service/src/test/java/com/huaweicloud/sermant/router/dubbo/service/AbstractDirectoryServiceTest.java @@ -19,6 +19,7 @@ import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; import com.huaweicloud.sermant.core.utils.StringUtils; import com.huaweicloud.sermant.router.common.config.RouterConfig; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import com.huaweicloud.sermant.router.common.constants.RouterConstant; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; import com.huaweicloud.sermant.router.config.cache.ConfigCache; @@ -68,6 +69,9 @@ public static void before() { mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)) .thenReturn(config); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(new TransmitConfig()); + service = new AbstractDirectoryServiceImpl(); } diff --git a/sermant-plugins/sermant-router/pom.xml b/sermant-plugins/sermant-router/pom.xml index 9e28342e16..b28c030c1c 100644 --- a/sermant-plugins/sermant-router/pom.xml +++ b/sermant-plugins/sermant-router/pom.xml @@ -33,6 +33,7 @@ router-common router-config-common router-config-service + router-transmit-plugin spring-router-plugin spring-router-service @@ -45,6 +46,7 @@ router-common router-config-common router-config-service + router-transmit-plugin spring-router-plugin spring-router-service @@ -57,6 +59,7 @@ router-common router-config-common router-config-service + router-transmit-plugin spring-router-plugin spring-router-service diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/config/TransmitConfig.java b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/config/TransmitConfig.java new file mode 100644 index 0000000000..2049aea873 --- /dev/null +++ b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/config/TransmitConfig.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.common.config; + +import com.huaweicloud.sermant.core.config.common.ConfigFieldKey; +import com.huaweicloud.sermant.core.config.common.ConfigTypeKey; +import com.huaweicloud.sermant.core.plugin.config.PluginConfig; + +/** + * 路由配置 + * + * @author provenceee + * @since 2021-11-18 + */ +@ConfigTypeKey("transmit.plugin") +public class TransmitConfig implements PluginConfig { + /** + * 是否在直接new Thread时传递标签 + */ + @ConfigFieldKey("enabled-thread") + private boolean enabledThread; + + /** + * 是否在非定时线程池中传递标签 + */ + @ConfigFieldKey("enabled-thread-pool") + private boolean enabledThreadPool; + + /** + * 是否在定时线程池的schedule/scheduleAtFixedRate/scheduleWithFixedDelay方法中传递标签 + */ + @ConfigFieldKey("enabled-scheduler") + private boolean enabledScheduler; + + public boolean isEnabledThread() { + return enabledThread; + } + + public void setEnabledThread(boolean enabledThread) { + this.enabledThread = enabledThread; + } + + public boolean isEnabledThreadPool() { + return enabledThreadPool; + } + + public void setEnabledThreadPool(boolean enabledThreadPool) { + this.enabledThreadPool = enabledThreadPool; + } + + public boolean isEnabledScheduler() { + return enabledScheduler; + } + + public void setEnabledScheduler(boolean enabledScheduler) { + this.enabledScheduler = enabledScheduler; + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/request/RequestData.java b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/request/RequestData.java index 6550037440..c2a04ff2a5 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/request/RequestData.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/request/RequestData.java @@ -50,4 +50,13 @@ public String getPath() { public String getHttpMethod() { return httpMethod; } + + @Override + public String toString() { + return "{" + + "path='" + path + '\'' + + ", httpMethod='" + httpMethod + '\'' + + ", tag='" + getTag() + '\'' + + '}'; + } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/request/RequestTag.java b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/request/RequestTag.java index d71b0e95a7..70967ec87b 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/request/RequestTag.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/request/RequestTag.java @@ -52,4 +52,11 @@ public Map> getTag() { public void addTag(Map> map) { this.tag.putAll(map); } + + @Override + public String toString() { + return "{" + + "tag='" + getTag() + '\'' + + '}'; + } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/utils/ThreadLocalUtils.java b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/utils/ThreadLocalUtils.java index e19bd7aeb6..8efa1ec370 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/utils/ThreadLocalUtils.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/utils/ThreadLocalUtils.java @@ -16,6 +16,8 @@ package com.huaweicloud.sermant.router.common.utils; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import com.huaweicloud.sermant.router.common.request.RequestData; import com.huaweicloud.sermant.router.common.request.RequestTag; @@ -29,13 +31,24 @@ * @since 2022-07-08 */ public class ThreadLocalUtils { - private static final ThreadLocal TAG = new ThreadLocal<>(); + private static final ThreadLocal TAG; - private static final ThreadLocal DATA = new ThreadLocal<>(); + private static final ThreadLocal DATA; private ThreadLocalUtils() { } + static { + TransmitConfig transmitConfig = PluginConfigManager.getPluginConfig(TransmitConfig.class); + if (transmitConfig.isEnabledThread()) { + TAG = new InheritableThreadLocal<>(); + DATA = new InheritableThreadLocal<>(); + } else { + TAG = new ThreadLocal<>(); + DATA = new ThreadLocal<>(); + } + } + /** * 获取线程变量 * @@ -63,6 +76,15 @@ public static void setRequestData(RequestData value) { DATA.set(value); } + /** + * 存入线程变量 + * + * @param value 线程变量 + */ + public static void setRequestTag(RequestTag value) { + TAG.set(value); + } + /** * 增加线程中的请求标记 * diff --git a/sermant-plugins/sermant-router/router-common/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.config.PluginConfig b/sermant-plugins/sermant-router/router-common/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.config.PluginConfig index 9074549e1a..986a4c44ff 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.config.PluginConfig +++ b/sermant-plugins/sermant-router/router-common/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.config.PluginConfig @@ -3,3 +3,4 @@ # com.huaweicloud.sermant.router.common.config.RouterConfig +com.huaweicloud.sermant.router.common.config.TransmitConfig diff --git a/sermant-plugins/sermant-router/router-config-service/src/test/java/com/huaweicloud/sermant/router/config/service/ConfigServiceTest.java b/sermant-plugins/sermant-router/router-config-service/src/test/java/com/huaweicloud/sermant/router/config/service/ConfigServiceTest.java index 523970fab6..c19aec1d29 100644 --- a/sermant-plugins/sermant-router/router-config-service/src/test/java/com/huaweicloud/sermant/router/config/service/ConfigServiceTest.java +++ b/sermant-plugins/sermant-router/router-config-service/src/test/java/com/huaweicloud/sermant/router/config/service/ConfigServiceTest.java @@ -18,6 +18,7 @@ import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; import com.huaweicloud.sermant.router.common.config.RouterConfig; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import com.huaweicloud.sermant.router.common.constants.RouterConstant; import com.huaweicloud.sermant.router.config.entity.EntireRule; import com.huaweicloud.sermant.router.config.entity.Match; @@ -57,6 +58,8 @@ public static void init() { config.setRequestTags(Arrays.asList("foo", "bar", "version")); mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)).thenReturn(config); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(new TransmitConfig()); } /** diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/pom.xml b/sermant-plugins/sermant-router/router-transmit-plugin/pom.xml new file mode 100644 index 0000000000..3ad78451f1 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/pom.xml @@ -0,0 +1,65 @@ + + + + sermant-router + com.huaweicloud.sermant + 1.0.0 + + 4.0.0 + + router-transmit-plugin + + + 8 + 8 + UTF-8 + plugin + + + + + com.huaweicloud.sermant + sermant-agentcore-core + provided + + + com.huaweicloud.sermant + router-common + ${project.version} + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-inline + test + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/declarer/ExecutorDeclarer.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/declarer/ExecutorDeclarer.java new file mode 100644 index 0000000000..a9fb44173b --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/declarer/ExecutorDeclarer.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.declarer; + +import com.huaweicloud.sermant.core.plugin.agent.declarer.AbstractPluginDeclarer; +import com.huaweicloud.sermant.core.plugin.agent.declarer.InterceptDeclarer; +import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; +import com.huaweicloud.sermant.core.plugin.agent.matcher.MethodMatcher; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; + +/** + * 拦截Executor + * + * @author provenceee + * @since 2023-04-20 + */ +public class ExecutorDeclarer extends AbstractPluginDeclarer { + private static final String ENHANCE_CLASS = "java.util.concurrent.Executor"; + + private static final String INTERCEPT_CLASS + = "com.huaweicloud.sermant.router.transmit.interceptor.ExecutorInterceptor"; + + private static final String[] METHOD_NAME = {"execute", "submit"}; + + @Override + public ClassMatcher getClassMatcher() { + return ClassMatcher.isExtendedFrom(ENHANCE_CLASS); + } + + @Override + public InterceptDeclarer[] getInterceptDeclarers(ClassLoader classLoader) { + return new InterceptDeclarer[]{ + InterceptDeclarer.build(MethodMatcher.nameContains(METHOD_NAME).and(MethodMatcher.isPublicMethod()), + INTERCEPT_CLASS) + }; + } + + @Override + public boolean isEnabled() { + TransmitConfig pluginConfig = PluginConfigManager.getPluginConfig(TransmitConfig.class); + return pluginConfig.isEnabledThread() || pluginConfig.isEnabledThreadPool(); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/declarer/ScheduledExecutorServiceDeclarer.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/declarer/ScheduledExecutorServiceDeclarer.java new file mode 100644 index 0000000000..3cc0be9bba --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/declarer/ScheduledExecutorServiceDeclarer.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.declarer; + +import com.huaweicloud.sermant.core.plugin.agent.declarer.AbstractPluginDeclarer; +import com.huaweicloud.sermant.core.plugin.agent.declarer.InterceptDeclarer; +import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; +import com.huaweicloud.sermant.core.plugin.agent.matcher.MethodMatcher; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; + +/** + * ScheduledExecutorService拦截点 + * + * @author provenceee + * @since 2023-06-07 + */ +public class ScheduledExecutorServiceDeclarer extends AbstractPluginDeclarer { + private static final String ENHANCE_CLASS = "java.util.concurrent.ScheduledExecutorService"; + + private static final String INTERCEPT_CLASS + = "com.huaweicloud.sermant.router.transmit.interceptor.ScheduledExecutorServiceInterceptor"; + + private static final String[] METHOD_NAME = {"schedule", "scheduleAtFixedRate", "scheduleWithFixedDelay"}; + + @Override + public ClassMatcher getClassMatcher() { + return ClassMatcher.isExtendedFrom(ENHANCE_CLASS); + } + + @Override + public InterceptDeclarer[] getInterceptDeclarers(ClassLoader classLoader) { + return new InterceptDeclarer[]{ + InterceptDeclarer.build(MethodMatcher.nameContains(METHOD_NAME).and(MethodMatcher.isPublicMethod()), + INTERCEPT_CLASS) + }; + } + + @Override + public boolean isEnabled() { + TransmitConfig pluginConfig = PluginConfigManager.getPluginConfig(TransmitConfig.class); + return pluginConfig.isEnabledThread() || pluginConfig.isEnabledScheduler(); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/interceptor/AbstractExecutorInterceptor.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/interceptor/AbstractExecutorInterceptor.java new file mode 100644 index 0000000000..3aaff5a1c6 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/interceptor/AbstractExecutorInterceptor.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.interceptor; + +import com.huaweicloud.sermant.core.common.LoggerFactory; +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.transmit.wrapper.CallableWrapper; +import com.huaweicloud.sermant.router.transmit.wrapper.RunnableAndCallableWrapper; +import com.huaweicloud.sermant.router.transmit.wrapper.RunnableWrapper; + +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 线程池拦截器抽象类 + * + * @author provenceee + * @since 2023-06-08 + */ +public abstract class AbstractExecutorInterceptor extends AbstractInterceptor { + private static final Logger LOGGER = LoggerFactory.getLogger(); + + private final boolean cannotTransmit; + + /** + * 构造方法 + * + * @param cannotTransmit 执行方法之前是否需要删除线程变量 + */ + protected AbstractExecutorInterceptor(boolean cannotTransmit) { + this.cannotTransmit = cannotTransmit; + } + + @Override + public ExecuteContext before(ExecuteContext context) { + Object[] arguments = context.getArguments(); + if (arguments == null || arguments.length == 0 || arguments[0] == null) { + return context; + } + RequestTag requestTag = ThreadLocalUtils.getRequestTag(); + RequestData requestData = ThreadLocalUtils.getRequestData(); + if (requestTag != null || requestData != null) { + Object argument = arguments[0]; + if (argument instanceof RunnableAndCallableWrapper || argument instanceof RunnableWrapper + || argument instanceof CallableWrapper) { + return context; + } + if (argument instanceof Runnable && argument instanceof Callable) { + log(argument, requestTag, requestData, "runnableAndCallableWrapper"); + arguments[0] = new RunnableAndCallableWrapper<>((Runnable) argument, (Callable) argument, + requestTag, requestData, cannotTransmit); + return context; + } + if (argument instanceof Runnable) { + log(argument, requestTag, requestData, "runnableWrapper"); + arguments[0] = new RunnableWrapper<>((Runnable) argument, requestTag, requestData, + cannotTransmit); + return context; + } + if (argument instanceof Callable) { + log(argument, requestTag, requestData, "callableWrapper"); + arguments[0] = new CallableWrapper<>((Callable) argument, requestTag, requestData, + cannotTransmit); + return context; + } + } + return context; + } + + private void log(Object argument, RequestTag requestTag, RequestData requestData, String wrapperClassName) { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Class name is {0}, hash code is {1}, requestTag is {2}, " + + "requestData is {3}, will be converted to {4}.", + new Object[]{argument.getClass().getName(), Integer.toHexString(argument.hashCode()), + requestTag, requestData, wrapperClassName}); + } + } + + @Override + public ExecuteContext after(ExecuteContext context) { + return context; + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/interceptor/ExecutorInterceptor.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/interceptor/ExecutorInterceptor.java new file mode 100644 index 0000000000..0de2129500 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/interceptor/ExecutorInterceptor.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.interceptor; + +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; + +/** + * 拦截Executor + * + * @author provenceee + * @since 2023-04-21 + */ +public class ExecutorInterceptor extends AbstractExecutorInterceptor { + /** + * 构造方法 + */ + public ExecutorInterceptor() { + super(!PluginConfigManager.getPluginConfig(TransmitConfig.class).isEnabledThreadPool()); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/interceptor/ScheduledExecutorServiceInterceptor.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/interceptor/ScheduledExecutorServiceInterceptor.java new file mode 100644 index 0000000000..4e0b4749ae --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/interceptor/ScheduledExecutorServiceInterceptor.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.interceptor; + +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; + +/** + * 拦截ScheduledExecutorService + * + * @author provenceee + * @since 2023-06-07 + */ +public class ScheduledExecutorServiceInterceptor extends AbstractExecutorInterceptor { + /** + * 构造方法 + */ + public ScheduledExecutorServiceInterceptor() { + super(!PluginConfigManager.getPluginConfig(TransmitConfig.class).isEnabledScheduler()); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/AbstractWrapper.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/AbstractWrapper.java new file mode 100644 index 0000000000..df64718c6c --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/AbstractWrapper.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.wrapper; + +import com.huaweicloud.sermant.core.common.LoggerFactory; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; + +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 包装抽象类 + * + * @param 泛型 + * @author provenceee + * @since 2023-06-08 + */ +public abstract class AbstractWrapper { + private static final Logger LOGGER = LoggerFactory.getLogger(); + + private final Runnable runnable; + + private final Callable callable; + + private final RequestTag requestTag; + + private final RequestData requestData; + + private final boolean cannotTransmit; + + /** + * 构造方法 + * + * @param runnable runnable + * @param callable callable + * @param requestTag 请求标记 + * @param requestData 请求数据 + * @param cannotTransmit 执行方法之前是否需要删除线程变量 + */ + public AbstractWrapper(Runnable runnable, Callable callable, RequestTag requestTag, + RequestData requestData, boolean cannotTransmit) { + this.runnable = runnable; + this.callable = callable; + if (cannotTransmit) { + this.requestTag = null; + this.requestData = null; + } else { + this.requestTag = requestTag; + this.requestData = requestData; + } + this.cannotTransmit = cannotTransmit; + } + + /** + * run方法 + */ + public void run() { + try { + before(runnable); + runnable.run(); + } finally { + after(); + } + } + + /** + * call + * + * @return callable调用结果 + * @throws Exception 异常 + */ + public T call() throws Exception { + try { + before(callable); + return callable.call(); + } finally { + after(); + } + } + + private void before(Object obj) { + if (cannotTransmit) { + // 当开启普通线程透传,不开启线程池透传时,需要在执行方法之前,删除由InheritableThreadLocal透传的数据 + ThreadLocalUtils.removeRequestTag(); + ThreadLocalUtils.removeRequestData(); + } + if (requestTag != null) { + ThreadLocalUtils.setRequestTag(requestTag); + } + if (requestData != null) { + ThreadLocalUtils.setRequestData(requestData); + } + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Current thread is {0}, class name is {1}, hash code is {2}, requestTag is {3}, " + + "requestData is {4}, will be executed.", + new Object[]{Thread.currentThread().getName(), obj.getClass().getName(), + Integer.toHexString(obj.hashCode()), requestTag, requestData}); + } + } + + private void after() { + ThreadLocalUtils.removeRequestTag(); + ThreadLocalUtils.removeRequestData(); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/CallableWrapper.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/CallableWrapper.java new file mode 100644 index 0000000000..d5bff00523 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/CallableWrapper.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.wrapper; + +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; + +import java.util.concurrent.Callable; + +/** + * Callable包装类 + * + * @param 泛型 + * @author provenceee + * @since 2023-04-21 + */ +public class CallableWrapper extends AbstractWrapper implements Callable { + /** + * 构造方法 + * + * @param callable callable + * @param requestTag 请求标记 + * @param requestData 请求数据 + * @param cannotTransmit 执行方法之前是否需要删除线程变量 + */ + public CallableWrapper(Callable callable, RequestTag requestTag, RequestData requestData, + boolean cannotTransmit) { + super(null, callable, requestTag, requestData, cannotTransmit); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableAndCallableWrapper.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableAndCallableWrapper.java new file mode 100644 index 0000000000..b10d20c7ab --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableAndCallableWrapper.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.wrapper; + +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; + +import java.util.concurrent.Callable; + +/** + * Runnable&Callable包装类,例如reactor.core.scheduler.WorkerTask + * + * @param 泛型 + * @author provenceee + * @since 2023-04-21 + */ +public class RunnableAndCallableWrapper extends AbstractWrapper implements Runnable, Callable { + /** + * 构造方法 + * + * @param runnable runnable + * @param callable callable + * @param requestTag 请求标记 + * @param requestData 请求数据 + * @param cannotTransmit 执行方法之前是否需要删除线程变量 + */ + public RunnableAndCallableWrapper(Runnable runnable, Callable callable, RequestTag requestTag, + RequestData requestData, boolean cannotTransmit) { + super(runnable, callable, requestTag, requestData, cannotTransmit); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableWrapper.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableWrapper.java new file mode 100644 index 0000000000..534b7f3845 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableWrapper.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.wrapper; + +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; + +/** + * Runnable包装类 + * + * @param 泛型 + * @author provenceee + * @since 2023-04-21 + */ +public class RunnableWrapper extends AbstractWrapper implements Runnable { + /** + * 构造方法 + * + * @param runnable runnable + * @param requestTag 请求标记 + * @param requestData 请求数据 + * @param cannotTransmit 执行方法之前是否需要删除线程变量 + */ + public RunnableWrapper(Runnable runnable, RequestTag requestTag, RequestData requestData, boolean cannotTransmit) { + super(runnable, null, requestTag, requestData, cannotTransmit); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer new file mode 100644 index 0000000000..250f5b71a2 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer @@ -0,0 +1,2 @@ +com.huaweicloud.sermant.router.transmit.declarer.ExecutorDeclarer +com.huaweicloud.sermant.router.transmit.declarer.ScheduledExecutorServiceDeclarer \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/BaseTest.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/BaseTest.java new file mode 100644 index 0000000000..7da4d93430 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/BaseTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit; + +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +/** + * 测试基类 + * + * @author provenceee + * @since 2023-06-08 + */ +public abstract class BaseTest { + protected static MockedStatic mockPluginConfigManager; + + @BeforeClass + public static void before() { + mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(new TransmitConfig()); + } + + /** + * UT执行后释放mock对象 + */ + @AfterClass + public static void after() { + mockPluginConfigManager.close(); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/RunnableAndCallable.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/RunnableAndCallable.java new file mode 100644 index 0000000000..c5fa2f553c --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/RunnableAndCallable.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit; + +import java.util.concurrent.Callable; + +/** + * @author provenceee + * @since 2023-06-13 + */ +public class RunnableAndCallable implements Runnable, Callable { + @Override + public void run() { + } + + @Override + public Object call() { + return new Object(); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/interceptor/ExecutorInterceptorTest.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/interceptor/ExecutorInterceptorTest.java new file mode 100644 index 0000000000..1c0a1d8562 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/interceptor/ExecutorInterceptorTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.transmit.BaseTest; +import com.huaweicloud.sermant.router.transmit.RunnableAndCallable; +import com.huaweicloud.sermant.router.transmit.wrapper.CallableWrapper; +import com.huaweicloud.sermant.router.transmit.wrapper.RunnableAndCallableWrapper; +import com.huaweicloud.sermant.router.transmit.wrapper.RunnableWrapper; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; +import java.util.concurrent.Callable; + +/** + * 测试ExecutorInterceptor + * + * @author provenceee + * @since 2023-05-26 + */ +public class ExecutorInterceptorTest extends BaseTest { + private final ExecutorInterceptor interceptor; + + private final ExecuteContext context; + + private final Object[] arguments; + + public ExecutorInterceptorTest() { + arguments = new Object[1]; + interceptor = new ExecutorInterceptor(); + context = ExecuteContext.forMemberMethod(new Object(), null, arguments, null, null); + } + + @Test + public void testBefore() { + // 测试null + interceptor.before(context); + Assert.assertNull(context.getArguments()[0]); + + // 测试没有路由数据 + Runnable runnable = () -> { + }; + arguments[0] = runnable; + interceptor.before(context); + Assert.assertEquals(runnable, context.getArguments()[0]); + + // 存入路由数据 + ThreadLocalUtils.addRequestTag(Collections.singletonMap("foo", Collections.singletonList("bar"))); + + // 测试已经包装过了 + RunnableWrapper runnableWrapper = new RunnableWrapper<>(null, null, null, false); + arguments[0] = runnableWrapper; + interceptor.before(context); + Assert.assertEquals(runnableWrapper, context.getArguments()[0]); + + // 包装RunnableAndCallable + RunnableAndCallable runnableAndCallable = new RunnableAndCallable(); + arguments[0] = runnableAndCallable; + interceptor.before(context); + Assert.assertTrue(context.getArguments()[0] instanceof RunnableAndCallableWrapper); + + // 包装Runnable + Runnable runnable1 = () -> { + }; + arguments[0] = runnable1; + interceptor.before(context); + Assert.assertTrue(context.getArguments()[0] instanceof RunnableWrapper); + + // 包装Callable + Callable callable = () -> null; + arguments[0] = callable; + interceptor.before(context); + Assert.assertTrue(context.getArguments()[0] instanceof CallableWrapper); + } + + @After + public void clear() { + ThreadLocalUtils.removeRequestData(); + ThreadLocalUtils.removeRequestTag(); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/interceptor/ScheduledExecutorServiceInterceptorTest.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/interceptor/ScheduledExecutorServiceInterceptorTest.java new file mode 100644 index 0000000000..47c279ea61 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/interceptor/ScheduledExecutorServiceInterceptorTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.transmit.BaseTest; +import com.huaweicloud.sermant.router.transmit.RunnableAndCallable; +import com.huaweicloud.sermant.router.transmit.wrapper.CallableWrapper; +import com.huaweicloud.sermant.router.transmit.wrapper.RunnableAndCallableWrapper; +import com.huaweicloud.sermant.router.transmit.wrapper.RunnableWrapper; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; +import java.util.concurrent.Callable; + +/** + * 测试ScheduledExecutorService + * + * @author provenceee + * @since 2023-06-13 + */ +public class ScheduledExecutorServiceInterceptorTest extends BaseTest { + private final ScheduledExecutorServiceInterceptor interceptor; + + private final ExecuteContext context; + + private final Object[] arguments; + + public ScheduledExecutorServiceInterceptorTest() { + arguments = new Object[1]; + interceptor = new ScheduledExecutorServiceInterceptor(); + context = ExecuteContext.forMemberMethod(new Object(), null, arguments, null, null); + } + + @Test + public void testBefore() { + // 测试null + interceptor.before(context); + Assert.assertNull(context.getArguments()[0]); + + // 测试没有路由数据 + Runnable runnable = () -> { + }; + arguments[0] = runnable; + interceptor.before(context); + Assert.assertEquals(runnable, context.getArguments()[0]); + + // 存入路由数据 + ThreadLocalUtils.addRequestTag(Collections.singletonMap("foo", Collections.singletonList("bar"))); + + // 测试已经包装过了 + RunnableWrapper runnableWrapper = new RunnableWrapper<>(null, null, null, false); + arguments[0] = runnableWrapper; + interceptor.before(context); + Assert.assertEquals(runnableWrapper, context.getArguments()[0]); + + // 包装RunnableAndCallable + RunnableAndCallable runnableAndCallable = new RunnableAndCallable(); + arguments[0] = runnableAndCallable; + interceptor.before(context); + Assert.assertTrue(context.getArguments()[0] instanceof RunnableAndCallableWrapper); + + // 包装Runnable + Runnable runnable1 = () -> { + }; + arguments[0] = runnable1; + interceptor.before(context); + Assert.assertTrue(context.getArguments()[0] instanceof RunnableWrapper); + + // 包装Callable + Callable callable = () -> null; + arguments[0] = callable; + interceptor.before(context); + Assert.assertTrue(context.getArguments()[0] instanceof CallableWrapper); + } + + @After + public void clear() { + ThreadLocalUtils.removeRequestData(); + ThreadLocalUtils.removeRequestTag(); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/wrapper/CallableWrapperTest.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/wrapper/CallableWrapperTest.java new file mode 100644 index 0000000000..da50cc9653 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/wrapper/CallableWrapperTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.wrapper; + +import com.huaweicloud.sermant.core.utils.ReflectUtils; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.transmit.BaseTest; + +import org.junit.Assert; +import org.junit.Test; + +/** + * 测试CallableWrapper + * + * @author provenceee + * @since 2023-05-27 + */ +public class CallableWrapperTest extends BaseTest { + @Test + public void testCanTransmit() throws Exception { + Object obj = new Object(); + CallableWrapper wrapper = new CallableWrapper<>(() -> { + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + return obj; + }, new RequestTag(null), new RequestData(null, null, null), false); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + + Assert.assertEquals(obj, wrapper.call()); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + } + + @Test + public void testCannotTransmit() throws Exception { + // 初始条件 + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); + + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + + Object obj = new Object(); + CallableWrapper wrapper = new CallableWrapper<>(() -> { + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + return obj; + }, new RequestTag(null), new RequestData(null, null, null), true); + + Assert.assertNull(ReflectUtils.getFieldValue(wrapper, "requestData").orElse(null)); + Assert.assertNull(ReflectUtils.getFieldValue(wrapper, "requestTag").orElse(null)); + + Assert.assertEquals(obj, wrapper.call()); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableAndCallableWrapperTest.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableAndCallableWrapperTest.java new file mode 100644 index 0000000000..3f70518cea --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableAndCallableWrapperTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.wrapper; + +import com.huaweicloud.sermant.core.utils.ReflectUtils; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.transmit.BaseTest; + +import org.junit.Assert; +import org.junit.Test; + +/** + * 测试RunnableAndCallableWrapper + * + * @author provenceee + * @since 2023-05-27 + */ +public class RunnableAndCallableWrapperTest extends BaseTest { + @Test + public void testRunCanTransmit() { + RunnableAndCallableWrapper wrapper = new RunnableAndCallableWrapper<>(() -> { + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + }, null, new RequestTag(null), new RequestData(null, null, null), false); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + + wrapper.run(); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + } + + @Test + public void testRunCannotTransmit() { + // 初始条件 + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); + + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + + RunnableWrapper wrapper = new RunnableWrapper<>(() -> { + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + }, new RequestTag(null), new RequestData(null, null, null), true); + + Assert.assertNull(ReflectUtils.getFieldValue(wrapper, "requestData").orElse(null)); + Assert.assertNull(ReflectUtils.getFieldValue(wrapper, "requestTag").orElse(null)); + + wrapper.run(); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + } + + @Test + public void testCallCanTransmit() throws Exception { + Object obj = new Object(); + RunnableAndCallableWrapper wrapper = new RunnableAndCallableWrapper<>(null, () -> { + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + return obj; + }, new RequestTag(null), new RequestData(null, null, null), false); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + + Assert.assertEquals(obj, wrapper.call()); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + } + + @Test + public void testCallCannotTransmit() throws Exception { + // 初始条件 + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); + + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + + Object obj = new Object(); + CallableWrapper wrapper = new CallableWrapper<>(() -> { + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + return obj; + }, new RequestTag(null), new RequestData(null, null, null), true); + + Assert.assertNull(ReflectUtils.getFieldValue(wrapper, "requestData").orElse(null)); + Assert.assertNull(ReflectUtils.getFieldValue(wrapper, "requestTag").orElse(null)); + + Assert.assertEquals(obj, wrapper.call()); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableWrapperTest.java b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableWrapperTest.java new file mode 100644 index 0000000000..849265c280 --- /dev/null +++ b/sermant-plugins/sermant-router/router-transmit-plugin/src/test/java/com/huaweicloud/sermant/router/transmit/wrapper/RunnableWrapperTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.transmit.wrapper; + +import com.huaweicloud.sermant.core.utils.ReflectUtils; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.transmit.BaseTest; + +import org.junit.Assert; +import org.junit.Test; + +/** + * 测试RunnableWrapper + * + * @author provenceee + * @since 2023-05-27 + */ +public class RunnableWrapperTest extends BaseTest { + @Test + public void testCanTransmit() { + RunnableWrapper wrapper = new RunnableWrapper<>(() -> { + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + }, new RequestTag(null), new RequestData(null, null, null), false); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + + wrapper.run(); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + } + + @Test + public void testCannotTransmit() { + // 初始条件 + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); + + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + + RunnableWrapper wrapper = new RunnableWrapper<>(() -> { + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + }, new RequestTag(null), new RequestData(null, null, null), true); + + Assert.assertNull(ReflectUtils.getFieldValue(wrapper, "requestData").orElse(null)); + Assert.assertNull(ReflectUtils.getFieldValue(wrapper, "requestTag").orElse(null)); + + wrapper.run(); + + Assert.assertNull(ThreadLocalUtils.getRequestData()); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/pom.xml b/sermant-plugins/sermant-router/spring-router-plugin/pom.xml index 74f71f6e58..af9f8fc0ad 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/pom.xml +++ b/sermant-plugins/sermant-router/spring-router-plugin/pom.xml @@ -28,6 +28,7 @@ 4.5.13 4.1.5 3.0.4 + 0.9.0.RELEASE @@ -66,6 +67,12 @@ ${spring.version} provided + + org.springframework + spring-webflux + ${spring.version} + provided + org.springframework spring-webmvc @@ -78,6 +85,12 @@ ${spring.version} provided + + io.projectreactor.netty + reactor-netty + ${reactor.version} + provided + io.github.openfeign feign-core diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ControllerDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ControllerDeclarer.java deleted file mode 100644 index c391be3aed..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ControllerDeclarer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * 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.huaweicloud.sermant.router.spring.declarer; - -import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; -import com.huaweicloud.sermant.core.plugin.agent.matcher.MethodMatcher; - -/** - * 增强Controller的RequestMapping方法 - * - * @author provenceee - * @since 2022-10-29 - */ -public class ControllerDeclarer extends AbstractDeclarer { - private static final String CONTROLLER_ANNOTATION = "org.springframework.stereotype.Controller"; - - private static final String REST_CONTROLLER_ANNOTATION = "org.springframework.web.bind.annotation.RestController"; - - private static final String INTERCEPT_CLASS - = "com.huaweicloud.sermant.router.spring.interceptor.ControllerInterceptor"; - - private static final String REQUEST_MAPPING_NAME = "org.springframework.web.bind.annotation.RequestMapping"; - - private static final String POST_MAPPING_NAME = "org.springframework.web.bind.annotation.PostMapping"; - - private static final String GET_MAPPING_NAME = "org.springframework.web.bind.annotation.GetMapping"; - - private static final String DELETE_MAPPING_NAME = "org.springframework.web.bind.annotation.DeleteMapping"; - - private static final String PATCH_MAPPING_NAME = "org.springframework.web.bind.annotation.PatchMapping"; - - private static final String PUT_MAPPING_NAME = "org.springframework.web.bind.annotation.PutMapping"; - - /** - * 构造方法 - */ - public ControllerDeclarer() { - super(null, INTERCEPT_CLASS, null); - } - - @Override - public ClassMatcher getClassMatcher() { - return ClassMatcher.isAnnotatedWith(CONTROLLER_ANNOTATION) - .or(ClassMatcher.isAnnotatedWith(REST_CONTROLLER_ANNOTATION)); - } - - @Override - public MethodMatcher getMethodMatcher() { - return MethodMatcher.isAnnotatedWith(REQUEST_MAPPING_NAME) - .or(MethodMatcher.isAnnotatedWith(POST_MAPPING_NAME)) - .or(MethodMatcher.isAnnotatedWith(GET_MAPPING_NAME)) - .or(MethodMatcher.isAnnotatedWith(DELETE_MAPPING_NAME)) - .or(MethodMatcher.isAnnotatedWith(PATCH_MAPPING_NAME)) - .or(MethodMatcher.isAnnotatedWith(PUT_MAPPING_NAME)); - } -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HttpServerHandleDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HttpServerHandleDeclarer.java new file mode 100644 index 0000000000..536794db49 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HttpServerHandleDeclarer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.declarer; + +import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; + +/** + * HttpServerHandle拦截点,只引入spring-boot-starter-webflux进行响应式编程时,需要在后置方法移除线程变量 + *

spring cloud Greenwich.RELEASE+ + * + * @author provenceee + * @since 2023-06-09 + */ +public class HttpServerHandleDeclarer extends AbstractDeclarer { + private static final String[] ENHANCE_CLASS + = {"reactor.netty.http.server.HttpServerHandle", "reactor.netty.http.server.HttpServer$HttpServerHandle"}; + + private static final String INTERCEPT_CLASS + = "com.huaweicloud.sermant.router.spring.interceptor.HttpServerHandleInterceptor"; + + private static final String METHOD_NAME = "onStateChange"; + + /** + * 构造方法 + */ + public HttpServerHandleDeclarer() { + super(null, INTERCEPT_CLASS, METHOD_NAME); + } + + @Override + public ClassMatcher getClassMatcher() { + return ClassMatcher.nameContains(ENHANCE_CLASS); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HttpServerOperationsDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HttpServerOperationsDeclarer.java new file mode 100644 index 0000000000..3ce4b8c43f --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HttpServerOperationsDeclarer.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.declarer; + +import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; + +/** + * HttpServerOperations拦截点,只引入spring-boot-starter-webflux进行响应式编程时,需要在后置方法移除线程变量 + *

spring cloud Finchley.x + * + * @author provenceee + * @since 2023-06-09 + */ +public class HttpServerOperationsDeclarer extends AbstractDeclarer { + private static final String ENHANCE_CLASS = "reactor.ipc.netty.http.server.HttpServerOperations"; + + private static final String INTERCEPT_CLASS + = "com.huaweicloud.sermant.router.spring.interceptor.HttpServerOperationsInterceptor"; + + private static final String METHOD_NAME = "onHandlerStart"; + + /** + * 构造方法 + */ + public HttpServerOperationsDeclarer() { + super(null, INTERCEPT_CLASS, METHOD_NAME); + } + + @Override + public ClassMatcher getClassMatcher() { + return ClassMatcher.nameEquals(ENHANCE_CLASS); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HystrixActionDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HystrixActionDeclarer.java index 79278032b0..523adb3a30 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HystrixActionDeclarer.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/HystrixActionDeclarer.java @@ -18,6 +18,8 @@ import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; import com.huaweicloud.sermant.core.plugin.agent.matcher.MethodMatcher; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import net.bytebuddy.matcher.ElementMatchers; @@ -51,4 +53,9 @@ public ClassMatcher getClassMatcher() { public MethodMatcher getMethodMatcher() { return MethodMatcher.isConstructor().and(ElementMatchers.takesArguments(ARGS_LENGTH)); } + + @Override + public boolean isEnabled() { + return !PluginConfigManager.getPluginConfig(TransmitConfig.class).isEnabledThreadPool(); + } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/LoadBalancerClientFilterDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/LoadBalancerClientFilterDeclarer.java index bcd1999a2b..94df647a5a 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/LoadBalancerClientFilterDeclarer.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/LoadBalancerClientFilterDeclarer.java @@ -25,8 +25,7 @@ * @since 2022-07-12 */ public class LoadBalancerClientFilterDeclarer extends AbstractDeclarer { - private static final String[] ENHANCE_CLASS = {"org.springframework.cloud.gateway.filter.LoadBalancerClientFilter", - "org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter"}; + private static final String ENHANCE_CLASS = "org.springframework.cloud.gateway.filter.LoadBalancerClientFilter"; private static final String INTERCEPT_CLASS = "com.huaweicloud.sermant.router.spring.interceptor.LoadBalancerClientFilterInterceptor"; @@ -42,6 +41,6 @@ public LoadBalancerClientFilterDeclarer() { @Override public ClassMatcher getClassMatcher() { - return ClassMatcher.nameContains(ENHANCE_CLASS); + return ClassMatcher.nameEquals(ENHANCE_CLASS); } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/LoadBalancerDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/LoadBalancerDeclarer.java new file mode 100644 index 0000000000..c0c6de4969 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/LoadBalancerDeclarer.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.declarer; + +import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; + +/** + * spring cloud loadbalancer拦截点 + * + * @author provenceee + * @since 2023-04-21 + */ +public class LoadBalancerDeclarer extends AbstractDeclarer { + private static final String[] ENHANCE_CLASS = {"org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer", + "org.springframework.cloud.loadbalancer.core.RandomLoadBalancer"}; + + private static final String INTERCEPT_CLASS + = "com.huaweicloud.sermant.router.spring.interceptor.LoadBalancerInterceptor"; + + private static final String METHOD_NAME = "getInstanceResponse"; + + /** + * 构造方法 + */ + public LoadBalancerDeclarer() { + super(null, INTERCEPT_CLASS, METHOD_NAME); + } + + @Override + public ClassMatcher getClassMatcher() { + return ClassMatcher.nameContains(ENHANCE_CLASS); + } + + @Override + public boolean isEnabled() { + return PluginConfigManager.getPluginConfig(TransmitConfig.class).isEnabledThreadPool(); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ReactiveLoadBalancerClientFilterDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ReactiveLoadBalancerClientFilterDeclarer.java new file mode 100644 index 0000000000..0f93ddcff7 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ReactiveLoadBalancerClientFilterDeclarer.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.declarer; + +import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; + +/** + * spring cloud gateway ReactiveLoadBalancerClientFilter增强类,获取请求数据 + * + * @author provenceee + * @since 2023-06-07 + */ +public class ReactiveLoadBalancerClientFilterDeclarer extends AbstractDeclarer { + private static final String ENHANCE_CLASS + = "org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter"; + + private static final String INTERCEPT_CLASS + = "com.huaweicloud.sermant.router.spring.interceptor.ReactiveLoadBalancerClientFilterInterceptor"; + + private static final String METHOD_NAME = "filter"; + + /** + * 构造方法 + */ + public ReactiveLoadBalancerClientFilterDeclarer() { + super(null, INTERCEPT_CLASS, METHOD_NAME); + } + + @Override + public ClassMatcher getClassMatcher() { + return ClassMatcher.nameEquals(ENHANCE_CLASS); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ReactiveTypeHandlerDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ReactiveTypeHandlerDeclarer.java new file mode 100644 index 0000000000..83f2028399 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ReactiveTypeHandlerDeclarer.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.declarer; + +import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; + +/** + * ReactiveTypeHandler拦截点,同时引入spring-boot-starter-web、spring-boot-starter-webflux进行响应式编程时,需要在后置方法移除线程变量 + *

spring cloud Finchley.RELEASE+ + * + * @author provenceee + * @since 2023-06-09 + */ +public class ReactiveTypeHandlerDeclarer extends AbstractDeclarer { + private static final String ENHANCE_CLASS + = "org.springframework.web.servlet.mvc.method.annotation.ReactiveTypeHandler"; + + private static final String INTERCEPT_CLASS + = "com.huaweicloud.sermant.router.spring.interceptor.ReactiveTypeHandlerInterceptor"; + + private static final String METHOD_NAME = "handleValue"; + + /** + * 构造方法 + */ + public ReactiveTypeHandlerDeclarer() { + super(null, INTERCEPT_CLASS, METHOD_NAME); + } + + @Override + public ClassMatcher getClassMatcher() { + return ClassMatcher.nameEquals(ENHANCE_CLASS); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ServiceInstanceListSupplierDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ServiceInstanceListSupplierDeclarer.java index b5fcfeab9d..8956edc74b 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ServiceInstanceListSupplierDeclarer.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/ServiceInstanceListSupplierDeclarer.java @@ -17,6 +17,8 @@ package com.huaweicloud.sermant.router.spring.declarer; import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; /** * CachingServiceInstanceListSupplier/DiscoveryClientServiceInstanceListSupplier增强类,筛选下游实例 @@ -45,4 +47,9 @@ public ServiceInstanceListSupplierDeclarer() { public ClassMatcher getClassMatcher() { return ClassMatcher.nameContains(ENHANCE_CLASS); } + + @Override + public boolean isEnabled() { + return !PluginConfigManager.getPluginConfig(TransmitConfig.class).isEnabledThreadPool(); + } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/WebClientBuilderDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/WebClientBuilderDeclarer.java new file mode 100644 index 0000000000..3c30f07c29 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/declarer/WebClientBuilderDeclarer.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.declarer; + +/** + * webclient拦截点,springboot 2.0.0.RELEASE+,注入请求过滤器 + * + * @author provenceee + * @since 2023-06-12 + */ +public class WebClientBuilderDeclarer extends AbstractDeclarer { + private static final String ENHANCE_CLASS = "org.springframework.web.reactive.function.client.WebClient$Builder"; + + private static final String INTERCEPT_CLASS + = "com.huaweicloud.sermant.router.spring.interceptor.WebClientBuilderInterceptor"; + + private static final String METHOD_NAME = "build"; + + /** + * 构造方法 + */ + public WebClientBuilderDeclarer() { + super(ENHANCE_CLASS, INTERCEPT_CLASS, METHOD_NAME); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptor.java index e2a343f889..98283f90f8 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptor.java @@ -58,6 +58,7 @@ public AbstractHandlerMappingInterceptor() { @Override public ExecuteContext before(ExecuteContext context) { if (shouldHandle(context)) { + ThreadLocalUtils.removeRequestTag(); ServerWebExchange exchange = (ServerWebExchange) context.getArguments()[0]; ServerHttpRequest request = exchange.getRequest(); HttpHeaders headers = request.getHeaders(); @@ -72,7 +73,8 @@ public ExecuteContext before(ExecuteContext context) { @Override public ExecuteContext after(ExecuteContext context) { - // 方法会在controller方法之前结束,所以不能在这里释放线程变量,线程变量会在ControllerInterceptor进行释放 + // 响应式编程不能在after方法中删除,否则会导致线程变量无法透传到负载均衡线程中 + // 会在HttpServerHandleInterceptor、ReactiveTypeHandlerInterceptor中删除 return context; } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/FeignClientInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/FeignClientInterceptor.java index 6286feb25f..8d1b3a32d3 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/FeignClientInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/FeignClientInterceptor.java @@ -18,8 +18,10 @@ import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; import com.huaweicloud.sermant.core.utils.LogUtils; import com.huaweicloud.sermant.core.utils.StringUtils; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import com.huaweicloud.sermant.router.common.request.RequestData; import com.huaweicloud.sermant.router.common.request.RequestTag; import com.huaweicloud.sermant.router.common.utils.CollectionUtils; @@ -161,6 +163,9 @@ private Map> decodeTags(Map> headers) } private boolean canLoadHystrix() { + if (PluginConfigManager.getPluginConfig(TransmitConfig.class).isEnabledThreadPool()) { + return false; + } try { Class.forName(HystrixRequestContext.class.getCanonicalName()); } catch (NoClassDefFoundError | ClassNotFoundException error) { diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerHandleInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerHandleInterceptor.java new file mode 100644 index 0000000000..73eb37d049 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerHandleInterceptor.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; + +import reactor.netty.ConnectionObserver.State; + +/** + * 拦截HttpServerHandle,只引入spring-boot-starter-webflux进行响应式编程时,需要在后置方法移除线程变量 + *

spring cloud Greenwich.RELEASE+ + * + * @author provenceee + * @since 2023-06-09 + */ +public class HttpServerHandleInterceptor extends AbstractInterceptor { + @Override + public ExecuteContext before(ExecuteContext context) { + return context; + } + + @Override + public ExecuteContext after(ExecuteContext context) { + if (shouldHandle(context)) { + ThreadLocalUtils.removeRequestData(); + ThreadLocalUtils.removeRequestTag(); + } + return context; + } + + @Override + public ExecuteContext onThrow(ExecuteContext context) { + if (shouldHandle(context)) { + ThreadLocalUtils.removeRequestData(); + ThreadLocalUtils.removeRequestTag(); + } + return context; + } + + private boolean shouldHandle(ExecuteContext context) { + Object argument = context.getArguments()[1]; + if (argument instanceof State) { + State state = (State) argument; + return state == State.DISCONNECTING; + } + return false; + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/ControllerInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerOperationsInterceptor.java similarity index 75% rename from sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/ControllerInterceptor.java rename to sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerOperationsInterceptor.java index efd6f8aa08..6703a80eaf 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/ControllerInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerOperationsInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,12 +21,13 @@ import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; /** - * 增强Controller的RequestMapping方法 + * 拦截HttpServerOperations,只引入spring-boot-starter-webflux进行响应式编程时,需要在后置方法移除线程变量 + *

spring cloud Finchley.x * * @author provenceee - * @since 2022-10-29 + * @since 2023-06-12 */ -public class ControllerInterceptor extends AbstractInterceptor { +public class HttpServerOperationsInterceptor extends AbstractInterceptor { @Override public ExecuteContext before(ExecuteContext context) { return context; @@ -34,12 +35,14 @@ public ExecuteContext before(ExecuteContext context) { @Override public ExecuteContext after(ExecuteContext context) { + ThreadLocalUtils.removeRequestData(); ThreadLocalUtils.removeRequestTag(); return context; } @Override public ExecuteContext onThrow(ExecuteContext context) { + ThreadLocalUtils.removeRequestData(); ThreadLocalUtils.removeRequestTag(); return context; } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerInterceptor.java new file mode 100644 index 0000000000..2944bb5968 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerInterceptor.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import com.huaweicloud.sermant.core.service.ServiceManager; +import com.huaweicloud.sermant.core.utils.StringUtils; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.utils.CollectionUtils; +import com.huaweicloud.sermant.router.common.utils.ReflectUtils; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.service.LoadBalancerService; + +import java.util.List; +import java.util.Optional; + +/** + * spring cloud loadbalancer拦截点 + * + * @author provenceee + * @since 2023-04-21 + */ +public class LoadBalancerInterceptor extends AbstractInterceptor { + private final LoadBalancerService loadBalancerService; + + /** + * 构造方法 + */ + public LoadBalancerInterceptor() { + loadBalancerService = ServiceManager.getService(LoadBalancerService.class); + } + + @Override + public ExecuteContext before(ExecuteContext context) { + Object object = context.getObject(); + String serviceId = getServiceId(object).orElse(null); + if (StringUtils.isBlank(serviceId)) { + return context; + } + Object[] arguments = context.getArguments(); + List instances = (List) arguments[0]; + if (CollectionUtils.isEmpty(instances)) { + return context; + } + RequestData requestData = ThreadLocalUtils.getRequestData(); + List targetInstances = loadBalancerService.getTargetInstances(serviceId, instances, requestData); + arguments[0] = targetInstances; + return context; + } + + @Override + public ExecuteContext after(ExecuteContext context) { + return context; + } + + private Optional getServiceId(Object object) { + return ReflectUtils.getFieldValue(object, "serviceId").map(obj -> (String) obj); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveLoadBalancerClientFilterInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveLoadBalancerClientFilterInterceptor.java new file mode 100644 index 0000000000..b6ae15f5bc --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveLoadBalancerClientFilterInterceptor.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.web.server.ServerWebExchange; + +/** + * spring cloud gateway ReactiveLoadBalancerClientFilter增强类,获取请求数据 + * + * @author provenceee + * @since 2023-06-07 + */ +public class ReactiveLoadBalancerClientFilterInterceptor extends AbstractInterceptor { + private final TransmitConfig config; + + /** + * 构造方法 + */ + public ReactiveLoadBalancerClientFilterInterceptor() { + this.config = PluginConfigManager.getPluginConfig(TransmitConfig.class); + } + + @Override + public ExecuteContext before(ExecuteContext context) { + if (context.getArguments()[0] instanceof ServerWebExchange) { + ServerHttpRequest request = getExchangeAfterPutHeaders(context).getRequest(); + String path = request.getURI().getPath(); + ThreadLocalUtils.setRequestData(new RequestData(request.getHeaders(), path, request.getMethod().name())); + } + return context; + } + + @Override + public ExecuteContext after(ExecuteContext context) { + // ReactiveLoadBalancerClientFilter为响应式编程,开启线程池透传时不能在after方法中删除,否则会导致线程变量无法透传到负载均衡线程中 + // 会在HttpServerHandleInterceptor、ReactiveTypeHandlerInterceptor中删除 + if (!config.isEnabledThreadPool()) { + ThreadLocalUtils.removeRequestTag(); + ThreadLocalUtils.removeRequestData(); + } + return context; + } + + @Override + public ExecuteContext onThrow(ExecuteContext context) { + ThreadLocalUtils.removeRequestTag(); + ThreadLocalUtils.removeRequestData(); + return context; + } + + private ServerWebExchange getExchangeAfterPutHeaders(ExecuteContext context) { + ServerWebExchange exchange = (ServerWebExchange) context.getArguments()[0]; + RequestTag requestTag = ThreadLocalUtils.getRequestTag(); + if (requestTag == null) { + return exchange; + } + HttpHeaders httpHeaders = HttpHeaders.writableHttpHeaders(exchange.getRequest().getHeaders()); + requestTag.getTag().forEach(httpHeaders::putIfAbsent); + return exchange; + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveTypeHandlerInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveTypeHandlerInterceptor.java new file mode 100644 index 0000000000..1aa03772db --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveTypeHandlerInterceptor.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; + +/** + * 拦截ReactiveTypeHandler,同时引入spring-boot-starter-web、spring-boot-starter-webflux进行响应式编程时,需要在后置方法移除线程变量 + *

spring cloud Finchley.RELEASE+ + * + * @author provenceee + * @since 2023-06-09 + */ +public class ReactiveTypeHandlerInterceptor extends AbstractInterceptor { + @Override + public ExecuteContext before(ExecuteContext context) { + return context; + } + + @Override + public ExecuteContext after(ExecuteContext context) { + ThreadLocalUtils.removeRequestData(); + ThreadLocalUtils.removeRequestTag(); + return context; + } + + @Override + public ExecuteContext onThrow(ExecuteContext context) { + ThreadLocalUtils.removeRequestData(); + ThreadLocalUtils.removeRequestTag(); + return context; + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/RouterExchangeFilterFunction.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/RouterExchangeFilterFunction.java new file mode 100644 index 0000000000..c6111867ac --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/RouterExchangeFilterFunction.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; + +import reactor.core.publisher.Mono; + +import org.springframework.http.HttpHeaders; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientRequest.Builder; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.ExchangeFunction; + +/** + * webclient拦截器,获取&注入请求头 + * + * @author provenceee + * @since 2023-06-12 + */ +public class RouterExchangeFilterFunction implements ExchangeFilterFunction { + @Override + public Mono filter(ClientRequest request, ExchangeFunction exchangeFunction) { + HttpHeaders readOnlyHttpHeaders = request.headers(); + RequestTag requestTag = ThreadLocalUtils.getRequestTag(); + if (requestTag == null) { + ThreadLocalUtils.setRequestData(new RequestData(readOnlyHttpHeaders, request.url().getPath(), + request.method().name())); + return exchangeFunction.exchange(request); + } + Builder newRequestBuilder = ClientRequest.from(request); + requestTag.getTag().forEach((key, value) -> newRequestBuilder.header(key, value.toArray(new String[0]))); + ClientRequest newRequest = newRequestBuilder.build(); + ThreadLocalUtils.setRequestData(new RequestData(newRequest.headers(), newRequest.url().getPath(), + newRequest.method().name())); + return exchangeFunction.exchange(newRequest); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/WebClientBuilderInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/WebClientBuilderInterceptor.java new file mode 100644 index 0000000000..1c6f589e08 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/WebClientBuilderInterceptor.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import com.huaweicloud.sermant.core.utils.ClassUtils; +import com.huaweicloud.sermant.core.utils.ReflectUtils; + +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient.Builder; + +import java.util.List; +import java.util.Optional; + +/** + * 注入请求过滤器 + * + * @author provenceee + * @since 2023-06-12 + */ +public class WebClientBuilderInterceptor extends AbstractInterceptor { + private static final String EXCHANGE_FILTER_FUNCTION_CLASS_NAME + = "com.huaweicloud.sermant.router.spring.interceptor.RouterExchangeFilterFunction"; + + private static volatile boolean init; + + @Override + public ExecuteContext before(ExecuteContext context) { + if (context.getObject() instanceof Builder) { + init(); + Builder builder = (Builder) context.getObject(); + Optional filters = ReflectUtils.getFieldValue(builder, "filters"); + if (filters.isPresent()) { + List list = (List) filters.get(); + for (ExchangeFilterFunction filterFunction : list) { + if (filterFunction instanceof RouterExchangeFilterFunction) { + // 已经注入重试的不再注入 + return context; + } + } + + // 存在过滤器时,注入到第一个 + list.add(0, new RouterExchangeFilterFunction()); + } else { + builder.filter(new RouterExchangeFilterFunction()); + } + } + return context; + } + + @Override + public ExecuteContext after(ExecuteContext context) { + return context; + } + + private void init() { + if (!init) { + synchronized (WebClientBuilderInterceptor.class) { + if (!init) { + ClassUtils.defineClass(EXCHANGE_FILTER_FUNCTION_CLASS_NAME, getClass().getClassLoader()); + init = true; + } + } + } + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer b/sermant-plugins/sermant-router/spring-router-plugin/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer index 52c751a1cd..53a7e3cfbf 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/resources/META-INF/services/com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer @@ -1,7 +1,6 @@ com.huaweicloud.sermant.router.spring.declarer.AbstractHandlerMappingDeclarer com.huaweicloud.sermant.router.spring.declarer.BaseLoadBalancerDeclarer com.huaweicloud.sermant.router.spring.declarer.ClientHttpRequestDeclarer -com.huaweicloud.sermant.router.spring.declarer.ControllerDeclarer com.huaweicloud.sermant.router.spring.declarer.DiscoveryManagerDeclarer com.huaweicloud.sermant.router.spring.declarer.EurekaHttpClientDeclarer com.huaweicloud.sermant.router.spring.declarer.FeignClientDeclarer @@ -18,4 +17,10 @@ com.huaweicloud.sermant.router.spring.declarer.HttpUrlConnectionConnectDeclarer com.huaweicloud.sermant.router.spring.declarer.RestTemplateDeclarer com.huaweicloud.sermant.router.spring.declarer.SpringBootLoadClassDeclarer com.huaweicloud.sermant.router.spring.declarer.HttpAsyncClient4xDeclarer -com.huaweicloud.sermant.router.spring.declarer.ZuulServletDeclarer \ No newline at end of file +com.huaweicloud.sermant.router.spring.declarer.ZuulServletDeclarer +com.huaweicloud.sermant.router.spring.declarer.LoadBalancerDeclarer +com.huaweicloud.sermant.router.spring.declarer.ReactiveLoadBalancerClientFilterDeclarer +com.huaweicloud.sermant.router.spring.declarer.HttpServerHandleDeclarer +com.huaweicloud.sermant.router.spring.declarer.ReactiveTypeHandlerDeclarer +com.huaweicloud.sermant.router.spring.declarer.WebClientBuilderDeclarer +com.huaweicloud.sermant.router.spring.declarer.HttpServerOperationsDeclarer \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/BaseTransmitConfigTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/BaseTransmitConfigTest.java new file mode 100644 index 0000000000..f3f7ec430e --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/BaseTransmitConfigTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring; + +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +/** + * mock TransmitConfig测试基类 + * + * @author provenceee + * @since 2023-06-08 + */ +public abstract class BaseTransmitConfigTest { + protected static MockedStatic mockPluginConfigManager; + + /** + * UT执行前进行mock + */ + @BeforeClass + public static void initTransmitConfig() { + mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(new TransmitConfig()); + } + + /** + * UT执行后释放mock对象 + */ + @AfterClass + public static void closeMock() { + mockPluginConfigManager.close(); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptorTest.java index 82005fde93..c3238ea4f5 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptorTest.java @@ -20,6 +20,7 @@ import com.huaweicloud.sermant.core.service.ServiceManager; import com.huaweicloud.sermant.router.common.request.RequestTag; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; import com.huaweicloud.sermant.router.spring.TestSpringConfigService; import com.huaweicloud.sermant.router.spring.service.SpringConfigService; @@ -44,7 +45,7 @@ * @author provenceee * @since 2022-10-10 */ -public class AbstractHandlerMappingInterceptorTest { +public class AbstractHandlerMappingInterceptorTest extends BaseTransmitConfigTest { private final AbstractHandlerMappingInterceptor interceptor; private final ExecuteContext context; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/BaseLoadBalancerInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/BaseLoadBalancerInterceptorTest.java index 6d56f8da1b..37971f3f99 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/BaseLoadBalancerInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/BaseLoadBalancerInterceptorTest.java @@ -20,6 +20,7 @@ import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; import com.huaweicloud.sermant.core.service.ServiceManager; import com.huaweicloud.sermant.router.common.config.RouterConfig; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import com.huaweicloud.sermant.router.common.request.RequestData; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; import com.huaweicloud.sermant.router.spring.service.LoadBalancerService; @@ -54,8 +55,6 @@ public class BaseLoadBalancerInterceptorTest { private final BaseLoadBalancer loadBalancer; - // private static TestSpringConfigService configService; - private static MockedStatic mockServiceManager; private static MockedStatic mockPluginConfigManager; @@ -65,7 +64,6 @@ public class BaseLoadBalancerInterceptorTest { */ @BeforeClass public static void before() { - // configService = new TestSpringConfigService(); mockServiceManager = Mockito.mockStatic(ServiceManager.class); mockServiceManager.when(() -> ServiceManager.getService(LoadBalancerService.class)) .thenReturn(new TestLoadBalancerService()); @@ -73,6 +71,8 @@ public static void before() { mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)) .thenReturn(new RouterConfig()); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(new TransmitConfig()); } /** diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ClientHttpRequestInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ClientHttpRequestInterceptorTest.java index 4f3c15fd75..03147bbbff 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ClientHttpRequestInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ClientHttpRequestInterceptorTest.java @@ -19,6 +19,7 @@ import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; import com.huaweicloud.sermant.router.common.request.RequestData; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; import org.junit.Assert; import org.junit.Before; @@ -37,7 +38,7 @@ * @author provenceee * @since 2022-09-08 */ -public class ClientHttpRequestInterceptorTest { +public class ClientHttpRequestInterceptorTest extends BaseTransmitConfigTest { private final ClientHttpRequestInterceptor interceptor; private final ExecuteContext context; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/FeignClientInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/FeignClientInterceptorTest.java index 2282c593a1..5bce5c0ab6 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/FeignClientInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/FeignClientInterceptorTest.java @@ -19,6 +19,7 @@ import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; import com.huaweicloud.sermant.router.common.config.RouterConfig; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import com.huaweicloud.sermant.router.common.request.RequestData; import com.huaweicloud.sermant.router.common.request.RequestTag; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; @@ -73,6 +74,8 @@ public static void before() { mockStatic = Mockito.mockStatic(PluginConfigManager.class); RouterConfig config = new RouterConfig(); mockStatic.when(() -> PluginConfigManager.getPluginConfig(Mockito.any())).thenReturn(config); + mockStatic.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(new TransmitConfig()); } @AfterClass diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerHandleInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerHandleInterceptorTest.java new file mode 100644 index 0000000000..5f1f4baa7c --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerHandleInterceptorTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; + +import reactor.netty.ConnectionObserver.State; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * 测试HttpServerHandleInterceptor + * + * @author provenceee + * @since 2023-06-13 + */ +public class HttpServerHandleInterceptorTest extends BaseTransmitConfigTest { + private final HttpServerHandleInterceptor interceptor; + + private final ExecuteContext context; + + private final Object[] arguments; + + public HttpServerHandleInterceptorTest() { + interceptor = new HttpServerHandleInterceptor(); + arguments = new Object[2]; + context = ExecuteContext.forMemberMethod(new Object(), null, arguments, null, null); + } + + @Before + public void clear() { + ThreadLocalUtils.removeRequestTag(); + ThreadLocalUtils.removeRequestData(); + } + + @Test + public void testAfter() { + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); + + // State为null + interceptor.after(context); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + + // State不为DISCONNECTING + arguments[1] = State.CONFIGURED; + interceptor.after(context); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + + // State为DISCONNECTING + arguments[1] = State.DISCONNECTING; + interceptor.after(context); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNull(ThreadLocalUtils.getRequestData()); + } + + @Test + public void testOnThrow() { + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); + + // State为null + interceptor.onThrow(context); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + + // State不为DISCONNECTING + arguments[1] = State.CONFIGURED; + interceptor.onThrow(context); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + + // State为DISCONNECTING + arguments[1] = State.DISCONNECTING; + interceptor.onThrow(context); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNull(ThreadLocalUtils.getRequestData()); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerOperationsInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerOperationsInterceptorTest.java new file mode 100644 index 0000000000..0749ecbadf --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HttpServerOperationsInterceptorTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * 测试HttpServerOperationsInterceptor + * + * @author provenceee + * @since 2023-06-13 + */ +public class HttpServerOperationsInterceptorTest extends BaseTransmitConfigTest { + private final HttpServerOperationsInterceptor interceptor; + + private final ExecuteContext context; + + public HttpServerOperationsInterceptorTest() { + interceptor = new HttpServerOperationsInterceptor(); + context = ExecuteContext.forMemberMethod(new Object(), null, null, null, null); + } + + @Before + public void clear() { + ThreadLocalUtils.removeRequestTag(); + ThreadLocalUtils.removeRequestData(); + } + + @Test + public void testAfter() { + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); + + interceptor.after(context); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNull(ThreadLocalUtils.getRequestData()); + } + + @Test + public void testOnThrow() { + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); + + interceptor.onThrow(context); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNull(ThreadLocalUtils.getRequestData()); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HystrixActionInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HystrixActionInterceptorTest.java index d407fd3bcf..f37c2ac243 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HystrixActionInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/HystrixActionInterceptorTest.java @@ -20,6 +20,7 @@ import com.huaweicloud.sermant.router.common.request.RequestTag; import com.huaweicloud.sermant.router.common.utils.ReflectUtils; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault; import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; @@ -41,7 +42,7 @@ * @author provenceee * @since 2022-09-08 */ -public class HystrixActionInterceptorTest { +public class HystrixActionInterceptorTest extends BaseTransmitConfigTest { private final HystrixActionInterceptor interceptor; private final ExecuteContext context; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerClientFilterInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerClientFilterInterceptorTest.java index ec91f142b4..55b796932b 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerClientFilterInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerClientFilterInterceptorTest.java @@ -19,6 +19,7 @@ import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; import com.huaweicloud.sermant.router.common.request.RequestData; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; import org.junit.Assert; import org.junit.Before; @@ -37,7 +38,7 @@ * @author provenceee * @since 2022-09-08 */ -public class LoadBalancerClientFilterInterceptorTest { +public class LoadBalancerClientFilterInterceptorTest extends BaseTransmitConfigTest { private final LoadBalancerClientFilterInterceptor interceptor; private final ExecuteContext context; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerInterceptorTest.java new file mode 100644 index 0000000000..09184b37fc --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/LoadBalancerInterceptorTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.service.ServiceManager; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; +import com.huaweicloud.sermant.router.spring.service.LoadBalancerService; + +import reactor.core.publisher.Mono; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.reactive.Request; +import org.springframework.cloud.client.loadbalancer.reactive.Response; +import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 测试LoadBalancerInterceptor + * + * @author provenceee + * @since 2023-05-27 + */ +public class LoadBalancerInterceptorTest extends BaseTransmitConfigTest { + private static MockedStatic mockServiceManager; + + private final LoadBalancerInterceptor interceptor; + + private final ExecuteContext context; + + private final Object[] arguments; + + private final TestLoadBalancer loadBalancer; + + /** + * UT执行前进行mock + */ + @BeforeClass + public static void before() { + mockServiceManager = Mockito.mockStatic(ServiceManager.class); + mockServiceManager.when(() -> ServiceManager.getService(LoadBalancerService.class)) + .thenReturn(new TestLoadBalancerService()); + } + + /** + * UT执行后释放mock对象 + */ + @AfterClass + public static void after() { + mockServiceManager.close(); + } + + public LoadBalancerInterceptorTest() { + interceptor = new LoadBalancerInterceptor(); + arguments = new Object[1]; + loadBalancer = new TestLoadBalancer(); + context = ExecuteContext.forMemberMethod(loadBalancer, null, arguments, null, null); + } + + /** + * 重置测试数据 + */ + @Before + public void reset() { + ThreadLocalUtils.removeRequestTag(); + ThreadLocalUtils.removeRequestData(); + List list = new ArrayList<>(); + list.add(new DefaultServiceInstance("foo1", "foo", "foo", 8080, false)); + list.add(new DefaultServiceInstance("bar2", "foo", "bar", 8081, false)); + arguments[0] = list; + loadBalancer.setServiceId("foo"); + } + + /** + * 测试路由规则无效时 + */ + @Test + public void testBeforeWhenServiceIdIsNull() { + loadBalancer.setServiceId(null); + interceptor.before(context); + List instances = (List) context.getArguments()[0]; + Assert.assertNotNull(instances); + Assert.assertEquals(2, instances.size()); + } + + /** + * 测试实例列表为空时 + */ + @Test + public void testBeforeWithEmptyInstances() { + arguments[0] = Collections.emptyList(); + ThreadLocalUtils.setRequestData(new RequestData(Collections.emptyMap(), "", "")); + interceptor.before(context); + List instances = (List) context.getArguments()[0]; + Assert.assertNotNull(instances); + Assert.assertEquals(0, instances.size()); + } + + /** + * 测试正常情况 + */ + @Test + public void testBefore() { + ThreadLocalUtils.setRequestData(new RequestData(Collections.emptyMap(), "", "")); + interceptor.before(context); + List instances = (List) context.getArguments()[0]; + Assert.assertNotNull(instances); + Assert.assertEquals(1, instances.size()); + } + + public static class TestLoadBalancer implements ReactorServiceInstanceLoadBalancer { + private String serviceId; + + @Override + public Mono> choose(Request request) { + return Mono.empty(); + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/NopInstanceFilterInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/NopInstanceFilterInterceptorTest.java index f18ffb111d..97e30c629c 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/NopInstanceFilterInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/NopInstanceFilterInterceptorTest.java @@ -20,6 +20,7 @@ import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; import com.huaweicloud.sermant.core.service.ServiceManager; import com.huaweicloud.sermant.router.common.config.RouterConfig; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import com.huaweicloud.sermant.router.common.request.RequestData; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; import com.huaweicloud.sermant.router.spring.service.LoadBalancerService; @@ -54,8 +55,6 @@ public class NopInstanceFilterInterceptorTest { private static MockedStatic mockPluginConfigManager; - private static RouterConfig config; - /** * UT执行前进行mock */ @@ -65,10 +64,11 @@ public static void before() { mockServiceManager.when(() -> ServiceManager.getService(LoadBalancerService.class)) .thenReturn(new TestLoadBalancerService()); - config = new RouterConfig(); mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)) - .thenReturn(config); + .thenReturn(new RouterConfig()); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(new TransmitConfig()); } /** @@ -83,8 +83,7 @@ public static void after() { public NopInstanceFilterInterceptorTest() throws NoSuchMethodException { interceptor = new NopInstanceFilterInterceptor(); arguments = new Object[2]; - context = ExecuteContext.forMemberMethod(new Object(), String.class.getMethod("trim"), arguments, null, - null); + context = ExecuteContext.forMemberMethod(new Object(), String.class.getMethod("trim"), arguments, null, null); } /** @@ -104,4 +103,18 @@ public void testGetTargetInstances() { Assert.assertEquals(1, result.size()); Assert.assertEquals(instance2, result.get(0)); } + + @Test + public void testAfter() { + ThreadLocalUtils.setRequestData(new RequestData(null, "", "")); + interceptor.after(context); + Assert.assertNull(ThreadLocalUtils.getRequestData()); + } + + @Test + public void testOnThrow() { + ThreadLocalUtils.setRequestData(new RequestData(null, "", "")); + interceptor.onThrow(context); + Assert.assertNull(ThreadLocalUtils.getRequestData()); + } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveLoadBalancerClientFilterInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveLoadBalancerClientFilterInterceptorTest.java new file mode 100644 index 0000000000..110f81d664 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveLoadBalancerClientFilterInterceptorTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.springframework.http.HttpMethod; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 测试ReactiveLoadBalancerClientFilterInterceptor + * + * @author provenceee + * @since 2023-06-07 + */ +public class ReactiveLoadBalancerClientFilterInterceptorTest { + private static MockedStatic mockPluginConfigManager; + + private final ReactiveLoadBalancerClientFilterInterceptor interceptor; + + private final ExecuteContext context; + + public ReactiveLoadBalancerClientFilterInterceptorTest() { + interceptor = new ReactiveLoadBalancerClientFilterInterceptor(); + Object[] arguments = new Object[1]; + MockServerHttpRequest request = MockServerHttpRequest.get("") + .header("bar", "bar1").header("foo", "foo1").build(); + MockServerWebExchange exchange = MockServerWebExchange.from(request); + arguments[0] = exchange; + context = ExecuteContext.forMemberMethod(new Object(), null, arguments, null, null); + } + + /** + * UT执行前进行mock + */ + @BeforeClass + public static void initTransmitConfig() { + mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); + TransmitConfig transmitConfig = new TransmitConfig(); + transmitConfig.setEnabledThreadPool(true); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(transmitConfig); + } + + /** + * UT执行后释放mock对象 + */ + @AfterClass + public static void closeMock() { + mockPluginConfigManager.close(); + } + + /** + * 重置测试数据 + */ + @Before + public void clear() { + ThreadLocalUtils.removeRequestTag(); + ThreadLocalUtils.removeRequestData(); + } + + /** + * 测试before方法 + */ + @Test + public void testBefore() { + // RequestTag为null时 + interceptor.before(context); + RequestData requestData = ThreadLocalUtils.getRequestData(); + Assert.assertEquals(HttpMethod.GET.name(), requestData.getHttpMethod()); + Assert.assertEquals("", requestData.getPath()); + Assert.assertNotNull(requestData); + Map> headerData = requestData.getTag(); + Assert.assertEquals(2, headerData.size()); + Assert.assertEquals("bar1", headerData.get("bar").get(0)); + Assert.assertEquals("foo1", headerData.get("foo").get(0)); + + // RequestTag不为null时 + ThreadLocalUtils.addRequestTag(Collections.singletonMap("bar-foo", Collections.singletonList("foo2"))); + interceptor.before(context); + requestData = ThreadLocalUtils.getRequestData(); + Assert.assertEquals(HttpMethod.GET.name(), requestData.getHttpMethod()); + Assert.assertEquals("", requestData.getPath()); + Assert.assertNotNull(requestData); + headerData = requestData.getTag(); + Assert.assertEquals(3, headerData.size()); + Assert.assertEquals("bar1", headerData.get("bar").get(0)); + Assert.assertEquals("foo1", headerData.get("foo").get(0)); + Assert.assertEquals("foo2", headerData.get("bar-foo").get(0)); + } + + /** + * 测试after方法 + */ + @Test + public void testAfter() { + ThreadLocalUtils.setRequestData(new RequestData(Collections.emptyMap(), "", "")); + interceptor.after(context); + Assert.assertNotNull(ThreadLocalUtils.getRequestData()); + } + + /** + * 测试onThrow方法 + */ + @Test + public void testOnThrow() { + ThreadLocalUtils.setRequestData(new RequestData(Collections.emptyMap(), "", "")); + interceptor.onThrow(context); + Assert.assertNull(ThreadLocalUtils.getRequestData()); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ControllerInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveTypeHandlerInterceptorTest.java similarity index 59% rename from sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ControllerInterceptorTest.java rename to sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveTypeHandlerInterceptorTest.java index ebb42ebc17..9eca99577c 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ControllerInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ReactiveTypeHandlerInterceptorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,60 +17,54 @@ package com.huaweicloud.sermant.router.spring.interceptor; import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.request.RequestTag; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import java.util.Collections; - /** - * 测试ControllerInterceptor + * 测试ReactiveTypeHandlerInterceptor * * @author provenceee - * @since 2022-10-29 + * @since 2023-06-13 */ -public class ControllerInterceptorTest { - private final ControllerInterceptor interceptor; +public class ReactiveTypeHandlerInterceptorTest extends BaseTransmitConfigTest { + private final ReactiveTypeHandlerInterceptor interceptor; private final ExecuteContext context; - public ControllerInterceptorTest() { - interceptor = new ControllerInterceptor(); + public ReactiveTypeHandlerInterceptorTest() { + interceptor = new ReactiveTypeHandlerInterceptor(); context = ExecuteContext.forMemberMethod(new Object(), null, null, null, null); } - /** - * 重置测试数据 - */ @Before public void clear() { ThreadLocalUtils.removeRequestTag(); ThreadLocalUtils.removeRequestData(); } - /** - * 测试after方法,验证是否释放线程变量 - */ @Test public void testAfter() { - ThreadLocalUtils.addRequestTag(Collections.emptyMap()); + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); - // 测试after方法,验证是否释放线程变量 interceptor.after(context); Assert.assertNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNull(ThreadLocalUtils.getRequestData()); } - /** - * 测试onThrow方法,验证是否释放线程变量 - */ @Test public void testOnThrow() { - ThreadLocalUtils.addRequestTag(Collections.emptyMap()); + ThreadLocalUtils.setRequestTag(new RequestTag(null)); + ThreadLocalUtils.setRequestData(new RequestData(null, null, null)); - // 测试onThrow方法,验证是否释放线程变量 interceptor.onThrow(context); Assert.assertNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNull(ThreadLocalUtils.getRequestData()); } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/RouteHandlerInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/RouteHandlerInterceptorTest.java index 286db2157d..75cfe734f2 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/RouteHandlerInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/RouteHandlerInterceptorTest.java @@ -19,6 +19,7 @@ import com.huaweicloud.sermant.core.service.ServiceManager; import com.huaweicloud.sermant.router.common.request.RequestTag; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; import com.huaweicloud.sermant.router.spring.TestSpringConfigService; import com.huaweicloud.sermant.router.spring.service.SpringConfigService; @@ -42,7 +43,7 @@ * @author provenceee * @since 2022-09-07 */ -public class RouteHandlerInterceptorTest { +public class RouteHandlerInterceptorTest extends BaseTransmitConfigTest { private final RouteHandlerInterceptor interceptor; private static TestSpringConfigService configService; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/RouterExchangeFilterFunctionTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/RouterExchangeFilterFunctionTest.java new file mode 100644 index 0000000000..84ba9d999a --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/RouterExchangeFilterFunctionTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.router.common.request.RequestData; +import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; + +import reactor.core.publisher.Mono; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ClientResponse.Builder; +import org.springframework.web.reactive.function.client.ExchangeFunction; + +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 测试RouterExchangeFilterFunction + * + * @author provenceee + * @since 2023-06-13 + */ +public class RouterExchangeFilterFunctionTest extends BaseTransmitConfigTest { + private final RouterExchangeFilterFunction function; + + private final ExchangeFunction exchangeFunction; + + private final ClientRequest request; + + public RouterExchangeFilterFunctionTest() { + function = new RouterExchangeFilterFunction(); + exchangeFunction = clientRequest -> { + Builder responseBuilder = ClientResponse.create(HttpStatus.OK); + clientRequest.headers().forEach( + (key, value) -> responseBuilder.header(key, value.toArray(new String[0]))); + return Mono.just(responseBuilder.build()); + }; + request = ClientRequest.create(HttpMethod.GET, URI.create("http://127.0.0.1/foo")) + .header("foo", "foo1").build(); + } + + @Before + public void clear() { + ThreadLocalUtils.removeRequestTag(); + ThreadLocalUtils.removeRequestData(); + } + + @Test + public void testFilterWithoutRequestTag() { + // requestTag为null时 + ClientResponse response = function.filter(request, exchangeFunction).block(); + Assert.assertNotNull(response); + HttpHeaders httpHeaders = response.headers().asHttpHeaders(); + Assert.assertEquals(1, httpHeaders.size()); + List foos = httpHeaders.get("foo"); + Assert.assertNotNull(foos); + Assert.assertEquals("foo1", foos.get(0)); + RequestData requestData = ThreadLocalUtils.getRequestData(); + Map> tag = requestData.getTag(); + Assert.assertEquals("foo1", tag.get("foo").get(0)); + Assert.assertEquals("/foo", requestData.getPath()); + Assert.assertEquals("GET", requestData.getHttpMethod()); + } + + @Test + public void testFilterWithRequestTag() { + // requestTag不为null时 + ThreadLocalUtils.addRequestTag(Collections.singletonMap("bar", Collections.singletonList("bar1"))); + ClientResponse response = function.filter(request, exchangeFunction).block(); + Assert.assertNotNull(response); + HttpHeaders httpHeaders = response.headers().asHttpHeaders(); + Assert.assertEquals(2, httpHeaders.size()); + List foos = httpHeaders.get("foo"); + Assert.assertNotNull(foos); + Assert.assertEquals("foo1", foos.get(0)); + List bars = httpHeaders.get("bar"); + Assert.assertNotNull(bars); + Assert.assertEquals("bar1", bars.get(0)); + RequestData requestData = ThreadLocalUtils.getRequestData(); + Map> tag = requestData.getTag(); + Assert.assertEquals("foo1", tag.get("foo").get(0)); + Assert.assertEquals("bar1", tag.get("bar").get(0)); + Assert.assertEquals("/foo", requestData.getPath()); + Assert.assertEquals("GET", requestData.getHttpMethod()); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ServiceInstanceListSupplierInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ServiceInstanceListSupplierInterceptorTest.java index 6d79b321e3..4a2db83abb 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ServiceInstanceListSupplierInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ServiceInstanceListSupplierInterceptorTest.java @@ -20,6 +20,7 @@ import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; import com.huaweicloud.sermant.core.service.ServiceManager; import com.huaweicloud.sermant.router.common.config.RouterConfig; +import com.huaweicloud.sermant.router.common.config.TransmitConfig; import com.huaweicloud.sermant.router.common.request.RequestData; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; import com.huaweicloud.sermant.router.spring.service.LoadBalancerService; @@ -70,6 +71,8 @@ public static void before() { mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)) .thenReturn(new RouterConfig()); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) + .thenReturn(new TransmitConfig()); } /** diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/WebClientBuilderInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/WebClientBuilderInterceptorTest.java new file mode 100644 index 0000000000..d1d657578e --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/WebClientBuilderInterceptorTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.router.spring.interceptor; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.utils.ReflectUtils; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClient.Builder; + +import java.util.List; + +/** + * 测试WebClientBuilderInterceptor + * + * @author provenceee + * @since 2023-06-13 + */ +public class WebClientBuilderInterceptorTest { + private final WebClientBuilderInterceptor interceptor; + + private final ExecuteContext context; + + private final Builder builder; + + public WebClientBuilderInterceptorTest() { + builder = WebClient.builder(); + interceptor = new WebClientBuilderInterceptor(); + context = ExecuteContext.forMemberMethod(builder, null, null, null, null); + } + + @Test + public void testBefore() { + // 不存在过滤器时 + interceptor.before(context); + List list = (List) ReflectUtils + .getFieldValue(builder, "filters").orElse(null); + Assert.assertNotNull(list); + Assert.assertTrue(list.get(0) instanceof RouterExchangeFilterFunction); + + // 已存在RouterExchangeFilterFunction时 + interceptor.before(context); + list = (List) ReflectUtils.getFieldValue(builder, "filters").orElse(null); + Assert.assertNotNull(list); + Assert.assertTrue(list.get(0) instanceof RouterExchangeFilterFunction); + Assert.assertEquals(1, list.size()); + + // 清空数据 + ReflectUtils.setFieldValue(builder, "filters", null); + + // 测试已有过滤器的情况 + ExchangeFilterFunction function = (clientRequest, exchangeFunction) -> exchangeFunction.exchange(clientRequest); + builder.filter(function); + interceptor.before(context); + list = (List) ReflectUtils.getFieldValue(builder, "filters").orElse(null); + Assert.assertNotNull(list); + Assert.assertEquals(2, list.size()); + Assert.assertTrue(list.get(0) instanceof RouterExchangeFilterFunction); + Assert.assertEquals(function, list.get(1)); + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ZuulServletInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ZuulServletInterceptorTest.java index f21f104b05..0d1c18c60b 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ZuulServletInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/com/huaweicloud/sermant/router/spring/interceptor/ZuulServletInterceptorTest.java @@ -17,6 +17,7 @@ package com.huaweicloud.sermant.router.spring.interceptor; import com.huaweicloud.sermant.router.common.utils.ThreadLocalUtils; +import com.huaweicloud.sermant.router.spring.BaseTransmitConfigTest; import com.netflix.zuul.context.RequestContext; @@ -32,7 +33,7 @@ * @author provenceee * @since 2023-02-28 */ -public class ZuulServletInterceptorTest { +public class ZuulServletInterceptorTest extends BaseTransmitConfigTest { private final ZuulServletInterceptor interceptor; public ZuulServletInterceptorTest() {