diff --git a/CHANGELOG.md b/CHANGELOG.md index fa0e66af2..2db83e4ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,4 +6,6 @@ - [Optimize: Register the service with the ProviderAPI#registerInstance method.](https://github.com/Tencent/spring-cloud-tencent/pull/686) - [docs:update PR template.](https://github.com/Tencent/spring-cloud-tencent/pull/690) - [enhancement: revert default value when the field is deleted in @ConfigurationProperties bean](https://github.com/Tencent/spring-cloud-tencent/issues/681) +- [Code optimize & add junit tests.](https://github.com/Tencent/spring-cloud-tencent/pull/701) - [Optimize: remote deprecated method](https://github.com/Tencent/spring-cloud-tencent/pull/697) +- [Test:support environment variable metadata test](https://github.com/Tencent/spring-cloud-tencent/pull/698) diff --git a/spring-cloud-tencent-commons/pom.xml b/spring-cloud-tencent-commons/pom.xml index 6cf993ed3..5e373d142 100644 --- a/spring-cloud-tencent-commons/pom.xml +++ b/spring-cloud-tencent-commons/pom.xml @@ -99,6 +99,11 @@ spring-boot-actuator-autoconfigure true - + + uk.org.webcompere + system-stubs-junit4 + test + + diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java index 9581d8ca5..63ea080fb 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java @@ -107,7 +107,8 @@ public class StaticMetadataManager { String value = entry.getValue(); if (StringUtils.isNotBlank(key) && (key.startsWith(ENV_METADATA_PREFIX) || key.equals(ENV_TRAFFIC_CONTENT_RAW_TRANSHEADERS)) - && !key.equals(ENV_METADATA_CONTENT_TRANSITIVE)) { + && !key.equals(ENV_METADATA_CONTENT_TRANSITIVE) + && !key.equals(ENV_METADATA_CONTENT_DISPOSABLE)) { String sourceKey = ""; if (key.equals(ENV_TRAFFIC_CONTENT_RAW_TRANSHEADERS)) { sourceKey = key; diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/rule/ConditionUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/rule/ConditionUtils.java index 6092c0516..c5f924d6e 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/rule/ConditionUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/rule/ConditionUtils.java @@ -31,7 +31,6 @@ public final class ConditionUtils { } public static boolean match(Map actualValues, List conditions) { - boolean allMatched = true; for (Condition condition : conditions) { List expectedValues = condition.getValues(); String operation = condition.getOperation(); @@ -39,10 +38,9 @@ public final class ConditionUtils { String actualValue = actualValues.get(key); if (!Operation.match(expectedValues, actualValue, operation)) { - allMatched = false; - break; + return false; } } - return allMatched; + return true; } } diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/StaticMetadataManagerTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/StaticMetadataManagerTest.java index 64aa20bcb..4ca51fdc8 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/StaticMetadataManagerTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/StaticMetadataManagerTest.java @@ -27,10 +27,12 @@ import java.util.Set; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.spi.InstanceMetadataProvider; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import uk.org.webcompere.systemstubs.rules.EnvironmentVariablesRule; import org.springframework.util.CollectionUtils; @@ -48,6 +50,12 @@ public class StaticMetadataManagerTest { @Mock private MetadataLocalProperties metadataLocalProperties; + /** + * EnvironmentVariablesRule. + */ + @Rule + public EnvironmentVariablesRule rule = new EnvironmentVariablesRule(); + @Test public void testParseConfigMetadata() { Map content = new HashMap<>(); @@ -134,12 +142,12 @@ public class StaticMetadataManagerTest { Assert.assertEquals("v1", metadata.get("k1")); Assert.assertEquals("v22", metadata.get("k2")); - Assert.assertEquals("zone2", metadataManager.getZone()); - Assert.assertEquals("region1", metadataManager.getRegion()); - Assert.assertTrue(CollectionUtils.isEmpty(metadataManager.getAllEnvMetadata())); Assert.assertTrue(CollectionUtils.isEmpty(metadataManager.getEnvTransitiveMetadata())); + Assert.assertEquals("zone2", metadataManager.getZone()); + Assert.assertEquals("region1", metadataManager.getRegion()); + Map locationInfo = metadataManager.getLocationMetadata(); Assert.assertEquals("zone2", locationInfo.get("zone")); Assert.assertEquals("region1", locationInfo.get("region")); @@ -147,6 +155,32 @@ public class StaticMetadataManagerTest { } + @Test + public void testEnvMetadata() { + // set env + rule.set("SCT_METADATA_CONTENT_TRANSITIVE", "transitiveKey"); + rule.set("SCT_METADATA_CONTENT_DISPOSABLE", "disposableKey"); + rule.set("SCT_METADATA_CONTENT_transitiveKey", "transitiveValue"); + rule.set("SCT_METADATA_CONTENT_disposableKey", "disposableValue"); + rule.set("SCT_TRAFFIC_CONTENT_RAW_TRANSHEADERS", "header1,header2,header3"); + + StaticMetadataManager metadataManager = new StaticMetadataManager(metadataLocalProperties, null); + Map allEnvMetadata = metadataManager.getAllEnvMetadata(); + Assert.assertTrue(allEnvMetadata.containsKey("transitiveKey")); + Assert.assertTrue(allEnvMetadata.containsKey("disposableKey")); + + Map envDisposableMetadata = metadataManager.getEnvDisposableMetadata(); + Assert.assertTrue(envDisposableMetadata.containsKey("disposableKey")); + Assert.assertEquals(envDisposableMetadata.get("disposableKey"), "disposableValue"); + + Map envTransitiveMetadata = metadataManager.getEnvTransitiveMetadata(); + Assert.assertTrue(envTransitiveMetadata.containsKey("transitiveKey")); + Assert.assertEquals(envTransitiveMetadata.get("transitiveKey"), "transitiveValue"); + + String transHeaderFromEnv = metadataManager.getTransHeaderFromEnv(); + Assert.assertEquals(transHeaderFromEnv, "header1,header2,header3"); + } + static class MockedMetadataProvider implements InstanceMetadataProvider { @Override diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 8126a44b3..3c89b07cf 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -80,6 +80,7 @@ 1.12.10 3.16.1 1.69 + 2.0.1 3.2.0 @@ -248,6 +249,13 @@ ${mocktio.version} test + + + uk.org.webcompere + system-stubs-junit4 + ${system-stubs-junit4.version} + test + diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/pom.xml index 06a9c65e0..863f6fc9a 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/pom.xml +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/pom.xml @@ -30,5 +30,11 @@ spring-boot-starter-test test + + + org.mockito + mockito-inline + test + diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfiguration.java index 1d33cfb49..16ca5303b 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfiguration.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfiguration.java @@ -20,7 +20,6 @@ package com.tencent.cloud.plugin.gateway; import java.util.List; -import com.tencent.cloud.plugin.gateway.staining.StainingProperties; import com.tencent.cloud.plugin.gateway.staining.TrafficStainer; import com.tencent.cloud.plugin.gateway.staining.TrafficStainingGatewayFilter; import com.tencent.cloud.plugin.gateway.staining.rule.RuleStainingExecutor; @@ -45,44 +44,33 @@ import org.springframework.context.annotation.Configuration; public class SCGPluginsAutoConfiguration { @Configuration - @ConditionalOnProperty("spring.cloud.tencent.plugin.scg.staining.enabled") - public static class StainingPluginConfiguration { + @ConditionalOnProperty("spring.cloud.tencent.plugin.scg.staining.rule-staining.enabled") + @ConditionalOnPolarisConfigEnabled + public static class RuleStainingPluginConfiguration { @Bean - public StainingProperties stainingProperties() { - return new StainingProperties(); + public RuleStainingProperties ruleStainingProperties() { + return new RuleStainingProperties(); } - @Configuration - @ConditionalOnProperty(value = "spring.cloud.tencent.plugin.scg.staining.rule-staining.enabled", matchIfMissing = true) - @ConditionalOnPolarisConfigEnabled - public static class RuleStainingPluginConfiguration { - - @Bean - public RuleStainingProperties ruleStainingProperties() { - return new RuleStainingProperties(); - } - - @Bean - public StainingRuleManager stainingRuleManager(RuleStainingProperties stainingProperties, ConfigFileService configFileService) { - return new StainingRuleManager(stainingProperties, configFileService); - } + @Bean + public StainingRuleManager stainingRuleManager(RuleStainingProperties stainingProperties, ConfigFileService configFileService) { + return new StainingRuleManager(stainingProperties, configFileService); + } - @Bean - public TrafficStainingGatewayFilter trafficStainingGatewayFilter(List trafficStainer) { - return new TrafficStainingGatewayFilter(trafficStainer); - } + @Bean + public TrafficStainingGatewayFilter trafficStainingGatewayFilter(List trafficStainer) { + return new TrafficStainingGatewayFilter(trafficStainer); + } - @Bean - public RuleStainingExecutor ruleStainingExecutor() { - return new RuleStainingExecutor(); - } + @Bean + public RuleStainingExecutor ruleStainingExecutor() { + return new RuleStainingExecutor(); + } - @Bean - public RuleTrafficStainer ruleTrafficStainer(StainingRuleManager stainingRuleManager, - RuleStainingExecutor ruleStainingExecutor) { - return new RuleTrafficStainer(stainingRuleManager, ruleStainingExecutor); - } + @Bean + public RuleTrafficStainer ruleTrafficStainer(StainingRuleManager stainingRuleManager, RuleStainingExecutor ruleStainingExecutor) { + return new RuleTrafficStainer(stainingRuleManager, ruleStainingExecutor); } } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/staining/StainingProperties.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/staining/StainingProperties.java deleted file mode 100644 index 226563bb9..000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/staining/StainingProperties.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.plugin.gateway.staining; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * The properties for traffic staining. - * @author lepdou 2022-07-07 - */ -@ConfigurationProperties("spring.cloud.tencent.plugin.scg.staining") -public class StainingProperties { - - private boolean enabled; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } -} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfigurationTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfigurationTest.java new file mode 100644 index 000000000..21314544d --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfigurationTest.java @@ -0,0 +1,72 @@ +/* + * 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.plugin.gateway; + +import com.tencent.cloud.plugin.gateway.staining.TrafficStainingGatewayFilter; +import com.tencent.cloud.plugin.gateway.staining.rule.RuleStainingExecutor; +import com.tencent.cloud.plugin.gateway.staining.rule.RuleStainingProperties; +import com.tencent.cloud.plugin.gateway.staining.rule.RuleTrafficStainer; +import com.tencent.cloud.plugin.gateway.staining.rule.StainingRuleManager; +import com.tencent.polaris.client.api.SDKContext; +import com.tencent.polaris.configuration.api.core.ConfigFileService; +import com.tencent.polaris.configuration.factory.ConfigFileServiceFactory; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; + +/** + * Test for {@link SCGPluginsAutoConfiguration}. + * @author derek.yi 2022-11-03 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = DEFINED_PORT, classes = SCGPluginsAutoConfigurationTest.TestApplication.class, + properties = {"server.port=8081", "spring.config.location = classpath:application-test.yml", + "spring.cloud.tencent.plugin.scg.staining.rule-staining.enabled = true"}) +public class SCGPluginsAutoConfigurationTest { + + @Autowired + private ApplicationContext applicationContext; + + @Test + public void testAutoConfiguration() { + Assert.assertEquals(1, applicationContext.getBeansOfType(RuleStainingProperties.class).size()); + Assert.assertEquals(1, applicationContext.getBeansOfType(StainingRuleManager.class).size()); + Assert.assertEquals(1, applicationContext.getBeansOfType(TrafficStainingGatewayFilter.class).size()); + Assert.assertEquals(1, applicationContext.getBeansOfType(RuleStainingExecutor.class).size()); + Assert.assertEquals(1, applicationContext.getBeansOfType(RuleTrafficStainer.class).size()); + } + + @SpringBootApplication + public static class TestApplication { + + @Bean + public ConfigFileService configFileService(SDKContext sdkContext) { + return ConfigFileServiceFactory.createConfigFileService(sdkContext); + } + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainerGatewayFilterTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainerGatewayFilterTest.java deleted file mode 100644 index 6339691db..000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainerGatewayFilterTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.plugin.gateway.staining; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; -import reactor.core.publisher.Mono; - -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.util.CollectionUtils; -import org.springframework.web.server.ServerWebExchange; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * Test for {@link TrafficStainingGatewayFilter}. - * @author lepdou 2022-07-12 - */ -@RunWith(MockitoJUnitRunner.class) -public class TrafficStainerGatewayFilterTest { - - @Mock - private GatewayFilterChain chain; - @Mock - private ServerWebExchange exchange; - - @Test - public void testNoneTrafficStainingImplement() { - TrafficStainingGatewayFilter filter = new TrafficStainingGatewayFilter(null); - - when(chain.filter(exchange)).thenReturn(Mono.empty()); - - filter.filter(exchange, chain); - - verify(chain).filter(exchange); - } - - @Test - public void testMultiStaining() { - TrafficStainer trafficStainer1 = Mockito.mock(TrafficStainer.class); - TrafficStainer trafficStainer2 = Mockito.mock(TrafficStainer.class); - - when(trafficStainer1.getOrder()).thenReturn(1); - when(trafficStainer2.getOrder()).thenReturn(2); - - Map labels1 = new HashMap<>(); - labels1.put("k1", "v1"); - labels1.put("k2", "v2"); - when(trafficStainer1.apply(exchange)).thenReturn(labels1); - - Map labels2 = new HashMap<>(); - labels2.put("k1", "v11"); - labels2.put("k3", "v3"); - when(trafficStainer2.apply(exchange)).thenReturn(labels2); - - TrafficStainingGatewayFilter filter = new TrafficStainingGatewayFilter(Arrays.asList(trafficStainer1, trafficStainer2)); - Map result = filter.getStainedLabels(exchange); - - Assert.assertFalse(CollectionUtils.isEmpty(result)); - Assert.assertEquals("v1", result.get("k1")); - Assert.assertEquals("v2", result.get("k2")); - Assert.assertEquals("v3", result.get("k3")); - } -} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainingGatewayFilterTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainingGatewayFilterTest.java new file mode 100644 index 000000000..9178161a3 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainingGatewayFilterTest.java @@ -0,0 +1,176 @@ +/* + * 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.plugin.gateway.staining; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +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.plugin.gateway.staining.rule.RuleStainingExecutor; +import com.tencent.cloud.plugin.gateway.staining.rule.RuleStainingProperties; +import com.tencent.cloud.plugin.gateway.staining.rule.RuleTrafficStainer; +import com.tencent.cloud.plugin.gateway.staining.rule.StainingRuleManager; +import com.tencent.polaris.configuration.api.core.ConfigFile; +import com.tencent.polaris.configuration.api.core.ConfigFileService; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import reactor.core.publisher.Mono; + +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.util.CollectionUtils; +import org.springframework.web.server.ServerWebExchange; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Test for {@link TrafficStainingGatewayFilter}. + * @author lepdou 2022-07-12 + */ +@RunWith(MockitoJUnitRunner.class) +public class TrafficStainingGatewayFilterTest { + + @Mock + private GatewayFilterChain chain; + @Mock + private ServerWebExchange exchange; + @Mock + private ConfigFileService configFileService; + + private final String testNamespace = "testNamespace"; + private final String testGroup = "testGroup"; + private final String testFileName = "rule.json"; + + @BeforeClass + public static void before() { + Mockito.mockStatic(ApplicationContextAwareUtils.class); + when(ApplicationContextAwareUtils + .getProperties(any())).thenReturn("fooBar"); + } + + @Test + public void testNoneTrafficStainingImplement() { + TrafficStainingGatewayFilter filter = new TrafficStainingGatewayFilter(null); + + when(chain.filter(exchange)).thenReturn(Mono.empty()); + + filter.filter(exchange, chain); + + verify(chain).filter(exchange); + } + + @Test + public void testMultiStaining() { + TrafficStainer trafficStainer1 = Mockito.mock(TrafficStainer.class); + TrafficStainer trafficStainer2 = Mockito.mock(TrafficStainer.class); + + when(trafficStainer1.getOrder()).thenReturn(1); + when(trafficStainer2.getOrder()).thenReturn(2); + + Map labels1 = new HashMap<>(); + labels1.put("k1", "v1"); + labels1.put("k2", "v2"); + when(trafficStainer1.apply(exchange)).thenReturn(labels1); + + Map labels2 = new HashMap<>(); + labels2.put("k1", "v11"); + labels2.put("k3", "v3"); + when(trafficStainer2.apply(exchange)).thenReturn(labels2); + + TrafficStainingGatewayFilter filter = new TrafficStainingGatewayFilter(Arrays.asList(trafficStainer1, trafficStainer2)); + Map result = filter.getStainedLabels(exchange); + + Assert.assertFalse(CollectionUtils.isEmpty(result)); + Assert.assertEquals("v1", result.get("k1")); + Assert.assertEquals("v2", result.get("k2")); + Assert.assertEquals("v3", result.get("k3")); + } + + @Test + public void testNoTrafficStainers() { + MetadataContext metadataContext = new MetadataContext(); + MetadataContextHolder.set(metadataContext); + + TrafficStainingGatewayFilter filter = new TrafficStainingGatewayFilter(null); + filter.filter(exchange, chain); + Map map = metadataContext.getTransitiveMetadata(); + Assert.assertTrue(CollectionUtils.isEmpty(map)); + } + + @Test + public void testWithTrafficStainers() { + MetadataContext metadataContext = new MetadataContext(); + MetadataContextHolder.set(metadataContext); + + RuleStainingProperties ruleStainingProperties = new RuleStainingProperties(); + ruleStainingProperties.setNamespace(testNamespace); + ruleStainingProperties.setGroup(testGroup); + ruleStainingProperties.setFileName(testFileName); + + ConfigFile configFile = Mockito.mock(ConfigFile.class); + when(configFile.getContent()).thenReturn("{\n" + + " \"rules\":[\n" + + " {\n" + + " \"conditions\":[\n" + + " {\n" + + " \"key\":\"${http.query.uid}\",\n" + + " \"values\":[\"1000\"],\n" + + " \"operation\":\"EQUALS\"\n" + + " }\n" + + " ],\n" + + " \"labels\":[\n" + + " {\n" + + " \"key\":\"env\",\n" + + " \"value\":\"blue\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}"); + when(configFileService.getConfigFile(testNamespace, testGroup, testFileName)).thenReturn(configFile); + + StainingRuleManager stainingRuleManager = new StainingRuleManager(ruleStainingProperties, configFileService); + RuleStainingExecutor ruleStainingExecutor = new RuleStainingExecutor(); + RuleTrafficStainer ruleTrafficStainer = new RuleTrafficStainer(stainingRuleManager, ruleStainingExecutor); + + TrafficStainingGatewayFilter filter = new TrafficStainingGatewayFilter(Collections.singletonList(ruleTrafficStainer)); + + MockServerHttpRequest request = MockServerHttpRequest.get("/users") + .queryParam("uid", "1000").build(); + MockServerWebExchange exchange = new MockServerWebExchange.Builder(request).build(); + + filter.filter(exchange, chain); + Map map = metadataContext.getTransitiveMetadata(); + Assert.assertNotNull(map); + Assert.assertEquals(1, map.size()); + Assert.assertEquals("blue", map.get("env")); + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/RuleStainingExecutorTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/RuleStainingExecutorTest.java index 91c0c42d8..c320c0ca6 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/RuleStainingExecutorTest.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/RuleStainingExecutorTest.java @@ -32,6 +32,7 @@ import org.mockito.junit.MockitoJUnitRunner; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.util.CollectionUtils; /** * Test for {@link RuleStainingExecutor}. @@ -178,4 +179,11 @@ public class RuleStainingExecutorTest { Assert.assertEquals("value1", stainedLabels.get("label1")); Assert.assertEquals("value2", stainedLabels.get("label2")); } + + @Test + public void testNoStainingRule() { + RuleStainingExecutor executor = new RuleStainingExecutor(); + Assert.assertTrue(CollectionUtils.isEmpty(executor.execute(null, null))); + Assert.assertTrue(CollectionUtils.isEmpty(executor.execute(null, new StainingRule()))); + } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/RuleTrafficStainerTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/RuleTrafficStainerTest.java new file mode 100644 index 000000000..d8e678750 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/RuleTrafficStainerTest.java @@ -0,0 +1,112 @@ +/* + * 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.plugin.gateway.staining.rule; + +import java.util.Map; + +import com.tencent.polaris.configuration.api.core.ConfigFile; +import com.tencent.polaris.configuration.api.core.ConfigFileService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.util.CollectionUtils; + +import static org.mockito.Mockito.when; + +/** + * Test for {@link RuleTrafficStainer}. + * @author derek.yi 2022-11-03 + */ +@RunWith(MockitoJUnitRunner.class) +public class RuleTrafficStainerTest { + + @Mock + private ConfigFileService configFileService; + + private final String testNamespace = "testNamespace"; + private final String testGroup = "testGroup"; + private final String testFileName = "rule.json"; + + @Test + public void testNoStainingRule() { + RuleStainingProperties ruleStainingProperties = new RuleStainingProperties(); + ruleStainingProperties.setNamespace(testNamespace); + ruleStainingProperties.setGroup(testGroup); + ruleStainingProperties.setFileName(testFileName); + + ConfigFile configFile = Mockito.mock(ConfigFile.class); + when(configFile.getContent()).thenReturn(""); + when(configFileService.getConfigFile(testNamespace, testGroup, testFileName)).thenReturn(configFile); + + StainingRuleManager stainingRuleManager = new StainingRuleManager(ruleStainingProperties, configFileService); + RuleStainingExecutor ruleStainingExecutor = new RuleStainingExecutor(); + RuleTrafficStainer ruleTrafficStainer = new RuleTrafficStainer(stainingRuleManager, ruleStainingExecutor); + Map map = ruleTrafficStainer.apply(null); + Assert.assertTrue(CollectionUtils.isEmpty(map)); + } + + @Test + public void testWithStainingRule() { + RuleStainingProperties ruleStainingProperties = new RuleStainingProperties(); + ruleStainingProperties.setNamespace(testNamespace); + ruleStainingProperties.setGroup(testGroup); + ruleStainingProperties.setFileName(testFileName); + + ConfigFile configFile = Mockito.mock(ConfigFile.class); + when(configFile.getContent()).thenReturn("{\n" + + " \"rules\":[\n" + + " {\n" + + " \"conditions\":[\n" + + " {\n" + + " \"key\":\"${http.query.uid}\",\n" + + " \"values\":[\"1000\"],\n" + + " \"operation\":\"EQUALS\"\n" + + " }\n" + + " ],\n" + + " \"labels\":[\n" + + " {\n" + + " \"key\":\"env\",\n" + + " \"value\":\"blue\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}"); + when(configFileService.getConfigFile(testNamespace, testGroup, testFileName)).thenReturn(configFile); + + StainingRuleManager stainingRuleManager = new StainingRuleManager(ruleStainingProperties, configFileService); + RuleStainingExecutor ruleStainingExecutor = new RuleStainingExecutor(); + RuleTrafficStainer ruleTrafficStainer = new RuleTrafficStainer(stainingRuleManager, ruleStainingExecutor); + + MockServerHttpRequest request = MockServerHttpRequest.get("/users") + .queryParam("uid", "1000").build(); + MockServerWebExchange exchange = new MockServerWebExchange.Builder(request).build(); + + Map map = ruleTrafficStainer.apply(exchange); + Assert.assertNotNull(map); + Assert.assertEquals(1, map.size()); + Assert.assertEquals("blue", map.get("env")); + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/StainingRuleManagerTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/StainingRuleManagerTest.java index 1ac88e3c8..2972d0d84 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/StainingRuleManagerTest.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/staining/rule/StainingRuleManagerTest.java @@ -59,7 +59,7 @@ public class StainingRuleManagerTest { + " {\n" + " \"key\":\"${http.query.uid}\",\n" + " \"values\":[\"1000\"],\n" - + " \"operation\":\"EQUAL\"\n" + + " \"operation\":\"EQUALS\"\n" + " }\n" + " ],\n" + " \"labels\":[\n" @@ -99,7 +99,7 @@ public class StainingRuleManagerTest { + " {\n" + " \"key\":\"${http.query.uid}\",\n" + " \"values\":[\"1000\"],\n" - + " \"operation\":\"EQUAL\"\n" + + " \"operation\":\"EQUALS\"\n" + " }\n" + " ],\n" + " \"labels\":[\n" diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/resources/application-test.yml b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/resources/application-test.yml new file mode 100644 index 000000000..48a51f7a9 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/resources/application-test.yml @@ -0,0 +1,14 @@ +spring: + application: + name: test + cloud: + polaris: + address: grpc://127.0.0.1:8091 + namespace: default + config: + connect-remote-server: false + shutdown-if-connect-to-config-server-failed: false + # auto-refresh: true + config: + import: + - optional:polaris