From 2a4da2ac514a421be4b31497cf1129b380237212 Mon Sep 17 00:00:00 2001 From: Sunrisea <1336317033@qq.com> Date: Thu, 21 Nov 2024 14:08:40 +0800 Subject: [PATCH] Refactor ConfigCache and related pathways ,remove md5GBK to uniformly use UTF-8 encoding for md5 fields. Utilize the SPI mechanism in related pathways and methods to ensure extensibility for support of other types of encoding. Fix test. --- .../notify/DefaultSharePublisherTest.java | 2 +- .../NacosConfigConfiguration.java | 2 + .../server/controller/ConfigServletInner.java | 7 +- .../nacos/config/server/model/CacheItem.java | 4 +- .../config/server/model/ConfigCache.java | 44 ++----- .../server/model/ConfigCacheFactory.java | 66 ++++++++++ .../model/ConfigCacheFactoryDelegate.java | 81 +++++++++++++ .../config/server/model/ConfigCacheGray.java | 4 +- .../model/ConfigCacheMd5PostProcessor.java | 40 ++++++ .../ConfigCacheMd5PostProcessorDelegate.java | 68 +++++++++++ .../server/model/NacosConfigCacheFactory.java | 50 ++++++++ .../NacosConfigCacheMd5PostProcessor.java | 34 ++++++ .../remote/ConfigQueryRequestHandler.java | 5 +- .../server/service/ConfigCacheService.java | 58 +++++---- .../nacos/config/server/utils/MD5Util.java | 15 +-- .../config/server/utils/Md5Comparator.java | 48 ++++++++ .../server/utils/Md5ComparatorDelegate.java | 72 +++++++++++ .../server/utils/NacosMd5Comparator.java | 57 +++++++++ .../controller/ConfigServletInnerTest.java | 11 +- .../model/ConfigCacheFactoryDelegateTest.java | 102 ++++++++++++++++ ...nfigCacheMd5PostProcessorDelegateTest.java | 103 ++++++++++++++++ .../model/NacosConfigCacheFactoryTest.java | 53 ++++++++ .../NacosConfigCacheMd5PostProcessorTest.java | 31 +++++ .../remote/ConfigQueryRequestHandlerTest.java | 21 ++-- .../service/ClientTrackServiceTest.java | 19 ++- .../service/ConfigCacheServiceTest.java | 18 +-- .../dump/DumpChangeConfigWorkerTest.java | 8 +- .../service/dump/DumpProcessorTest.java | 2 +- .../dump/processor/DumpAllProcessorTest.java | 14 ++- .../utils/Md5ComparatorDelegateTest.java | 107 ++++++++++++++++ .../server/utils/NacosMd5ComparatorTest.java | 114 ++++++++++++++++++ 31 files changed, 1133 insertions(+), 127 deletions(-) create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheFactory.java create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheFactoryDelegate.java create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessor.java create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessorDelegate.java create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/model/NacosConfigCacheFactory.java create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/model/NacosConfigCacheMd5PostProcessor.java create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/utils/Md5Comparator.java create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/utils/Md5ComparatorDelegate.java create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/utils/NacosMd5Comparator.java create mode 100644 config/src/test/java/com/alibaba/nacos/config/server/model/ConfigCacheFactoryDelegateTest.java create mode 100644 config/src/test/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessorDelegateTest.java create mode 100644 config/src/test/java/com/alibaba/nacos/config/server/model/NacosConfigCacheFactoryTest.java create mode 100644 config/src/test/java/com/alibaba/nacos/config/server/model/NacosConfigCacheMd5PostProcessorTest.java create mode 100644 config/src/test/java/com/alibaba/nacos/config/server/utils/Md5ComparatorDelegateTest.java create mode 100644 config/src/test/java/com/alibaba/nacos/config/server/utils/NacosMd5ComparatorTest.java diff --git a/common/src/test/java/com/alibaba/nacos/common/notify/DefaultSharePublisherTest.java b/common/src/test/java/com/alibaba/nacos/common/notify/DefaultSharePublisherTest.java index 3d297743186..834c8e632a3 100644 --- a/common/src/test/java/com/alibaba/nacos/common/notify/DefaultSharePublisherTest.java +++ b/common/src/test/java/com/alibaba/nacos/common/notify/DefaultSharePublisherTest.java @@ -106,7 +106,7 @@ void testIgnoreExpiredEvent() throws InterruptedException { defaultSharePublisher.addSubscriber(smartSubscriber2, MockSlowEvent2.class); defaultSharePublisher.publish(mockSlowEvent1); defaultSharePublisher.publish(mockSlowEvent2); - TimeUnit.MILLISECONDS.sleep(1100); + TimeUnit.MILLISECONDS.sleep(1500); verify(smartSubscriber1).onEvent(mockSlowEvent1); verify(smartSubscriber2).onEvent(mockSlowEvent2); reset(smartSubscriber1); diff --git a/config/src/main/java/com/alibaba/nacos/config/server/configuration/NacosConfigConfiguration.java b/config/src/main/java/com/alibaba/nacos/config/server/configuration/NacosConfigConfiguration.java index 1c6038c2f72..f45a8679e39 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/configuration/NacosConfigConfiguration.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/configuration/NacosConfigConfiguration.java @@ -19,6 +19,7 @@ import com.alibaba.nacos.config.server.filter.CircuitFilter; import com.alibaba.nacos.config.server.filter.NacosWebFilter; import com.alibaba.nacos.persistence.configuration.condition.ConditionDistributedEmbedStorage; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; @@ -34,6 +35,7 @@ public class NacosConfigConfiguration { @Bean + @ConditionalOnProperty(name = "nacos.web.charset.filter", havingValue = "nacos", matchIfMissing = true) public FilterRegistrationBean nacosWebFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean<>(); registration.setFilter(nacosWebFilter()); diff --git a/config/src/main/java/com/alibaba/nacos/config/server/controller/ConfigServletInner.java b/config/src/main/java/com/alibaba/nacos/config/server/controller/ConfigServletInner.java index f5c94e66265..cae7de46e35 100755 --- a/config/src/main/java/com/alibaba/nacos/config/server/controller/ConfigServletInner.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/controller/ConfigServletInner.java @@ -55,7 +55,6 @@ import java.util.List; import java.util.Map; -import static com.alibaba.nacos.config.server.constant.Constants.ENCODE_UTF8; import static com.alibaba.nacos.config.server.utils.LogUtil.PULL_LOG; /** @@ -135,8 +134,6 @@ public String doGetConfig(HttpServletRequest request, HttpServletResponse respon boolean notify = StringUtils.isNotBlank(isNotify) && Boolean.parseBoolean(isNotify); - String acceptCharset = ENCODE_UTF8; - if (isV2) { response.setHeader(HttpHeaderConsts.CONTENT_TYPE, MediaType.APPLICATION_JSON); } @@ -187,7 +184,7 @@ public String doGetConfig(HttpServletRequest request, HttpServletResponse respon String encryptedDataKey; if (matchedGray != null) { - md5 = matchedGray.getMd5(acceptCharset); + md5 = matchedGray.getMd5(); lastModified = matchedGray.getLastModifiedTs(); encryptedDataKey = matchedGray.getEncryptedDataKey(); content = ConfigDiskServiceFactory.getInstance() @@ -211,7 +208,7 @@ public String doGetConfig(HttpServletRequest request, HttpServletResponse respon response.setHeader(com.alibaba.nacos.api.common.Constants.VIPSERVER_TAG, URLEncoder.encode(tag, StandardCharsets.UTF_8.displayName())); } else { - md5 = cacheItem.getConfigCache().getMd5(acceptCharset); + md5 = cacheItem.getConfigCache().getMd5(); lastModified = cacheItem.getConfigCache().getLastModifiedTs(); encryptedDataKey = cacheItem.getConfigCache().getEncryptedDataKey(); content = ConfigDiskServiceFactory.getInstance().getContent(dataId, group, tenant); diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/CacheItem.java b/config/src/main/java/com/alibaba/nacos/config/server/model/CacheItem.java index e0423f3daa7..edb7d741a68 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/model/CacheItem.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/CacheItem.java @@ -35,7 +35,7 @@ public class CacheItem { public String type; - ConfigCache configCache = new ConfigCache(); + ConfigCache configCache = ConfigCacheFactoryDelegate.getInstance().createConfigCache(); /** * Use for gray. @@ -92,7 +92,7 @@ public void initConfigGrayIfEmpty() { public void initConfigGrayIfEmpty(String grayName) { initConfigGrayIfEmpty(); if (!this.configCacheGray.containsKey(grayName)) { - this.configCacheGray.put(grayName, new ConfigCacheGray(grayName)); + this.configCacheGray.put(grayName, ConfigCacheFactoryDelegate.getInstance().createConfigCacheGray(grayName)); } } diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCache.java b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCache.java index 21e43ab23c7..c1aa1643ae6 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCache.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCache.java @@ -21,8 +21,6 @@ import java.io.Serializable; -import static java.nio.charset.StandardCharsets.UTF_8; - /** * config cache . * @@ -30,9 +28,7 @@ */ public class ConfigCache implements Serializable { - volatile String md5Gbk = Constants.NULL; - - volatile String md5Utf8 = Constants.NULL; + volatile String md5 = Constants.NULL; volatile String encryptedDataKey; @@ -42,8 +38,7 @@ public class ConfigCache implements Serializable { * clear cache. */ public void clear() { - this.md5Gbk = Constants.NULL; - this.md5Utf8 = Constants.NULL; + this.md5 = Constants.NULL; this.encryptedDataKey = null; this.lastModifiedTs = -1L; } @@ -51,12 +46,13 @@ public void clear() { public ConfigCache() { } - public String getMd5(String encode) { - if (UTF_8.name().equalsIgnoreCase(encode)) { - return md5Utf8; - } else { - return md5Gbk; - } + public ConfigCache(String md5, long lastModifiedTs) { + this.md5 = StringPool.get(md5); + this.lastModifiedTs = lastModifiedTs; + } + + public String getMd5() { + return md5; } public String getEncryptedDataKey() { @@ -67,26 +63,8 @@ public void setEncryptedDataKey(String encryptedDataKey) { this.encryptedDataKey = encryptedDataKey; } - public ConfigCache(String md5Gbk, String md5Utf8, long lastModifiedTs) { - this.md5Gbk = StringPool.get(md5Gbk); - this.md5Utf8 = StringPool.get(md5Utf8); - this.lastModifiedTs = lastModifiedTs; - } - - public String getMd5Gbk() { - return md5Gbk; - } - - public void setMd5Gbk(String md5Gbk) { - this.md5Gbk = StringPool.get(md5Gbk); - } - - public String getMd5Utf8() { - return md5Utf8; - } - - public void setMd5Utf8(String md5Utf8) { - this.md5Utf8 = StringPool.get(md5Utf8); + public void setMd5(String md5) { + this.md5 = StringPool.get(md5); } public long getLastModifiedTs() { diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheFactory.java b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheFactory.java new file mode 100644 index 00000000000..a379afdaadb --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheFactory.java @@ -0,0 +1,66 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +/** + * The interface Config cache factory. + * + * @author Sunrisea + */ +public interface ConfigCacheFactory { + + /** + * Create config cache config cache. + * + * @return the config cache + */ + public ConfigCache createConfigCache(); + + /** + * Create config cache config cache. + * + * @param md5 the md 5 + * @param lastModifiedTs the last modified ts + * @return the config cache + */ + public ConfigCache createConfigCache(String md5, long lastModifiedTs); + + /** + * Create config cache gray config cache gray. + * + * @param grayName the gray name + * @return the config cache gray + */ + public ConfigCacheGray createConfigCacheGray(String grayName); + + /** + * Create config cache gray config cache gray. + * + * @param md5 the md 5 + * @param lastModifiedTs the last modified ts + * @param grayRule the gray rule + * @return the config cache gray + */ + public ConfigCacheGray createConfigCacheGray(String md5, long lastModifiedTs, String grayRule); + + /** + * Gets config cache factroy name. + * + * @return the config cache factory name + */ + public String getConfigCacheFactoryName(); +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheFactoryDelegate.java b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheFactoryDelegate.java new file mode 100644 index 00000000000..6b2e04a448a --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheFactoryDelegate.java @@ -0,0 +1,81 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; + +/** + * The type Config cache factory delegate. + * + * @author Sunrisea + */ +public class ConfigCacheFactoryDelegate { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCacheFactoryDelegate.class); + + private static final ConfigCacheFactoryDelegate INSTANCE = new ConfigCacheFactoryDelegate(); + + private String configCacheFactoryType = EnvUtil.getProperty("nacos.config.cache.type", "nacos"); + + private ConfigCacheFactory configCacheFactory = null; + + private ConfigCacheFactoryDelegate() { + Collection configCacheFactories = NacosServiceLoader.load(ConfigCacheFactory.class); + for (ConfigCacheFactory each : configCacheFactories) { + if (StringUtils.isEmpty(each.getConfigCacheFactoryName())) { + LOGGER.warn("[ConfigCacheFactory] Load ConfigCacheFactory({}) ConfigFactroyName (null/empty) fail. " + + "Please add ConfigFactoryName to resolve", + each.getClass()); + continue; + } + LOGGER.info("[ConfigCacheFactory] Load ConfigCacheFactory({}) ConfigCacheFactoryName({}) successfully. ", + each.getClass(), each.getConfigCacheFactoryName()); + if (StringUtils.equals(configCacheFactoryType, each.getConfigCacheFactoryName())) { + this.configCacheFactory = each; + } + } + if (this.configCacheFactory == null) { + this.configCacheFactory = new NacosConfigCacheFactory(); + } + } + + public static ConfigCacheFactoryDelegate getInstance() { + return INSTANCE; + } + + public ConfigCache createConfigCache() { + return configCacheFactory.createConfigCache(); + } + + public ConfigCache createConfigCache(String md5, long lastModifiedTs) { + return configCacheFactory.createConfigCache(md5, lastModifiedTs); + } + + public ConfigCacheGray createConfigCacheGray(String grayName) { + return configCacheFactory.createConfigCacheGray(grayName); + } + + public ConfigCacheGray createConfigCacheGray(String md5, long lastModifiedTs, String grayRule) { + return configCacheFactory.createConfigCacheGray(md5, lastModifiedTs, grayRule); + } +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheGray.java b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheGray.java index f3c8ccfd700..8ca1f2999dd 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheGray.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheGray.java @@ -49,9 +49,9 @@ public GrayRule getGrayRule() { return grayRule; } - public ConfigCacheGray(String md5Gbk, String md5Utf8, long lastModifiedTs, String grayRule) + public ConfigCacheGray(String md5, long lastModifiedTs, String grayRule) throws RuntimeException { - super(md5Gbk, md5Utf8, lastModifiedTs); + super(md5, lastModifiedTs); this.grayRule = GrayRuleManager.constructGrayRule(GrayRuleManager.deserializeConfigGrayPersistInfo(grayRule)); if (this.grayRule == null || !this.grayRule.isValid()) { throw new RuntimeException("raw gray rule is invalid"); diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessor.java b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessor.java new file mode 100644 index 00000000000..c86ce353768 --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessor.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +/** + * The interface Config cache md5 post processor. + * + * @author Sunrisea + */ +public interface ConfigCacheMd5PostProcessor { + + /** + * Gets post processor name. + * + * @return the post processor name + */ + public String getPostProcessorName(); + + /** + * Post process. + * + * @param configCache the config cache + * @param content the content + */ + public void postProcess(ConfigCache configCache, String content); +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessorDelegate.java b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessorDelegate.java new file mode 100644 index 00000000000..44c901efb01 --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessorDelegate.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; + +/** + * The type Config cache md5 post processor delegate. + * + * @author Sunrisea + */ +public class ConfigCacheMd5PostProcessorDelegate { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCacheFactoryDelegate.class); + + private static final ConfigCacheMd5PostProcessorDelegate INSTANCE = new ConfigCacheMd5PostProcessorDelegate(); + + private String configCacheMd5PostProcessorType = EnvUtil.getProperty("nacos.config.cache.type", "nacos"); + + private ConfigCacheMd5PostProcessor configCacheMd5PostProcessor; + + private ConfigCacheMd5PostProcessorDelegate() { + Collection processors = NacosServiceLoader.load(ConfigCacheMd5PostProcessor.class); + for (ConfigCacheMd5PostProcessor processor : processors) { + if (StringUtils.isEmpty(processor.getPostProcessorName())) { + LOGGER.warn( + "[ConfigCacheMd5PostProcessor] Load ConfigCacheMd5PostProcessor({}) PostProcessorName(null/empty) fail. " + + "Please add PostProcessorName to resolve", + processor.getClass().getName()); + continue; + } + if (StringUtils.equals(configCacheMd5PostProcessorType, processor.getPostProcessorName())) { + this.configCacheMd5PostProcessor = processor; + } + } + if (configCacheMd5PostProcessor == null) { + configCacheMd5PostProcessor = new NacosConfigCacheMd5PostProcessor(); + } + } + + public static ConfigCacheMd5PostProcessorDelegate getInstance() { + return INSTANCE; + } + + public void postProcess(ConfigCache configCache, String content) { + configCacheMd5PostProcessor.postProcess(configCache, content); + } +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/NacosConfigCacheFactory.java b/config/src/main/java/com/alibaba/nacos/config/server/model/NacosConfigCacheFactory.java new file mode 100644 index 00000000000..a94a0f58fbc --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/NacosConfigCacheFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +/** + * The type Nacos config cache factory. + * + * @author Sunrisea + */ +public class NacosConfigCacheFactory implements ConfigCacheFactory { + + @Override + public ConfigCache createConfigCache() { + return new ConfigCache(); + } + + @Override + public ConfigCache createConfigCache(String md5, long lastModifiedTs) { + return new ConfigCache(md5, lastModifiedTs); + } + + @Override + public ConfigCacheGray createConfigCacheGray(String grayName) { + return new ConfigCacheGray(grayName); + } + + @Override + public ConfigCacheGray createConfigCacheGray(String md5, long lastModifiedTs, String grayRule) { + return new ConfigCacheGray(md5, lastModifiedTs, grayRule); + } + + @Override + public String getConfigCacheFactoryName() { + return "nacos"; + } +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/NacosConfigCacheMd5PostProcessor.java b/config/src/main/java/com/alibaba/nacos/config/server/model/NacosConfigCacheMd5PostProcessor.java new file mode 100644 index 00000000000..acee73d4e38 --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/NacosConfigCacheMd5PostProcessor.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +/** + * The type Nacos config cache md 5 post processor. + * + * @author Sunrisea + */ +public class NacosConfigCacheMd5PostProcessor implements ConfigCacheMd5PostProcessor { + + @Override + public String getPostProcessorName() { + return "nacos"; + } + + @Override + public void postProcess(ConfigCache configCache, String content) { + } +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/remote/ConfigQueryRequestHandler.java b/config/src/main/java/com/alibaba/nacos/config/server/remote/ConfigQueryRequestHandler.java index 7b0d4d88f69..568095bfe1a 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/remote/ConfigQueryRequestHandler.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/remote/ConfigQueryRequestHandler.java @@ -88,7 +88,6 @@ private ConfigQueryResponse getContext(ConfigQueryRequest configQueryRequest, Re String groupKey = GroupKey2.getKey(configQueryRequest.getDataId(), configQueryRequest.getGroup(), configQueryRequest.getTenant()); String requestIpApp = meta.getLabels().get(CLIENT_APPNAME_HEADER); - String acceptCharset = ENCODE_UTF8; ParamUtils.checkParam(tag); int lockResult = ConfigCacheService.tryConfigReadLock(groupKey); String pullEvent = ConfigTraceService.PULL_EVENT; @@ -129,7 +128,7 @@ private ConfigQueryResponse getContext(ConfigQueryRequest configQueryRequest, Re } } if (matchedGray != null) { - md5 = matchedGray.getMd5(acceptCharset); + md5 = matchedGray.getMd5(); lastModified = matchedGray.getLastModifiedTs(); encryptedDataKey = matchedGray.getEncryptedDataKey(); content = ConfigDiskServiceFactory.getInstance() @@ -150,7 +149,7 @@ private ConfigQueryResponse getContext(ConfigQueryRequest configQueryRequest, Re pullEvent = ConfigTraceService.PULL_EVENT + "-" + TagGrayRule.TYPE_TAG + "-" + tag; response.setTag(tag); } else { - md5 = cacheItem.getConfigCache().getMd5(acceptCharset); + md5 = cacheItem.getConfigCache().getMd5(); lastModified = cacheItem.getConfigCache().getLastModifiedTs(); encryptedDataKey = cacheItem.getConfigCache().getEncryptedDataKey(); content = ConfigDiskServiceFactory.getInstance().getContent(dataId, group, tenant); diff --git a/config/src/main/java/com/alibaba/nacos/config/server/service/ConfigCacheService.java b/config/src/main/java/com/alibaba/nacos/config/server/service/ConfigCacheService.java index da9ed9ef5f2..05b947c4f54 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/service/ConfigCacheService.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/service/ConfigCacheService.java @@ -22,6 +22,7 @@ import com.alibaba.nacos.config.server.model.CacheItem; import com.alibaba.nacos.config.server.model.ConfigCache; import com.alibaba.nacos.config.server.model.ConfigCacheGray; +import com.alibaba.nacos.config.server.model.ConfigCacheMd5PostProcessorDelegate; import com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent; import com.alibaba.nacos.config.server.model.gray.GrayRule; import com.alibaba.nacos.config.server.model.gray.GrayRuleManager; @@ -124,7 +125,7 @@ public static boolean dumpWithMd5(String dataId, String group, String tenant, St DUMP_LOG.info( "[dump] md5 changed, update md5 and timestamp in jvm cache ,groupKey={}, newMd5={},oldMd5={},lastModifiedTs={}", groupKey, md5, localContentMd5, lastModifiedTs); - updateMd5(groupKey, md5, lastModifiedTs, encryptedDataKey); + updateMd5(groupKey, md5, content, lastModifiedTs, encryptedDataKey); } else if (newLastModified) { DUMP_LOG.info( "[dump] md5 consistent ,timestamp changed, update timestamp only in jvm cache ,groupKey={},lastModifiedTs={}", @@ -229,7 +230,7 @@ public static boolean dumpGray(String dataId, String group, String tenant, Strin "[dump-gray] md5 changed, update local jvm cache& local disk cache, groupKey={},grayName={}, " + "newMd5={},oldMd5={}, newGrayRule={}, oldGrayRule={},lastModifiedTs={}", groupKey, grayName, md5, localContentGrayMd5, grayRule, localGrayRule, lastModifiedTs); - updateGrayMd5(groupKey, grayName, grayRule, md5, lastModifiedTs, encryptedDataKey); + updateGrayMd5(groupKey, grayName, grayRule, md5, content, lastModifiedTs, encryptedDataKey); ConfigDiskServiceFactory.getInstance().saveGrayToDisk(dataId, group, tenant, grayName, content); } else if (grayRuleChanged) { @@ -349,16 +350,20 @@ public static boolean remove(String dataId, String group, String tenant) { /** * Update md5 value. * - * @param groupKey groupKey string value. - * @param md5Utf8 md5 string value. - * @param lastModifiedTs lastModifiedTs long value. + * @param groupKey the group key + * @param md5 the md 5 + * @param content the content + * @param lastModifiedTs the last modified ts + * @param encryptedDataKey the encrypted data key */ - public static void updateMd5(String groupKey, String md5Utf8, long lastModifiedTs, String encryptedDataKey) { + public static void updateMd5(String groupKey, String md5, String content, long lastModifiedTs, String encryptedDataKey) { CacheItem cache = makeSure(groupKey, encryptedDataKey); - if (cache.getConfigCache().getMd5Utf8() == null || !cache.getConfigCache().getMd5Utf8().equals(md5Utf8)) { - cache.getConfigCache().setMd5Utf8(md5Utf8); - cache.getConfigCache().setLastModifiedTs(lastModifiedTs); - cache.getConfigCache().setEncryptedDataKey(encryptedDataKey); + ConfigCache configCache = cache.getConfigCache(); + if (configCache.getMd5() == null || !configCache.getMd5().equals(md5)) { + configCache.setMd5(md5); + configCache.setLastModifiedTs(lastModifiedTs); + configCache.setEncryptedDataKey(encryptedDataKey); + ConfigCacheMd5PostProcessorDelegate.getInstance().postProcess(configCache, content); NotifyCenter.publishEvent(new LocalDataChangeEvent(groupKey)); } } @@ -366,23 +371,25 @@ public static void updateMd5(String groupKey, String md5Utf8, long lastModifiedT /** * Update gray md5 value. * - * @param groupKey groupKey string value. - * @param grayName grayName string value. - * @param grayRule grayRule string value. - * @param md5Utf8 md5UTF8 string value. - * @param lastModifiedTs lastModifiedTs long value. - * @param encryptedDataKey encryptedDataKey string value. + * @param groupKey the group key + * @param grayName the gray name + * @param grayRule the gray rule + * @param md5 the md 5 + * @param content the content + * @param lastModifiedTs the last modified ts + * @param encryptedDataKey the encrypted data key */ - private static void updateGrayMd5(String groupKey, String grayName, String grayRule, String md5Utf8, + public static void updateGrayMd5(String groupKey, String grayName, String grayRule, String md5, String content, long lastModifiedTs, String encryptedDataKey) { CacheItem cache = makeSure(groupKey, null); cache.initConfigGrayIfEmpty(grayName); ConfigCacheGray configCache = cache.getConfigCacheGray().get(grayName); - configCache.setMd5Utf8(md5Utf8); + configCache.setMd5(md5); configCache.setLastModifiedTs(lastModifiedTs); configCache.setEncryptedDataKey(encryptedDataKey); configCache.resetGrayRule(grayRule); cache.sortConfigGray(); + ConfigCacheMd5PostProcessorDelegate.getInstance().postProcess(configCache, content); NotifyCenter.publishEvent(new LocalDataChangeEvent(groupKey)); } @@ -394,11 +401,10 @@ public static String getContentMd5(String groupKey) { } public static String getContentMd5(String groupKey, String ip, String tag) { - return getContentMd5(groupKey, ip, tag, null, ENCODE_UTF8); + return getContentMd5(groupKey, ip, tag, null); } - public static String getContentMd5(String groupKey, String ip, String tag, Map connLabels, - String encode) { + public static String getContentMd5(String groupKey, String ip, String tag, Map connLabels) { CacheItem item = CACHE.get(groupKey); if (item == null) { return NULL; @@ -419,11 +425,11 @@ public static String getContentMd5(String groupKey, String ip, String tag, Map appLabels) { - String serverMd5 = ConfigCacheService.getContentMd5(groupKey, ip, tag, appLabels, ENCODE_UTF8); + String serverMd5 = ConfigCacheService.getContentMd5(groupKey, ip, tag, appLabels); return StringUtils.equals(md5, serverMd5); } @@ -593,7 +599,7 @@ private static void updateTimeStamp(String groupKey, long lastModifiedTs, String * try config read lock with spin of try get lock times. * * @param groupKey group key of config. - * @return + * @return 0 - No data and failed. Positive number - lock succeeded. Negative number - lock failed. */ public static int tryConfigReadLock(String groupKey) { diff --git a/config/src/main/java/com/alibaba/nacos/config/server/utils/MD5Util.java b/config/src/main/java/com/alibaba/nacos/config/server/utils/MD5Util.java index 9d9faa84a91..16b170dabc6 100755 --- a/config/src/main/java/com/alibaba/nacos/config/server/utils/MD5Util.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/utils/MD5Util.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.config.server.utils; import com.alibaba.nacos.config.server.constant.Constants; -import com.alibaba.nacos.config.server.service.ConfigCacheService; import com.alibaba.nacos.core.utils.StringPool; import com.alibaba.nacos.common.utils.StringUtils; @@ -35,7 +34,6 @@ import java.util.List; import java.util.Map; -import static com.alibaba.nacos.api.common.Constants.VIPSERVER_TAG; import static com.alibaba.nacos.config.server.constant.Constants.LINE_SEPARATOR; import static com.alibaba.nacos.config.server.constant.Constants.WORD_SEPARATOR; @@ -52,18 +50,7 @@ public class MD5Util { */ public static List compareMd5(HttpServletRequest request, HttpServletResponse response, Map clientMd5Map) { - List changedGroupKeys = new ArrayList<>(); - String tag = request.getHeader(VIPSERVER_TAG); - for (Map.Entry entry : clientMd5Map.entrySet()) { - String groupKey = entry.getKey(); - String clientMd5 = entry.getValue(); - String ip = RequestUtil.getRemoteIp(request); - boolean isUptodate = ConfigCacheService.isUptodate(groupKey, clientMd5, ip, tag); - if (!isUptodate) { - changedGroupKeys.add(groupKey); - } - } - return changedGroupKeys; + return Md5ComparatorDelegate.getInstance().compareMd5(request, response, clientMd5Map); } /** diff --git a/config/src/main/java/com/alibaba/nacos/config/server/utils/Md5Comparator.java b/config/src/main/java/com/alibaba/nacos/config/server/utils/Md5Comparator.java new file mode 100644 index 00000000000..ca42c807b06 --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/utils/Md5Comparator.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.utils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; +import java.util.Map; + +/** + * The interface Md5 comparator. + * + * @author Sunrisea + */ +public interface Md5Comparator { + + /** + * Gets md 5 comparator name. + * + * @return the md 5 comparator name + */ + public String getMd5ComparatorName(); + + /** + * Compare md 5 list. + * + * @param request the request + * @param response the response + * @param clientMd5Map the client md 5 map + * @return the list + */ + public List compareMd5(HttpServletRequest request, HttpServletResponse response, + Map clientMd5Map); +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/utils/Md5ComparatorDelegate.java b/config/src/main/java/com/alibaba/nacos/config/server/utils/Md5ComparatorDelegate.java new file mode 100644 index 00000000000..3eb4fcb585e --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/utils/Md5ComparatorDelegate.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.utils; + +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * The type Md5 comparator delegate. + * + * @author Sunrisea + */ +public class Md5ComparatorDelegate { + + private static final Logger LOGGER = LoggerFactory.getLogger(Md5ComparatorDelegate.class); + + private static final Md5ComparatorDelegate INSTANCE = new Md5ComparatorDelegate(); + + private String md5ComparatorType = EnvUtil.getProperty("nacos.config.cache.type", "nacos"); + + private Md5Comparator md5Comparator; + + private Md5ComparatorDelegate() { + Collection md5Comparators = NacosServiceLoader.load(Md5Comparator.class); + for (Md5Comparator each : md5Comparators) { + if (StringUtils.isEmpty(each.getMd5ComparatorName())) { + LOGGER.warn( + "[Md5Comparator] Load Md5Comparator({}) Md5ComparatorName(null/empty) fail. Please add Md5ComparatorName to resolve", + each.getClass().getName()); + continue; + } + if (StringUtils.equals(md5ComparatorType, each.getMd5ComparatorName())) { + md5Comparator = each; + } + } + if (md5Comparator == null) { + md5Comparator = new NacosMd5Comparator(); + } + } + + public static Md5ComparatorDelegate getInstance() { + return INSTANCE; + } + + public List compareMd5(HttpServletRequest request, HttpServletResponse response, + Map clientMd5Map) { + return md5Comparator.compareMd5(request, response, clientMd5Map); + } +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/utils/NacosMd5Comparator.java b/config/src/main/java/com/alibaba/nacos/config/server/utils/NacosMd5Comparator.java new file mode 100644 index 00000000000..14876b26ad2 --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/utils/NacosMd5Comparator.java @@ -0,0 +1,57 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.utils; + +import com.alibaba.nacos.config.server.service.ConfigCacheService; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.alibaba.nacos.api.common.Constants.VIPSERVER_TAG; + +/** + * The type Nacos md5 comparator. + * + * @author Sunrisea + */ +public class NacosMd5Comparator implements Md5Comparator { + + @Override + public String getMd5ComparatorName() { + return "nacos"; + } + + @Override + public List compareMd5(HttpServletRequest request, HttpServletResponse response, + Map clientMd5Map) { + List changedGroupKeys = new ArrayList<>(); + String tag = request.getHeader(VIPSERVER_TAG); + for (Map.Entry entry : clientMd5Map.entrySet()) { + String groupKey = entry.getKey(); + String clientMd5 = entry.getValue(); + String ip = RequestUtil.getRemoteIp(request); + boolean isUptodate = ConfigCacheService.isUptodate(groupKey, clientMd5, ip, tag); + if (!isUptodate) { + changedGroupKeys.add(groupKey); + } + } + return changedGroupKeys; + } +} diff --git a/config/src/test/java/com/alibaba/nacos/config/server/controller/ConfigServletInnerTest.java b/config/src/test/java/com/alibaba/nacos/config/server/controller/ConfigServletInnerTest.java index 651ca61fb84..24ad8d2ff31 100644 --- a/config/src/test/java/com/alibaba/nacos/config/server/controller/ConfigServletInnerTest.java +++ b/config/src/test/java/com/alibaba/nacos/config/server/controller/ConfigServletInnerTest.java @@ -60,7 +60,6 @@ import static com.alibaba.nacos.api.common.Constants.VIPSERVER_TAG; import static com.alibaba.nacos.config.server.constant.Constants.CONTENT_MD5; -import static com.alibaba.nacos.config.server.constant.Constants.ENCODE_GBK; import static com.alibaba.nacos.config.server.constant.Constants.ENCODE_UTF8; import static com.alibaba.nacos.config.server.utils.RequestUtil.CLIENT_APPNAME_HEADER; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -178,8 +177,7 @@ void testDoGetConfigV1Beta() throws Exception { private void mockGray4Beta(CacheItem cacheItem, String content, String betaIps, String dataKey) { cacheItem.initConfigGrayIfEmpty(BetaGrayRule.TYPE_BETA); ConfigCacheGray configCacheGray = cacheItem.getConfigCacheGray().get(BetaGrayRule.TYPE_BETA); - configCacheGray.setMd5Utf8(MD5Utils.md5Hex(content, ENCODE_UTF8)); - configCacheGray.setMd5Gbk(MD5Utils.md5Hex(content, ENCODE_GBK)); + configCacheGray.setMd5(MD5Utils.md5Hex(content, ENCODE_UTF8)); configCacheGray.setEncryptedDataKey(dataKey); ConfigGrayPersistInfo configGrayPersistInfo = new ConfigGrayPersistInfo(BetaGrayRule.TYPE_BETA, BetaGrayRule.VERSION, betaIps, -1000); @@ -190,8 +188,7 @@ private void mockGray4Beta(CacheItem cacheItem, String content, String betaIps, private void mockGray4Tag(CacheItem cacheItem, String content, String tagValue, String dataKey, long ts) { cacheItem.initConfigGrayIfEmpty(TagGrayRule.TYPE_TAG + "_" + tagValue); ConfigCacheGray configCacheGray = cacheItem.getConfigCacheGray().get(TagGrayRule.TYPE_TAG + "_" + tagValue); - configCacheGray.setMd5Utf8(MD5Utils.md5Hex(content, ENCODE_UTF8)); - configCacheGray.setMd5Gbk(MD5Utils.md5Hex(content, ENCODE_GBK)); + configCacheGray.setMd5(MD5Utils.md5Hex(content, ENCODE_UTF8)); configCacheGray.setLastModifiedTs(ts); configCacheGray.setEncryptedDataKey(dataKey); ConfigGrayPersistInfo configGrayPersistInfo = new ConfigGrayPersistInfo(TagGrayRule.TYPE_TAG, @@ -284,7 +281,7 @@ void testDoGetConfigFormal() throws Exception { CacheItem cacheItem = new CacheItem("test"); String md5 = "md5wertyui"; String content = "content345678"; - cacheItem.getConfigCache().setMd5Utf8(md5); + cacheItem.getConfigCache().setMd5(md5); long ts = System.currentTimeMillis(); cacheItem.getConfigCache().setLastModifiedTs(ts); cacheItem.getConfigCache().setEncryptedDataKey("key2345678"); @@ -316,7 +313,7 @@ void testDoGetConfigFormalV2() throws Exception { CacheItem cacheItem = new CacheItem("test"); String md5 = "md5wertyui"; String content = "content345678"; - cacheItem.getConfigCache().setMd5Utf8(md5); + cacheItem.getConfigCache().setMd5(md5); long ts = System.currentTimeMillis(); cacheItem.getConfigCache().setLastModifiedTs(ts); cacheItem.getConfigCache().setEncryptedDataKey("key2345678"); diff --git a/config/src/test/java/com/alibaba/nacos/config/server/model/ConfigCacheFactoryDelegateTest.java b/config/src/test/java/com/alibaba/nacos/config/server/model/ConfigCacheFactoryDelegateTest.java new file mode 100644 index 00000000000..63bd05f43f4 --- /dev/null +++ b/config/src/test/java/com/alibaba/nacos/config/server/model/ConfigCacheFactoryDelegateTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedConstruction; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.lang.reflect.Constructor; +import java.util.Collections; + +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ConfigCacheFactoryDelegateTest { + + MockedStatic envUtilMockedStatic; + + MockedStatic nacosServiceLoaderMockedStatic; + + MockedConstruction nacosConfigCacheFactoryMockedConstruction; + + @Mock + NacosConfigCacheFactory nacosConfigCacheFactory; + + @BeforeEach + void setUp() { + envUtilMockedStatic = mockStatic(EnvUtil.class); + nacosServiceLoaderMockedStatic = mockStatic(NacosServiceLoader.class); + nacosConfigCacheFactoryMockedConstruction = mockConstruction(NacosConfigCacheFactory.class); + } + + @AfterEach + void tearDown() { + envUtilMockedStatic.close(); + nacosServiceLoaderMockedStatic.close(); + nacosConfigCacheFactoryMockedConstruction.close(); + } + + @Test + public void test() { + when(nacosConfigCacheFactory.getConfigCacheFactoryName()).thenReturn("nacos"); + nacosServiceLoaderMockedStatic.when(() -> NacosServiceLoader.load(ConfigCacheFactory.class)) + .thenReturn(Collections.singletonList(nacosConfigCacheFactory)); + envUtilMockedStatic.when(() -> EnvUtil.getProperty("nacos.config.cache.type", "nacos")).thenReturn("lalala"); + ConfigCache configCache = ConfigCacheFactoryDelegate.getInstance().createConfigCache(); + ConfigCache configCache1 = ConfigCacheFactoryDelegate.getInstance().createConfigCache("md5", 123456789L); + ConfigCacheGray configCacheGray = ConfigCacheFactoryDelegate.getInstance().createConfigCacheGray("grayName"); + ConfigCacheGray configCacheGray1 = ConfigCacheFactoryDelegate.getInstance().createConfigCacheGray("md5", 123456789L, "grayRule"); + verify(nacosConfigCacheFactoryMockedConstruction.constructed().get(0), times(1)).createConfigCache(); + verify(nacosConfigCacheFactoryMockedConstruction.constructed().get(0), times(1)).createConfigCache("md5", + 123456789L); + verify(nacosConfigCacheFactoryMockedConstruction.constructed().get(0), times(1)).createConfigCacheGray( + "grayName"); + verify(nacosConfigCacheFactoryMockedConstruction.constructed().get(0), times(1)).createConfigCacheGray("md5", + 123456789L, "grayRule"); + } + + @Test + public void test2() throws Exception { + when(nacosConfigCacheFactory.getConfigCacheFactoryName()).thenReturn("nacos"); + nacosServiceLoaderMockedStatic.when(() -> NacosServiceLoader.load(ConfigCacheFactory.class)) + .thenReturn(Collections.singletonList(nacosConfigCacheFactory)); + envUtilMockedStatic.when(() -> EnvUtil.getProperty("nacos.config.cache.type", "nacos")).thenReturn("nacos"); + Constructor constructor = ConfigCacheFactoryDelegate.class.getDeclaredConstructor(); + constructor.setAccessible(true); + ConfigCacheFactoryDelegate configCacheFactoryDelegate = (ConfigCacheFactoryDelegate) constructor.newInstance(); + configCacheFactoryDelegate.createConfigCache(); + configCacheFactoryDelegate.createConfigCache("md5", 123456789L); + configCacheFactoryDelegate.createConfigCacheGray("grayName"); + configCacheFactoryDelegate.createConfigCacheGray("md5", 123456789L, "grayRule"); + verify(nacosConfigCacheFactory, times(1)).createConfigCache(); + verify(nacosConfigCacheFactory, times(1)).createConfigCache("md5", 123456789L); + verify(nacosConfigCacheFactory, times(1)).createConfigCacheGray("grayName"); + verify(nacosConfigCacheFactory, times(1)).createConfigCacheGray("md5", 123456789L, "grayRule"); + } +} \ No newline at end of file diff --git a/config/src/test/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessorDelegateTest.java b/config/src/test/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessorDelegateTest.java new file mode 100644 index 00000000000..9c59a18f3b1 --- /dev/null +++ b/config/src/test/java/com/alibaba/nacos/config/server/model/ConfigCacheMd5PostProcessorDelegateTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedConstruction; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.Collections; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ConfigCacheMd5PostProcessorDelegateTest { + + MockedConstruction mockedConstruction; + + MockedStatic envUtilMockedStatic; + + MockedStatic nacosServiceLoaderMockedStatic; + + @Mock + public NacosConfigCacheMd5PostProcessor mockConfigCacheMd5PostProcessor; + + @BeforeEach + void setUp() { + envUtilMockedStatic = mockStatic(EnvUtil.class); + mockedConstruction = mockConstruction(NacosConfigCacheMd5PostProcessor.class); + nacosServiceLoaderMockedStatic = mockStatic(NacosServiceLoader.class); + + } + + @AfterEach + void tearDown() { + envUtilMockedStatic.close(); + mockedConstruction.close(); + nacosServiceLoaderMockedStatic.close(); + } + + @Test + void test1() { + when(mockConfigCacheMd5PostProcessor.getPostProcessorName()).thenReturn("nacos"); + envUtilMockedStatic.when(() -> EnvUtil.getProperty("nacos.config.cache.type", "nacos")).thenReturn("lalala"); + nacosServiceLoaderMockedStatic.when(() -> NacosServiceLoader.load(ConfigCacheMd5PostProcessor.class)) + .thenReturn(Collections.singletonList(mockConfigCacheMd5PostProcessor)); + ConfigCacheMd5PostProcessorDelegate.getInstance().postProcess(null, null); + doNothing().when(mockedConstruction.constructed().get(0)).postProcess(null, null); + verify(mockConfigCacheMd5PostProcessor, times(0)).postProcess(null, null); + verify(mockedConstruction.constructed().get(0), times(1)).postProcess(null, null); + } + + @Test + void test2() + throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + + when(mockConfigCacheMd5PostProcessor.getPostProcessorName()).thenReturn("nacos"); + doNothing().when(mockConfigCacheMd5PostProcessor).postProcess(null, null); + envUtilMockedStatic.when(() -> EnvUtil.getProperty("nacos.config.cache.type", "nacos")).thenReturn("nacos"); + nacosServiceLoaderMockedStatic.when(() -> NacosServiceLoader.load(ConfigCacheMd5PostProcessor.class)) + .thenReturn(Collections.singletonList(mockConfigCacheMd5PostProcessor)); + Constructor constructor = ConfigCacheMd5PostProcessorDelegate.class.getDeclaredConstructor(); + constructor.setAccessible(true); + Field field = ConfigCacheMd5PostProcessorDelegate.class.getDeclaredField("INSTANCE"); + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + field.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + ConfigCacheMd5PostProcessorDelegate delegate = (ConfigCacheMd5PostProcessorDelegate) constructor.newInstance(); + field.set(null, delegate); + ConfigCacheMd5PostProcessorDelegate.getInstance().postProcess(null, null); + verify(mockConfigCacheMd5PostProcessor, times(1)).postProcess(null, null); + } +} \ No newline at end of file diff --git a/config/src/test/java/com/alibaba/nacos/config/server/model/NacosConfigCacheFactoryTest.java b/config/src/test/java/com/alibaba/nacos/config/server/model/NacosConfigCacheFactoryTest.java new file mode 100644 index 00000000000..ea02b26151d --- /dev/null +++ b/config/src/test/java/com/alibaba/nacos/config/server/model/NacosConfigCacheFactoryTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +import com.alibaba.nacos.config.server.model.gray.BetaGrayRule; +import com.alibaba.nacos.config.server.model.gray.ConfigGrayPersistInfo; +import com.google.gson.Gson; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class NacosConfigCacheFactoryTest { + + @Test + public void testCreateConfigCache() { + NacosConfigCacheFactory nacosConfigCacheFactory = new NacosConfigCacheFactory(); + ConfigCache configCache = nacosConfigCacheFactory.createConfigCache(); + assertEquals(ConfigCache.class, configCache.getClass()); + ConfigCache configCache2 = nacosConfigCacheFactory.createConfigCache("md5", 1L); + assertEquals(ConfigCache.class, configCache2.getClass()); + assertEquals("md5", configCache2.getMd5()); + assertEquals(1L, configCache2.getLastModifiedTs()); + ConfigCacheGray configCacheGray = nacosConfigCacheFactory.createConfigCacheGray("grayName"); + assertEquals(ConfigCacheGray.class, configCacheGray.getClass()); + assertEquals("grayName", configCacheGray.getGrayName()); + ConfigGrayPersistInfo localConfigGrayPersistInfo = new ConfigGrayPersistInfo(BetaGrayRule.TYPE_BETA, + BetaGrayRule.VERSION, "1.1.1.1", Integer.MAX_VALUE); + ConfigCacheGray configCacheGray2 = nacosConfigCacheFactory.createConfigCacheGray("md5", 1L, (new Gson()).toJson(localConfigGrayPersistInfo)); + assertEquals(ConfigCacheGray.class, configCacheGray2.getClass()); + assertEquals("md5", configCacheGray2.getMd5()); + assertEquals(1L, configCacheGray2.getLastModifiedTs()); + } + + @Test + public void testGetConfigCacheFactoryName() { + NacosConfigCacheFactory nacosConfigCacheFactory = new NacosConfigCacheFactory(); + assertEquals("nacos", nacosConfigCacheFactory.getConfigCacheFactoryName()); + } +} \ No newline at end of file diff --git a/config/src/test/java/com/alibaba/nacos/config/server/model/NacosConfigCacheMd5PostProcessorTest.java b/config/src/test/java/com/alibaba/nacos/config/server/model/NacosConfigCacheMd5PostProcessorTest.java new file mode 100644 index 00000000000..9e015caeb0b --- /dev/null +++ b/config/src/test/java/com/alibaba/nacos/config/server/model/NacosConfigCacheMd5PostProcessorTest.java @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class NacosConfigCacheMd5PostProcessorTest { + + @Test + public void test() { + NacosConfigCacheMd5PostProcessor nacosConfigCacheMd5PostProcessor = new NacosConfigCacheMd5PostProcessor(); + assertEquals("nacos", nacosConfigCacheMd5PostProcessor.getPostProcessorName()); + nacosConfigCacheMd5PostProcessor.postProcess(null, null); + } +} \ No newline at end of file diff --git a/config/src/test/java/com/alibaba/nacos/config/server/remote/ConfigQueryRequestHandlerTest.java b/config/src/test/java/com/alibaba/nacos/config/server/remote/ConfigQueryRequestHandlerTest.java index 7762f6f56c0..d7aa392c5bb 100644 --- a/config/src/test/java/com/alibaba/nacos/config/server/remote/ConfigQueryRequestHandlerTest.java +++ b/config/src/test/java/com/alibaba/nacos/config/server/remote/ConfigQueryRequestHandlerTest.java @@ -106,8 +106,7 @@ void testGetNormal() throws Exception { when(ConfigDiskServiceFactory.getInstance()).thenReturn(configRocksDbDiskService); CacheItem cacheItem = new CacheItem(groupKey); - cacheItem.getConfigCache().setMd5Gbk(MD5Utils.md5Hex(content, "GBK")); - cacheItem.getConfigCache().setMd5Utf8(MD5Utils.md5Hex(content, "UTF-8")); + cacheItem.getConfigCache().setMd5(MD5Utils.md5Hex(content, "UTF-8")); cacheItem.getConfigCache().setEncryptedDataKey("key_testGetNormal_NotDirectRead"); when(ConfigCacheService.getContentCache(eq(groupKey))).thenReturn(cacheItem); @@ -146,8 +145,7 @@ void testGetBeta() throws Exception { cacheItem.initConfigGrayIfEmpty(BetaGrayRule.TYPE_BETA); String content = "content_from_beta_notdirectreadÄãºÃ" + System.currentTimeMillis(); ConfigCacheGray configCacheGrayBeta = cacheItem.getConfigCacheGray().get(BetaGrayRule.TYPE_BETA); - configCacheGrayBeta.setMd5Gbk(MD5Utils.md5Hex(content, "GBK")); - configCacheGrayBeta.setMd5Utf8(MD5Utils.md5Hex(content, "UTF-8")); + configCacheGrayBeta.setMd5(MD5Utils.md5Hex(content, "UTF-8")); configCacheGrayBeta.setEncryptedDataKey("key_testGetBeta_NotDirectRead"); ConfigGrayPersistInfo configGrayPersistInfo = new ConfigGrayPersistInfo(BetaGrayRule.TYPE_BETA, BetaGrayRule.VERSION, "127.0.0.1", -1000); @@ -187,8 +185,7 @@ void testGetTagNotFound() throws Exception { when(ConfigDiskServiceFactory.getInstance()).thenReturn(configRocksDbDiskService); CacheItem cacheItem = new CacheItem(groupKey); - cacheItem.getConfigCache().setMd5Gbk(MD5Utils.md5Hex(content, "GBK")); - cacheItem.getConfigCache().setMd5Utf8(MD5Utils.md5Hex(content, "UTF-8")); + cacheItem.getConfigCache().setMd5(MD5Utils.md5Hex(content, "UTF-8")); cacheItem.getConfigCache().setEncryptedDataKey("key_testGetTag_NotFound"); when(ConfigCacheService.getContentCache(eq(groupKey))).thenReturn(cacheItem); @@ -231,8 +228,7 @@ void testGetTagWithTag() throws Exception { when(ConfigDiskServiceFactory.getInstance()).thenReturn(configRocksDbDiskService); CacheItem cacheItem = new CacheItem(groupKey); - cacheItem.getConfigCache().setMd5Gbk(MD5Utils.md5Hex(content, "GBK")); - cacheItem.getConfigCache().setMd5Utf8(MD5Utils.md5Hex(content, "UTF-8")); + cacheItem.getConfigCache().setMd5(MD5Utils.md5Hex(content, "UTF-8")); cacheItem.getConfigCache().setEncryptedDataKey("key_formal"); String specificTag = "specific_tag"; @@ -240,8 +236,7 @@ void testGetTagWithTag() throws Exception { ConfigCacheGray configCacheGrayTag = cacheItem.getConfigCacheGray() .get(TagGrayRule.TYPE_TAG + "_" + specificTag); String tagContent = "content_from_specific_tag_directreadÄãºÃ" + System.currentTimeMillis(); - configCacheGrayTag.setMd5Gbk(MD5Utils.md5Hex(tagContent, "GBK")); - configCacheGrayTag.setMd5Utf8(MD5Utils.md5Hex(tagContent, "UTF-8")); + configCacheGrayTag.setMd5(MD5Utils.md5Hex(tagContent, "UTF-8")); configCacheGrayTag.setEncryptedDataKey("key_testGetTag_NotDirectRead"); ConfigGrayPersistInfo configGrayPersistInfo = new ConfigGrayPersistInfo(TagGrayRule.TYPE_TAG, TagGrayRule.VERSION, specificTag, -999); @@ -290,12 +285,10 @@ void testGetTagAutoTag() throws Exception { String autoTag = "auto_tag"; CacheItem cacheItem = new CacheItem(groupKey); cacheItem.initConfigGrayIfEmpty(TagGrayRule.TYPE_TAG + "_" + autoTag); - cacheItem.getConfigCache().setMd5Gbk(MD5Utils.md5Hex(content, "GBK")); - cacheItem.getConfigCache().setMd5Utf8(MD5Utils.md5Hex(content, "UTF-8")); + cacheItem.getConfigCache().setMd5(MD5Utils.md5Hex(content, "UTF-8")); ConfigCacheGray configCacheGrayTag = cacheItem.getConfigCacheGray().get(TagGrayRule.TYPE_TAG + "_" + autoTag); String tagContent = "content_from_specific_tag_directreadÄãºÃ" + System.currentTimeMillis(); - configCacheGrayTag.setMd5Gbk(MD5Utils.md5Hex(tagContent, "GBK")); - configCacheGrayTag.setMd5Utf8(MD5Utils.md5Hex(tagContent, "UTF-8")); + configCacheGrayTag.setMd5(MD5Utils.md5Hex(tagContent, "UTF-8")); configCacheGrayTag.setEncryptedDataKey("key_testGetTag_AutoTag_NotDirectRead"); ConfigGrayPersistInfo configGrayPersistInfo = new ConfigGrayPersistInfo(TagGrayRule.TYPE_TAG, TagGrayRule.VERSION, autoTag, -999); diff --git a/config/src/test/java/com/alibaba/nacos/config/server/service/ClientTrackServiceTest.java b/config/src/test/java/com/alibaba/nacos/config/server/service/ClientTrackServiceTest.java index edb32244646..b8b79b60c15 100644 --- a/config/src/test/java/com/alibaba/nacos/config/server/service/ClientTrackServiceTest.java +++ b/config/src/test/java/com/alibaba/nacos/config/server/service/ClientTrackServiceTest.java @@ -17,9 +17,13 @@ package com.alibaba.nacos.config.server.service; import com.alibaba.nacos.config.server.utils.GroupKey2; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration; @@ -31,9 +35,19 @@ @WebAppConfiguration class ClientTrackServiceTest { + MockedStatic envUtilMockedStatic; + @BeforeEach void before() { ClientTrackService.clientRecords.clear(); + envUtilMockedStatic = Mockito.mockStatic(EnvUtil.class); + envUtilMockedStatic.when(() -> EnvUtil.getProperty("nacos.config.cache.type", "nacos")) + .thenReturn("nacos"); + } + + @AfterEach + void after() { + envUtilMockedStatic.close(); } @Test @@ -43,8 +57,9 @@ void testTrackClientMd5() { String group = "online"; String groupKey = GroupKey2.getKey(dataId, group); String md5 = "xxxxxxxxxxxxx"; + String content = "test"; - ConfigCacheService.updateMd5(groupKey, md5, System.currentTimeMillis(), ""); + ConfigCacheService.updateMd5(groupKey, md5, content, System.currentTimeMillis(), ""); ClientTrackService.trackClientMd5(clientIp, groupKey, md5); ClientTrackService.trackClientMd5(clientIp, groupKey, md5); @@ -54,7 +69,7 @@ void testTrackClientMd5() { assertEquals(1, ClientTrackService.subscriberCount()); //服务端数据更新 - ConfigCacheService.updateMd5(groupKey, md5 + "111", System.currentTimeMillis(), ""); + ConfigCacheService.updateMd5(groupKey, md5 + "111", content, System.currentTimeMillis(), ""); assertFalse(ClientTrackService.isClientUptodate(clientIp).get(groupKey)); } diff --git a/config/src/test/java/com/alibaba/nacos/config/server/service/ConfigCacheServiceTest.java b/config/src/test/java/com/alibaba/nacos/config/server/service/ConfigCacheServiceTest.java index b23610b1e1b..cfa563e88c3 100644 --- a/config/src/test/java/com/alibaba/nacos/config/server/service/ConfigCacheServiceTest.java +++ b/config/src/test/java/com/alibaba/nacos/config/server/service/ConfigCacheServiceTest.java @@ -98,7 +98,7 @@ void testDumpFormal() throws Exception { //verify cache. CacheItem contentCache1 = ConfigCacheService.getContentCache(groupKey); assertEquals(ts, contentCache1.getConfigCache().getLastModifiedTs()); - assertEquals(md5, contentCache1.getConfigCache().getMd5Utf8()); + assertEquals(md5, contentCache1.getConfigCache().getMd5()); assertEquals(type, contentCache1.getType()); assertEquals(encryptedDataKey, contentCache1.getConfigCache().getEncryptedDataKey()); Mockito.verify(configDiskService, times(1)).saveToDisk(eq(dataId), eq(group), eq(tenant), eq(content)); @@ -111,7 +111,7 @@ void testDumpFormal() throws Exception { Mockito.verify(configDiskService, times(1)).saveToDisk(eq(dataId), eq(group), eq(tenant), eq(contentNew)); assertEquals(newTs, contentCache1.getConfigCache().getLastModifiedTs()); String newMd5 = MD5Utils.md5Hex(contentNew, "UTF-8"); - assertEquals(newMd5, contentCache1.getConfigCache().getMd5Utf8()); + assertEquals(newMd5, contentCache1.getConfigCache().getMd5()); //modified ts old long oldTs2 = newTs - 123L; @@ -121,7 +121,7 @@ void testDumpFormal() throws Exception { Mockito.verify(configDiskService, times(0)).saveToDisk(eq(dataId), eq(group), eq(tenant), eq(contentWithOldTs)); //not change ts and md5 assertEquals(newTs, contentCache1.getConfigCache().getLastModifiedTs()); - assertEquals(newMd5, contentCache1.getConfigCache().getMd5Utf8()); + assertEquals(newMd5, contentCache1.getConfigCache().getMd5()); //modified ts new only long newTs2 = newTs + 123L; @@ -168,7 +168,7 @@ public void testDumpGray() throws Exception { encryptedDataKey); assertTrue(result); CacheItem contentCache = ConfigCacheService.getContentCache(groupKey); - assertEquals(md5, contentCache.getConfigCacheGray().get(grayName).getMd5Utf8()); + assertEquals(md5, contentCache.getConfigCacheGray().get(grayName).getMd5()); assertEquals(ts, contentCache.getConfigCacheGray().get(grayName).getLastModifiedTs()); assertEquals(encryptedDataKey, contentCache.getConfigCacheGray().get(grayName).getEncryptedDataKey()); Mockito.verify(configDiskService, times(1)) @@ -181,7 +181,7 @@ public void testDumpGray() throws Exception { boolean resultNew = ConfigCacheService.dumpGray(dataId, group, tenant, grayName, grayRule, contentNew, tsNew, encryptedDataKey); assertTrue(resultNew); - assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5Utf8()); + assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5()); assertEquals(tsNew, contentCache.getConfigCacheGray().get(grayName).getLastModifiedTs()); assertEquals(encryptedDataKey, contentCache.getConfigCacheGray().get(grayName).getEncryptedDataKey()); Mockito.verify(configDiskService, times(1)) @@ -193,7 +193,7 @@ public void testDumpGray() throws Exception { boolean resultOld = ConfigCacheService.dumpGray(dataId, group, tenant, grayName, grayRule, contentWithOldTs, tsOld, encryptedDataKey); assertTrue(resultOld); - assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5Utf8()); + assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5()); assertEquals(tsNew, contentCache.getConfigCacheGray().get(grayName).getLastModifiedTs()); assertEquals(encryptedDataKey, contentCache.getConfigCacheGray().get(grayName).getEncryptedDataKey()); Mockito.verify(configDiskService, times(0)) @@ -207,7 +207,7 @@ public void testDumpGray() throws Exception { boolean resultNew2 = ConfigCacheService.dumpGray(dataId, group, tenant, grayName, grayRuleNew, contentWithPrev, tsNew2, encryptedDataKey); assertTrue(resultNew2); - assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5Utf8()); + assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5()); assertEquals(tsNew2, contentCache.getConfigCacheGray().get(grayName).getLastModifiedTs()); assertEquals(encryptedDataKey, contentCache.getConfigCacheGray().get(grayName).getEncryptedDataKey()); assertEquals(GrayRuleManager.constructGrayRule(GrayRuleManager.deserializeConfigGrayPersistInfo(grayRuleNew)), @@ -220,7 +220,7 @@ public void testDumpGray() throws Exception { boolean resultNew3 = ConfigCacheService.dumpGray(dataId, group, tenant, grayName, grayRulePrev, contentWithPrev2, tsNew3, encryptedDataKey); assertTrue(resultNew3); - assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5Utf8()); + assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5()); assertEquals(tsNew3, contentCache.getConfigCacheGray().get(grayName).getLastModifiedTs()); assertEquals(encryptedDataKey, contentCache.getConfigCacheGray().get(grayName).getEncryptedDataKey()); assertEquals(GrayRuleManager.constructGrayRule(GrayRuleManager.deserializeConfigGrayPersistInfo(grayRuleNew)), @@ -232,7 +232,7 @@ public void testDumpGray() throws Exception { boolean resultNew4 = ConfigCacheService.dumpGray(dataId, group, tenant, grayName, grayRulePrev, contentWithPrev4, tsNew4, encryptedDataKey); assertTrue(resultNew4); - assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5Utf8()); + assertEquals(md5New, contentCache.getConfigCacheGray().get(grayName).getMd5()); assertEquals(tsNew3, contentCache.getConfigCacheGray().get(grayName).getLastModifiedTs()); assertEquals(encryptedDataKey, contentCache.getConfigCacheGray().get(grayName).getEncryptedDataKey()); assertEquals(GrayRuleManager.constructGrayRule(GrayRuleManager.deserializeConfigGrayPersistInfo(grayRuleNew)), diff --git a/config/src/test/java/com/alibaba/nacos/config/server/service/dump/DumpChangeConfigWorkerTest.java b/config/src/test/java/com/alibaba/nacos/config/server/service/dump/DumpChangeConfigWorkerTest.java index 614d655c90e..2ebb02fd5fd 100644 --- a/config/src/test/java/com/alibaba/nacos/config/server/service/dump/DumpChangeConfigWorkerTest.java +++ b/config/src/test/java/com/alibaba/nacos/config/server/service/dump/DumpChangeConfigWorkerTest.java @@ -188,7 +188,7 @@ void testDumpChangeOfChangedConfigsNewTimestampOverride() { .getLastModifiedTs()); assertEquals(MD5Utils.md5Hex(configInfoWrapperNewForId1.getContent(), "UTF-8"), ConfigCacheService.getContentCache(GroupKey.getKeyTenant(dataIdPrefix + 1, "group" + 1, "tenant" + 1)).getConfigCache() - .getMd5Utf8()); + .getMd5()); } @Test @@ -224,7 +224,7 @@ void testDumpChangeOfChangedConfigsNewTimestampEqualMd5() { .getLastModifiedTs()); assertEquals(MD5Utils.md5Hex(configInfoWrapperNewForId1.getContent(), "UTF-8"), ConfigCacheService.getContentCache(GroupKey.getKeyTenant(dataIdPrefix + 1, "group" + 1, "tenant" + 1)).getConfigCache() - .getMd5Utf8()); + .getMd5()); } @@ -263,7 +263,7 @@ void testDumpChangeOfChangedConfigsOldTimestamp() { .getLastModifiedTs()); assertEquals(MD5Utils.md5Hex("content" + 1, "UTF-8"), ConfigCacheService.getContentCache(GroupKey.getKeyTenant(dataIdPrefix + 1, "group" + 1, "tenant" + 1)).getConfigCache() - .getMd5Utf8()); + .getMd5()); } @@ -302,7 +302,7 @@ void testDumpChangeOfChangedConfigsEqualsTimestampMd5Update() { .getLastModifiedTs()); assertEquals(MD5Utils.md5Hex(configInfoWrapperNewForId1.getContent(), "UTF-8"), ConfigCacheService.getContentCache(GroupKey.getKeyTenant(dataIdPrefix + 1, "group" + 1, "tenant" + 1)).getConfigCache() - .getMd5Utf8()); + .getMd5()); } diff --git a/config/src/test/java/com/alibaba/nacos/config/server/service/dump/DumpProcessorTest.java b/config/src/test/java/com/alibaba/nacos/config/server/service/dump/DumpProcessorTest.java index 819063612a7..e3d8ccf93d8 100644 --- a/config/src/test/java/com/alibaba/nacos/config/server/service/dump/DumpProcessorTest.java +++ b/config/src/test/java/com/alibaba/nacos/config/server/service/dump/DumpProcessorTest.java @@ -138,7 +138,7 @@ void testDumpNormalAndRemove() throws IOException { //Check cache CacheItem contentCache = ConfigCacheService.getContentCache(GroupKey2.getKey(dataId, group, tenant)); - assertEquals(MD5Utils.md5Hex(content, "UTF-8"), contentCache.getConfigCache().getMd5Utf8()); + assertEquals(MD5Utils.md5Hex(content, "UTF-8"), contentCache.getConfigCache().getMd5()); assertEquals(time, contentCache.getConfigCache().getLastModifiedTs()); //check disk String contentFromDisk = ConfigDiskServiceFactory.getInstance().getContent(dataId, group, tenant); diff --git a/config/src/test/java/com/alibaba/nacos/config/server/service/dump/processor/DumpAllProcessorTest.java b/config/src/test/java/com/alibaba/nacos/config/server/service/dump/processor/DumpAllProcessorTest.java index b765d3a2e72..4a5d90325df 100644 --- a/config/src/test/java/com/alibaba/nacos/config/server/service/dump/processor/DumpAllProcessorTest.java +++ b/config/src/test/java/com/alibaba/nacos/config/server/service/dump/processor/DumpAllProcessorTest.java @@ -70,6 +70,8 @@ class DumpAllProcessorTest { MockedStatic dynamicDataSourceMockedStatic; + MockedStatic propertyUtilMockedStatic; + @Mock ConfigInfoPersistService configInfoPersistService; @@ -81,6 +83,8 @@ class DumpAllProcessorTest { void init() throws Exception { dynamicDataSourceMockedStatic = Mockito.mockStatic(DynamicDataSource.class); envUtilMockedStatic = Mockito.mockStatic(EnvUtil.class); + propertyUtilMockedStatic = Mockito.mockStatic(PropertyUtil.class); + propertyUtilMockedStatic.when(PropertyUtil::getAllDumpPageSize).thenReturn(100); dumpAllProcessor = new DumpAllProcessor(configInfoPersistService); when(EnvUtil.getNacosHome()).thenReturn(System.getProperty("user.home")); when(EnvUtil.getProperty(eq(CommonConstant.NACOS_PLUGIN_DATASOURCE_LOG), eq(Boolean.class), eq(false))).thenReturn(false); @@ -93,12 +97,14 @@ void init() throws Exception { dumpAllProcessor = new DumpAllProcessor(configInfoPersistService); envUtilMockedStatic.when(() -> EnvUtil.getProperty(eq("memory_limit_file_path"), eq("/sys/fs/cgroup/memory/memory.limit_in_bytes"))) .thenReturn(mockMem); + } @AfterEach void after() throws Exception { dynamicDataSourceMockedStatic.close(); envUtilMockedStatic.close(); + propertyUtilMockedStatic.close(); } private ConfigInfoWrapper createNewConfig(int id) { @@ -153,7 +159,7 @@ void testDumpAllOnStartUp() throws Exception { //Check cache CacheItem contentCache1 = ConfigCacheService.getContentCache( GroupKey2.getKey(configInfoWrapper1.getDataId(), configInfoWrapper1.getGroup(), configInfoWrapper1.getTenant())); - assertEquals(md51, contentCache1.getConfigCache().getMd5Utf8()); + assertEquals(md51, contentCache1.getConfigCache().getMd5()); // check if config1 is updated assertTrue(timestamp < contentCache1.getConfigCache().getLastModifiedTs()); //check disk @@ -164,7 +170,7 @@ void testDumpAllOnStartUp() throws Exception { //Check cache CacheItem contentCache2 = ConfigCacheService.getContentCache( GroupKey2.getKey(configInfoWrapper2.getDataId(), configInfoWrapper2.getGroup(), configInfoWrapper2.getTenant())); - assertEquals(MD5Utils.md5Hex(configInfoWrapper2.getContent(), "UTF-8"), contentCache2.getConfigCache().getMd5Utf8()); + assertEquals(MD5Utils.md5Hex(configInfoWrapper2.getContent(), "UTF-8"), contentCache2.getConfigCache().getMd5()); // check if config2 is updated assertEquals(timestamp, contentCache2.getConfigCache().getLastModifiedTs()); //check disk @@ -226,7 +232,7 @@ void testDumpAllOnCheckAll() throws Exception { CacheItem contentCache1 = ConfigCacheService.getContentCache( GroupKey2.getKey(configInfoWrapper1.getDataId(), configInfoWrapper1.getGroup(), configInfoWrapper1.getTenant())); // check if config1 is not updated - assertEquals(md51, contentCache1.getConfigCache().getMd5Utf8()); + assertEquals(md51, contentCache1.getConfigCache().getMd5()); assertEquals(latterTimestamp, contentCache1.getConfigCache().getLastModifiedTs()); //check disk String contentFromDisk1 = ConfigDiskServiceFactory.getInstance() @@ -237,7 +243,7 @@ void testDumpAllOnCheckAll() throws Exception { CacheItem contentCache2 = ConfigCacheService.getContentCache( GroupKey2.getKey(configInfoWrapper2.getDataId(), configInfoWrapper2.getGroup(), configInfoWrapper2.getTenant())); // check if config2 is updated - assertEquals(MD5Utils.md5Hex(configInfoWrapperSingle2.getContent(), "UTF-8"), contentCache2.getConfigCache().getMd5Utf8()); + assertEquals(MD5Utils.md5Hex(configInfoWrapperSingle2.getContent(), "UTF-8"), contentCache2.getConfigCache().getMd5()); assertEquals(configInfoWrapper2.getLastModified(), contentCache2.getConfigCache().getLastModifiedTs()); //check disk String contentFromDisk2 = ConfigDiskServiceFactory.getInstance() diff --git a/config/src/test/java/com/alibaba/nacos/config/server/utils/Md5ComparatorDelegateTest.java b/config/src/test/java/com/alibaba/nacos/config/server/utils/Md5ComparatorDelegateTest.java new file mode 100644 index 00000000000..5d7ddbd5717 --- /dev/null +++ b/config/src/test/java/com/alibaba/nacos/config/server/utils/Md5ComparatorDelegateTest.java @@ -0,0 +1,107 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.utils; + +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedConstruction; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collections; +import java.util.HashMap; + +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class Md5ComparatorDelegateTest { + + public MockedStatic envUtilMockedStatic; + + public MockedStatic nacosServiceLoaderMockedStatic; + + public MockedConstruction nacosMd5ComparatorMockedConstruction; + + @Mock + public NacosMd5Comparator nacosMd5Comparator; + + @BeforeEach + void setUp() { + envUtilMockedStatic = mockStatic(EnvUtil.class); + nacosServiceLoaderMockedStatic = mockStatic(NacosServiceLoader.class); + nacosMd5ComparatorMockedConstruction = mockConstruction(NacosMd5Comparator.class); + } + + @AfterEach + void tearDown() { + envUtilMockedStatic.close(); + nacosServiceLoaderMockedStatic.close(); + nacosMd5ComparatorMockedConstruction.close(); + } + + @Test + public void test() { + when(nacosMd5Comparator.getMd5ComparatorName()).thenReturn("nacos"); + envUtilMockedStatic.when(() -> EnvUtil.getProperty("nacos.config.cache.type", "nacos")).thenReturn("lalala"); + nacosServiceLoaderMockedStatic.when(() -> NacosServiceLoader.load(Md5Comparator.class)) + .thenReturn(Collections.singletonList(nacosMd5Comparator)); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + HashMap clientMd5Map = new HashMap<>(); + Md5ComparatorDelegate.getInstance().compareMd5(request, response, clientMd5Map); + when(nacosMd5ComparatorMockedConstruction.constructed().get(0).compareMd5(request, response, clientMd5Map)).thenReturn(null); + verify(nacosMd5ComparatorMockedConstruction.constructed().get(0), times(1)).compareMd5(request, response, + clientMd5Map); + verify(nacosMd5Comparator, times(0)).compareMd5(request, response, clientMd5Map); + } + + @Test + public void test2() throws Exception { + when(nacosMd5Comparator.getMd5ComparatorName()).thenReturn("nacos"); + envUtilMockedStatic.when(() -> EnvUtil.getProperty("nacos.config.cache.type", "nacos")).thenReturn("nacos"); + nacosServiceLoaderMockedStatic.when(() -> NacosServiceLoader.load(Md5Comparator.class)) + .thenReturn(Collections.singletonList(nacosMd5Comparator)); + Constructor constructor = Md5ComparatorDelegate.class.getDeclaredConstructor(); + constructor.setAccessible(true); + Field field = Md5ComparatorDelegate.class.getDeclaredField("INSTANCE"); + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + field.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + Md5ComparatorDelegate delegate = (Md5ComparatorDelegate) constructor.newInstance(); + field.set(null, delegate); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + HashMap clientMd5Map = new HashMap<>(); + Md5ComparatorDelegate.getInstance().compareMd5(request, response, clientMd5Map); + verify(nacosMd5Comparator, times(1)).compareMd5(request, response, clientMd5Map); + } +} \ No newline at end of file diff --git a/config/src/test/java/com/alibaba/nacos/config/server/utils/NacosMd5ComparatorTest.java b/config/src/test/java/com/alibaba/nacos/config/server/utils/NacosMd5ComparatorTest.java new file mode 100644 index 00000000000..e7e58d2b12d --- /dev/null +++ b/config/src/test/java/com/alibaba/nacos/config/server/utils/NacosMd5ComparatorTest.java @@ -0,0 +1,114 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.utils; + +import com.alibaba.nacos.config.server.service.ConfigCacheService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; +import java.util.List; + +import static com.alibaba.nacos.api.common.Constants.VIPSERVER_TAG; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class NacosMd5ComparatorTest { + + MockedStatic mockRequestUtil; + + MockedStatic configCacheServiceMockedStatic; + + @Mock + HttpServletRequest request; + + @Mock + HttpServletResponse response; + + @BeforeEach + void setUp() { + mockRequestUtil = mockStatic(RequestUtil.class); + configCacheServiceMockedStatic = mockStatic(ConfigCacheService.class); + } + + @AfterEach + void tearDown() { + mockRequestUtil.close(); + configCacheServiceMockedStatic.close(); + } + + @Test + void getMd5ComparatorName() { + NacosMd5Comparator nacosMd5Comparator = new NacosMd5Comparator(); + assertEquals("nacos", nacosMd5Comparator.getMd5ComparatorName()); + } + + @Test + void compareMd5NoChange() { + String ip = "127.0.0.1"; + String tag = "tag"; + when(request.getHeader(VIPSERVER_TAG)).thenReturn(tag); + mockRequestUtil.when(() -> RequestUtil.getRemoteIp(request)).thenReturn(ip); + + String groupKey1 = "groupKey1"; + String groupKey2 = "groupKey2"; + String clientMd5 = "clientMd5"; + HashMap clientMd5Map = new HashMap<>(); + clientMd5Map.put(groupKey1, clientMd5); + clientMd5Map.put(groupKey2, clientMd5); + + NacosMd5Comparator nacosMd5Comparator = new NacosMd5Comparator(); + configCacheServiceMockedStatic.when( + () -> ConfigCacheService.isUptodate(anyString(), eq(clientMd5), eq(ip), eq(tag))).thenReturn(true); + + List changedGroupKeys = nacosMd5Comparator.compareMd5(request, response, clientMd5Map); + assertEquals(0, changedGroupKeys.size()); + } + + @Test + void compareMd5Change() { + String ip = "127.0.0.1"; + String tag = "tag"; + when(request.getHeader(VIPSERVER_TAG)).thenReturn(tag); + mockRequestUtil.when(() -> RequestUtil.getRemoteIp(request)).thenReturn(ip); + + String groupKey1 = "groupKey1"; + String groupKey2 = "groupKey2"; + String clientMd5 = "clientMd5"; + HashMap clientMd5Map = new HashMap<>(); + clientMd5Map.put(groupKey1, clientMd5); + clientMd5Map.put(groupKey2, clientMd5); + + NacosMd5Comparator nacosMd5Comparator = new NacosMd5Comparator(); + configCacheServiceMockedStatic.when( + () -> ConfigCacheService.isUptodate(anyString(), eq(clientMd5), eq(ip), eq(tag))).thenReturn(false); + + List changedGroupKeys = nacosMd5Comparator.compareMd5(request, response, clientMd5Map); + assertEquals(2, changedGroupKeys.size()); + } +} \ No newline at end of file