From dfc7264adea91261aa1be49e6ec186fe3ad846f2 Mon Sep 17 00:00:00 2001 From: lepdou Date: Fri, 27 May 2022 15:18:19 +0800 Subject: [PATCH] add router unit test --- .github/workflows/junit_test.yml | 4 + .../discovery/PolarisDiscoveryClientTest.java | 6 +- .../PolarisReactiveDiscoveryClientTest.java | 6 +- .../pom.xml | 14 +- .../filter/QuotaCheckReactiveFilterTest.java | 37 +- .../filter/QuotaCheckServletFilterTest.java | 37 +- .../ratelimit/utils/QuotaCheckUtilsTest.java | 10 +- .../ratelimit/utils/RateLimitUtilsTest.java | 12 +- .../pom.xml | 24 ++ .../PolarisLoadBalancerCompositeRule.java | 23 +- .../polaris/router/PolarisRouterContext.java | 6 +- .../cloud/polaris/router/RouterConstants.java | 2 +- .../polaris/router/SimpleLoadBalancer.java | 16 +- .../feign/FeignExpressionLabelUtils.java | 4 +- .../feign/PolarisFeignLoadBalancer.java | 13 +- .../feign/RouterLabelFeignInterceptor.java | 23 +- .../PolarisLoadBalancerInterceptor.java | 26 +- .../PolarisLoadBalancerCompositeRuleTest.java | 362 ++++++++++++++++++ .../router/PolarisRouterContextTest.java | 64 ++++ .../router/RouterRuleLabelResolverTest.java | 93 +++++ .../router/SimpleLoadBalancerTest.java | 71 ++++ .../feign/FeignExpressionLabelUtilsTest.java | 140 +++++++ ...isCachingSpringLoadBalanceFactoryTest.java | 104 +++++ .../feign/PolarisFeignLoadBalancerTest.java | 121 ++++++ .../RouterLabelFeignInterceptorTest.java | 142 +++++++ ...arisLoadBalancerBeanPostProcessorTest.java | 93 +++++ .../PolarisLoadBalancerInterceptorTest.java | 250 ++++++++++++ .../cloud/common/util/AddressUtils.java | 6 + .../common/util/ExpressionLabelUtils.java | 11 +- .../cloud/common/util/AddressUtilsTest.java | 66 ++++ .../common/util/ExpressionLabelUtilsTest.java | 246 ++++++++++++ .../cloud/common/util/JacksonUtilsTest.java | 50 +++ .../common/util/ResourceFileUtilsTest.java | 46 +++ .../src/test/resources/test.txt | 1 + spring-cloud-tencent-dependencies/pom.xml | 23 ++ 35 files changed, 2048 insertions(+), 104 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolverTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/SimpleLoadBalancerTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisCachingSpringLoadBalanceFactoryTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptorTest.java create mode 100644 spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/AddressUtilsTest.java create mode 100644 spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java create mode 100644 spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/JacksonUtilsTest.java create mode 100644 spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ResourceFileUtilsTest.java create mode 100644 spring-cloud-tencent-commons/src/test/resources/test.txt diff --git a/.github/workflows/junit_test.yml b/.github/workflows/junit_test.yml index 5738a4508..4e397fa2b 100644 --- a/.github/workflows/junit_test.yml +++ b/.github/workflows/junit_test.yml @@ -26,3 +26,7 @@ jobs: # run: mvn -B package --file pom.xml - name: Test with Maven run: mvn -B test --file pom.xml + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + file: ${{ github.workspace }}/target/site/jacoco/jacoco.xml diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java index e72393161..33231b2ff 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java @@ -24,8 +24,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.modules.junit4.PowerMockRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.springframework.cloud.client.ServiceInstance; @@ -41,8 +40,7 @@ import static org.mockito.Mockito.when; * * @author Haotian Zhang */ -@RunWith(PowerMockRunner.class) -@PowerMockIgnore("javax.management.*") +@RunWith(MockitoJUnitRunner.class) public class PolarisDiscoveryClientTest { @Mock diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java index 300a94cd9..88c34028a 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java @@ -25,8 +25,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.modules.junit4.PowerMockRunner; +import org.mockito.junit.MockitoJUnitRunner; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -41,8 +40,7 @@ import static org.mockito.Mockito.when; * * @author Haotian Zhang */ -@RunWith(PowerMockRunner.class) -@PowerMockIgnore("javax.management.*") +@RunWith(MockitoJUnitRunner.class) public class PolarisReactiveDiscoveryClientTest { @Mock diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml b/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml index fe07a8d90..aaccef814 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml +++ b/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml @@ -91,14 +91,20 @@ - org.powermock - powermock-module-junit4 + org.mockito + mockito-inline test - org.powermock - powermock-api-mockito2 + org.mockito + mockito-core + test + + + + net.bytebuddy + byte-buddy test diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java index ae8774386..3bae2e3bd 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.Map; import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ExpressionLabelUtils; import com.tencent.cloud.polaris.ratelimit.RateLimitRuleLabelResolver; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; @@ -33,14 +34,14 @@ import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; import reactor.core.publisher.Mono; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -49,7 +50,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; -import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilterChain; @@ -58,19 +58,16 @@ import static org.assertj.core.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.ArgumentMatchers.anyString; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.when; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; /** * Test for {@link QuotaCheckReactiveFilter}. * * @author Haotian Zhang */ -@RunWith(PowerMockRunner.class) -@PowerMockIgnore({"javax.management.*", "javax.script.*"}) -@PowerMockRunnerDelegate(SpringRunner.class) -@PrepareForTest(ExpressionLabelUtils.class) +@RunWith(MockitoJUnitRunner.class) @SpringBootTest(classes = QuotaCheckReactiveFilterTest.TestApplication.class, properties = { "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" }) @@ -80,11 +77,23 @@ public class QuotaCheckReactiveFilterTest { private QuotaCheckReactiveFilter quotaCheckReactiveFilter; + private static MockedStatic mockedApplicationContextAwareUtils; + private static MockedStatic expressionLabelUtilsMockedStatic; + @BeforeClass public static void beforeClass() { - // mock ExpressionLabelUtils.resolve() - mockStatic(ExpressionLabelUtils.class); + expressionLabelUtilsMockedStatic = mockStatic(ExpressionLabelUtils.class); when(ExpressionLabelUtils.resolve(any(ServerWebExchange.class), anySet())).thenReturn(Collections.singletonMap("RuleLabelResolver", "RuleLabelResolver")); + + mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn("unit-test"); + } + + @AfterClass + public static void afterClass() { + mockedApplicationContextAwareUtils.close(); + expressionLabelUtilsMockedStatic.close(); } @Before diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java index b9cf5cb67..a2cc344dc 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java @@ -29,6 +29,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ExpressionLabelUtils; import com.tencent.cloud.polaris.ratelimit.RateLimitRuleLabelResolver; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; @@ -37,20 +38,19 @@ import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.server.ServerWebExchange; import static org.assertj.core.api.Assertions.assertThat; @@ -58,19 +58,16 @@ import static org.assertj.core.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.ArgumentMatchers.anyString; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.when; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; /** * Test for {@link QuotaCheckServletFilter}. * * @author Haotian Zhang */ -@RunWith(PowerMockRunner.class) -@PowerMockIgnore({"javax.management.*", "javax.script.*"}) -@PowerMockRunnerDelegate(SpringRunner.class) -@PrepareForTest(ExpressionLabelUtils.class) +@RunWith(MockitoJUnitRunner.class) @SpringBootTest(classes = QuotaCheckServletFilterTest.TestApplication.class, properties = { "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" }) @@ -80,11 +77,23 @@ public class QuotaCheckServletFilterTest { private QuotaCheckServletFilter quotaCheckServletFilter; + private static MockedStatic mockedApplicationContextAwareUtils; + private static MockedStatic expressionLabelUtilsMockedStatic; @BeforeClass public static void beforeClass() { - // mock ExpressionLabelUtils.resolve() - mockStatic(ExpressionLabelUtils.class); + expressionLabelUtilsMockedStatic = mockStatic(ExpressionLabelUtils.class); when(ExpressionLabelUtils.resolve(any(ServerWebExchange.class), anySet())).thenReturn(Collections.singletonMap("RuleLabelResolver", "RuleLabelResolver")); + + mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn("unit-test"); + + } + + @AfterClass + public static void afterClass() throws Exception { + mockedApplicationContextAwareUtils.close(); + expressionLabelUtilsMockedStatic.close(); } @Before diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java index 8589a2b6b..d679381cb 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java @@ -25,21 +25,19 @@ import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.modules.junit4.PowerMockRunner; +import org.mockito.junit.MockitoJUnitRunner; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.when; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * Test for {@link QuotaCheckUtils}. * * @author Haotian Zhang */ -@RunWith(PowerMockRunner.class) -@PowerMockIgnore({"javax.management.*", "javax.script.*"}) +@RunWith(MockitoJUnitRunner.class) public class QuotaCheckUtilsTest { private LimitAPI limitAPI; diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtilsTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtilsTest.java index 5eb7901df..351e0b737 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtilsTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtilsTest.java @@ -24,24 +24,20 @@ import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; +import org.mockito.junit.MockitoJUnitRunner; import static com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant.QUOTA_LIMITED_INFO; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyString; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.when; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; /** * Test for {@link RateLimitUtils}. * * @author Haotian Zhang */ -@RunWith(PowerMockRunner.class) -@PowerMockIgnore({"javax.management.*", "javax.script.*"}) -@PrepareForTest(ResourceFileUtils.class) +@RunWith(MockitoJUnitRunner.class) public class RateLimitUtilsTest { @BeforeClass diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index 3aa7ecc12..91e482abb 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -52,6 +52,30 @@ true + + org.springframework.boot + spring-boot-starter-test + test + + + + org.mockito + mockito-inline + test + + + + org.mockito + mockito-core + test + + + + net.bytebuddy + byte-buddy + test + + diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java index 89e87e18d..0c9b285d4 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java @@ -71,14 +71,14 @@ import org.springframework.util.CollectionUtils; */ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule { - private final static String STRATEGY_RANDOM = "random"; - private final static String STRATEGY_ROUND_ROBIN = "roundRobin"; - private final static String STRATEGY_WEIGHT = "polarisWeighted"; - private final static String STRATEGY_RETRY = "retry"; - private final static String STRATEGY_RESPONSE_TIME_WEIGHTED = "responseTimeWeighted"; - private final static String STRATEGY_BEST_AVAILABLE = "bestAvailable"; - private final static String STRATEGY_ZONE_AVOIDANCE = "zoneAvoidance"; - private final static String STRATEGY_AVAILABILITY_FILTERING = "availabilityFilteringRule"; + final static String STRATEGY_RANDOM = "random"; + final static String STRATEGY_ROUND_ROBIN = "roundRobin"; + final static String STRATEGY_WEIGHT = "polarisWeighted"; + final static String STRATEGY_RETRY = "retry"; + final static String STRATEGY_RESPONSE_TIME_WEIGHTED = "responseTimeWeighted"; + final static String STRATEGY_BEST_AVAILABLE = "bestAvailable"; + final static String STRATEGY_ZONE_AVOIDANCE = "zoneAvoidance"; + final static String STRATEGY_AVAILABILITY_FILTERING = "availabilityFilteringRule"; private final PolarisLoadBalancerProperties loadBalancerProperties; private final PolarisNearByRouterProperties polarisNearByRouterProperties; @@ -129,7 +129,7 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule { return delegateRule.choose(key); } - private List doRouter(List allServers, Object key) { + List doRouter(List allServers, Object key) { ServiceInstances serviceInstances = LoadBalancerUtils.transferServersToServiceInstances(allServers); // filter instance by routers @@ -145,7 +145,7 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule { return filteredInstances; } - private ProcessRoutersRequest buildProcessRoutersRequest(ServiceInstances serviceInstances, Object key) { + ProcessRoutersRequest buildProcessRoutersRequest(ServiceInstances serviceInstances, Object key) { ProcessRoutersRequest processRoutersRequest = new ProcessRoutersRequest(); processRoutersRequest.setDstInstances(serviceInstances); @@ -195,9 +195,6 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule { public AbstractLoadBalancerRule getRule() { String loadBalanceStrategy = loadBalancerProperties.getStrategy(); - if (org.springframework.util.StringUtils.isEmpty(loadBalanceStrategy)) { - return new RoundRobinRule(); - } switch (loadBalanceStrategy) { case STRATEGY_RANDOM: diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java index ebcc8fd42..114548722 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java @@ -46,7 +46,11 @@ public class PolarisRouterContext { if (CollectionUtils.isEmpty(labels)) { return Collections.emptyMap(); } - return Collections.unmodifiableMap(labels.get(labelType)); + Map subLabels = labels.get(labelType); + if (CollectionUtils.isEmpty(subLabels)) { + return Collections.emptyMap(); + } + return Collections.unmodifiableMap(subLabels); } public void setLabels(String labelType, Map subLabels) { diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConstants.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConstants.java index 77266cc02..6437c83e8 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConstants.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConstants.java @@ -28,5 +28,5 @@ public class RouterConstants { /** * the header of router label. */ - public static final String ROUTER_LABEL_HEADER = "router-label"; + public static final String ROUTER_LABEL_HEADER = "internal-router-label"; } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/SimpleLoadBalancer.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/SimpleLoadBalancer.java index c8ab04c3c..d509c1bbf 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/SimpleLoadBalancer.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/SimpleLoadBalancer.java @@ -18,6 +18,7 @@ package com.tencent.cloud.polaris.router; +import java.util.Collections; import java.util.List; import com.netflix.loadbalancer.ILoadBalancer; @@ -48,16 +49,25 @@ public class SimpleLoadBalancer implements ILoadBalancer { @Override public List getServerList(boolean availableOnly) { - return servers; + if (servers == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(servers); } @Override public List getReachableServers() { - return servers; + if (servers == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(servers); } @Override public List getAllServers() { - return servers; + if (servers == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(servers); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java index cf4408d37..92b8a6608 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java @@ -18,6 +18,7 @@ package com.tencent.cloud.polaris.router.feign; +import java.net.URI; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -62,7 +63,8 @@ public class FeignExpressionLabelUtils { labels.put(labelKey, request.method()); } else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_URI, labelKey)) { - labels.put(labelKey, request.request().url()); + URI uri = URI.create(request.request().url()); + labels.put(labelKey, uri.getPath()); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java index 5a13e219f..e46b17498 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java @@ -51,11 +51,18 @@ public class PolarisFeignLoadBalancer extends FeignLoadBalancer { protected void customizeLoadBalancerCommandBuilder(RibbonRequest request, IClientConfig config, LoadBalancerCommand.Builder builder) { Map> headers = request.getRequest().headers(); + + PolarisRouterContext routerContext = buildRouterContext(headers); + + builder.withServerLocator(routerContext); + } + + //set method to public for unit test + PolarisRouterContext buildRouterContext(Map> headers) { Collection labelHeaderValues = headers.get(RouterConstants.ROUTER_LABEL_HEADER); if (CollectionUtils.isEmpty(labelHeaderValues)) { - builder.withServerLocator(null); - return; + return null; } PolarisRouterContext routerContext = new PolarisRouterContext(); @@ -76,6 +83,6 @@ public class PolarisFeignLoadBalancer extends FeignLoadBalancer { } }); - builder.withServerLocator(routerContext); + return routerContext; } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java index ef4ac450f..fac0879b4 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java @@ -74,12 +74,13 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered @Override public void apply(RequestTemplate requestTemplate) { - Map labels = new HashMap<>(); + // local service labels + Map labels = new HashMap<>(metadataLocalProperties.getContent()); - // labels from downstream - Map transitiveLabels = MetadataContextHolder.get() - .getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - labels.putAll(transitiveLabels); + // labels from rule expression + String peerServiceName = requestTemplate.feignTarget().name(); + Map ruleExpressionLabels = getRuleExpressionLabels(requestTemplate, peerServiceName); + labels.putAll(ruleExpressionLabels); // labels from request if (!CollectionUtils.isEmpty(routerLabelResolvers)) { @@ -96,14 +97,10 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered }); } - // labels from rule expression - String peerServiceName = requestTemplate.feignTarget().name(); - Map ruleExpressionLabels = getRuleExpressionLabels(requestTemplate, peerServiceName); - labels.putAll(ruleExpressionLabels); - - - //local service labels - labels.putAll(metadataLocalProperties.getContent()); + // labels from downstream + Map transitiveLabels = MetadataContextHolder.get() + .getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + labels.putAll(transitiveLabels); // Because when the label is placed in RequestTemplate.header, // RequestTemplate will parse the header according to the regular, which conflicts with the expression. diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java index 938652497..de474c3f1 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java @@ -105,13 +105,15 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor { this.requestFactory.createRequest(request, body, execution)); } - private PolarisRouterContext genRouterContext(HttpRequest request, byte[] body, String peerServiceName) { - Map labels = new HashMap<>(); + PolarisRouterContext genRouterContext(HttpRequest request, byte[] body, String peerServiceName) { + // local service labels + Map labels = new HashMap<>(metadataLocalProperties.getContent()); - // labels from downstream - Map transitiveLabels = MetadataContextHolder.get() - .getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - labels.putAll(transitiveLabels); + // labels from rule expression + Map ruleExpressionLabels = getExpressionLabels(request, peerServiceName); + if (!CollectionUtils.isEmpty(ruleExpressionLabels)) { + labels.putAll(ruleExpressionLabels); + } // labels from request if (!CollectionUtils.isEmpty(routerLabelResolvers)) { @@ -128,14 +130,10 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor { }); } - // labels from rule expression - Map ruleExpressionLabels = getExpressionLabels(request, peerServiceName); - if (!CollectionUtils.isEmpty(ruleExpressionLabels)) { - labels.putAll(ruleExpressionLabels); - } - - // local service labels - labels.putAll(metadataLocalProperties.getContent()); + // labels from downstream + Map transitiveLabels = MetadataContextHolder.get() + .getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + labels.putAll(transitiveLabels); PolarisRouterContext routerContext = new PolarisRouterContext(); diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java new file mode 100644 index 000000000..1eccb542c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java @@ -0,0 +1,362 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.netflix.client.config.DefaultClientConfigImpl; +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.AbstractLoadBalancerRule; +import com.netflix.loadbalancer.AvailabilityFilteringRule; +import com.netflix.loadbalancer.BestAvailableRule; +import com.netflix.loadbalancer.RandomRule; +import com.netflix.loadbalancer.RetryRule; +import com.netflix.loadbalancer.RoundRobinRule; +import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.WeightedResponseTimeRule; +import com.netflix.loadbalancer.ZoneAvoidanceRule; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.pojo.PolarisServer; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRule; +import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; +import com.tencent.cloud.polaris.router.config.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.PolarisNearByRouterProperties; +import com.tencent.cloud.polaris.router.config.PolarisRuleBasedRouterProperties; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.pojo.DefaultServiceInstances; +import com.tencent.polaris.api.pojo.Instance; +import com.tencent.polaris.api.pojo.ServiceInstances; +import com.tencent.polaris.api.pojo.ServiceKey; +import com.tencent.polaris.plugins.router.metadata.MetadataRouter; +import com.tencent.polaris.plugins.router.nearby.NearbyRouter; +import com.tencent.polaris.plugins.router.rule.RuleBasedRouter; +import com.tencent.polaris.router.api.core.RouterAPI; +import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; +import com.tencent.polaris.router.api.rpc.ProcessRoutersResponse; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +/** + * test for {@link PolarisLoadBalancerCompositeRule} + *@author lepdou 2022-05-26 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisLoadBalancerCompositeRuleTest { + + @Mock + private PolarisLoadBalancerProperties polarisLoadBalancerProperties; + @Mock + private PolarisNearByRouterProperties polarisNearByRouterProperties; + @Mock + private PolarisMetadataRouterProperties polarisMetadataRouterProperties; + @Mock + private PolarisRuleBasedRouterProperties polarisRuleBasedRouterProperties; + @Mock + private RouterAPI routerAPI; + + private IClientConfig config; + + private static AtomicBoolean initTransitiveMetadata = new AtomicBoolean(false); + + private String testNamespace = "testNamespace"; + private String testCallerService = "testCallerService"; + private String testCalleeService = "testCalleeService"; + + @Before + public void before() { + config = new DefaultClientConfigImpl(); + config.loadDefaultValues(); + } + + @Test + public void testGetDefaultLB() { + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(""); + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + AbstractLoadBalancerRule defaultRule = compositeRule.getRule(); + + Assert.assertTrue(defaultRule instanceof ZoneAvoidanceRule); + } + + @Test + public void testRandomLB() { + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(PolarisLoadBalancerCompositeRule.STRATEGY_RANDOM); + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + AbstractLoadBalancerRule lbRule = compositeRule.getRule(); + + Assert.assertTrue(lbRule instanceof RandomRule); + } + + @Test + public void testWeightLB() { + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(PolarisLoadBalancerCompositeRule.STRATEGY_WEIGHT); + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + AbstractLoadBalancerRule lbRule = compositeRule.getRule(); + + Assert.assertTrue(lbRule instanceof PolarisWeightedRule); + } + + @Test + public void testRetryLB() { + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(PolarisLoadBalancerCompositeRule.STRATEGY_RETRY); + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + AbstractLoadBalancerRule lbRule = compositeRule.getRule(); + + Assert.assertTrue(lbRule instanceof RetryRule); + } + + @Test + public void testWeightedResponseTimeLB() { + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(PolarisLoadBalancerCompositeRule.STRATEGY_RESPONSE_TIME_WEIGHTED); + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + AbstractLoadBalancerRule lbRule = compositeRule.getRule(); + + Assert.assertTrue(lbRule instanceof WeightedResponseTimeRule); + } + + @Test + public void tesBestAvailableLB() { + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(PolarisLoadBalancerCompositeRule.STRATEGY_BEST_AVAILABLE); + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + AbstractLoadBalancerRule lbRule = compositeRule.getRule(); + + Assert.assertTrue(lbRule instanceof BestAvailableRule); + } + + @Test + public void tesRoundRobinLB() { + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(PolarisLoadBalancerCompositeRule.STRATEGY_ROUND_ROBIN); + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + AbstractLoadBalancerRule lbRule = compositeRule.getRule(); + + Assert.assertTrue(lbRule instanceof RoundRobinRule); + } + + @Test + public void testAvailabilityFilteringLB() { + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(PolarisLoadBalancerCompositeRule.STRATEGY_AVAILABILITY_FILTERING); + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + AbstractLoadBalancerRule lbRule = compositeRule.getRule(); + + Assert.assertTrue(lbRule instanceof AvailabilityFilteringRule); + } + + @Test + public void testBuildMetadataRouteRequest() { + when(polarisMetadataRouterProperties.isEnabled()).thenReturn(true); + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(""); + + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn(testCallerService); + + setTransitiveMetadata(); + + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + ServiceInstances serviceInstances = assembleServiceInstances(); + PolarisRouterContext routerContext = assembleRouterContext(); + + ProcessRoutersRequest request = compositeRule.buildProcessRoutersRequest(serviceInstances, routerContext); + + Map routerMetadata = request.getRouterMetadata(MetadataRouter.ROUTER_TYPE_METADATA); + + Assert.assertEquals(1, routerMetadata.size()); + Assert.assertEquals(0, request.getRouterMetadata(NearbyRouter.ROUTER_TYPE_NEAR_BY).size()); + Assert.assertEquals(1, request.getRouterMetadata(RuleBasedRouter.ROUTER_TYPE_RULE_BASED).size()); + Assert.assertEquals("false", request.getRouterMetadata(RuleBasedRouter.ROUTER_TYPE_RULE_BASED) + .get(RuleBasedRouter.ROUTER_ENABLED)); + } + } + + @Test + public void testBuildNearbyRouteRequest() { + when(polarisNearByRouterProperties.isEnabled()).thenReturn(true); + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(""); + + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn(testCallerService); + + setTransitiveMetadata(); + + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + ServiceInstances serviceInstances = assembleServiceInstances(); + PolarisRouterContext routerContext = assembleRouterContext(); + + ProcessRoutersRequest request = compositeRule.buildProcessRoutersRequest(serviceInstances, routerContext); + + Map routerMetadata = request.getRouterMetadata(NearbyRouter.ROUTER_TYPE_NEAR_BY); + + Assert.assertEquals(0, request.getRouterMetadata(MetadataRouter.ROUTER_TYPE_METADATA).size()); + Assert.assertEquals(1, routerMetadata.size()); + Assert.assertEquals("true", routerMetadata.get(NearbyRouter.ROUTER_ENABLED)); + Assert.assertEquals(1, request.getRouterMetadata(RuleBasedRouter.ROUTER_TYPE_RULE_BASED).size()); + Assert.assertEquals("false", request.getRouterMetadata(RuleBasedRouter.ROUTER_TYPE_RULE_BASED) + .get(RuleBasedRouter.ROUTER_ENABLED)); + } + } + + @Test + public void testBuildRuleBasedRouteRequest() { + when(polarisRuleBasedRouterProperties.isEnabled()).thenReturn(true); + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(""); + + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())). + thenReturn(testCallerService); + + setTransitiveMetadata(); + + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + ServiceInstances serviceInstances = assembleServiceInstances(); + PolarisRouterContext routerContext = assembleRouterContext(); + + ProcessRoutersRequest request = compositeRule.buildProcessRoutersRequest(serviceInstances, routerContext); + + Map routerMetadata = request.getRouterMetadata(RuleBasedRouter.ROUTER_TYPE_RULE_BASED); + + Assert.assertEquals(1, routerMetadata.size()); + Assert.assertEquals(0, request.getRouterMetadata(MetadataRouter.ROUTER_TYPE_METADATA).size()); + Assert.assertEquals(0, request.getRouterMetadata(NearbyRouter.ROUTER_TYPE_NEAR_BY).size()); + Assert.assertEquals(1, request.getRouterMetadata(RuleBasedRouter.ROUTER_TYPE_RULE_BASED).size()); + Assert.assertEquals("true", request.getRouterMetadata(RuleBasedRouter.ROUTER_TYPE_RULE_BASED) + .get(RuleBasedRouter.ROUTER_ENABLED)); + } + } + + @Test + public void testRouter() { + when(polarisRuleBasedRouterProperties.isEnabled()).thenReturn(true); + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(""); + + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn(testCallerService); + + setTransitiveMetadata(); + + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, polarisNearByRouterProperties, + polarisMetadataRouterProperties, polarisRuleBasedRouterProperties, config); + + ProcessRoutersResponse assembleResponse = assembleProcessRoutersResponse(); + when(routerAPI.processRouters(any())).thenReturn(assembleResponse); + + List servers = compositeRule.doRouter(assembleServers(), assembleRouterContext()); + + Assert.assertEquals(assembleResponse.getServiceInstances().getInstances().size(), servers.size()); + } + } + + private void setTransitiveMetadata() { + if (initTransitiveMetadata.compareAndSet(false, true)) { + // mock transitive metadata + MetadataContext metadataContext = Mockito.mock(MetadataContext.class); + try (MockedStatic mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) { + mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); + } + } + } + + private ServiceInstances assembleServiceInstances() { + ServiceKey serviceKey = new ServiceKey(testNamespace, testCalleeService); + List instances = new LinkedList<>(); + instances.add(new DefaultInstance()); + instances.add(new DefaultInstance()); + instances.add(new DefaultInstance()); + instances.add(new DefaultInstance()); + instances.add(new DefaultInstance()); + + return new DefaultServiceInstances(serviceKey, instances); + } + + private PolarisRouterContext assembleRouterContext() { + PolarisRouterContext routerContext = new PolarisRouterContext(); + Map transitiveLabels = new HashMap<>(); + transitiveLabels.put("k1", "v1"); + Map routerLabels = new HashMap<>(); + routerLabels.put("k2", "v2"); + routerLabels.put("k3", "v3"); + routerContext.setLabels(PolarisRouterContext.TRANSITIVE_LABELS, transitiveLabels); + routerContext.setLabels(PolarisRouterContext.RULE_ROUTER_LABELS, routerLabels); + return routerContext; + } + + private ProcessRoutersResponse assembleProcessRoutersResponse() { + return new ProcessRoutersResponse(assembleServiceInstances()); + } + + private List assembleServers() { + ServiceInstances serviceInstances = assembleServiceInstances(); + List servers = new LinkedList<>(); + servers.add(new PolarisServer(serviceInstances, new DefaultInstance())); + servers.add(new PolarisServer(serviceInstances, new DefaultInstance())); + servers.add(new PolarisServer(serviceInstances, new DefaultInstance())); + servers.add(new PolarisServer(serviceInstances, new DefaultInstance())); + return servers; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java new file mode 100644 index 000000000..2a8d38752 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java @@ -0,0 +1,64 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +/** + * test for {@link PolarisRouterContext} + * + *@author lepdou 2022-05-26 + */ +public class PolarisRouterContextTest { + + @Test + public void testNormalGetterSetter() { + Map labels = new HashMap<>(); + labels.put("k1", "v1"); + labels.put("k2", "v2"); + + PolarisRouterContext routerContext = new PolarisRouterContext(); + routerContext.setLabels(PolarisRouterContext.RULE_ROUTER_LABELS, labels); + + Assert.assertEquals(0, routerContext.getLabels(PolarisRouterContext.TRANSITIVE_LABELS).size()); + Assert.assertEquals(2, routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).size()); + Assert.assertEquals("v1", routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).get("k1")); + Assert.assertEquals("v2", routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).get("k2")); + Assert.assertNull(routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).get("k3")); + } + + @Test + public void testSetNull() { + PolarisRouterContext routerContext = new PolarisRouterContext(); + routerContext.setLabels(PolarisRouterContext.RULE_ROUTER_LABELS, null); + Assert.assertEquals(0, routerContext.getLabels(PolarisRouterContext.TRANSITIVE_LABELS).size()); + Assert.assertEquals(0, routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).size()); + } + + @Test + public void testGetEmptyRouterContext() { + PolarisRouterContext routerContext = new PolarisRouterContext(); + Assert.assertEquals(0, routerContext.getLabels(PolarisRouterContext.TRANSITIVE_LABELS).size()); + Assert.assertEquals(0, routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).size()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolverTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolverTest.java new file mode 100644 index 000000000..26c1dfb13 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolverTest.java @@ -0,0 +1,93 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router; + + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Lists; +import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.polaris.client.pb.ModelProto; +import com.tencent.polaris.client.pb.RoutingProto; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.when; + +/** + * test for {@link RouterRuleLabelResolver} + *@author lepdou 2022-05-26 + */ +@RunWith(MockitoJUnitRunner.class) +public class RouterRuleLabelResolverTest { + + @Mock + private ServiceRuleManager serviceRuleManager; + + private final String testNamespace = "testNamespace"; + private final String testSourceService = "sourceService"; + private final String testDstService = "dstService"; + + @Test + public void test() { + Map labels = new HashMap<>(); + ModelProto.MatchString matchString = ModelProto.MatchString.getDefaultInstance(); + String validKey1 = "${http.header.uid}"; + String validKey2 = "${http.query.name}"; + String validKey3 = "${http.method}"; + String validKey4 = "${http.uri}"; + String invalidKey = "${http.expression.wrong}"; + labels.put(validKey1, matchString); + labels.put(validKey2, matchString); + labels.put(validKey3, matchString); + labels.put(validKey4, matchString); + labels.put(invalidKey, matchString); + + RoutingProto.Source source1 = RoutingProto.Source.newBuilder().putAllMetadata(labels).build(); + RoutingProto.Source source2 = RoutingProto.Source.newBuilder().putAllMetadata(labels).build(); + RoutingProto.Source source3 = RoutingProto.Source.newBuilder().putAllMetadata(new HashMap<>()).build(); + + List routes = new LinkedList<>(); + RoutingProto.Route route = RoutingProto.Route.newBuilder() + .addAllSources(Lists.newArrayList(source1, source2, source3)) + .build(); + routes.add(route); + + when(serviceRuleManager.getServiceRouterRule(testNamespace, testSourceService, testDstService)).thenReturn(routes); + + RouterRuleLabelResolver resolver = new RouterRuleLabelResolver(serviceRuleManager); + + Set resolvedExpressionLabelKeys = resolver.getExpressionLabelKeys(testNamespace, testSourceService, testDstService); + + Assert.assertNotNull(resolvedExpressionLabelKeys); + Assert.assertEquals(4, resolvedExpressionLabelKeys.size()); + Assert.assertTrue(resolvedExpressionLabelKeys.contains(validKey1)); + Assert.assertTrue(resolvedExpressionLabelKeys.contains(validKey2)); + Assert.assertTrue(resolvedExpressionLabelKeys.contains(validKey3)); + Assert.assertTrue(resolvedExpressionLabelKeys.contains(validKey4)); + Assert.assertFalse(resolvedExpressionLabelKeys.contains(invalidKey)); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/SimpleLoadBalancerTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/SimpleLoadBalancerTest.java new file mode 100644 index 000000000..36e512b4c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/SimpleLoadBalancerTest.java @@ -0,0 +1,71 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router; + +import java.util.LinkedList; +import java.util.List; + +import com.netflix.loadbalancer.Server; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +/** + * test for {@link SimpleLoadBalancer} + *@author lepdou 2022-05-26 + */ +public class SimpleLoadBalancerTest { + + @Test + public void testSetterGetter() { + List servers = new LinkedList<>(); + servers.add(Mockito.mock(Server.class)); + servers.add(Mockito.mock(Server.class)); + servers.add(Mockito.mock(Server.class)); + servers.add(Mockito.mock(Server.class)); + servers.add(Mockito.mock(Server.class)); + + SimpleLoadBalancer simpleLoadBalancer = new SimpleLoadBalancer(); + + simpleLoadBalancer.addServers(servers); + + List allServers = simpleLoadBalancer.getAllServers(); + List reachableServers = simpleLoadBalancer.getReachableServers(); + List availableServers = simpleLoadBalancer.getServerList(true); + + Assert.assertEquals(servers.size(), allServers.size()); + Assert.assertEquals(servers.size(), reachableServers.size()); + Assert.assertEquals(servers.size(), availableServers.size()); + } + + @Test + public void testSetNull() { + SimpleLoadBalancer simpleLoadBalancer = new SimpleLoadBalancer(); + + simpleLoadBalancer.addServers(null); + + List allServers = simpleLoadBalancer.getAllServers(); + List reachableServers = simpleLoadBalancer.getReachableServers(); + List availableServers = simpleLoadBalancer.getServerList(true); + + Assert.assertEquals(0, allServers.size()); + Assert.assertEquals(0, reachableServers.size()); + Assert.assertEquals(0, availableServers.size()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java new file mode 100644 index 000000000..6078be75c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java @@ -0,0 +1,140 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router.feign; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.Sets; +import feign.Request; +import feign.RequestTemplate; +import org.junit.Assert; +import org.junit.Test; + +import org.springframework.util.StringUtils; + +/** + * Test for {@link FeignExpressionLabelUtils} + *@author lepdou 2022-05-26 + */ +public class FeignExpressionLabelUtilsTest { + + @Test + public void testGetHeaderLabel() { + String headerKey = "uid"; + String headerValue = "1000"; + String headerKey2 = "teacher.age"; + String headerValue2 = "1000"; + + RequestTemplate requestTemplate = new RequestTemplate(); + requestTemplate.header(headerKey, headerValue); + requestTemplate.header(headerKey2, headerValue2); + + String labelKey1 = "${http.header.uid}"; + String labelKey2 = "${http.header.name}"; + String labelKey3 = "${http.headername}"; + String labelKey4 = "${http.header.}"; + String labelKey5 = "${http.header.teacher.age}"; + Map result = FeignExpressionLabelUtils.resolve(requestTemplate, + Sets.newHashSet(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5)); + + Assert.assertFalse(result.isEmpty()); + Assert.assertEquals(headerValue, result.get(labelKey1)); + Assert.assertEquals(headerValue2, result.get(labelKey5)); + Assert.assertTrue(StringUtils.isEmpty(result.get(labelKey2))); + Assert.assertTrue(StringUtils.isEmpty(result.get(labelKey3))); + Assert.assertTrue(StringUtils.isEmpty(result.get(labelKey4))); + } + + @Test + public void testGetQueryLabel() { + String headerKey = "uid"; + String headerValue = "1000"; + String headerKey2 = "teacher.age"; + String headerValue2 = "1000"; + + RequestTemplate requestTemplate = new RequestTemplate(); + requestTemplate.query(headerKey, headerValue); + requestTemplate.query(headerKey2, headerValue2); + + String labelKey1 = "${http.query.uid}"; + String labelKey2 = "${http.query.name}"; + String labelKey3 = "${http.queryname}"; + String labelKey4 = "${http.query.}"; + String labelKey5 = "${http.query.teacher.age}"; + Map result = FeignExpressionLabelUtils.resolve(requestTemplate, + Sets.newHashSet(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5)); + + Assert.assertFalse(result.isEmpty()); + Assert.assertEquals(headerValue, result.get(labelKey1)); + Assert.assertEquals(headerValue2, result.get(labelKey5)); + Assert.assertTrue(StringUtils.isEmpty(result.get(labelKey2))); + Assert.assertTrue(StringUtils.isEmpty(result.get(labelKey3))); + Assert.assertTrue(StringUtils.isEmpty(result.get(labelKey4))); + } + + @Test + public void testGetMethod() { + RequestTemplate requestTemplate = new RequestTemplate(); + requestTemplate.method(Request.HttpMethod.GET); + + String labelKey1 = "${http.method}"; + Map result = FeignExpressionLabelUtils.resolve(requestTemplate, + Sets.newHashSet(labelKey1)); + + Assert.assertFalse(result.isEmpty()); + Assert.assertEquals("GET", result.get(labelKey1)); + } + + @Test + public void testGetUri() { + String uri = "/user/get"; + + RequestTemplate requestTemplate = new RequestTemplate(); + requestTemplate.uri(uri); + requestTemplate.method(Request.HttpMethod.GET); + requestTemplate.target("http://localhost"); + requestTemplate = requestTemplate.resolve(new HashMap<>()); + + String labelKey1 = "${http.uri}"; + Map result = FeignExpressionLabelUtils.resolve(requestTemplate, + Sets.newHashSet(labelKey1)); + + Assert.assertFalse(result.isEmpty()); + Assert.assertEquals(uri, result.get(labelKey1)); + } + + @Test + public void testGetUri2() { + String uri = "/"; + + RequestTemplate requestTemplate = new RequestTemplate(); + requestTemplate.uri(uri); + requestTemplate.method(Request.HttpMethod.GET); + requestTemplate.target("http://localhost"); + requestTemplate = requestTemplate.resolve(new HashMap<>()); + + String labelKey1 = "${http.uri}"; + Map result = FeignExpressionLabelUtils.resolve(requestTemplate, + Sets.newHashSet(labelKey1)); + + Assert.assertFalse(result.isEmpty()); + Assert.assertEquals(uri, result.get(labelKey1)); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisCachingSpringLoadBalanceFactoryTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisCachingSpringLoadBalanceFactoryTest.java new file mode 100644 index 000000000..c259e3b60 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisCachingSpringLoadBalanceFactoryTest.java @@ -0,0 +1,104 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router.feign; + +import com.netflix.client.config.DefaultClientConfigImpl; +import com.netflix.loadbalancer.ILoadBalancer; +import com.tencent.cloud.polaris.router.SimpleLoadBalancer; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector; +import org.springframework.cloud.netflix.ribbon.ServerIntrospector; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Test for {@link PolarisCachingSpringLoadBalanceFactory} + *@author lepdou 2022-05-26 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisCachingSpringLoadBalanceFactoryTest { + + @Mock + private SpringClientFactory factory; + + private String service1 = "service1"; + private String service2 = "service2"; + + @Test + public void test() { + PolarisCachingSpringLoadBalanceFactory polarisCachingSpringLoadBalanceFactory = + new PolarisCachingSpringLoadBalanceFactory(factory, null); + + DefaultClientConfigImpl config1 = new DefaultClientConfigImpl(); + config1.loadDefaultValues(); + config1.setClientName(service1); + DefaultClientConfigImpl config2 = new DefaultClientConfigImpl(); + config2.loadDefaultValues(); + config2.setClientName(service2); + + when(factory.getClientConfig(service1)).thenReturn(config1); + when(factory.getClientConfig(service2)).thenReturn(config2); + + ILoadBalancer loadBalancer = new SimpleLoadBalancer(); + when(factory.getLoadBalancer(service1)).thenReturn(loadBalancer); + when(factory.getLoadBalancer(service2)).thenReturn(loadBalancer); + + ServerIntrospector serverIntrospector = new DefaultServerIntrospector(); + when(factory.getInstance(service1, ServerIntrospector.class)).thenReturn(serverIntrospector); + when(factory.getInstance(service2, ServerIntrospector.class)).thenReturn(serverIntrospector); + + // load balancer for service1 + FeignLoadBalancer feignLoadBalancer = polarisCachingSpringLoadBalanceFactory.create(service1); + + Assert.assertNotNull(feignLoadBalancer); + verify(factory).getClientConfig(service1); + verify(factory, times(0)).getClientConfig(service2); + verify(factory).getLoadBalancer(service1); + verify(factory, times(0)).getLoadBalancer(service2); + verify(factory).getInstance(service1, ServerIntrospector.class); + verify(factory, times(0)).getInstance(service2, ServerIntrospector.class); + Assert.assertEquals(loadBalancer, feignLoadBalancer.getLoadBalancer()); + Assert.assertEquals(service1, feignLoadBalancer.getClientName()); + + // load balancer for service2 + FeignLoadBalancer feignLoadBalancer2 = polarisCachingSpringLoadBalanceFactory.create(service2); + // load balancer for service1 again + feignLoadBalancer = polarisCachingSpringLoadBalanceFactory.create(service1); + + Assert.assertNotNull(feignLoadBalancer); + verify(factory).getClientConfig(service1); + verify(factory).getClientConfig(service2); + verify(factory).getLoadBalancer(service1); + verify(factory).getLoadBalancer(service2); + verify(factory).getInstance(service1, ServerIntrospector.class); + verify(factory).getInstance(service2, ServerIntrospector.class); + Assert.assertEquals(loadBalancer, feignLoadBalancer2.getLoadBalancer()); + Assert.assertEquals(service2, feignLoadBalancer2.getClientName()); + + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java new file mode 100644 index 000000000..52be650b6 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java @@ -0,0 +1,121 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router.feign; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.netflix.client.config.DefaultClientConfigImpl; +import com.netflix.loadbalancer.ILoadBalancer; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.router.PolarisRouterContext; +import com.tencent.cloud.polaris.router.RouterConstants; +import com.tencent.cloud.polaris.router.SimpleLoadBalancer; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector; +import org.springframework.cloud.netflix.ribbon.ServerIntrospector; + +import static org.mockito.Mockito.anyString; + +/** + * test for {@link PolarisFeignLoadBalancer} + * @author lepdou 2022-05-26 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisFeignLoadBalancerTest { + + @Test + public void testHasRouterContext() { + DefaultClientConfigImpl config = new DefaultClientConfigImpl(); + config.loadDefaultValues(); + ILoadBalancer loadBalancer = new SimpleLoadBalancer(); + ServerIntrospector serverIntrospector = new DefaultServerIntrospector(); + + PolarisFeignLoadBalancer polarisFeignLoadBalancer = new PolarisFeignLoadBalancer(loadBalancer, config, serverIntrospector); + + Map labels = new HashMap<>(); + labels.put("k1", "v1"); + labels.put("k2", "v2"); + + List headerValues = new ArrayList<>(); + headerValues.add(JacksonUtils.serialize2Json(labels)); + + Map> headers = new HashMap<>(); + headers.put(RouterConstants.ROUTER_LABEL_HEADER, headerValues); + + // mock ApplicationContextAwareUtils#getProperties + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())).thenReturn("unit-test"); + + MetadataContext metadataContext = Mockito.mock(MetadataContext.class); + // mock MetadataContextHolder#get + try (MockedStatic mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) { + mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); + + PolarisRouterContext routerContext = polarisFeignLoadBalancer.buildRouterContext(headers); + + Assert.assertNotNull(routerContext); + Map routerLabels = routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS); + Assert.assertNotNull(routerLabels); + Assert.assertEquals("v1", routerLabels.get("k1")); + Assert.assertEquals("v2", routerLabels.get("k2")); + Assert.assertNull(routerLabels.get("k3")); + } + } + } + + @Test + public void testHasNoneRouterContext() { + DefaultClientConfigImpl config = new DefaultClientConfigImpl(); + config.loadDefaultValues(); + ILoadBalancer loadBalancer = new SimpleLoadBalancer(); + ServerIntrospector serverIntrospector = new DefaultServerIntrospector(); + + PolarisFeignLoadBalancer polarisFeignLoadBalancer = new PolarisFeignLoadBalancer(loadBalancer, config, serverIntrospector); + + Map> headers = new HashMap<>(); + + // mock ApplicationContextAwareUtils#getProperties + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())).thenReturn("unit-test"); + + MetadataContext metadataContext = Mockito.mock(MetadataContext.class); + // mock MetadataContextHolder#get + try (MockedStatic mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) { + mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); + + PolarisRouterContext routerContext = polarisFeignLoadBalancer.buildRouterContext(headers); + + Assert.assertNull(routerContext); + } + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java new file mode 100644 index 000000000..d5f7076fc --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java @@ -0,0 +1,142 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router.feign; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.common.util.ExpressionLabelUtils; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.router.RouterConstants; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; +import feign.RequestTemplate; +import feign.Target; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +/** + * test for {@link RouterLabelFeignInterceptor} + * @author lepdou 2022-05-26 + */ +@RunWith(MockitoJUnitRunner.class) +public class RouterLabelFeignInterceptorTest { + + @Mock + private MetadataLocalProperties metadataLocalProperties; + @Mock + private RouterRuleLabelResolver routerRuleLabelResolver; + @Mock + private RouterLabelResolver routerLabelResolver; + + @Test + public void testResolveRouterLabel() { + RouterLabelFeignInterceptor routerLabelFeignInterceptor = new RouterLabelFeignInterceptor( + Collections.singletonList(routerLabelResolver), + metadataLocalProperties, routerRuleLabelResolver); + + // mock request template + RequestTemplate requestTemplate = new RequestTemplate(); + String headerUidKey = "uid"; + String headerUidValue = "1000"; + requestTemplate.header(headerUidKey, headerUidValue); + String peerService = "peerService"; + Target.EmptyTarget target = Target.EmptyTarget.create(Object.class, peerService); + requestTemplate.feignTarget(target); + + // mock ApplicationContextAwareUtils#getProperties + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + String testService = "callerService"; + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn(testService); + + MetadataContext metadataContext = Mockito.mock(MetadataContext.class); + + // mock transitive metadata + Map transitiveLabels = new HashMap<>(); + transitiveLabels.put("k1", "v1"); + transitiveLabels.put("k2", "v22"); + when(metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE)).thenReturn(transitiveLabels); + + // mock MetadataContextHolder#get + try (MockedStatic mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) { + mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); + + // mock custom resolved labels from request + Map customResolvedLabels = new HashMap<>(); + customResolvedLabels.put("k2", "v2"); + customResolvedLabels.put("k3", "v3"); + when(routerLabelResolver.resolve(requestTemplate)).thenReturn(customResolvedLabels); + + // mock expression rule labels + Set expressionKeys = new HashSet<>(); + expressionKeys.add("${http.header.uid}"); + expressionKeys.add("${http.header.name}"); + when(routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE, + MetadataContext.LOCAL_SERVICE, peerService)).thenReturn(expressionKeys); + + // mock local metadata + Map localMetadata = new HashMap<>(); + localMetadata.put("k3", "v31"); + localMetadata.put("k4", "v4"); + when(metadataLocalProperties.getContent()).thenReturn(localMetadata); + + routerLabelFeignInterceptor.apply(requestTemplate); + + Collection routerLabels = requestTemplate.headers().get(RouterConstants.ROUTER_LABEL_HEADER); + + Assert.assertNotNull(routerLabels); + for (String value : routerLabels) { + Map labels = unescape(JacksonUtils.deserialize2Map(value)); + + Assert.assertEquals("v1", labels.get("k1")); + Assert.assertEquals("v22", labels.get("k2")); + Assert.assertEquals("v3", labels.get("k3")); + Assert.assertEquals("v4", labels.get("k4")); + Assert.assertEquals(headerUidValue, labels.get("${http.header.uid}")); + Assert.assertEquals("", labels.get("${http.header.name}")); + } + } + } + } + + private Map unescape(Map labels) { + Map result = new HashMap<>(); + for (Map.Entry entry : labels.entrySet()) { + result.put(ExpressionLabelUtils.unescape(entry.getKey()), ExpressionLabelUtils.unescape(entry.getValue())); + } + return result; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java new file mode 100644 index 000000000..e335e83fa --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java @@ -0,0 +1,93 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router.resttemplate; + +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.BeanFactoryUtils; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; +import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory; + +import static org.mockito.Mockito.when; + +/** + * Test for ${@link PolarisLoadBalancerBeanPostProcessor} + * @author lepdou 2022-05-26 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisLoadBalancerBeanPostProcessorTest { + + @Mock + private LoadBalancerClient loadBalancerClient; + @Mock + private LoadBalancerRequestFactory loadBalancerRequestFactory; + @Mock + private MetadataLocalProperties metadataLocalProperties; + @Mock + private RouterRuleLabelResolver routerRuleLabelResolver; + @Mock + private BeanFactory beanFactory; + + @Test + public void testWrapperLoadBalancerInterceptor() { + when(beanFactory.getBean(LoadBalancerRequestFactory.class)).thenReturn(loadBalancerRequestFactory); + when(beanFactory.getBean(LoadBalancerClient.class)).thenReturn(loadBalancerClient); + when(beanFactory.getBean(MetadataLocalProperties.class)).thenReturn(metadataLocalProperties); + when(beanFactory.getBean(RouterRuleLabelResolver.class)).thenReturn(routerRuleLabelResolver); + + try (MockedStatic mockedBeanFactoryUtils = Mockito.mockStatic(BeanFactoryUtils.class)) { + mockedBeanFactoryUtils.when(() -> BeanFactoryUtils.getBeans(beanFactory, RouterLabelResolver.class)) + .thenReturn(null); + LoadBalancerInterceptor loadBalancerInterceptor = new LoadBalancerInterceptor(loadBalancerClient, loadBalancerRequestFactory); + + PolarisLoadBalancerBeanPostProcessor processor = new PolarisLoadBalancerBeanPostProcessor(); + processor.setBeanFactory(beanFactory); + + Object bean = processor.postProcessBeforeInitialization(loadBalancerInterceptor, ""); + + Assert.assertTrue(bean instanceof PolarisLoadBalancerInterceptor); + } + } + + @Test + public void testNotWrapperLoadBalancerInterceptor() { + PolarisLoadBalancerBeanPostProcessor processor = new PolarisLoadBalancerBeanPostProcessor(); + processor.setBeanFactory(beanFactory); + + OtherBean otherBean = new OtherBean(); + Object bean = processor.postProcessBeforeInitialization(otherBean, ""); + Assert.assertFalse(bean instanceof PolarisLoadBalancerInterceptor); + Assert.assertTrue(bean instanceof OtherBean); + } + + static class OtherBean { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptorTest.java new file mode 100644 index 000000000..edbe8f240 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptorTest.java @@ -0,0 +1,250 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.polaris.router.resttemplate; + + +import java.io.IOException; +import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.polaris.router.PolarisRouterContext; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest; +import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.mock.http.client.MockClientHttpResponse; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * test for {@link PolarisLoadBalancerInterceptor} + * @author lepdou 2022-05-26 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisLoadBalancerInterceptorTest { + + @Mock + private RibbonLoadBalancerClient loadBalancerClient; + @Mock + private LoadBalancerRequestFactory loadBalancerRequestFactory; + @Mock + private RouterLabelResolver routerLabelResolver; + @Mock + private MetadataLocalProperties metadataLocalProperties; + @Mock + private RouterRuleLabelResolver routerRuleLabelResolver; + + @Test + public void testProxyRibbonLoadBalance() throws Exception { + String callerService = "callerService"; + String calleeService = "calleeService"; + HttpRequest request = new MockedHttpRequest("http://" + calleeService + "/user/get"); + + // mock local metadata + Map localMetadata = new HashMap<>(); + localMetadata.put("k1", "v1"); + localMetadata.put("k2", "v2"); + when(metadataLocalProperties.getContent()).thenReturn(localMetadata); + + // mock custom resolved from request + Map customResolvedLabels = new HashMap<>(); + customResolvedLabels.put("k3", "v3"); + customResolvedLabels.put("k4", "v4"); + when(routerLabelResolver.resolve(request, null)).thenReturn(customResolvedLabels); + + // mock expression rule labels + + Set expressionKeys = new HashSet<>(); + expressionKeys.add("${http.method}"); + expressionKeys.add("${http.uri}"); + when(routerRuleLabelResolver.getExpressionLabelKeys(callerService, callerService, calleeService)).thenReturn(expressionKeys); + + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn(callerService); + + MetadataContext metadataContext = Mockito.mock(MetadataContext.class); + + // mock transitive metadata + Map transitiveLabels = new HashMap<>(); + transitiveLabels.put("k1", "v1"); + transitiveLabels.put("k2", "v22"); + when(metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE)).thenReturn(transitiveLabels); + + try (MockedStatic mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) { + mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); + + LoadBalancerRequest loadBalancerRequest = new MockedLoadBalancerRequest<>(); + when(loadBalancerRequestFactory.createRequest(request, null, null)).thenReturn(loadBalancerRequest); + + PolarisLoadBalancerInterceptor polarisLoadBalancerInterceptor = new PolarisLoadBalancerInterceptor(loadBalancerClient, + loadBalancerRequestFactory, Collections.singletonList(routerLabelResolver), metadataLocalProperties, routerRuleLabelResolver); + + polarisLoadBalancerInterceptor.intercept(request, null, null); + + verify(metadataLocalProperties).getContent(); + verify(routerRuleLabelResolver).getExpressionLabelKeys(callerService, callerService, calleeService); + verify(routerLabelResolver).resolve(request, null); + } + } + } + + @Test + public void testNotProxyRibbonLoadBalance() throws IOException { + String calleeService = "calleeService"; + HttpRequest request = new MockedHttpRequest("http://" + calleeService + "/user/get"); + + LoadBalancerRequest loadBalancerRequest = new MockedLoadBalancerRequest<>(); + when(loadBalancerRequestFactory.createRequest(request, null, null)).thenReturn(loadBalancerRequest); + + LoadBalancerClient notRibbonLoadBalancerClient = Mockito.mock(LoadBalancerClient.class); + ClientHttpResponse mockedResponse = new MockClientHttpResponse(new byte[] {}, HttpStatus.OK); + when(notRibbonLoadBalancerClient.execute(calleeService, loadBalancerRequest)).thenReturn(mockedResponse); + + PolarisLoadBalancerInterceptor polarisLoadBalancerInterceptor = new PolarisLoadBalancerInterceptor( + notRibbonLoadBalancerClient, loadBalancerRequestFactory, + Collections.singletonList(routerLabelResolver), metadataLocalProperties, + routerRuleLabelResolver); + + ClientHttpResponse response = polarisLoadBalancerInterceptor.intercept(request, null, null); + + Assert.assertEquals(mockedResponse, response); + verify(loadBalancerRequestFactory).createRequest(request, null, null); + verify(notRibbonLoadBalancerClient).execute(calleeService, loadBalancerRequest); + + } + + @Test + public void testRouterContext() throws Exception { + String callerService = "callerService"; + String calleeService = "calleeService"; + HttpRequest request = new MockedHttpRequest("http://" + calleeService + "/user/get"); + + // mock local metadata + Map localMetadata = new HashMap<>(); + localMetadata.put("k1", "v1"); + localMetadata.put("k2", "v2"); + when(metadataLocalProperties.getContent()).thenReturn(localMetadata); + + // mock custom resolved from request + Map customResolvedLabels = new HashMap<>(); + customResolvedLabels.put("k2", "v22"); + customResolvedLabels.put("k4", "v4"); + when(routerLabelResolver.resolve(request, null)).thenReturn(customResolvedLabels); + + // mock expression rule labels + + Set expressionKeys = new HashSet<>(); + expressionKeys.add("${http.method}"); + expressionKeys.add("${http.uri}"); + when(routerRuleLabelResolver.getExpressionLabelKeys(callerService, callerService, calleeService)).thenReturn(expressionKeys); + + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn(callerService); + + MetadataContext metadataContext = Mockito.mock(MetadataContext.class); + + // mock transitive metadata + Map transitiveLabels = new HashMap<>(); + transitiveLabels.put("k1", "v1"); + transitiveLabels.put("k2", "v22"); + when(metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE)).thenReturn(transitiveLabels); + + try (MockedStatic mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) { + mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); + + PolarisLoadBalancerInterceptor polarisLoadBalancerInterceptor = new PolarisLoadBalancerInterceptor(loadBalancerClient, + loadBalancerRequestFactory, Collections.singletonList(routerLabelResolver), metadataLocalProperties, routerRuleLabelResolver); + + PolarisRouterContext routerContext = polarisLoadBalancerInterceptor.genRouterContext(request, null, calleeService); + + verify(metadataLocalProperties).getContent(); + verify(routerRuleLabelResolver).getExpressionLabelKeys(callerService, callerService, calleeService); + verify(routerLabelResolver).resolve(request, null); + + Assert.assertEquals("v1", routerContext.getLabels(PolarisRouterContext.TRANSITIVE_LABELS).get("k1")); + Assert.assertEquals("v22", routerContext.getLabels(PolarisRouterContext.TRANSITIVE_LABELS).get("k2")); + Assert.assertEquals("v1", routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).get("k1")); + Assert.assertEquals("v22", routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).get("k2")); + Assert.assertEquals("v4", routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).get("k4")); + Assert.assertEquals("GET", routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).get("${http.method}")); + Assert.assertEquals("/user/get", routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS).get("${http.uri}")); + } + } + } + + static class MockedLoadBalancerRequest implements LoadBalancerRequest { + + @Override + public T apply(ServiceInstance instance) throws Exception { + return null; + } + } + + static class MockedHttpRequest implements HttpRequest { + + private URI uri; + + MockedHttpRequest(String url) { + this.uri = URI.create(url); + } + + @Override + public String getMethodValue() { + return HttpMethod.GET.name(); + } + + @Override + public URI getURI() { + return uri; + } + + @Override + public HttpHeaders getHeaders() { + return null; + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java index 4cfcb11a1..0bda18cde 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java @@ -20,8 +20,11 @@ package com.tencent.cloud.common.util; import java.net.URI; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import org.springframework.util.StringUtils; + /** * the utils of parse address. * @@ -36,6 +39,9 @@ public final class AddressUtils { } public static List parseAddressList(String addressInfo) { + if (StringUtils.isEmpty(addressInfo)) { + return Collections.emptyList(); + } List addressList = new ArrayList<>(); String[] addresses = addressInfo.split(ADDRESS_SEPARATOR); for (String address : addresses) { diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java index 26557aa3d..41d70abd7 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java @@ -87,7 +87,7 @@ public class ExpressionLabelUtils { /** * the escape prefix of label. */ - public static final String LABEL_ESCAPE_PREFIX = "$$$$"; + public static final String LABEL_ESCAPE_PREFIX = "##@$@##"; public static boolean isExpressionLabel(String labelKey) { if (StringUtils.isEmpty(labelKey)) { @@ -119,6 +119,9 @@ public class ExpressionLabelUtils { Map labels = new HashMap<>(); for (String labelKey : labelKeys) { + if (!isExpressionLabel(labelKey)) { + continue; + } if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) { String headerKey = parseHeaderKey(labelKey); if (StringUtils.isBlank(headerKey)) { @@ -159,6 +162,9 @@ public class ExpressionLabelUtils { Map labels = new HashMap<>(); for (String labelKey : labelKeys) { + if (!isExpressionLabel(labelKey)) { + continue; + } if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) { String headerKey = parseHeaderKey(labelKey); if (StringUtils.isBlank(headerKey)) { @@ -199,6 +205,9 @@ public class ExpressionLabelUtils { Map labels = new HashMap<>(); for (String labelKey : labelKeys) { + if (!isExpressionLabel(labelKey)) { + continue; + } if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) { String headerKey = parseHeaderKey(labelKey); if (StringUtils.isBlank(headerKey)) { diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/AddressUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/AddressUtilsTest.java new file mode 100644 index 000000000..8040e7add --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/AddressUtilsTest.java @@ -0,0 +1,66 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.common.util; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * test for {@link AddressUtils} + *@author lepdou 2022-05-27 + */ +@RunWith(MockitoJUnitRunner.class) +public class AddressUtilsTest { + + @Test + public void testEmptyStr() { + List result = AddressUtils.parseAddressList(""); + Assert.assertEquals(0, result.size()); + } + + @Test + public void testNullStr() { + List result = AddressUtils.parseAddressList(null); + Assert.assertEquals(0, result.size()); + } + + @Test + public void testOneStr() { + String host1 = "http://localhost"; + List result = AddressUtils.parseAddressList(host1); + Assert.assertEquals(1, result.size()); + Assert.assertTrue(result.contains("localhost")); + } + + @Test + public void testMultiStr() { + String host1 = "http://localhost"; + String host2 = "http://localhost2"; + String host3 = "http://localhost3"; + List result = AddressUtils.parseAddressList(host1 + "," + host2 + "," + host3); + Assert.assertEquals(3, result.size()); + Assert.assertTrue(result.contains("localhost")); + Assert.assertTrue(result.contains("localhost2")); + Assert.assertTrue(result.contains("localhost3")); + } +} diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java new file mode 100644 index 000000000..3c7eabed7 --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java @@ -0,0 +1,246 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.common.util; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Sets; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.http.HttpCookie; +import org.springframework.http.HttpMethod; +import org.springframework.mock.http.client.MockClientHttpRequest; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.MockCookie; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.server.MockServerWebExchange; + +/** + * test for {@link ExpressionLabelUtils} + *@author lepdou 2022-05-27 + */ +@RunWith(MockitoJUnitRunner.class) +public class ExpressionLabelUtilsTest { + + @Test + public void testExpressionLabel() { + String validLabel1 = "${http.query.uid}"; + String validLabel2 = "${http.header.uid}"; + String validLabel3 = "${http.cookie.uid}"; + String validLabel4 = "${http.method}"; + String validLabel5 = "${http.uri}"; + String invalidLabel1 = "${http.queryuid}"; + String invalidLabel2 = "{http.query.uid}"; + String invalidLabel3 = "${http.query.uid"; + String invalidLabel4 = "$ {http.query.uid}"; + String invalidLabel5 = "${ http.query.uid}"; + String invalidLabel6 = "${query.uid}"; + String invalidLabel7 = "http.query.uid"; + String invalidLabel8 = "$${http.uri}"; + String invalidLabel9 = "#{http.uri}"; + + Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel1)); + Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel2)); + Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel3)); + Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel4)); + Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel5)); + Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel1)); + Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel2)); + Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel3)); + Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel4)); + Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel5)); + Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel6)); + Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel7)); + Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel8)); + Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel9)); + } + + @Test + public void testEscape() { + String validLabel1 = "${http.query.uid}"; + String validLabel2 = "${http.header.uid}"; + String validLabel3 = "${http.cookie.uid}"; + String validLabel4 = "${http.method}"; + String validLabel5 = "${http.uri}"; + String invalidLabel1 = "${http.queryuid}"; + String invalidLabel2 = "{http.query.uid}"; + String invalidLabel3 = "${http.query.uid"; + String invalidLabel4 = "$ {http.query.uid}"; + String invalidLabel5 = "${ http.query.uid}"; + String invalidLabel6 = "${query.uid}"; + String invalidLabel7 = "http.query.uid"; + String invalidLabel8 = "$${http.uri}"; + String invalidLabel9 = "#{http.uri}"; + + Assert.assertEquals(validLabel1, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel1))); + Assert.assertEquals(validLabel2, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel2))); + Assert.assertEquals(validLabel3, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel3))); + Assert.assertEquals(validLabel4, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel4))); + Assert.assertEquals(validLabel5, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel5))); + Assert.assertEquals(invalidLabel1, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel1))); + Assert.assertEquals(invalidLabel2, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel2))); + Assert.assertEquals(invalidLabel3, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel3))); + Assert.assertEquals(invalidLabel4, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel4))); + Assert.assertEquals(invalidLabel5, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel5))); + Assert.assertEquals(invalidLabel6, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel6))); + Assert.assertEquals(invalidLabel7, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel7))); + Assert.assertEquals(invalidLabel8, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel8))); + Assert.assertEquals(invalidLabel9, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel9))); + } + + @Test + public void testResolveHttpServletRequest() { + String validLabel1 = "${http.query.uid}"; + String validLabel2 = "${http.header.uid}"; + String validLabel3 = "${http.cookie.uid}"; + String validLabel4 = "${http.method}"; + String validLabel5 = "${http.uri}"; + String invalidLabel1 = "${http.queryuid}"; + String invalidLabel2 = "{http.query.uid}"; + String invalidLabel3 = "${http.query.uid"; + String invalidLabel4 = "$ {http.query.uid}"; + String invalidLabel5 = "${ http.query.uid}"; + String invalidLabel6 = "${query.uid}"; + String invalidLabel7 = "http.query.uid"; + String invalidLabel8 = "$${http.uri}"; + String invalidLabel9 = "#{http.uri}"; + + Set labelKeys = Sets.newHashSet(validLabel1, validLabel2, validLabel3, validLabel4, validLabel5, + invalidLabel1, invalidLabel2, invalidLabel3, invalidLabel4, invalidLabel5, invalidLabel6, invalidLabel7, + invalidLabel8, invalidLabel9); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setQueryString("uid=zhangsan"); + request.addHeader("uid", "zhangsan"); + request.setCookies(new MockCookie("uid", "zhangsan")); + request.setMethod(HttpMethod.GET.name()); + request.setRequestURI("/users"); + + Map result = ExpressionLabelUtils.resolve(request, labelKeys); + + Assert.assertEquals("zhangsan", result.get(validLabel1)); + Assert.assertEquals("zhangsan", result.get(validLabel2)); + Assert.assertEquals("zhangsan", result.get(validLabel3)); + Assert.assertEquals("GET", result.get(validLabel4)); + Assert.assertEquals("/users", result.get(validLabel5)); + Assert.assertNull(result.get(invalidLabel1)); + Assert.assertNull(result.get(invalidLabel2)); + Assert.assertNull(result.get(invalidLabel3)); + Assert.assertNull(result.get(invalidLabel4)); + Assert.assertNull(result.get(invalidLabel5)); + Assert.assertNull(result.get(invalidLabel6)); + Assert.assertNull(result.get(invalidLabel7)); + Assert.assertNull(result.get(invalidLabel8)); + Assert.assertNull(result.get(invalidLabel9)); + } + + @Test + public void testResolveServerWebExchange() { + String validLabel1 = "${http.query.uid}"; + String validLabel2 = "${http.header.uid}"; + String validLabel3 = "${http.cookie.uid}"; + String validLabel4 = "${http.method}"; + String validLabel5 = "${http.uri}"; + String invalidLabel1 = "${http.queryuid}"; + String invalidLabel2 = "{http.query.uid}"; + String invalidLabel3 = "${http.query.uid"; + String invalidLabel4 = "$ {http.query.uid}"; + String invalidLabel5 = "${ http.query.uid}"; + String invalidLabel6 = "${query.uid}"; + String invalidLabel7 = "http.query.uid"; + String invalidLabel8 = "$${http.uri}"; + String invalidLabel9 = "#{http.uri}"; + + Set labelKeys = Sets.newHashSet(validLabel1, validLabel2, validLabel3, validLabel4, validLabel5, + invalidLabel1, invalidLabel2, invalidLabel3, invalidLabel4, invalidLabel5, invalidLabel6, invalidLabel7, + invalidLabel8, invalidLabel9); + + MockServerHttpRequest httpRequest = MockServerHttpRequest.get("http://calleeService/user/get?uid=zhangsan") + .header("uid", "zhangsan") + .cookie(new HttpCookie("uid", "zhangsan")).build(); + MockServerWebExchange exchange = new MockServerWebExchange.Builder(httpRequest).build(); + + Map result = ExpressionLabelUtils.resolve(exchange, labelKeys); + + Assert.assertEquals("zhangsan", result.get(validLabel1)); + Assert.assertEquals("zhangsan", result.get(validLabel2)); + Assert.assertEquals("zhangsan", result.get(validLabel3)); + Assert.assertEquals("GET", result.get(validLabel4)); + Assert.assertEquals("/user/get", result.get(validLabel5)); + Assert.assertNull(result.get(invalidLabel1)); + Assert.assertNull(result.get(invalidLabel2)); + Assert.assertNull(result.get(invalidLabel3)); + Assert.assertNull(result.get(invalidLabel4)); + Assert.assertNull(result.get(invalidLabel5)); + Assert.assertNull(result.get(invalidLabel6)); + Assert.assertNull(result.get(invalidLabel7)); + Assert.assertNull(result.get(invalidLabel8)); + Assert.assertNull(result.get(invalidLabel9)); + } + + @Test + public void testResolveHttpRequest() { + String validLabel1 = "${http.query.uid}"; + String validLabel2 = "${http.header.uid}"; + String validLabel3 = "${http.cookie.uid}"; + String validLabel4 = "${http.method}"; + String validLabel5 = "${http.uri}"; + String invalidLabel1 = "${http.queryuid}"; + String invalidLabel2 = "{http.query.uid}"; + String invalidLabel3 = "${http.query.uid"; + String invalidLabel4 = "$ {http.query.uid}"; + String invalidLabel5 = "${ http.query.uid}"; + String invalidLabel6 = "${query.uid}"; + String invalidLabel7 = "http.query.uid"; + String invalidLabel8 = "$${http.uri}"; + String invalidLabel9 = "#{http.uri}"; + + Set labelKeys = Sets.newHashSet(validLabel1, validLabel2, validLabel3, validLabel4, validLabel5, + invalidLabel1, invalidLabel2, invalidLabel3, invalidLabel4, invalidLabel5, invalidLabel6, invalidLabel7, + invalidLabel8, invalidLabel9); + + MockClientHttpRequest request = new MockClientHttpRequest(); + request.setMethod(HttpMethod.GET); + request.setURI(URI.create("http://calleeService/user/get?uid=zhangsan")); + request.getHeaders().add("uid", "zhangsan"); + + Map result = ExpressionLabelUtils.resolve(request, labelKeys); + + Assert.assertEquals("zhangsan", result.get(validLabel1)); + Assert.assertEquals("zhangsan", result.get(validLabel2)); + Assert.assertNull(result.get(validLabel3)); + Assert.assertEquals("GET", result.get(validLabel4)); + Assert.assertEquals("/user/get", result.get(validLabel5)); + Assert.assertNull(result.get(invalidLabel1)); + Assert.assertNull(result.get(invalidLabel2)); + Assert.assertNull(result.get(invalidLabel3)); + Assert.assertNull(result.get(invalidLabel4)); + Assert.assertNull(result.get(invalidLabel5)); + Assert.assertNull(result.get(invalidLabel6)); + Assert.assertNull(result.get(invalidLabel7)); + Assert.assertNull(result.get(invalidLabel8)); + Assert.assertNull(result.get(invalidLabel9)); + } + +} diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/JacksonUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/JacksonUtilsTest.java new file mode 100644 index 000000000..5bd61a7d6 --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/JacksonUtilsTest.java @@ -0,0 +1,50 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.common.util; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * test for {@link JacksonUtils} + *@author lepdou 2022-05-27 + */ +@RunWith(MockitoJUnitRunner.class) +public class JacksonUtilsTest { + + @Test + public void test() { + Map sourceMap = new HashMap<>(); + sourceMap.put("k1", "v1"); + sourceMap.put("k2", "v2"); + sourceMap.put("k3", "v3"); + + Map map = JacksonUtils.deserialize2Map(JacksonUtils.serialize2Json(sourceMap)); + + Assert.assertEquals(sourceMap.size(), map.size()); + Assert.assertEquals(sourceMap.get("k1"), map.get("k1")); + Assert.assertEquals(sourceMap.get("k2"), map.get("k2")); + Assert.assertEquals(sourceMap.get("k3"), map.get("k3")); + } +} diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ResourceFileUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ResourceFileUtilsTest.java new file mode 100644 index 000000000..334cd4e20 --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ResourceFileUtilsTest.java @@ -0,0 +1,46 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.common.util; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * test for {@link ResourceFileUtils} + *@author lepdou 2022-05-27 + */ +@RunWith(MockitoJUnitRunner.class) +public class ResourceFileUtilsTest { + + @Test + public void testReadExistedFile() throws IOException { + String content = ResourceFileUtils.readFile("test.txt"); + Assert.assertEquals("just for test\n", content); + } + + @Test + public void testReadNotExistedFile() throws IOException { + String content = ResourceFileUtils.readFile("not_existed_test.txt"); + Assert.assertEquals("", content); + } +} diff --git a/spring-cloud-tencent-commons/src/test/resources/test.txt b/spring-cloud-tencent-commons/src/test/resources/test.txt new file mode 100644 index 000000000..63d3c2d75 --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/resources/test.txt @@ -0,0 +1 @@ +just for test diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 573b296f7..1caacd35f 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -73,6 +73,8 @@ 1.5.0-Hoxton.SR9-SNAPSHOT 1.6.0-SNAPSHOT 2.0.0 + 4.5.1 + 1.12.10 3.2.0 @@ -158,6 +160,27 @@ powermock-api-mockito2 ${powermock.version} + + + org.mockito + mockito-inline + ${mocktio.version} + test + + + + org.mockito + mockito-core + ${mocktio.version} + test + + + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + test +