diff --git a/CHANGELOG.md b/CHANGELOG.md index a2021ef03..fa589fc70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,3 +20,5 @@ - [fix:cancel reporting useless metadata.](https://github.com/Tencent/spring-cloud-tencent/pull/639) - [Feature: support read config file from local file system](https://github.com/Tencent/spring-cloud-tencent/pull/640) - [fix:optimize expression parser V1.](https://github.com/Tencent/spring-cloud-tencent/pull/642) +- [Optimize: add transfer metadata unit test.](https://github.com/Tencent/spring-cloud-tencent/pull/646) +- [feat: publish spring event named ConfigChangeSpringEvent when the configuration is changed](https://github.com/Tencent/spring-cloud-tencent/pull/647) diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/TransHeadersTransferTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/TransHeadersTransferTest.java new file mode 100644 index 000000000..eb0c780f0 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/TransHeadersTransferTest.java @@ -0,0 +1,86 @@ +/* + * 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.metadata.core; + +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.util.JacksonUtils; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.runner.RunWith; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * Test for {@link TransHeadersTransfer}. + * + * @author lingxiao.wlx + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, + classes = DecodeTransferMetadataServletFilterTest.TestApplication.class, + properties = {"spring.config.location = classpath:application-test.yml"}) +public class TransHeadersTransferTest { + @AfterClass + public static void afterClass() { + MetadataContextHolder.remove(); + } + + @Test + public void transferServletTest() { + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransHeaders("header1,header2,header3", ""); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("header1", "1"); + request.addHeader("header2", "2"); + request.addHeader("header3", "3"); + TransHeadersTransfer.transfer(request); + Map transHeadersKV = MetadataContextHolder.get().getTransHeadersKV(); + Assertions.assertEquals(transHeadersKV.get("header1"), "1"); + Assertions.assertEquals(transHeadersKV.get("header2"), "2"); + Assertions.assertEquals(transHeadersKV.get("header3"), "3"); + } + + @Test + public void transferReactiveTest() { + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransHeaders("header1,header2,header3", ""); + MockServerHttpRequest.BaseBuilder builder = MockServerHttpRequest.get(""); + String[] header1 = {"1"}; + String[] header2 = {"2"}; + String[] header3 = {"3"}; + builder.header("header1", header1); + builder.header("header2", header2); + builder.header("header3", header3); + MockServerHttpRequest request = builder.build(); + TransHeadersTransfer.transfer(request); + Map transHeadersKV = MetadataContextHolder.get().getTransHeadersKV(); + Assertions.assertEquals(transHeadersKV.get("header1"), JacksonUtils.serialize2Json(header1)); + Assertions.assertEquals(transHeadersKV.get("header2"), JacksonUtils.serialize2Json(header2)); + Assertions.assertEquals(transHeadersKV.get("header3"), JacksonUtils.serialize2Json(header3)); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java index 901898994..087f9f6ed 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java @@ -23,11 +23,14 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import com.google.common.collect.Maps; +import com.tencent.cloud.polaris.config.spring.event.ConfigChangeSpringEvent; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.cloud.context.environment.EnvironmentChangeEvent; import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; @@ -44,10 +47,12 @@ import static com.tencent.cloud.polaris.config.listener.PolarisConfigListenerCon * * @author Elve.Xu 2022-06-08 */ -public final class PolarisConfigChangeEventListener implements ApplicationListener { +public final class PolarisConfigChangeEventListener implements ApplicationListener, ApplicationEventPublisherAware { private static final AtomicBoolean started = new AtomicBoolean(); + private ApplicationEventPublisher eventPublisher; + /** * Handle an application event. * @@ -72,6 +77,8 @@ public final class PolarisConfigChangeEventListener implements ApplicationListen ConfigurableEnvironment environment = context.getEnvironment(); Map ret = loadEnvironmentProperties(environment); Map changes = merge(ret); + ConfigChangeSpringEvent configChangeSpringEvent = new ConfigChangeSpringEvent(Maps.newHashMap(changes)); + eventPublisher.publishEvent(configChangeSpringEvent); fireConfigChange(changes.keySet(), Maps.newHashMap(changes)); changes.clear(); } @@ -106,4 +113,9 @@ public final class PolarisConfigChangeEventListener implements ApplicationListen }); return ret; } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/event/ConfigChangeSpringEvent.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/event/ConfigChangeSpringEvent.java new file mode 100644 index 000000000..cd5eca7ed --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/event/ConfigChangeSpringEvent.java @@ -0,0 +1,70 @@ +/* + * 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.spring.event; + +import java.util.Map; +import java.util.Set; + +import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; + +import org.springframework.context.ApplicationEvent; + +/** + * A spring change event when config is changed. + * + * @author Derek Yi 2022-10-16 + */ +public class ConfigChangeSpringEvent extends ApplicationEvent { + /** + * @param source all changed keys map. + */ + public ConfigChangeSpringEvent(Map source) { + super(source); + } + + /** + * Get the changed keys. + * @return the list of the keys + */ + public Set changedKeys() { + return changeMap().keySet(); + } + + /** + * Get a specific change instance for the key specified. + * @param key the changed key + * @return the change instance + */ + public ConfigPropertyChangeInfo getChange(String key) { + return changeMap().get(key); + } + + /** + * Check whether the specified key is changed . + * @param key the key + * @return true if the key is changed, false otherwise. + */ + public boolean isChanged(String key) { + return changeMap().containsKey(key); + } + + private Map changeMap() { + return (Map) getSource(); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/event/ConfigChangeSpringEventTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/event/ConfigChangeSpringEventTest.java new file mode 100644 index 000000000..2e44c476e --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/event/ConfigChangeSpringEventTest.java @@ -0,0 +1,80 @@ +/* + * 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.spring.event; + +import java.util.HashMap; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import com.tencent.polaris.configuration.api.core.ChangeType; +import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.Assert; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Configuration; + + +/** + * Test for {@link ConfigChangeSpringEvent}. + * + * @author derek.yi 2022-10-16 + */ +public class ConfigChangeSpringEventTest { + + private static CountDownLatch countDownLatch = new CountDownLatch(1); + + private static AtomicInteger receiveEventTimes = new AtomicInteger(); + + @Test + public void testPublishConfigChangeSpringEvent() { + ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(ConfigChangeSpringEventListener.class)); + contextRunner.run(context -> { + HashMap changeMap = new HashMap<>(); + changeMap.put("key", new ConfigPropertyChangeInfo("key", null, "value", ChangeType.ADDED)); + context.publishEvent(new ConfigChangeSpringEvent(changeMap)); + countDownLatch.await(5, TimeUnit.SECONDS); + Assert.assertEquals(1, receiveEventTimes.get()); + }); + } + + @Configuration + static class ConfigChangeSpringEventListener implements ApplicationListener { + + @Override + public void onApplicationEvent(ConfigChangeSpringEvent event) { + Set changedKeys = event.changedKeys(); + Assert.assertEquals(1, changedKeys.size()); + Assert.assertTrue(event.isChanged("key")); + ConfigPropertyChangeInfo changeInfo = event.getChange("key"); + Assert.assertNotNull(changeInfo); + Assert.assertEquals("key", changeInfo.getPropertyName()); + Assert.assertEquals("value", changeInfo.getNewValue()); + Assert.assertEquals(ChangeType.ADDED, changeInfo.getChangeType()); + + receiveEventTimes.incrementAndGet(); + countDownLatch.countDown(); + } + } +}