This is an automated email from the ASF dual-hosted git repository.
jianbin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push:
new b056604771 optimize: Add empty push protection for Configuration
(#7576)
b056604771 is described below
commit b0566047717a485ba0b62e16d8724d50ffe77e6c
Author: xiaoyu <[email protected]>
AuthorDate: Fri Aug 15 09:17:06 2025 +0800
optimize: Add empty push protection for Configuration (#7576)
---
changes/en-us/2.x.md | 5 +-
changes/zh-cn/2.x.md | 1 +
.../seata/common/util/Http5ClientUtilTest.java | 5 +-
.../seata/config/consul/ConsulConfiguration.java | 4 +
.../config/consul/ConsulConfigurationTest.java | 27 ++++
.../seata/config/processor/ProcessorYamlTest.java | 67 +++++++++
.../seata/config/etcd3/EtcdConfiguration.java | 4 +
.../seata/config/nacos/NacosConfiguration.java | 17 ++-
.../seata/config/nacos/NacosConfigurationTest.java | 163 +++++++++++++++++++++
.../seata/config/zk/ZookeeperConfiguration.java | 17 ++-
.../seata/config/zk/ZkConfigurationTest.java | 51 +++++++
11 files changed, 343 insertions(+), 18 deletions(-)
diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 4cfd3314b4..4033b5b6b0 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -40,8 +40,9 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#7478](https://github.com/apache/incubator-seata/pull/7484)] optimize:
remove client id metric
- [[#7557](https://github.com/seata/seata/pull/7557)] upgrade some npmjs
dependencies
-- [[#7577](https://github.com/seata/seata/pull/7577)] remove the 4MB size
limit when decompressing with zstd
-- [[#7578](https://github.com/seata/seata/pull/7578)] zstd decompression is
changed from jni to ZstdInputStream
+- [[#7576](https://github.com/seata/seata/pull/7576)] Add empty push
protection for Configuration
+- [[#7577](https://github.com/seata/seata/pull/7577)] remove the 4MB size
limit when decompressing with zstd
+- [[#7578](https://github.com/seata/seata/pull/7578)] zstd decompression is
changed from jni to ZstdInputStream
### security:
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index c6e1db12f6..9515ca0a4a 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -39,6 +39,7 @@
- [[#7478](https://github.com/apache/incubator-seata/pull/7484)] 删除client id指标
- [[#7557](https://github.com/seata/seata/pull/7557)] 升级 npmjs 依赖
+- [[#7576](https://github.com/seata/seata/pull/7576)] 针对配置变更增加空推保护
- [[#7577](https://github.com/seata/seata/pull/7577)] 去除zstd解压时4MB的限制
### security:
diff --git
a/common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java
b/common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java
index 058ea439e0..9b550067e7 100644
--- a/common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java
+++ b/common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java
@@ -26,7 +26,10 @@ import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
class Http5ClientUtilTest {
diff --git
a/config/seata-config-consul/src/main/java/org/apache/seata/config/consul/ConsulConfiguration.java
b/config/seata-config-consul/src/main/java/org/apache/seata/config/consul/ConsulConfiguration.java
index 86ef1de6c2..f7d8d4be2e 100644
---
a/config/seata-config-consul/src/main/java/org/apache/seata/config/consul/ConsulConfiguration.java
+++
b/config/seata-config-consul/src/main/java/org/apache/seata/config/consul/ConsulConfiguration.java
@@ -351,6 +351,10 @@ public class ConsulConfiguration extends
AbstractConfiguration {
String value = response.getValue().getDecodedValue();
consulIndex = currentIndex;
if (dataId.equals(getConsulConfigKey())) {
+ if (StringUtils.isBlank(value)) {
+ LOGGER.warn("Empty config from Consul,
dataId='{}'. Skipped.", dataId);
+ continue;
+ }
// The new config change listener
Properties seataConfigNew;
try {
diff --git
a/config/seata-config-consul/src/test/java/org/apache/seata/config/consul/ConsulConfigurationTest.java
b/config/seata-config-consul/src/test/java/org/apache/seata/config/consul/ConsulConfigurationTest.java
index 652a437f59..6dc8e84933 100644
---
a/config/seata-config-consul/src/test/java/org/apache/seata/config/consul/ConsulConfigurationTest.java
+++
b/config/seata-config-consul/src/test/java/org/apache/seata/config/consul/ConsulConfigurationTest.java
@@ -17,11 +17,13 @@
package org.apache.seata.config.consul;
import com.ecwid.consul.v1.ConsulClient;
+import com.ecwid.consul.v1.QueryParams;
import com.ecwid.consul.v1.Response;
import com.ecwid.consul.v1.kv.model.GetValue;
import com.ecwid.consul.v1.kv.model.PutParams;
import org.apache.seata.common.util.NetUtil;
import org.apache.seata.config.Configuration;
+import org.apache.seata.config.ConfigurationChangeEvent;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -131,6 +133,31 @@ class ConsulConfigurationTest {
assertEquals("val1", value, "KV should be visible after a short
await");
}
+ @Test
+ void testOnChangeEvent_skipWhenValueIsBlank() throws InterruptedException {
+
+ String dataId = "seata.properties";
+ ConsulConfiguration.ConsulListener listener = new
ConsulConfiguration.ConsulListener(dataId, null);
+
+ GetValue blankValue = mock(GetValue.class);
+ when(blankValue.getDecodedValue()).thenReturn("");
+
+ Response<GetValue> blankResponse = new Response<>(blankValue, 2L,
false, 2L);
+ when(mockConsulClient.getKVValue(eq(dataId), isNull(),
any(QueryParams.class)))
+ .thenReturn(blankResponse);
+
+ // Run onChangeEvent in a separate thread since it loops indefinitely
+ Thread thread = new Thread(() -> listener.onChangeEvent(new
ConfigurationChangeEvent()));
+ thread.start();
+ Thread.sleep(100);
+ // Interrupt to break the loop
+ thread.interrupt();
+ thread.join(500);
+
+ // Assert: Test passes as long as no exceptions are thrown
+ assertTrue(true);
+ }
+
// Utility method to set private fields via reflection
private void setField(Object target, String fieldName, Object value) {
try {
diff --git
a/config/seata-config-core/src/test/java/org/apache/seata/config/processor/ProcessorYamlTest.java
b/config/seata-config-core/src/test/java/org/apache/seata/config/processor/ProcessorYamlTest.java
new file mode 100644
index 0000000000..cb63334a18
--- /dev/null
+++
b/config/seata-config-core/src/test/java/org/apache/seata/config/processor/ProcessorYamlTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.seata.config.processor;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Properties;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class ProcessorYamlTest {
+
+ @Test
+ void testProcessor_NormalYaml() {
+ String yamlConfig = "server:\n" + " port: 8080\n"
+ + " host: localhost\n"
+ + "spring:\n"
+ + " datasource:\n"
+ + " url: jdbc:mysql://localhost:3306/test\n"
+ + " username: root";
+
+ ProcessorYaml processorYaml = new ProcessorYaml();
+ Properties props = processorYaml.processor(yamlConfig);
+
+ assertEquals(8080, props.get("server.port"));
+ assertEquals("", props.getProperty("server.port", ""));
+ assertEquals("localhost", props.getProperty("server.host"));
+ assertEquals("jdbc:mysql://localhost:3306/test",
props.getProperty("spring.datasource.url"));
+ assertEquals("root", props.getProperty("spring.datasource.username"));
+ }
+
+ @Test
+ void testProcessor_InvalidYaml_ShouldThrowException() {
+
+ String invalidYaml = "server:\n" + " port: 8080\n" + "::host
localhost";
+
+ ProcessorYaml processorYaml = new ProcessorYaml();
+
+ Assertions.assertThrows(Exception.class, () -> {
+ processorYaml.processor(invalidYaml);
+ });
+ }
+
+ @Test
+ void testProcessor_EmptyYaml() {
+ String emptyYaml = "";
+ ProcessorYaml processorYaml = new ProcessorYaml();
+ Properties props = processorYaml.processor(emptyYaml);
+ assertTrue(props.size() == 1);
+ }
+}
diff --git
a/config/seata-config-etcd3/src/main/java/org/apache/seata/config/etcd3/EtcdConfiguration.java
b/config/seata-config-etcd3/src/main/java/org/apache/seata/config/etcd3/EtcdConfiguration.java
index d911084e06..b4a9631674 100644
---
a/config/seata-config-etcd3/src/main/java/org/apache/seata/config/etcd3/EtcdConfiguration.java
+++
b/config/seata-config-etcd3/src/main/java/org/apache/seata/config/etcd3/EtcdConfiguration.java
@@ -400,6 +400,10 @@ public class EtcdConfiguration extends
AbstractConfiguration {
.getValue()
.getBytes();
Properties seataConfigNew;
+ if (bytes == null || bytes.length == 0) {
+ LOGGER.warn("config '{}' value is empty from
watchResponse", dataId);
+ return;
+ }
try {
seataConfigNew = ConfigProcessor.processConfig(
new String(bytes, StandardCharsets.UTF_8),
getEtcdDataType());
diff --git
a/config/seata-config-nacos/src/main/java/org/apache/seata/config/nacos/NacosConfiguration.java
b/config/seata-config-nacos/src/main/java/org/apache/seata/config/nacos/NacosConfiguration.java
index 82eaf348f8..81b76f429b 100644
---
a/config/seata-config-nacos/src/main/java/org/apache/seata/config/nacos/NacosConfiguration.java
+++
b/config/seata-config-nacos/src/main/java/org/apache/seata/config/nacos/NacosConfiguration.java
@@ -442,14 +442,17 @@ public class NacosConfiguration extends
AbstractConfiguration implements Dispose
public void innerReceive(String dataId, String group, String
configInfo) {
// The new configuration method to puts all configurations into a
dateId
if (getNacosDataId().equals(dataId)) {
+ if (StringUtils.isBlank(configInfo)) {
+ LOGGER.warn("Empty config from Nacos, dataId='{}'.
Skipped.", dataId);
+ return;
+ }
Properties seataConfigNew = new Properties();
- if (StringUtils.isNotBlank(configInfo)) {
- try {
- seataConfigNew =
ConfigProcessor.processConfig(configInfo, getNacosDataType());
- } catch (IOException e) {
- LOGGER.error("load config properties error", e);
- return;
- }
+
+ try {
+ seataConfigNew = ConfigProcessor.processConfig(configInfo,
getNacosDataType());
+ } catch (IOException e) {
+ LOGGER.error("load config properties error", e);
+ return;
}
// Get all the monitored dataids and judge whether it has been
modified
diff --git
a/config/seata-config-nacos/src/test/java/org/apache/seata/config/nacos/NacosConfigurationTest.java
b/config/seata-config-nacos/src/test/java/org/apache/seata/config/nacos/NacosConfigurationTest.java
index 7346ac5b49..470cce840d 100644
---
a/config/seata-config-nacos/src/test/java/org/apache/seata/config/nacos/NacosConfigurationTest.java
+++
b/config/seata-config-nacos/src/test/java/org/apache/seata/config/nacos/NacosConfigurationTest.java
@@ -19,14 +19,28 @@ package org.apache.seata.config.nacos;
import com.alibaba.nacos.api.exception.NacosException;
import org.apache.seata.common.util.ReflectionUtil;
import org.apache.seata.config.Configuration;
+import org.apache.seata.config.ConfigurationChangeEvent;
+import org.apache.seata.config.ConfigurationChangeListener;
import org.apache.seata.config.ConfigurationFactory;
import org.apache.seata.config.Dispose;
+import org.apache.seata.config.processor.ConfigProcessor;
+import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.mockito.ArgumentMatchers.anyString;
/**
* The type Nacos configuration test
@@ -58,4 +72,153 @@ public class NacosConfigurationTest {
Assertions.assertEquals("/foo", properties.getProperty("contextPath"));
System.clearProperty("contextPath");
}
+
+ @Test
+ public void testInnerReceiveEmptyPushShouldNotUpdateConfig() throws
Exception {
+
+ String dataId = "seata.properties";
+ String group = "SEATA_GROUP";
+ String configKey = "session.mode";
+
+ Properties oldConfig = new Properties();
+ oldConfig.setProperty(configKey, "db");
+
+ Field seataConfigField =
NacosConfiguration.class.getDeclaredField("seataConfig");
+ seataConfigField.setAccessible(true);
+ seataConfigField.set(null, oldConfig);
+
+ TestListener listener = new TestListener();
+ NacosConfiguration.NacosListener nacosListener =
getNacosListener(dataId, listener);
+
+ ConcurrentMap<ConfigurationChangeListener,
NacosConfiguration.NacosListener> innerMap =
+ new ConcurrentHashMap<>();
+ innerMap.put(listener, nacosListener);
+
+ ConcurrentMap<String, ConcurrentMap<ConfigurationChangeListener,
NacosConfiguration.NacosListener>> outerMap =
+ new ConcurrentHashMap<>();
+ outerMap.put(dataId, innerMap);
+
+ Field listenerMapField =
NacosConfiguration.class.getDeclaredField("CONFIG_LISTENERS_MAP");
+ listenerMapField.setAccessible(true);
+ listenerMapField.set(null, outerMap);
+
+ // execute
+ nacosListener.innerReceive(dataId, group, "");
+
+ Properties actualConfig = (Properties) seataConfigField.get(null);
+ Assertions.assertEquals("db", actualConfig.getProperty(configKey));
+
+ Assertions.assertFalse(listener.invoked);
+ }
+
+ @Test
+ public void testInnerReceiveShouldReturn() throws Exception {
+
+ String dataId = "seata.properties";
+ String group = "SEATA_GROUP";
+ String configKey = "session.mode";
+
+ Properties oldConfig = new Properties();
+ oldConfig.setProperty(configKey, "db");
+
+ Field seataConfigField =
NacosConfiguration.class.getDeclaredField("seataConfig");
+ seataConfigField.setAccessible(true);
+ seataConfigField.set(null, oldConfig);
+
+ TestListener listener = new TestListener();
+ NacosConfiguration.NacosListener nacosListener =
getNacosListener(dataId, listener);
+
+ ConcurrentMap<ConfigurationChangeListener,
NacosConfiguration.NacosListener> innerMap =
+ new ConcurrentHashMap<>();
+ innerMap.put(listener, nacosListener);
+
+ ConcurrentMap<String, ConcurrentMap<ConfigurationChangeListener,
NacosConfiguration.NacosListener>> outerMap =
+ new ConcurrentHashMap<>();
+ outerMap.put(dataId, innerMap);
+
+ Field listenerMapField =
NacosConfiguration.class.getDeclaredField("CONFIG_LISTENERS_MAP");
+ listenerMapField.setAccessible(true);
+ listenerMapField.set(null, outerMap);
+
+ // execute
+ nacosListener.innerReceive(dataId, group, "session.mode=redis");
+
+ Properties actualConfig = (Properties) seataConfigField.get(null);
+ Assertions.assertEquals("redis", actualConfig.getProperty(configKey));
+
+ Assertions.assertFalse(listener.invoked);
+ }
+
+ @Test
+ public void testInnerReceiveThrowException() throws Exception {
+
+ String dataId = "seata.properties";
+ String group = "SEATA_GROUP";
+ String configKey = "session.mode";
+
+ Properties oldConfig = new Properties();
+ oldConfig.setProperty(configKey, "db");
+
+ Field seataConfigField =
NacosConfiguration.class.getDeclaredField("seataConfig");
+ seataConfigField.setAccessible(true);
+ seataConfigField.set(null, oldConfig);
+
+ TestListener listener = new TestListener();
+ NacosConfiguration.NacosListener nacosListener =
getNacosListener(dataId, listener);
+
+ ConcurrentMap<ConfigurationChangeListener,
NacosConfiguration.NacosListener> innerMap =
+ new ConcurrentHashMap<>();
+ innerMap.put(listener, nacosListener);
+
+ ConcurrentMap<String, ConcurrentMap<ConfigurationChangeListener,
NacosConfiguration.NacosListener>> outerMap =
+ new ConcurrentHashMap<>();
+ outerMap.put(dataId, innerMap);
+
+ Field listenerMapField =
NacosConfiguration.class.getDeclaredField("CONFIG_LISTENERS_MAP");
+ listenerMapField.setAccessible(true);
+ listenerMapField.set(null, outerMap);
+
+ try (MockedStatic<ConfigProcessor> processorMockedStatic =
Mockito.mockStatic(ConfigProcessor.class)) {
+ processorMockedStatic
+ .when(() ->
ConfigProcessor.resolverConfigDataType(anyString()))
+ .thenReturn("yaml");
+ processorMockedStatic
+ .when(() -> ConfigProcessor.processConfig(anyString(),
anyString()))
+ .thenThrow(new IOException("mock io exception"));
+ // execute
+ nacosListener.innerReceive(dataId, group, "session.mode=redis");
+ }
+
+ Properties actualConfig = (Properties) seataConfigField.get(null);
+ Assertions.assertEquals("db", actualConfig.getProperty(configKey));
+
+ Assertions.assertFalse(listener.invoked);
+ }
+
+ @NotNull
+ private static NacosConfiguration.NacosListener getNacosListener(String
dataId, TestListener listener)
+ throws ClassNotFoundException, NoSuchMethodException,
InstantiationException, IllegalAccessException,
+ InvocationTargetException {
+ Class<?> outerClass =
Class.forName("org.apache.seata.config.nacos.NacosConfiguration");
+ Constructor<?> constructor = outerClass.getDeclaredConstructor();
+ constructor.setAccessible(true);
+ Object nacosConfigurationInstance = constructor.newInstance();
+ Class<?> innerClass =
Class.forName("org.apache.seata.config.nacos.NacosConfiguration$NacosListener");
+
+ Constructor<?> innerConstructor =
+ innerClass.getDeclaredConstructor(outerClass, String.class,
ConfigurationChangeListener.class);
+ innerConstructor.setAccessible(true);
+ NacosConfiguration.NacosListener nacosListener =
(NacosConfiguration.NacosListener)
+ innerConstructor.newInstance(nacosConfigurationInstance,
dataId, listener);
+ return nacosListener;
+ }
+
+ private static class TestListener implements ConfigurationChangeListener {
+ boolean invoked = false;
+
+ @Override
+ public void onChangeEvent(ConfigurationChangeEvent event) {
+ invoked = true;
+ }
+ }
}
diff --git
a/config/seata-config-zk/src/main/java/org/apache/seata/config/zk/ZookeeperConfiguration.java
b/config/seata-config-zk/src/main/java/org/apache/seata/config/zk/ZookeeperConfiguration.java
index eb9dcf2c21..1bf720de63 100644
---
a/config/seata-config-zk/src/main/java/org/apache/seata/config/zk/ZookeeperConfiguration.java
+++
b/config/seata-config-zk/src/main/java/org/apache/seata/config/zk/ZookeeperConfiguration.java
@@ -394,15 +394,16 @@ public class ZookeeperConfiguration extends
AbstractConfiguration {
o = new String(data.getData());
}
if (path.equals(getConfigPath())) {
+ if (StringUtils.isBlank(o.toString())) {
+ LOGGER.warn("Empty config from Zookeeper, path='{}'.
Skipped.", path);
+ return;
+ }
Properties seataConfigNew = new Properties();
- if (StringUtils.isNotBlank(o.toString())) {
- try {
- seataConfigNew =
ConfigProcessor.processConfig(o.toString(), getZkDataType());
-
- } catch (IOException e) {
- LOGGER.error("load config properties error", e);
- return;
- }
+ try {
+ seataConfigNew =
ConfigProcessor.processConfig(o.toString(), getZkDataType());
+ } catch (IOException e) {
+ LOGGER.error("load config properties error", e);
+ return;
}
for (Map.Entry<String,
ConcurrentMap<ConfigurationChangeListener, NodeCacheListenerImpl>> entry :
diff --git
a/config/seata-config-zk/src/test/java/org/apache/seata/config/zk/ZkConfigurationTest.java
b/config/seata-config-zk/src/test/java/org/apache/seata/config/zk/ZkConfigurationTest.java
index d34d863c51..f34b43f4e0 100644
---
a/config/seata-config-zk/src/test/java/org/apache/seata/config/zk/ZkConfigurationTest.java
+++
b/config/seata-config-zk/src/test/java/org/apache/seata/config/zk/ZkConfigurationTest.java
@@ -16,20 +16,32 @@
*/
package org.apache.seata.config.zk;
+import org.apache.curator.framework.recipes.cache.ChildData;
+import org.apache.curator.framework.recipes.cache.CuratorCacheListener;
import org.apache.curator.test.TestingServer;
import org.apache.seata.config.ConfigurationChangeEvent;
import org.apache.seata.config.ConfigurationChangeListener;
import org.apache.seata.config.ConfigurationChangeType;
+import org.apache.seata.config.processor.ConfigProcessor;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
/**
* The type zk configuration test
*/
@@ -124,4 +136,43 @@ public class ZkConfigurationTest {
}
Assertions.assertTrue(listened[0]);
}
+
+ @Test
+ public void testEvent_pathEqualsConfigPath_blankValue() throws Exception {
+ Method getConfigPath =
ZookeeperConfiguration.class.getDeclaredMethod("getConfigPath");
+ getConfigPath.setAccessible(true);
+
+ String configPath = getConfigPath.invoke(null).toString();
+
+ ZookeeperConfiguration.NodeCacheListenerImpl listener =
+ new ZookeeperConfiguration.NodeCacheListenerImpl(configPath,
null);
+
+ ChildData mockData = mock(ChildData.class);
+ when(mockData.getData()).thenReturn(new byte[0]);
+
+ listener.event(CuratorCacheListener.Type.NODE_CHANGED, null, mockData);
+
+ // If it can run to this point, it indicates that the null value
branch has been overwritten
+ }
+
+ @Test
+ public void testEvent_pathEqualsConfigPath_throwException() throws
Exception {
+ Method getConfigPathMethod =
ZookeeperConfiguration.class.getDeclaredMethod("getConfigPath");
+ getConfigPathMethod.setAccessible(true);
+ String configPath = getConfigPathMethod.invoke(null).toString();
+ ZookeeperConfiguration.NodeCacheListenerImpl listener =
+ new ZookeeperConfiguration.NodeCacheListenerImpl(configPath,
null);
+ String invalidYaml = "server:\n" + " port: 8080\n" + "::host
localhost";
+ ChildData mockData = mock(ChildData.class);
+
when(mockData.getData()).thenReturn(invalidYaml.getBytes(StandardCharsets.UTF_8));
+ try (MockedStatic<ConfigProcessor> processorMockedStatic =
Mockito.mockStatic(ConfigProcessor.class)) {
+ processorMockedStatic
+ .when(() ->
ConfigProcessor.resolverConfigDataType(anyString()))
+ .thenReturn("yaml");
+ processorMockedStatic
+ .when(() -> ConfigProcessor.processConfig(anyString(),
anyString()))
+ .thenThrow(new IOException("mock io exception"));
+ listener.event(CuratorCacheListener.Type.NODE_CHANGED, null,
mockData);
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]