This is an automated email from the ASF dual-hosted git repository.

xyuanlu pushed a commit to branch metaclient
in repository https://gitbox.apache.org/repos/asf/helix.git

commit 7740fdec7ad0347a8b28d491435481bc5c2a4657
Author: Grant Palau Spencer <[email protected]>
AuthorDate: Thu Jun 1 15:17:59 2023 -0700

    tests for get, create, set, update, and data change listeners
---
 .../metaclient/impl/zk/TestStressZkClient.java     | 406 ++++++++++++++++++++-
 1 file changed, 388 insertions(+), 18 deletions(-)

diff --git 
a/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestStressZkClient.java
 
b/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestStressZkClient.java
index 9306891d6..3e7140f64 100644
--- 
a/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestStressZkClient.java
+++ 
b/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestStressZkClient.java
@@ -1,24 +1,394 @@
 package org.apache.helix.metaclient.impl.zk;
 
 /*
-    * 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.
-    */
+ * 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.
+ */
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.helix.metaclient.api.DataChangeListener;
+import org.apache.helix.metaclient.api.DataUpdater;
+import org.apache.helix.metaclient.api.MetaClientInterface;
+import org.apache.helix.metaclient.exception.MetaClientException;
+import org.apache.helix.metaclient.impl.zk.factory.ZkMetaClientConfig;
+import org.apache.helix.zookeeper.exception.ZkClientException;
+import org.testng.Assert;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+import static org.apache.helix.metaclient.api.MetaClientInterface.EntryMode.*;
 
 public class TestStressZkClient extends ZkMetaClientTestBase {
-  // TODO: add tests
+
+  private static final long TEST_ITERATION_COUNT = 1000;
+  private static final Logger LOG = 
LoggerFactory.getLogger(TestStressZkClient.class);
+
+  private void cleanUpTestNodes(String parentZnodeKey) {
+    try (ZkMetaClient<String> zkMetaClient = createZkMetaClient()) {
+      zkMetaClient.connect();
+      int retryCount = 0;
+      while (zkMetaClient.countDirectChildren(parentZnodeKey) > 0) {
+        try {
+          retryCount++;
+          zkMetaClient.recursiveDelete(parentZnodeKey);
+        } catch (ZkClientException e) {
+          if (retryCount >= 3) {
+            throw new ZkClientException("Failed to clean up test nodes after 3 
tries", e);
+          }
+        }
+      }
+      Assert.assertEquals(zkMetaClient.countDirectChildren(parentZnodeKey), 0);
+    }
+  }
+
+  @Test
+  public void testCreate() {
+    String zkParentKey = "/stressZk_testCreate";
+
+    try (ZkMetaClient<String> zkMetaClient = createZkMetaClient()) {
+      zkMetaClient.connect();
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.create(zkParentKey + "/" + i, i);
+      }
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        Assert.assertEquals(String.valueOf(zkMetaClient.get(zkParentKey + "/" 
+ i)), String.valueOf(i));
+      }
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        try {
+          zkMetaClient.create("/a/b/c", "invalid_path");
+          Assert.fail("Should have failed with incorrect path.");
+        } catch (MetaClientException ignoredException) {
+        }
+      }
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        try {
+          zkMetaClient.create("a/b/c", "invalid_path");
+          Assert.fail("Should have failed with invalid path - no leading /.");
+        } catch (Exception ignoredException) {
+        }
+      }
+      cleanUpTestNodes(zkParentKey);
+    }
+  }
+
+  @Test
+  public void testCreateContainer() {
+    final String zkParentKey = "/stressZk_testCreateContainer";
+    try (ZkMetaClient<String> zkMetaClient = createZkMetaClient()) {
+      zkMetaClient.connect();
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.create(zkParentKey + "/" + i, i, CONTAINER);
+      }
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        Assert.assertEquals(String.valueOf(zkMetaClient.get(zkParentKey + "/" 
+ i)), String.valueOf(i));
+      }
+
+      cleanUpTestNodes(zkParentKey);
+    }
+  }
+
+  @Test
+  public void testGet() {
+    final String zkParentKey = "/stressZk_testGet";
+    try (ZkMetaClient<String> zkMetaClient = createZkMetaClient()) {
+      zkMetaClient.connect();
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.create(zkParentKey + "/" + i, i);
+      }
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        Assert.assertEquals(zkMetaClient.get(zkParentKey + "/" + i), i);
+      }
+
+      // Test with non-existent node path
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        Assert.assertNull(zkMetaClient.get("/a/b/c"));
+      }
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        try {
+          zkMetaClient.get("a/b/c");
+          Assert.fail("Should have failed due to invalid path - no leading 
/.");
+        } catch (Exception ignoredException) {
+        }
+      }
+    }
+    cleanUpTestNodes(zkParentKey);
+  }
+
+  @Test
+  public void testSetSingleNode() {
+    final String zkParentKey = "/stressZk_testSetSingleNode";
+    try (ZkMetaClient<String> zkMetaClient = createZkMetaClient()) {
+      zkMetaClient.connect();
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      // Set with no expected version
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.set(zkParentKey, String.valueOf(i), -1);
+        MetaClientInterface.Stat entryStat = zkMetaClient.exists(zkParentKey);
+
+        Assert.assertEquals(zkMetaClient.get(zkParentKey), String.valueOf(i));
+        Assert.assertEquals(entryStat.getVersion(), i + 1);
+        Assert.assertEquals(entryStat.getEntryType().name(), 
PERSISTENT.name());
+      }
+
+      zkMetaClient.delete(zkParentKey);
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      // Set with expected version
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.set(zkParentKey, String.valueOf(i), i);
+        MetaClientInterface.Stat entryStat = zkMetaClient.exists(zkParentKey);
+
+        Assert.assertEquals(zkMetaClient.get(zkParentKey), String.valueOf(i));
+        Assert.assertEquals(entryStat.getVersion(), i + 1);
+      }
+
+      zkMetaClient.delete(zkParentKey);
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      // Set with bad expected version - should fail
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        try {
+          zkMetaClient.set(zkParentKey, "test-should-fail", 12345);
+          Assert.fail("Should have failed due to bad expected version in set 
function.");
+        } catch (MetaClientException ex) {
+          Assert.assertEquals(ex.getClass().getName(),
+              
"org.apache.helix.metaclient.exception.MetaClientBadVersionException");
+        }
+      }
+
+      zkMetaClient.delete(zkParentKey);
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      // Set with path to non-existent node - should fail
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        try {
+          zkMetaClient.set("/a/b/c", "test-should-fail", -1);
+          Assert.fail("Should have failed due to path to non-existent node");
+        } catch (Exception ignoredException) {
+        }
+      }
+
+      zkMetaClient.delete(zkParentKey);
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      // Set with invalid path - should fail
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        try {
+          zkMetaClient.set("a/b/c", "test-should-fail", -1);
+          Assert.fail("Should have failed due to invalid path - no leading 
/.");
+        } catch (Exception ignoredException) {
+        }
+      }
+    }
+
+    cleanUpTestNodes(zkParentKey);
+  }
+
+  @Test
+  public void testSetMultiNode() {
+    final String zkParentKey = "/stressZk_testSetMultiNode";
+    try (ZkMetaClient<String> zkMetaClient = createZkMetaClient()) {
+      zkMetaClient.connect();
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.create(zkParentKey + "/" + i, i);
+      }
+
+      // Set with no expected version
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.set(zkParentKey + "/" + i, "-" + i, -1);
+      }
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        String childKey = zkParentKey + "/" + i;
+        MetaClientInterface.Stat entryStat = zkMetaClient.exists(childKey);
+
+        Assert.assertEquals(zkMetaClient.get(childKey), "-" + i);
+        Assert.assertEquals(entryStat.getVersion(), 1);
+        Assert.assertEquals(entryStat.getEntryType().name(), 
PERSISTENT.name());
+      }
+
+      // Set with expected version
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        String childKey = zkParentKey + "/" + i;
+        zkMetaClient.set(childKey, String.valueOf(i), 1);
+        MetaClientInterface.Stat entryStat = zkMetaClient.exists(childKey);
+
+        Assert.assertEquals(zkMetaClient.get(childKey), String.valueOf(i));
+        Assert.assertEquals(entryStat.getVersion(), 2);
+      }
+    }
+    cleanUpTestNodes(zkParentKey);
+  }
+
+  @Test
+  public void testUpdateSingleNode() {
+    final String zkParentKey = "/stressZk_testUpdateSingleNode";
+    ZkMetaClientConfig config =
+        new 
ZkMetaClientConfig.ZkMetaClientConfigBuilder().setConnectionAddress(ZK_ADDR).build();
+    try (ZkMetaClient<Integer> zkMetaClient = new ZkMetaClient<>(config)) {
+      zkMetaClient.connect();
+      zkMetaClient.create(zkParentKey, 0);
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        MetaClientInterface.Stat entryStat = zkMetaClient.exists(zkParentKey);
+        Assert.assertEquals(entryStat.getVersion(), i);
+
+        Integer newData = zkMetaClient.update(zkParentKey, new 
DataUpdater<Integer>() {
+          @Override
+          public Integer update(Integer currentData) {
+            return currentData + 1;
+          }
+        });
+        Assert.assertEquals((int) newData, i + 1);
+      }
+
+      zkMetaClient.delete(zkParentKey);
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      // Set with path to non-existent node - should fail
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        try {
+          zkMetaClient.update("/a/b/c", new DataUpdater<Integer>() {
+            @Override
+            public Integer update(Integer currentData) {
+              return currentData + 1;
+            }
+          });
+
+          Assert.fail("Should have failed due to path to non-existent node");
+        } catch (Exception ignoredException) {
+        }
+      }
+
+      zkMetaClient.delete(zkParentKey);
+      zkMetaClient.create(zkParentKey, "parent_node");
+
+      // Set with invalid path - should fail
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        try {
+          zkMetaClient.update("/a/b/c", new DataUpdater<Integer>() {
+            @Override
+            public Integer update(Integer currentData) {
+              return currentData + 1;
+            }
+          });
+          Assert.fail("Should have failed due to invalid path - no leading 
/.");
+        } catch (Exception ignoredException) {
+        }
+      }
+    }
+    cleanUpTestNodes(zkParentKey);
+  }
+
+  @Test
+  public void testUpdateMultiNode() {
+    final String zkParentKey = "/stressZk_testUpdateSingleNode";
+    ZkMetaClientConfig config =
+        new 
ZkMetaClientConfig.ZkMetaClientConfigBuilder().setConnectionAddress(ZK_ADDR).build();
+    try (ZkMetaClient<Integer> zkMetaClient = new ZkMetaClient<>(config)) {
+      zkMetaClient.connect();
+      zkMetaClient.create(zkParentKey, "test_parent");
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.create(zkParentKey + "/" + i, 0);
+      }
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        String childKey = zkParentKey + "/" + i;
+        MetaClientInterface.Stat entryStat = zkMetaClient.exists(childKey);
+        Assert.assertEquals(entryStat.getVersion(), 0);
+
+        Integer newData = zkMetaClient.update(childKey, new 
DataUpdater<Integer>() {
+          @Override
+          public Integer update(Integer currentData) {
+            return currentData + 1;
+          }
+        });
+
+        Assert.assertEquals((int) newData, 1);
+        entryStat = zkMetaClient.exists(childKey);
+        Assert.assertEquals(entryStat.getVersion(), 1);
+      }
+    }
+    cleanUpTestNodes(zkParentKey);
+  }
+
+  @Test
+  public void testMultipleDataChangeListeners() throws Exception {
+    final String zkParentKey = "/stressZk_testMultipleDataChangeListeners";
+    final int listenerCount = 10;
+    final String testData = "test-data";
+    final AtomicBoolean dataExpected = new AtomicBoolean(true);
+
+    try (ZkMetaClient<String> zkMetaClient = createZkMetaClient()) {
+      zkMetaClient.connect();
+      zkMetaClient.create(zkParentKey, "parent_node");
+      Map<String, Set<DataChangeListener>> listeners = new HashMap<>();
+      CountDownLatch countDownLatch = new CountDownLatch((int) 
TEST_ITERATION_COUNT * listenerCount);
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.create(zkParentKey + "/" + i, i);
+      }
+
+      // create paths
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        String childKey = zkParentKey + "/" + i;
+        listeners.put(childKey, new HashSet<>());
+        for (int j = 0; j < listenerCount; j++) {
+          DataChangeListener listener = new DataChangeListener() {
+            @Override
+            public void handleDataChange(String key, Object data, ChangeType 
changeType) {
+              countDownLatch.countDown();
+              dataExpected.set(dataExpected.get() && testData.equals(data));
+            }
+          };
+          listeners.get(childKey).add(listener);
+          zkMetaClient.subscribeDataChange(childKey, listener, false);
+        }
+      }
+
+      for (int i = 0; i < TEST_ITERATION_COUNT; i++) {
+        zkMetaClient.set(zkParentKey + "/" + i, testData, -1);
+      }
+
+      Assert.assertTrue(countDownLatch.await(5000, TimeUnit.MILLISECONDS));
+      Assert.assertTrue(dataExpected.get());
+    }
+    cleanUpTestNodes(zkParentKey);
+  }
 }
\ No newline at end of file

Reply via email to