diff --git a/dubbo-remoting/dubbo-remoting-api/pom.xml b/dubbo-remoting/dubbo-remoting-api/pom.xml
index 73e160136e7..a083b2051ca 100644
--- a/dubbo-remoting/dubbo-remoting-api/pom.xml
+++ b/dubbo-remoting/dubbo-remoting-api/pom.xml
@@ -58,5 +58,11 @@
log4j-slf4j-impl
test
+
+ org.apache.dubbo
+ dubbo-test-check
+ ${project.parent.version}
+ test
+
diff --git a/dubbo-remoting/dubbo-remoting-http12/pom.xml b/dubbo-remoting/dubbo-remoting-http12/pom.xml
index 4d16603471c..64725c11e0e 100644
--- a/dubbo-remoting/dubbo-remoting-http12/pom.xml
+++ b/dubbo-remoting/dubbo-remoting-http12/pom.xml
@@ -85,5 +85,11 @@
log4j-slf4j-impl
test
+
+ org.apache.dubbo
+ dubbo-test-check
+ ${project.parent.version}
+ test
+
diff --git a/dubbo-remoting/dubbo-remoting-http3/pom.xml b/dubbo-remoting/dubbo-remoting-http3/pom.xml
index 4955a9ed08c..e9d2041e2f5 100644
--- a/dubbo-remoting/dubbo-remoting-http3/pom.xml
+++ b/dubbo-remoting/dubbo-remoting-http3/pom.xml
@@ -52,5 +52,11 @@
log4j-slf4j-impl
test
+
+ org.apache.dubbo
+ dubbo-test-check
+ ${project.parent.version}
+ test
+
diff --git a/dubbo-remoting/dubbo-remoting-netty/pom.xml b/dubbo-remoting/dubbo-remoting-netty/pom.xml
index 94f3924efa7..b5b43f59aae 100644
--- a/dubbo-remoting/dubbo-remoting-netty/pom.xml
+++ b/dubbo-remoting/dubbo-remoting-netty/pom.xml
@@ -57,5 +57,11 @@
${project.parent.version}
test
+
+ org.apache.dubbo
+ dubbo-test-check
+ ${project.parent.version}
+ test
+
diff --git a/dubbo-remoting/dubbo-remoting-netty4/pom.xml b/dubbo-remoting/dubbo-remoting-netty4/pom.xml
index 06d548d1bdf..82aa4b2a0c9 100644
--- a/dubbo-remoting/dubbo-remoting-netty4/pom.xml
+++ b/dubbo-remoting/dubbo-remoting-netty4/pom.xml
@@ -68,6 +68,12 @@
${project.parent.version}
test
+
+ org.apache.dubbo
+ dubbo-test-check
+ ${project.parent.version}
+ test
+
org.apache.logging.log4j
log4j-slf4j-impl
diff --git a/dubbo-remoting/dubbo-remoting-websocket/pom.xml b/dubbo-remoting/dubbo-remoting-websocket/pom.xml
index b27869d056a..551e8f195a5 100644
--- a/dubbo-remoting/dubbo-remoting-websocket/pom.xml
+++ b/dubbo-remoting/dubbo-remoting-websocket/pom.xml
@@ -37,5 +37,11 @@
dubbo-remoting-http12
${project.parent.version}
+
+ org.apache.dubbo
+ dubbo-test-check
+ ${project.parent.version}
+ test
+
diff --git a/dubbo-remoting/dubbo-remoting-zookeeper-curator5/pom.xml b/dubbo-remoting/dubbo-remoting-zookeeper-curator5/pom.xml
index 54de827c327..5556f236b56 100644
--- a/dubbo-remoting/dubbo-remoting-zookeeper-curator5/pom.xml
+++ b/dubbo-remoting/dubbo-remoting-zookeeper-curator5/pom.xml
@@ -39,13 +39,6 @@
${project.parent.version}
-
- org.apache.dubbo
- dubbo-test-common
- ${project.parent.version}
- test
-
-
org.apache.curator
curator-framework
diff --git a/dubbo-remoting/dubbo-remoting-zookeeper-curator5/src/test/java/org/apache/dubbo/remoting/zookeeper/curator5/Curator5ZookeeperClientTest.java b/dubbo-remoting/dubbo-remoting-zookeeper-curator5/src/test/java/org/apache/dubbo/remoting/zookeeper/curator5/Curator5ZookeeperClientTest.java
index e515fc6504b..4e784ee3e0f 100644
--- a/dubbo-remoting/dubbo-remoting-zookeeper-curator5/src/test/java/org/apache/dubbo/remoting/zookeeper/curator5/Curator5ZookeeperClientTest.java
+++ b/dubbo-remoting/dubbo-remoting-zookeeper-curator5/src/test/java/org/apache/dubbo/remoting/zookeeper/curator5/Curator5ZookeeperClientTest.java
@@ -18,48 +18,153 @@
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.config.configcenter.ConfigItem;
+import org.apache.dubbo.remoting.zookeeper.curator5.Curator5ZookeeperClient.CuratorWatcherImpl;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import com.google.common.collect.Lists;
+import org.apache.curator.CuratorZookeeperClient;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
-import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.curator.framework.WatcherRemoveCuratorFramework;
+import org.apache.curator.framework.api.CreateBuilder;
+import org.apache.curator.framework.api.CuratorWatcher;
+import org.apache.curator.framework.api.DeleteBuilder;
+import org.apache.curator.framework.api.ExistsBuilder;
+import org.apache.curator.framework.api.GetChildrenBuilder;
+import org.apache.curator.framework.api.GetDataBuilder;
+import org.apache.curator.framework.api.SetDataBuilder;
+import org.apache.curator.framework.listen.StandardListenerManager;
+import org.apache.curator.framework.recipes.cache.NodeCache;
+import org.apache.zookeeper.KeeperException.NodeExistsException;
import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher.Event;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.data.Stat;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.stubbing.Answer;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstructionWithAnswer;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
class Curator5ZookeeperClientTest {
private static Curator5ZookeeperClient curatorClient;
private static CuratorFramework client = null;
- private static int zookeeperServerPort1;
+ private static int zookeeperServerMockPort1;
private static String zookeeperConnectionAddress1;
+ @Spy
+ CuratorFrameworkFactory.Builder spyBuilder = CuratorFrameworkFactory.builder();
+
+ private CuratorFramework mockCuratorFramework;
+ private CreateBuilder mockCreateBuilder;
+ private ExistsBuilder mockExistsBuilder;
+ private GetChildrenBuilder mockGetChildrenBuilder;
+ private DeleteBuilder mockDeleteBuilder;
+ private GetDataBuilder mockGetDataBuilder;
+ private SetDataBuilder mockSetDataBuilder;
+ private CuratorZookeeperClient mockCuratorZookeeperClient;
+ private WatcherRemoveCuratorFramework mockWatcherRemoveCuratorFramework;
+
@BeforeAll
public static void setUp() throws Exception {
- zookeeperConnectionAddress1 = System.getProperty("zookeeper.connection.address.1");
- zookeeperServerPort1 = Integer.parseInt(
- zookeeperConnectionAddress1.substring(zookeeperConnectionAddress1.lastIndexOf(":") + 1));
+ zookeeperServerMockPort1 = 2181;
+ zookeeperConnectionAddress1 = "zookeeper://localhost:" + zookeeperServerMockPort1;
+
+ // mock begin
+ // create mock bean begin
+ CuratorFrameworkFactory.Builder realBuilder = CuratorFrameworkFactory.builder();
+ CuratorFrameworkFactory.Builder spyBuilder = spy(realBuilder);
+
+ MockedStatic curatorFrameworkFactoryMockedStatic = mockStatic(CuratorFrameworkFactory.class);
+ curatorFrameworkFactoryMockedStatic.when(CuratorFrameworkFactory::builder).thenReturn(spyBuilder);
+ }
+
+ @BeforeEach
+ public void init() throws Exception {
+ mockCreateBuilder = mock(CreateBuilder.class);
+ mockExistsBuilder = mock(ExistsBuilder.class);
+ mockDeleteBuilder = mock(DeleteBuilder.class);
+ mockCuratorFramework = mock(CuratorFramework.class);
+ mockGetChildrenBuilder = mock(GetChildrenBuilder.class);
+ mockGetDataBuilder = mock(GetDataBuilder.class);
+ mockCuratorZookeeperClient = mock(CuratorZookeeperClient.class);
+ mockWatcherRemoveCuratorFramework = mock(WatcherRemoveCuratorFramework.class);
+ mockSetDataBuilder = mock(SetDataBuilder.class);
+ doReturn(mockCuratorFramework).when(spyBuilder).build();
+ when(mockCuratorFramework.blockUntilConnected(anyInt(), any())).thenReturn(true);
+ when(mockCuratorFramework.getConnectionStateListenable()).thenReturn(StandardListenerManager.standard());
+ when(mockCuratorFramework.create()).thenReturn(mockCreateBuilder);
+ when(mockCuratorFramework.checkExists()).thenReturn(mockExistsBuilder);
+ when(mockCuratorFramework.getChildren()).thenReturn(mockGetChildrenBuilder);
+ when(mockCuratorFramework.getZookeeperClient()).thenReturn(mockCuratorZookeeperClient);
+ when(mockCuratorFramework.newWatcherRemoveCuratorFramework()).thenReturn(mockWatcherRemoveCuratorFramework);
+ when(mockCuratorZookeeperClient.isConnected()).thenReturn(true);
+ when(mockCuratorFramework.delete()).thenReturn(mockDeleteBuilder);
+ when(mockCreateBuilder.withMode(any())).thenReturn(mockCreateBuilder);
+ when(mockDeleteBuilder.deletingChildrenIfNeeded()).thenReturn(mockDeleteBuilder);
+ when(mockDeleteBuilder.forPath(any())).then((Answer) invocationOnMock -> null);
+ when(mockCuratorFramework.getData()).thenReturn(mockGetDataBuilder);
+ when(mockCuratorFramework.setData()).thenReturn(mockSetDataBuilder);
+ List paths = new ArrayList<>();
+ when(mockCreateBuilder.forPath(anyString())).thenAnswer(i-> {
+ String param = i.getArgument(0);
+ if (paths.contains(param)) {
+ throw new NodeExistsException("node existed: " + param);
+ }
+ paths.add(i.getArgument(0));
+ return i.getArgument(0);
+ });
+ when(mockCreateBuilder.forPath(anyString(), any())).thenAnswer(i-> {
+ String param = i.getArgument(0);
+ if (paths.contains(param)) {
+ throw new NodeExistsException("node existed: " + param);
+ }
+ paths.add(i.getArgument(0));
+ return i.getArgument(0);
+ });
+ when(mockExistsBuilder.forPath(anyString())).thenAnswer(i-> {
+ if (paths.contains(i.getArgument(0))) {
+ return new Stat();
+ }
+ return null;
+ });
+ when(mockDeleteBuilder.forPath(anyString())).thenAnswer(i-> {
+ if (paths.contains(i.getArgument(0))) {
+ paths.remove(i.getArgument(0));
+ }
+ return null;
+ });
+
+
curatorClient = new Curator5ZookeeperClient(
URL.valueOf(zookeeperConnectionAddress1 + "/org.apache.dubbo.registry.RegistryService"));
- client = CuratorFrameworkFactory.newClient(
- "127.0.0.1:" + zookeeperServerPort1, new ExponentialBackoffRetry(1000, 3));
- client.start();
}
@Test
@@ -71,7 +176,8 @@ void testCheckExists() {
}
@Test
- void testChildrenPath() {
+ void testChildrenPath() throws Exception {
+ when(mockGetChildrenBuilder.forPath(any())).thenReturn(Lists.newArrayList("provider1", "provider2"));
String path = "/dubbo/org.apache.dubbo.demo.DemoService/providers";
curatorClient.create(path, false, true);
curatorClient.create(path + "/provider1", false, true);
@@ -83,17 +189,21 @@ void testChildrenPath() {
@Test
@Timeout(value = 2)
- public void testChildrenListener() throws InterruptedException {
+ public void testChildrenListener() throws Exception {
String path = "/dubbo/org.apache.dubbo.demo.DemoListenerService/providers";
curatorClient.create(path, false, true);
final CountDownLatch countDownLatch = new CountDownLatch(1);
- curatorClient.addTargetChildListener(path, new Curator5ZookeeperClient.CuratorWatcherImpl() {
+ when(mockGetChildrenBuilder.usingWatcher(any(CuratorWatcher.class))).thenReturn(mockGetChildrenBuilder);
+ when(mockGetChildrenBuilder.forPath(any())).thenReturn(Lists.newArrayList("providers"));
+ CuratorWatcherImpl watcher = new CuratorWatcherImpl() {
@Override
public void process(WatchedEvent watchedEvent) {
countDownLatch.countDown();
}
- });
+ };
+ curatorClient.addTargetChildListener(path, watcher);
+ watcher.process(new WatchedEvent(Event.EventType.NodeDeleted, KeeperState.Closed, "providers"));
curatorClient.createPersistent(path + "/provider1", true);
countDownLatch.await();
}
@@ -107,8 +217,10 @@ void testWithInvalidServer() {
}
@Test
- void testRemoveChildrenListener() {
+ void testRemoveChildrenListener() throws Exception {
ChildListener childListener = mock(ChildListener.class);
+ when(mockGetChildrenBuilder.usingWatcher(any(CuratorWatcher.class))).thenReturn(mockGetChildrenBuilder);
+ when(mockGetChildrenBuilder.forPath(any())).thenReturn(Lists.newArrayList("children"));
curatorClient.addChildListener("/children", childListener);
curatorClient.removeChildListener("/children", childListener);
}
@@ -127,26 +239,28 @@ void testConnectedStatus() {
}
@Test
- void testCreateContent4Persistent() {
+ void testCreateContent4Persistent() throws Exception {
String path = "/curatorTest4CrContent/content.data";
String content = "createContentTest";
curatorClient.delete(path);
assertThat(curatorClient.checkExists(path), is(false));
assertNull(curatorClient.getContent(path));
+ when(mockGetDataBuilder.forPath(any())).then(invocationOnMock -> content.getBytes());
curatorClient.createOrUpdate(path, content, false);
assertThat(curatorClient.checkExists(path), is(true));
assertEquals(curatorClient.getContent(path), content);
}
@Test
- void testCreateContent4Temp() {
+ void testCreateContent4Temp() throws Exception{
String path = "/curatorTest4CrContent/content.data";
String content = "createContentTest";
curatorClient.delete(path);
assertThat(curatorClient.checkExists(path), is(false));
assertNull(curatorClient.getContent(path));
+ when(mockGetDataBuilder.forPath(any())).then(invocationOnMock -> content.getBytes());
curatorClient.createOrUpdate(path, content, true);
assertThat(curatorClient.checkExists(path), is(true));
assertEquals(curatorClient.getContent(path), content);
@@ -197,27 +311,41 @@ void testAddTargetDataListener() throws Exception {
String value = "vav";
curatorClient.createOrUpdate(path + "/d.json", value, true);
+ when(mockGetDataBuilder.forPath(any())).then(invocationOnMock -> value.getBytes());
String valueFromCache = curatorClient.getContent(path + "/d.json");
Assertions.assertEquals(value, valueFromCache);
final AtomicInteger atomicInteger = new AtomicInteger(0);
- curatorClient.addTargetDataListener(path + "/d.json", new Curator5ZookeeperClient.NodeCacheListenerImpl() {
+ NodeCache mockNodeCache = mock(NodeCache.class);
+ mockConstructionWithAnswer(NodeCache.class, invocationOnMock -> invocationOnMock.getMethod().invoke(mockNodeCache, invocationOnMock.getArguments()));
+ when(mockNodeCache.getListenable()).thenReturn(StandardListenerManager.standard());
+ Curator5ZookeeperClient.NodeCacheListenerImpl nodeCacheListener = new Curator5ZookeeperClient.NodeCacheListenerImpl() {
@Override
public void nodeChanged() {
atomicInteger.incrementAndGet();
}
- });
+ };
+ curatorClient.addTargetDataListener(path + "/d.json", nodeCacheListener);
valueFromCache = curatorClient.getContent(path + "/d.json");
Assertions.assertNotNull(valueFromCache);
int currentCount1 = atomicInteger.get();
+ when(mockSetDataBuilder.forPath(any(), any())).then(invocationOnMock -> {
+ nodeCacheListener.nodeChanged();
+ return null;
+ });
curatorClient.getClient().setData().forPath(path + "/d.json", "foo".getBytes());
await().until(() -> atomicInteger.get() > currentCount1);
int currentCount2 = atomicInteger.get();
curatorClient.getClient().setData().forPath(path + "/d.json", "bar".getBytes());
await().until(() -> atomicInteger.get() > currentCount2);
int currentCount3 = atomicInteger.get();
+ when(mockDeleteBuilder.forPath(any())).then(invocationOnMock -> {
+ nodeCacheListener.nodeChanged();
+ return null;
+ });
curatorClient.delete(path + "/d.json");
+ when(mockGetDataBuilder.forPath(any())).thenReturn(null);
valueFromCache = curatorClient.getContent(path + "/d.json");
Assertions.assertNull(valueFromCache);
await().until(() -> atomicInteger.get() > currentCount3);
@@ -256,10 +384,10 @@ protected void update(String path, String data, int version) {
throw new RuntimeException(e);
}
});
+ when(mockGetDataBuilder.forPath(any())).then(invocationOnMock -> "version x".getBytes());
Assertions.assertThrows(
IllegalStateException.class, () -> curatorClient.createOrUpdate(path, "version 1", false, 0));
Assertions.assertEquals("version x", curatorClient.getContent(path));
-
client.setData().forPath(path, "version 1".getBytes(StandardCharsets.UTF_8));
ConfigItem configItem = curatorClient.getConfigItem(path);
@@ -273,12 +401,14 @@ protected void update(String path, String data, int version) {
int version1 = ((Stat) configItem.getTicket()).getVersion();
Assertions.assertThrows(
IllegalStateException.class, () -> curatorClient.createOrUpdate(path, "version 2", false, version1));
+ when(mockGetDataBuilder.forPath(any())).then(invocationOnMock -> "version x".getBytes());
Assertions.assertEquals("version x", curatorClient.getContent(path));
runnable.set(null);
configItem = curatorClient.getConfigItem(path);
int version2 = ((Stat) configItem.getTicket()).getVersion();
curatorClient.createOrUpdate(path, "version 2", false, version2);
+ when(mockGetDataBuilder.forPath(any())).then(invocationOnMock -> "version 2".getBytes());
Assertions.assertEquals("version 2", curatorClient.getContent(path));
curatorClient.close();
diff --git a/dubbo-remoting/pom.xml b/dubbo-remoting/pom.xml
index 2546529bda7..3114ba96b28 100644
--- a/dubbo-remoting/pom.xml
+++ b/dubbo-remoting/pom.xml
@@ -40,12 +40,5 @@
false
-
-
- org.apache.dubbo
- dubbo-test-check
- ${project.parent.version}
- test
-
-
+