From 30f57c527dbe456b1fa0e26c508ece625547abac Mon Sep 17 00:00:00 2001 From: lepdou Date: Sat, 11 Jun 2022 18:26:21 +0800 Subject: [PATCH] add unit test for config module (#229) --- pom.xml | 6 +- ...odeTransferMedataFeignInterceptorTest.java | 15 +- ...sferMedataRestTemplateInterceptorTest.java | 45 ++--- .../pom.xml | 24 +++ ...nditionalOnConnectRemoteServerEnabled.java | 37 ++++ ...larisConfigBootstrapAutoConfiguration.java | 11 +- .../adapter/PolarisConfigFileLocator.java | 13 +- ...itional-spring-configuration-metadata.json | 7 + .../config/adapter/MockedConfigKVFile.java | 170 ++++++++++++++++ .../adapter/PolarisConfigFileLocatorTest.java | 188 ++++++++++++++++++ ...arisPropertiesSourceAutoRefresherTest.java | 122 ++++++++++++ .../listener/ConfigChangeListenerTest.java | 124 ++++++++++++ .../src/test/resources/application-test.yml | 9 + spring-cloud-tencent-coverage/pom.xml | 20 +- 14 files changed, 733 insertions(+), 58 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml diff --git a/pom.xml b/pom.xml index 656119d9..1b982d12 100644 --- a/pom.xml +++ b/pom.xml @@ -38,9 +38,11 @@ - spring-cloud-tencent-polaris-context spring-cloud-tencent-commons + spring-cloud-tencent-polaris-context + spring-cloud-tencent-polaris-loadbalancer spring-cloud-starter-tencent-metadata-transfer + spring-cloud-starter-tencent-polaris-config spring-cloud-starter-tencent-polaris-discovery spring-cloud-starter-tencent-polaris-ratelimit spring-cloud-starter-tencent-polaris-circuitbreaker @@ -48,8 +50,6 @@ spring-cloud-tencent-dependencies spring-cloud-tencent-examples spring-cloud-tencent-coverage - spring-cloud-starter-tencent-polaris-config - spring-cloud-tencent-polaris-loadbalancer diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java index ca967163..ef70e38c 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java @@ -19,9 +19,10 @@ package com.tencent.cloud.metadata.core.intercepter; import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import com.tencent.cloud.common.constant.MetadataConstant; +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.metadata.core.EncodeTransferMedataFeignInterceptor; import feign.RequestInterceptor; @@ -62,10 +63,9 @@ public class EncodeTransferMedataFeignInterceptorTest { private TestApplication.TestFeign testFeign; @Test - public void test1() { + public void testTransitiveMetadataFromApplicationConfig() { String metadata = testFeign.test(); - Assertions.assertThat(metadata) - .isEqualTo("{\"b\":\"2\"}"); + Assertions.assertThat(metadata).isEqualTo("2"); Assertions.assertThat(metadataLocalProperties.getContent().get("a")) .isEqualTo("1"); Assertions.assertThat(metadataLocalProperties.getContent().get("b")) @@ -81,16 +81,13 @@ public class EncodeTransferMedataFeignInterceptorTest { public String test( @RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr) throws UnsupportedEncodingException { - return URLDecoder.decode(customMetadataStr, "UTF-8"); + return MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"); } @FeignClient(name = "test-feign", url = "http://localhost:8081") public interface TestFeign { - @RequestMapping(value = "/test", - headers = {"X-SCT-Metadata-Transitive-a=11", - "X-SCT-Metadata-Transitive-b=22", - "X-SCT-Metadata-Transitive-c=33"}) + @RequestMapping("/test") String test(); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java index ba5524c9..78abb33a 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -19,11 +19,12 @@ package com.tencent.cloud.metadata.core.intercepter; import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; +import org.assertj.core.api.Assertions; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,6 +33,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; @@ -51,9 +55,6 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen properties = { "spring.config.location = classpath:application-test.yml" }) public class EncodeTransferMedataRestTemplateInterceptorTest { - @Autowired - private MetadataLocalProperties metadataLocalProperties; - @Autowired private RestTemplate restTemplate; @@ -61,30 +62,14 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { private int localServerPort; @Test - public void test1() { -// HttpHeaders httpHeaders = new HttpHeaders(); -// httpHeaders.set(MetadataConstant.HeaderName.CUSTOM_METADATA, -// "{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}"); -// HttpEntity httpEntity = new HttpEntity<>(httpHeaders); -// String metadata = restTemplate -// .exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET, -// httpEntity, String.class) -// .getBody(); -// Assertions.assertThat(metadata) -// .isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}"); -// Assertions.assertThat(metadataLocalProperties.getContent().get("a")) -// .isEqualTo("1"); -// Assertions.assertThat(metadataLocalProperties.getContent().get("b")) -// .isEqualTo("2"); -// Assertions -// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a")) -// .isEqualTo("11"); -// Assertions -// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b")) -// .isEqualTo("22"); -// Assertions -// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c")) -// .isEqualTo("33"); + public void testTransitiveMetadataFromApplicationConfig() { + HttpHeaders httpHeaders = new HttpHeaders(); + HttpEntity httpEntity = new HttpEntity<>(httpHeaders); + String metadata = restTemplate + .exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET, + httpEntity, String.class) + .getBody(); + Assertions.assertThat(metadata).isEqualTo("2"); } @SpringBootApplication @@ -100,7 +85,7 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { public String test( @RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr) throws UnsupportedEncodingException { - return URLDecoder.decode(customMetadataStr, "UTF-8"); + return MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"); } } diff --git a/spring-cloud-starter-tencent-polaris-config/pom.xml b/spring-cloud-starter-tencent-polaris-config/pom.xml index 10b362a6..a7f0e589 100644 --- a/spring-cloud-starter-tencent-polaris-config/pom.xml +++ b/spring-cloud-starter-tencent-polaris-config/pom.xml @@ -11,6 +11,7 @@ 4.0.0 spring-cloud-starter-tencent-polaris-config + Spring Cloud Starter Tencent Polaris Config @@ -64,5 +65,28 @@ + + 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-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java new file mode 100644 index 00000000..89283ae1 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java @@ -0,0 +1,37 @@ +/* + * 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.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +/** + * Whether to connect to a remote server, suitable for local development mode. + * + * @author lepdou 2022-06-11 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@ConditionalOnProperty(value = "spring.cloud.polaris.config.connect-remote-server", matchIfMissing = true) +public @interface ConditionalOnConnectRemoteServerEnabled { + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java index 1a7e05ac..101ca4a3 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java @@ -51,16 +51,18 @@ public class PolarisConfigBootstrapAutoConfiguration { } @Bean - public ConfigFileService configFileService(SDKContext sdkContext) { - return ConfigFileServiceFactory.createConfigFileService(sdkContext); + public PolarisPropertySourceManager polarisPropertySourceManager() { + return new PolarisPropertySourceManager(); } @Bean - public PolarisPropertySourceManager polarisPropertySourceManager() { - return new PolarisPropertySourceManager(); + @ConditionalOnConnectRemoteServerEnabled + public ConfigFileService configFileService(SDKContext sdkContext) { + return ConfigFileServiceFactory.createConfigFileService(sdkContext); } @Bean + @ConditionalOnConnectRemoteServerEnabled public PolarisConfigFileLocator polarisConfigFileLocator( PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties, @@ -73,6 +75,7 @@ public class PolarisConfigBootstrapAutoConfiguration { } @Bean + @ConditionalOnConnectRemoteServerEnabled public ConfigurationModifier configurationModifier(PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties) { return new ConfigurationModifier(polarisConfigProperties, polarisContextProperties); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java index cad31d1d..240eb4cc 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java @@ -84,13 +84,14 @@ public class PolarisConfigFileLocator implements PropertySourceLocator { CompositePropertySource compositePropertySource = new CompositePropertySource( POLARIS_CONFIG_PROPERTY_SOURCE_NAME); + // load spring boot default config files + initInternalConfigFiles(compositePropertySource); + + // load custom config files List configFileGroups = polarisConfigProperties.getGroups(); if (CollectionUtils.isEmpty(configFileGroups)) { return compositePropertySource; } - - initInternalConfigFiles(compositePropertySource); - initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); return compositePropertySource; @@ -190,12 +191,10 @@ public class PolarisConfigFileLocator implements PropertySourceLocator { // unknown extension is resolved as properties file if (ConfigFileFormat.isPropertyFile(fileName) || ConfigFileFormat.isUnknownFile(fileName)) { - configKVFile = configFileService.getConfigPropertiesFile(namespace, group, - fileName); + configKVFile = configFileService.getConfigPropertiesFile(namespace, group, fileName); } else if (ConfigFileFormat.isYamlFile(fileName)) { - configKVFile = configFileService.getConfigYamlFile(namespace, group, - fileName); + configKVFile = configFileService.getConfigYamlFile(namespace, group, fileName); } else { LOGGER.warn( diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json index ee84cbd4..9954a62c 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -34,6 +34,13 @@ "defaultValue": "", "description": "List of imported config files.", "sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties" + }, + { + "name": "spring.cloud.polaris.config.connect-remote-server", + "type": "java.lang.Boolean", + "defaultValue": "true", + "description": "Whether to connect to a remote server, suitable for local development mode.", + "sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties" } ] } diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java new file mode 100644 index 00000000..026fe4d5 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java @@ -0,0 +1,170 @@ +/* + * 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.config.adapter; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.tencent.polaris.configuration.api.core.ConfigFileChangeListener; +import com.tencent.polaris.configuration.api.core.ConfigKVFile; +import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; +import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeListener; + +/** + * Mock config kv file for test. + *@author lepdou 2022-06-11 + */ +public class MockedConfigKVFile implements ConfigKVFile { + + private final Map properties; + private final List listeners = new ArrayList<>(); + + public MockedConfigKVFile(Map properties) { + this.properties = properties; + } + + @Override + public String getProperty(String s, String s1) { + return String.valueOf(properties.get(s)); + } + + @Override + public Integer getIntProperty(String s, Integer integer) { + return null; + } + + @Override + public Long getLongProperty(String s, Long aLong) { + return null; + } + + @Override + public Short getShortProperty(String s, Short aShort) { + return null; + } + + @Override + public Float getFloatProperty(String s, Float aFloat) { + return null; + } + + @Override + public Double getDoubleProperty(String s, Double aDouble) { + return null; + } + + @Override + public Byte getByteProperty(String s, Byte aByte) { + return null; + } + + @Override + public Boolean getBooleanProperty(String s, Boolean aBoolean) { + return null; + } + + @Override + public String[] getArrayProperty(String s, String s1, String[] strings) { + return new String[0]; + } + + @Override + public > T getEnumProperty(String s, Class aClass, T t) { + return null; + } + + @Override + public T getJsonProperty(String s, Class aClass, T t) { + return null; + } + + @Override + public T getJsonProperty(String s, Type type, T t) { + return null; + } + + @Override + public Set getPropertyNames() { + return properties.keySet(); + } + + @Override + public void addChangeListener(ConfigKVFileChangeListener configKVFileChangeListener) { + listeners.add(configKVFileChangeListener); + } + + @Override + public void removeChangeListener(ConfigKVFileChangeListener configKVFileChangeListener) { + + } + + @Override + public String getContent() { + return null; + } + + @Override + public T asJson(Class aClass, T t) { + return null; + } + + @Override + public T asJson(Type type, T t) { + return null; + } + + @Override + public boolean hasContent() { + return false; + } + + @Override + public void addChangeListener(ConfigFileChangeListener configFileChangeListener) { + + } + + @Override + public void removeChangeListener(ConfigFileChangeListener configFileChangeListener) { + + } + + public void fireChangeListener(ConfigKVFileChangeEvent event) { + for (ConfigKVFileChangeListener listener : listeners) { + listener.onChange(event); + } + } + + @Override + public String getNamespace() { + return null; + } + + @Override + public String getFileGroup() { + return null; + } + + @Override + public String getFileName() { + return null; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java new file mode 100644 index 00000000..6fe0bfa2 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java @@ -0,0 +1,188 @@ +/* + * 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.config.adapter; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.Lists; +import com.tencent.cloud.polaris.config.config.ConfigFileGroup; +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.cloud.polaris.context.PolarisContextProperties; +import com.tencent.polaris.configuration.api.core.ConfigFileService; +import com.tencent.polaris.configuration.api.core.ConfigKVFile; +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.core.env.Environment; +import org.springframework.core.env.PropertySource; + +import static org.mockito.Mockito.when; + +/** + * test for {@link PolarisConfigFileLocator} + *@author lepdou 2022-06-11 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisConfigFileLocatorTest { + + @Mock + private PolarisConfigProperties polarisConfigProperties; + @Mock + private PolarisContextProperties polarisContextProperties; + @Mock + private ConfigFileService configFileService; + @Mock + private PolarisPropertySourceManager polarisPropertySourceManager; + @Mock + private Environment environment; + + private final String testNamespace = "testNamespace"; + private final String testServiceName = "testServiceName"; + + @Test + public void testLoadApplicationPropertiesFile() { + PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, + configFileService, polarisPropertySourceManager, environment); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + when(polarisContextProperties.getService()).thenReturn(testServiceName); + + // application.properties + Map applicationProperties = new HashMap<>(); + applicationProperties.put("k1", "v1"); + applicationProperties.put("k2", "v2"); + applicationProperties.put("k3", "v3"); + ConfigKVFile propertiesFile = new MockedConfigKVFile(applicationProperties); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application.properties")) + .thenReturn(propertiesFile); + + Map emptyMap = new HashMap<>(); + ConfigKVFile emptyConfigFile = new MockedConfigKVFile(emptyMap); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile); + + when(polarisConfigProperties.getGroups()).thenReturn(null); + when(environment.getActiveProfiles()).thenReturn(new String[] {}); + + PropertySource propertySource = locator.locate(environment); + + Assert.assertEquals("v1", propertySource.getProperty("k1")); + Assert.assertEquals("v2", propertySource.getProperty("k2")); + Assert.assertEquals("v3", propertySource.getProperty("k3")); + } + + @Test + public void testActiveProfileFilesPriorityBiggerThanDefault() { + PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, + configFileService, polarisPropertySourceManager, environment); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + when(polarisContextProperties.getService()).thenReturn(testServiceName); + + // application.properties + Map applicationProperties = new HashMap<>(); + applicationProperties.put("k1", "v1"); + applicationProperties.put("k2", "v2"); + applicationProperties.put("k3", "v3"); + ConfigKVFile propertiesFile = new MockedConfigKVFile(applicationProperties); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application.properties")) + .thenReturn(propertiesFile); + + // application-dev.properties + Map devProperties = new HashMap<>(); + devProperties.put("k1", "v11"); + ConfigKVFile devFile = new MockedConfigKVFile(devProperties); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application-dev.properties")) + .thenReturn(devFile); + + Map emptyMap = new HashMap<>(); + ConfigKVFile emptyConfigFile = new MockedConfigKVFile(emptyMap); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application-dev.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap-dev.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap-dev.yml")).thenReturn(emptyConfigFile); + + when(polarisConfigProperties.getGroups()).thenReturn(null); + when(environment.getActiveProfiles()).thenReturn(new String[] {"dev"}); + + PropertySource propertySource = locator.locate(environment); + + Assert.assertEquals("v11", propertySource.getProperty("k1")); + Assert.assertEquals("v2", propertySource.getProperty("k2")); + Assert.assertEquals("v3", propertySource.getProperty("k3")); + } + + @Test + public void testGetCustomFiles() { + PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, + configFileService, polarisPropertySourceManager, environment); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + when(polarisContextProperties.getService()).thenReturn(testServiceName); + + Map emptyMap = new HashMap<>(); + ConfigKVFile emptyConfigFile = new MockedConfigKVFile(emptyMap); + + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile); + + List customFiles = new LinkedList<>(); + ConfigFileGroup configFileGroup = new ConfigFileGroup(); + String customGroup = "group1"; + configFileGroup.setName(customGroup); + String customFile1 = "file1.properties"; + String customFile2 = "file2.properties"; + configFileGroup.setFiles(Lists.newArrayList(customFile1, customFile2)); + customFiles.add(configFileGroup); + + when(polarisConfigProperties.getGroups()).thenReturn(customFiles); + when(environment.getActiveProfiles()).thenReturn(new String[] {}); + + // file1.properties + Map file1Map = new HashMap<>(); + file1Map.put("k1", "v1"); + file1Map.put("k2", "v2"); + ConfigKVFile file1 = new MockedConfigKVFile(file1Map); + when(configFileService.getConfigPropertiesFile(testNamespace, customGroup, customFile1)).thenReturn(file1); + + // file2.properties + Map file2Map = new HashMap<>(); + file2Map.put("k1", "v11"); + file2Map.put("k3", "v3"); + ConfigKVFile file2 = new MockedConfigKVFile(file2Map); + when(configFileService.getConfigPropertiesFile(testNamespace, customGroup, customFile2)).thenReturn(file2); + + PropertySource propertySource = locator.locate(environment); + + Assert.assertEquals("v1", propertySource.getProperty("k1")); + Assert.assertEquals("v2", propertySource.getProperty("k2")); + Assert.assertEquals("v3", propertySource.getProperty("k3")); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java new file mode 100644 index 00000000..648860f3 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java @@ -0,0 +1,122 @@ +/* + * 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.config.adapter; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.Lists; +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.polaris.configuration.api.core.ChangeType; +import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; +import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +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.context.refresh.ContextRefresher; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * test for {@link PolarisPropertySourceAutoRefresher} + *@author lepdou 2022-06-11 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisPropertiesSourceAutoRefresherTest { + + @Mock + private PolarisConfigProperties polarisConfigProperties; + @Mock + private PolarisPropertySourceManager polarisPropertySourceManager; + @Mock + private ContextRefresher contextRefresher; + + private final String testNamespace = "testNamespace"; + private final String testServiceName = "testServiceName"; + private final String testFileName = "application.properties"; + + @Test + public void testConfigFileChanged() { + PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties, + polarisPropertySourceManager, contextRefresher); + + when(polarisConfigProperties.isAutoRefresh()).thenReturn(true); + + Map content = new HashMap<>(); + content.put("k1", "v1"); + content.put("k2", "v2"); + content.put("k3", "v3"); + MockedConfigKVFile file = new MockedConfigKVFile(content); + PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName, + file, content); + + when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + + ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", "v1", "v11", ChangeType.MODIFIED); + ConfigPropertyChangeInfo changeInfo2 = new ConfigPropertyChangeInfo("k4", null, "v4", ChangeType.ADDED); + ConfigPropertyChangeInfo changeInfo3 = new ConfigPropertyChangeInfo("k2", "v2", null, ChangeType.DELETED); + Map changeInfos = new HashMap<>(); + changeInfos.put("k1", changeInfo); + changeInfos.put("k2", changeInfo3); + changeInfos.put("k4", changeInfo2); + + ConfigKVFileChangeEvent event = new ConfigKVFileChangeEvent(changeInfos); + refresher.onApplicationEvent(null); + + file.fireChangeListener(event); + + Assert.assertEquals("v11", polarisPropertySource.getProperty("k1")); + Assert.assertEquals("v3", polarisPropertySource.getProperty("k3")); + Assert.assertNull(polarisPropertySource.getProperty("k2")); + Assert.assertEquals("v4", polarisPropertySource.getProperty("k4")); + verify(contextRefresher).refresh(); + } + + @Test + public void testNewConfigFile() { + PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties, + polarisPropertySourceManager, contextRefresher); + + when(polarisConfigProperties.isAutoRefresh()).thenReturn(true); + + Map emptyContent = new HashMap<>(); + MockedConfigKVFile file = new MockedConfigKVFile(emptyContent); + PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName, + file, emptyContent); + + when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + + ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", null, "v1", ChangeType.ADDED); + Map changeInfos = new HashMap<>(); + changeInfos.put("k1", changeInfo); + + ConfigKVFileChangeEvent event = new ConfigKVFileChangeEvent(changeInfos); + refresher.onApplicationEvent(null); + + file.fireChangeListener(event); + + Assert.assertEquals("v1", polarisPropertySource.getProperty("k1")); + verify(contextRefresher).refresh(); + } + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java new file mode 100644 index 00000000..f3f70b4b --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java @@ -0,0 +1,124 @@ +/* + * 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.config.listener; + +import com.google.common.collect.Sets; +import com.tencent.cloud.polaris.config.annotation.PolarisConfigKVFileChangeListener; +import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.stereotype.Component; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; + +/** + * Integration testing for change listener. + *@author lepdou 2022-06-11 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = DEFINED_PORT, + classes = ConfigChangeListenerTest.TestApplication.class, + properties = {"server.port=8081", + "spring.config.location = classpath:application-test.yml"}) +public class ConfigChangeListenerTest { + + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + @Autowired + private ConfigurableApplicationContext applicationContext; + @Autowired + private TestApplication.TestConfig testConfig; + + @Test + public void test() throws InterruptedException { + //before change + Assert.assertEquals(1000, testConfig.getTimeout()); + + //submit change event + System.setProperty("timeout", "2000"); + EnvironmentChangeEvent event = new EnvironmentChangeEvent(applicationContext, + Sets.newHashSet("timeout")); + + applicationEventPublisher.publishEvent(event); + + //after change + Assert.assertEquals(2, testConfig.getChangeCnt()); + Assert.assertEquals(2000, testConfig.getTimeout()); + } + + + @SpringBootApplication + protected static class TestApplication { + + @Component + protected static class TestConfig { + + @Value("${timeout:1000}") + private int timeout; + + private int changeCnt; + + public int getTimeout() { + return timeout; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + public int getChangeCnt() { + return changeCnt; + } + + @PolarisConfigKVFileChangeListener(interestedKeys = {"timeout"}) + public void configChangedListener(ConfigChangeEvent event) { + ConfigPropertyChangeInfo changeInfo = event.getChange("timeout"); + timeout = Integer.parseInt(changeInfo.getNewValue()); + changeCnt++; + } + + @PolarisConfigKVFileChangeListener(interestedKeyPrefixes = {"timeout"}) + public void configChangedListener2(ConfigChangeEvent event) { + ConfigPropertyChangeInfo changeInfo = event.getChange("timeout"); + timeout = Integer.parseInt(changeInfo.getNewValue()); + changeCnt++; + } + } + + @Component + protected static class EventPublisher implements ApplicationEventPublisher { + + @Override + public void publishEvent(Object o) { + + } + } + } + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml b/spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml new file mode 100644 index 00000000..c90d1340 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml @@ -0,0 +1,9 @@ +spring: + application: + name: test + cloud: + polaris: + address: grpc://127.0.0.1:8091 + namespace: default + config: + connect-remote-server: false diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml index 1c8ba0ed..37903c14 100644 --- a/spring-cloud-tencent-coverage/pom.xml +++ b/spring-cloud-tencent-coverage/pom.xml @@ -24,6 +24,16 @@ spring-cloud-tencent-commons + + com.tencent.cloud + spring-cloud-tencent-polaris-context + + + + com.tencent.cloud + spring-cloud-tencent-polaris-loadbalancer + + com.tencent.cloud spring-cloud-starter-tencent-polaris-discovery @@ -49,10 +59,10 @@ spring-cloud-starter-tencent-polaris-router - - com.tencent.cloud - spring-cloud-tencent-polaris-context - + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-config + @@ -75,4 +85,4 @@ - \ No newline at end of file +