Browse Source

ZOOKEEPER-1746. AsyncCallback.*Callback don't have any Javadoc (Hongchao Deng via phunt)

git-svn-id: https://svn.apache.org/repos/asf/zookeeper/trunk@1605503 13f79535-47bb-0310-9956-ffa450edef68
Patrick D. Hunt 11 years ago
parent
commit
d53be91194

+ 3 - 0
CHANGES.txt

@@ -936,6 +936,9 @@ IMPROVEMENTS:
   ZOOKEEPER-1928. add configurable throttling to the number of snapshots
   concurrently sent by a leader (Edward Carter via fpj)
 
+  ZOOKEEPER-1746. AsyncCallback.*Callback don't have any Javadoc
+  (Hongchao Deng via phunt)
+
 headers
 
 Release 3.4.0 - 

+ 255 - 2
src/java/main/org/apache/zookeeper/AsyncCallback.java

@@ -22,45 +22,298 @@ import java.util.List;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Stat;
 
+/**
+ * Interface definitions of asynchronous callbacks.
+ * An asynchronous callback is deferred to invoke after a function returns.
+ * Asynchronous calls usually improve system efficiency on IO-related APIs.
+ * <p/>
+ * ZooKeeper provides asynchronous version as equivalent to synchronous APIs.
+ */
 public interface AsyncCallback {
+
+    /**
+     * This callback is used to retrieve the stat of the node.
+     */
     interface StatCallback extends AsyncCallback {
+        /**
+         * Process the result of the asynchronous call.
+         * <p/>
+         * On success, rc is
+         * {@link org.apache.zookeeper.KeeperException.Code#OK}.
+         * <p/>
+         * On failure, rc is set to the corresponding failure code in
+         * {@link org.apache.zookeeper.KeeperException}.
+         * <ul>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}
+         * - The node on given path doesn't exist for some API calls.
+         * </li>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#BADVERSION}
+         * - The given version doesn't match the node's version
+         * for some API calls.
+         * </li>
+         * </ul>
+         *
+         * @param rc   The return code or the result of the call.
+         * @param path The path that we passed to asynchronous calls.
+         * @param ctx  Whatever context object that we passed to
+         *             asynchronous calls.
+         * @param stat {@link org.apache.zookeeper.data.Stat} object of
+         *             the node on given path.
+         */
         public void processResult(int rc, String path, Object ctx, Stat stat);
     }
 
+    /**
+     * This callback is used to retrieve the data and stat of the node.
+     */
     interface DataCallback extends AsyncCallback {
+        /**
+         * Process the result of asynchronous calls.
+         * <p/>
+         * On success, rc is
+         * {@link org.apache.zookeeper.KeeperException.Code#OK}.
+         * <p/>
+         * On failure, rc is set to the corresponding failure code in
+         * {@link org.apache.zookeeper.KeeperException}.
+         * <ul>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}
+         * - The node on given path doesn't exist for some API calls.
+         * </li>
+         * </ul>
+         *
+         * @param rc   The return code or the result of the call.
+         * @param path The path that we passed to asynchronous calls.
+         * @param ctx  Whatever context object that we passed to
+         *             asynchronous calls.
+         * @param data The {@link org.apache.zookeeper.server.DataNode#data}
+         *             of the node.
+         * @param stat {@link org.apache.zookeeper.data.Stat} object of
+         *             the node on given path.
+         */
         public void processResult(int rc, String path, Object ctx, byte data[],
                 Stat stat);
     }
 
+    /**
+     * This callback is used to retrieve the ACL and stat of the node.
+     */
     interface ACLCallback extends AsyncCallback {
+        /**
+         * Process the result of the asynchronous call.
+         * <p/>
+         * On success, rc is
+         * {@link org.apache.zookeeper.KeeperException.Code#OK}.
+         * <p/>
+         * On failure, rc is set to the corresponding failure code in
+         * {@link org.apache.zookeeper.KeeperException}.
+         * <ul>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}
+         * - The node on given path doesn't exist for some API calls.
+         * </li>
+         * </ul>
+         *
+         * @param rc   The return code or the result of the call.
+         * @param path The path that we passed to asynchronous calls.
+         * @param ctx  Whatever context object that we passed to
+         *             asynchronous calls.
+         * @param acl  ACL Id in
+         *             {@link org.apache.zookeeper.ZooDefs.Ids}.
+         * @param stat {@link org.apache.zookeeper.data.Stat} object of
+         *             the node on given path.
+         */
         public void processResult(int rc, String path, Object ctx,
                 List<ACL> acl, Stat stat);
     }
 
+    /**
+     * This callback is used to retrieve the children of the node.
+     */
     interface ChildrenCallback extends AsyncCallback {
+        /**
+         * Process the result of the asynchronous call.
+         * <p/>
+         * On success, rc is
+         * {@link org.apache.zookeeper.KeeperException.Code#OK}.
+         * <p/>
+         * On failure, rc is set to the corresponding failure code in
+         * {@link org.apache.zookeeper.KeeperException}.
+         * <ul>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}
+         * - The node on given path doesn't exist for some API calls.
+         * </li>
+         * </ul>
+         *
+         * @param rc       The return code or the result of the call.
+         * @param path     The path that we passed to asynchronous calls.
+         * @param ctx      Whatever context object that we passed to
+         *                 asynchronous calls.
+         * @param children An unordered array of children of the node on
+         *                 given path.
+         */
         public void processResult(int rc, String path, Object ctx,
                 List<String> children);
     }
 
+    /**
+     * This callback is used to retrieve the children and stat of the node.
+     */
     interface Children2Callback extends AsyncCallback {
+        /**
+         * Process the result of the asynchronous call.
+         * See {@link org.apache.zookeeper.AsyncCallback.ChildrenCallback}.
+         *
+         * @param rc       The return code or the result of the call.
+         * @param path     The path that we passed to asynchronous calls.
+         * @param ctx      Whatever context object that we passed to
+         *                 asynchronous calls.
+         * @param children An unordered array of children of the node on
+         *                 given path.
+         * @param stat     {@link org.apache.zookeeper.data.Stat} object of
+         *                 the node on given path.
+         */
         public void processResult(int rc, String path, Object ctx,
                 List<String> children, Stat stat);
     }
-    
+
+    /**
+     * This callback is used to retrieve the name and stat of the node.
+     */
     interface Create2Callback extends AsyncCallback {
+        /**
+         * Process the result of the asynchronous call.
+         * See {@link org.apache.zookeeper.AsyncCallback.StringCallback}.
+         *
+         * @param rc   The return code or the result of the call.
+         * @param path The path that we passed to asynchronous calls.
+         * @param ctx  Whatever context object that we passed to
+         *             asynchronous calls.
+         * @param name The name of the Znode that was created.
+         *             On success, <i>name</i> and <i>path</i> are usually
+         *             equal, unless a sequential node has been created.
+         * @param stat {@link org.apache.zookeeper.data.Stat} object of
+         *             the node on given path.
+         */
         public void processResult(int rc, String path, Object ctx,
         		String name, Stat stat);
     }
 
+    /**
+     * This callback is used to retrieve the name of the node.
+     */
     interface StringCallback extends AsyncCallback {
+        /**
+         * Process the result of the asynchronous call.
+         * <p/>
+         * On success, rc is
+         * {@link org.apache.zookeeper.KeeperException.Code#OK}.
+         * <p/>
+         * On failure, rc is set to the corresponding failure code in
+         * {@link org.apache.zookeeper.KeeperException}.
+         * <ul>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#NODEEXISTS}
+         * - The node on give path already exists for some API calls.
+         * </li>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}
+         * - The node on given path doesn't exist for some API calls.
+         * </li>
+         * <li>
+         * {@link
+         * org.apache.zookeeper.KeeperException.Code#NOCHILDRENFOREPHEMERALS}
+         * - an ephemeral node cannot have children. There is discussion in
+         * community. It might be changed in the future.
+         * </li>
+         * </ul>
+         *
+         * @param rc   The return code or the result of the call.
+         * @param path The path that we passed to asynchronous calls.
+         * @param ctx  Whatever context object that we passed to
+         *             asynchronous calls.
+         * @param name The name of the Znode that was created.
+         *             On success, <i>name</i> and <i>path</i> are usually
+         *             equal, unless a sequential node has been created.
+         */
         public void processResult(int rc, String path, Object ctx, String name);
     }
-    
+
+    /**
+     * This callback doesn't retrieve anything from the node. It is useful
+     * for some APIs that doesn't want anything sent back, e.g. {@link
+     * org.apache.zookeeper.ZooKeeper#sync(String,
+     * org.apache.zookeeper.AsyncCallback.VoidCallback, Object)}.
+     */
     interface VoidCallback extends AsyncCallback {
+        /**
+         * Process the result of the asynchronous call.
+         * <p/>
+         * On success, rc is
+         * {@link org.apache.zookeeper.KeeperException.Code#OK}.
+         * <p/>
+         * On failure, rc is set to the corresponding failure code in
+         * {@link org.apache.zookeeper.KeeperException}.
+         * <ul>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#NONODE}
+         * - The node on given path doesn't exist for some API calls.
+         * </li>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#BADVERSION}
+         * - The given version doesn't match the node's version
+         * for some API calls.
+         * </li>
+         * <li>
+         * {@link org.apache.zookeeper.KeeperException.Code#NOTEMPTY}
+         * - the node has children and some API calls cannnot succeed,
+         * e.g. {@link
+         * org.apache.zookeeper.ZooKeeper#delete(String, int,
+         * org.apache.zookeeper.AsyncCallback.VoidCallback, Object)}.
+         * </li>
+         * </ul>
+         *
+         * @param rc   The return code or the result of the call.
+         * @param path The path that we passed to asynchronous calls.
+         * @param ctx  Whatever context object that we passed to
+         *             asynchronous calls.
+         */
         public void processResult(int rc, String path, Object ctx);
     }
 
+    /**
+     * This callback is used to process the multiple results from
+     * a single multi call.
+     * See {@link org.apache.zookeeper.ZooKeeper#multi} for more information.
+     */
     interface MultiCallback extends AsyncCallback {
+        /**
+         * Process the result of the asynchronous call.
+         * <p/>
+         * On success, rc is
+         * {@link org.apache.zookeeper.KeeperException.Code#OK}.
+         * All opResults are
+         * non-{@link org.apache.zookeeper.OpResult.ErrorResult},
+         *
+         * <p/>
+         * On failure, rc is a failure code in
+         * {@link org.apache.zookeeper.KeeperException.Code}.
+         * All opResults are
+         * {@link org.apache.zookeeper.OpResult.ErrorResult}.
+         * All operations will be rollback-ed even if operations
+         * before the failing one were successful.
+         *
+         * @param rc   The return code or the result of the call.
+         * @param path The path that we passed to asynchronous calls.
+         * @param ctx  Whatever context object that we passed to
+         *             asynchronous calls.
+         * @param opResults The list of results.
+         *                  One result for each operation,
+         *                  and the order matches that of input.
+         */
         public void processResult(int rc, String path, Object ctx,
                 List<OpResult> opResults);
     }

+ 197 - 2
src/java/test/org/apache/zookeeper/test/AsyncOps.java

@@ -18,7 +18,9 @@
 
 package org.apache.zookeeper.test;
 
+import java.lang.Exception;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -26,6 +28,8 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.Op;
+import org.apache.zookeeper.OpResult;
 import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.AsyncCallback.ACLCallback;
 import org.apache.zookeeper.AsyncCallback.Children2Callback;
@@ -35,6 +39,7 @@ import org.apache.zookeeper.AsyncCallback.DataCallback;
 import org.apache.zookeeper.AsyncCallback.StatCallback;
 import org.apache.zookeeper.AsyncCallback.StringCallback;
 import org.apache.zookeeper.AsyncCallback.VoidCallback;
+import org.apache.zookeeper.AsyncCallback.MultiCallback;
 import org.apache.zookeeper.KeeperException.Code;
 import org.apache.zookeeper.ZooDefs.Ids;
 import org.apache.zookeeper.data.ACL;
@@ -149,11 +154,21 @@ public class AsyncOps {
             zk.create(path, data, acl, flags, this, toString());
             return this;
         }
+
+        public AsyncCB createEphemeral() {
+            zk.create(path, data, acl, CreateMode.EPHEMERAL, this, toString());
+            return this;
+        }
         
         public void verifyCreate() {
             create();
             verify();
         }
+
+        public void verifyCreateEphemeral() {
+            createEphemeral();
+            verify();
+        }
         
         public void verifyCreateFailure_NodeExists() {
             new StringCB(zk).verifyCreate();
@@ -163,7 +178,28 @@ public class AsyncOps {
             zk.create(path, data, acl, flags, this, toString());
             verify();
         }
-        
+
+        public void verifyCreateFailure_NoNode() {
+
+            rc = Code.NONODE;
+            name = null;
+            path = path + "/bar";
+            zk.create(path, data, acl, flags, this, toString());
+
+            verify();
+        }
+
+        public void verifyCreateFailure_NoChildForEphemeral() {
+            new StringCB(zk).verifyCreateEphemeral();
+
+            rc = Code.NOCHILDRENFOREPHEMERALS;
+            name = null;
+            path = path + "/bar";
+            zk.create(path, data, acl, flags, this, toString());
+
+            verify();
+        }
+
         @Override
         public String toString() {
             return super.toString() + name; 
@@ -202,11 +238,24 @@ public class AsyncOps {
             zk.getACL(path, stat, this, toString());
             verify();
         }
+
+        public void verifyGetACLFailure_NoNode(){
+            rc = Code.NONODE;
+            stat = null;
+            acl = null;
+            zk.getACL(path, stat, this, toString());
+
+            verify();
+        }
         
         public String toString(List<ACL> acls) {
+            if (acls == null) {
+                return "";
+            }
+
             StringBuilder result = new StringBuilder();
             for(ACL acl : acls) {
-                result.append(acl.getPerms() + "::");
+                result.append(acl.getPerms()).append("::");
             }
             return result.toString();
         }
@@ -438,10 +487,33 @@ public class AsyncOps {
             new Create2CB(zk).verifyCreate();
             rc = Code.NODEEXISTS;
             name = null;
+            stat = null;
             zk.create(path, data, acl, flags, this, toString());
             verify();
         }
 
+        public void verifyCreateFailure_NoNode() {
+            rc = Code.NONODE;
+            name = null;
+            stat = null;
+            path = path + "/bar";
+            zk.create(path, data, acl, flags, this, toString());
+
+            verify();
+        }
+
+        public void verifyCreateFailure_NoChildForEphemeral() {
+            new StringCB(zk).verifyCreateEphemeral();
+
+            rc = Code.NOCHILDRENFOREPHEMERALS;
+            name = null;
+            stat = null;
+            path = path + "/bar";
+            zk.create(path, data, acl, flags, this, toString());
+
+            verify();
+        }
+
         @Override
         public String toString() {
             return super.toString() + name + ":" +
@@ -537,6 +609,16 @@ public class AsyncOps {
             zk.setACL(path, acl, version, this, toString());
             verify();
         }
+
+        public void verifySetACLFailure_BadVersion() {
+            new StringCB(zk).verifyCreate();
+
+            rc = Code.BADVERSION;
+            stat = null;
+            zk.setACL(path, acl, version + 1, this, toString());
+
+            verify();
+        }
         
         public void setData() {
             zk.setData(path, data, version, this, toString());
@@ -556,6 +638,16 @@ public class AsyncOps {
             zk.setData(path, data, version, this, toString());
             verify();
         }
+
+        public void verifySetDataFailure_BadVersion() {
+            new StringCB(zk).verifyCreate();
+
+            rc = Code.BADVERSION;
+            stat = null;
+            zk.setData(path, data, version + 1, this, toString());
+
+            verify();
+        }
         
         public void verifyExists() {
             new StringCB(zk).verifyCreate();
@@ -612,6 +704,24 @@ public class AsyncOps {
             zk.delete(path, version, this, toString());
             verify();
         }
+
+        public void verifyDeleteFailure_BadVersion() {
+            new StringCB(zk).verifyCreate();
+            rc = Code.BADVERSION;
+            zk.delete(path, version + 1, this, toString());
+            verify();
+        }
+
+        public void verifyDeleteFailure_NotEmpty() {
+            StringCB scb = new StringCB(zk);
+            scb.create();
+            scb.setPath(path + "/bar");
+            scb.create();
+
+            rc = Code.NOTEMPTY;
+            zk.delete(path, version, this, toString());
+            verify();
+        }
         
         public void sync() {
             zk.sync(path, this, toString());
@@ -628,5 +738,90 @@ public class AsyncOps {
         }
     }
 
+    public static class MultiCB implements MultiCallback {
+        ZooKeeper zk;
+        int rc;
+        List<OpResult> opResults;
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        MultiCB(ZooKeeper zk) {
+            this.zk = zk;
+        }
+
+        public void processResult(int rc, String path, Object ctx,
+                                  List<OpResult> opResults) {
+            this.rc = rc;
+            this.opResults = opResults;
+            latch.countDown();
+        }
 
+        void latch_await(){
+            try {
+                latch.await(10000, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                Assert.fail("unexpected interrupt");
+            }
+            Assert.assertSame(0L, latch.getCount());
+        }
+
+        public void verifyMulti() {
+            List<Op> ops = Arrays.asList(
+                    Op.create("/multi", new byte[0],
+                            Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),
+                    Op.delete("/multi", -1));
+            zk.multi(ops, this, null);
+            latch_await();
+
+            Assert.assertEquals(this.rc, KeeperException.Code.OK.intValue());
+            Assert.assertTrue(this.opResults.get(0) instanceof OpResult.CreateResult);
+            Assert.assertTrue(this.opResults.get(1) instanceof OpResult.DeleteResult);
+        }
+
+        public void verifyMultiFailure_AllErrorResult() {
+            List<Op> ops = Arrays.asList(
+                    Op.create("/multi", new byte[0],
+                            Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),
+                    Op.delete("/nonexist1", -1),
+                    Op.setData("/multi", "test".getBytes(), -1));
+            zk.multi(ops, this, null);
+            latch_await();
+
+            Assert.assertTrue(this.opResults.get(0) instanceof OpResult.ErrorResult);
+            Assert.assertTrue(this.opResults.get(1) instanceof OpResult.ErrorResult);
+            Assert.assertTrue(this.opResults.get(2) instanceof OpResult.ErrorResult);
+        }
+
+        public void verifyMultiFailure_NoSideEffect() throws KeeperException, InterruptedException {
+            List<Op> ops = Arrays.asList(
+                    Op.create("/multi", new byte[0],
+                            Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),
+                    Op.delete("/nonexist1", -1));
+            zk.multi(ops, this, null);
+            latch_await();
+
+            Assert.assertTrue(this.opResults.get(0) instanceof OpResult.ErrorResult);
+            Assert.assertNull(zk.exists("/multi", false));
+        }
+
+        public void verifyMultiSequential_NoSideEffect() throws Exception{
+            StringCB scb = new StringCB(zk);
+            scb.verifyCreate();
+            String path = scb.path + "-";
+            String seqPath = path + "0000000002";
+
+            zk.create(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
+            Assert.assertNotNull(zk.exists(path + "0000000001", false));
+
+            List<Op> ops = Arrays.asList(
+                    Op.create(path , new byte[0],
+                            Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL),
+                    Op.delete("/nonexist", -1));
+            zk.multi(ops, this, null);
+            latch_await();
+
+            Assert.assertNull(zk.exists(seqPath, false));
+            zk.create(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
+            Assert.assertNotNull(zk.exists(seqPath, false));
+        }
+    }
 }

+ 74 - 1
src/java/test/org/apache/zookeeper/test/AsyncOpsTest.java

@@ -18,6 +18,7 @@
 
 package org.apache.zookeeper.test;
 
+import java.lang.Exception;
 import java.util.concurrent.CountDownLatch;
 
 import org.slf4j.Logger;
@@ -31,6 +32,7 @@ import org.apache.zookeeper.test.AsyncOps.DataCB;
 import org.apache.zookeeper.test.AsyncOps.StatCB;
 import org.apache.zookeeper.test.AsyncOps.StringCB;
 import org.apache.zookeeper.test.AsyncOps.VoidCB;
+import org.apache.zookeeper.test.AsyncOps.MultiCB;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -96,6 +98,32 @@ public class AsyncOpsTest extends ClientBase {
         new StringCB(zk).verifyCreateFailure_NodeExists();
     }
 
+    @Test
+    public void testAsyncCreateFailure_NoNode() {
+        new StringCB(zk).verifyCreateFailure_NoNode();
+    }
+
+    @Test
+    public void testAsyncCreateFailure_NoChildForEphemeral() {
+        new StringCB(zk).verifyCreateFailure_NoChildForEphemeral();
+    }
+
+    @Test
+    public void testAsyncCreate2Failure_NodeExists() {
+        new Create2CB(zk).verifyCreateFailure_NodeExists();
+    }
+
+    @Test
+    public void testAsyncCreate2Failure_NoNode() {
+        new Create2CB(zk).verifyCreateFailure_NoNode();
+    }
+
+
+    @Test
+    public void testAsyncCreate2Failure_NoChildForEphemeral() {
+        new Create2CB(zk).verifyCreateFailure_NoChildForEphemeral();
+    }
+
     @Test
     public void testAsyncDelete() {
         new VoidCB(zk).verifyDelete();
@@ -106,6 +134,16 @@ public class AsyncOpsTest extends ClientBase {
         new VoidCB(zk).verifyDeleteFailure_NoNode();
     }
 
+    @Test
+    public void testAsyncDeleteFailure_BadVersion() {
+        new VoidCB(zk).verifyDeleteFailure_BadVersion();
+    }
+
+    @Test
+    public void testAsyncDeleteFailure_NotEmpty() {
+        new VoidCB(zk).verifyDeleteFailure_NotEmpty();
+    }
+
     @Test
     public void testAsyncSync() {
         new VoidCB(zk).verifySync();
@@ -121,6 +159,11 @@ public class AsyncOpsTest extends ClientBase {
         new StatCB(zk).verifySetACLFailure_NoNode();
     }
 
+    @Test
+    public void testAsyncSetACLFailure_BadVersion() {
+        new StatCB(zk).verifySetACLFailure_BadVersion();
+    }
+
     @Test
     public void testAsyncSetData() {
         new StatCB(zk).verifySetData();
@@ -131,6 +174,11 @@ public class AsyncOpsTest extends ClientBase {
         new StatCB(zk).verifySetDataFailure_NoNode();
     }
 
+    @Test
+    public void testAsyncSetDataFailure_BadVersion() {
+        new StatCB(zk).verifySetDataFailure_BadVersion();
+    }
+
     @Test
     public void testAsyncExists() {
         new StatCB(zk).verifyExists();
@@ -146,6 +194,11 @@ public class AsyncOpsTest extends ClientBase {
         new ACLCB(zk).verifyGetACL();
     }
 
+    @Test
+    public void testAsyncGetACLFailure_NoNode() {
+        new ACLCB(zk).verifyGetACLFailure_NoNode();
+    }
+
     @Test
     public void testAsyncGetChildrenEmpty() {
         new ChildrenCB(zk).verifyGetChildrenEmpty();
@@ -168,7 +221,7 @@ public class AsyncOpsTest extends ClientBase {
 
     @Test
     public void testAsyncGetChildren2Empty() {
-        new ChildrenCB(zk).verifyGetChildrenEmpty();
+        new Children2CB(zk).verifyGetChildrenEmpty();
     }
 
     @Test
@@ -195,4 +248,24 @@ public class AsyncOpsTest extends ClientBase {
     public void testAsyncGetDataFailure_NoNode() {
         new DataCB(zk).verifyGetDataFailure_NoNode();
     }
+
+    @Test
+    public void testAsyncMulti() {
+        new MultiCB(zk).verifyMulti();
+    }
+
+    @Test
+    public void testAsyncMultiFailure_AllErrorResult() {
+        new MultiCB(zk).verifyMultiFailure_AllErrorResult();
+    }
+
+    @Test
+    public void testAsyncMultiFailure_NoSideEffect() throws Exception{
+        new MultiCB(zk).verifyMultiFailure_NoSideEffect();
+    }
+
+    @Test
+    public void testAsyncMultiSequential_NoSideEffect() throws Exception{
+        new MultiCB(zk).verifyMultiSequential_NoSideEffect();
+    }
 }