1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 package org.apache.zookeeper.test;
20 
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertNull;
24 import static org.junit.jupiter.api.Assertions.assertSame;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
26 import static org.junit.jupiter.api.Assertions.fail;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.TimeUnit;
33 import org.apache.zookeeper.AsyncCallback.ACLCallback;
34 import org.apache.zookeeper.AsyncCallback.Children2Callback;
35 import org.apache.zookeeper.AsyncCallback.ChildrenCallback;
36 import org.apache.zookeeper.AsyncCallback.Create2Callback;
37 import org.apache.zookeeper.AsyncCallback.DataCallback;
38 import org.apache.zookeeper.AsyncCallback.MultiCallback;
39 import org.apache.zookeeper.AsyncCallback.StatCallback;
40 import org.apache.zookeeper.AsyncCallback.StringCallback;
41 import org.apache.zookeeper.AsyncCallback.VoidCallback;
42 import org.apache.zookeeper.CreateMode;
43 import org.apache.zookeeper.KeeperException;
44 import org.apache.zookeeper.KeeperException.Code;
45 import org.apache.zookeeper.Op;
46 import org.apache.zookeeper.OpResult;
47 import org.apache.zookeeper.ZooDefs.Ids;
48 import org.apache.zookeeper.ZooKeeper;
49 import org.apache.zookeeper.data.ACL;
50 import org.apache.zookeeper.data.Stat;
51 
52 public class AsyncOps {
53 
54     /**
55      * This is the base class for all of the async callback classes. It will
56      * verify the expected value against the actual value.
57      *
58      * Basic operation is that the subclasses will generate an "expected" value
59      * which is defined by the "toString" method of the subclass. This is
60      * passed through to the verify clause by specifying it as the ctx object
61      * of each async call (processResult methods get the ctx as part of
62      * the callback). Additionally the callback will also overwrite any
63      * instance fields with matching parameter arguments to the processResult
64      * method. The cb instance can then compare the expected to the
65      * actual value by again calling toString and comparing the two.
66      *
67      * The format of each expected value differs (is defined) by subclass.
68      * Generally the expected value starts with the result code (rc) and path
69      * of the node being operated on, followed by the fields specific to
70      * each operation type (cb subclass). For example ChildrenCB specifies
71      * a list of the expected children suffixed onto the rc and path. See
72      * the toString() method of each subclass for details of it's format.
73      */
74     public abstract static class AsyncCB {
75 
76         protected final ZooKeeper zk;
77         protected long defaultTimeoutMillis = 30000;
78 
79         /** the latch is used to await the results from the server */
80         CountDownLatch latch;
81 
82         Code rc = Code.OK;
83         String path = "/foo";
84         String expected;
85 
AsyncCB(ZooKeeper zk, CountDownLatch latch)86         public AsyncCB(ZooKeeper zk, CountDownLatch latch) {
87             this.zk = zk;
88             this.latch = latch;
89         }
90 
setRC(Code rc)91         public void setRC(Code rc) {
92             this.rc = rc;
93         }
94 
setPath(String path)95         public void setPath(String path) {
96             this.path = path;
97         }
98 
processResult(Code rc, String path, Object ctx)99         public void processResult(Code rc, String path, Object ctx) {
100             this.rc = rc;
101             this.path = path;
102             this.expected = (String) ctx;
103             latch.countDown();
104         }
105 
106         /** String format is rc:path:<suffix> where <suffix> is defined by each
107          * subclass individually. */
108         @Override
toString()109         public String toString() {
110             return rc + ":" + path + ":";
111         }
112 
verify()113         protected void verify() {
114             try {
115                 latch.await(defaultTimeoutMillis, TimeUnit.MILLISECONDS);
116             } catch (InterruptedException e) {
117                 fail("unexpected interrupt");
118             }
119             // on the lookout for timeout
120             assertSame(0L, latch.getCount());
121 
122             String actual = toString();
123 
124             assertEquals(expected, actual);
125         }
126 
127     }
128 
129     public static class StringCB extends AsyncCB implements StringCallback {
130 
131         byte[] data = new byte[10];
132         List<ACL> acl = Ids.CREATOR_ALL_ACL;
133         CreateMode flags = CreateMode.PERSISTENT;
134         String name = path;
135 
StringCB(ZooKeeper zk)136         StringCB(ZooKeeper zk) {
137             this(zk, new CountDownLatch(1));
138         }
139 
StringCB(ZooKeeper zk, CountDownLatch latch)140         StringCB(ZooKeeper zk, CountDownLatch latch) {
141             super(zk, latch);
142         }
143 
setPath(String path)144         public void setPath(String path) {
145             super.setPath(path);
146             this.name = path;
147         }
148 
nodeName()149         public String nodeName() {
150             return path.substring(path.lastIndexOf('/') + 1);
151         }
152 
processResult(int rc, String path, Object ctx, String name)153         public void processResult(int rc, String path, Object ctx, String name) {
154             this.name = name;
155             super.processResult(Code.get(rc), path, ctx);
156         }
157 
create()158         public AsyncCB create() {
159             zk.create(path, data, acl, flags, this, toString());
160             return this;
161         }
162 
createEphemeral()163         public AsyncCB createEphemeral() {
164             zk.create(path, data, acl, CreateMode.EPHEMERAL, this, toString());
165             return this;
166         }
167 
verifyCreate()168         public void verifyCreate() {
169             create();
170             verify();
171         }
172 
verifyCreateEphemeral()173         public void verifyCreateEphemeral() {
174             createEphemeral();
175             verify();
176         }
177 
verifyCreateFailure_NodeExists()178         public void verifyCreateFailure_NodeExists() {
179             new StringCB(zk).verifyCreate();
180 
181             rc = Code.NODEEXISTS;
182             name = null;
183             zk.create(path, data, acl, flags, this, toString());
184             verify();
185         }
186 
verifyCreateFailure_NoNode()187         public void verifyCreateFailure_NoNode() {
188 
189             rc = Code.NONODE;
190             name = null;
191             path = path + "/bar";
192             zk.create(path, data, acl, flags, this, toString());
193 
194             verify();
195         }
196 
verifyCreateFailure_NoChildForEphemeral()197         public void verifyCreateFailure_NoChildForEphemeral() {
198             new StringCB(zk).verifyCreateEphemeral();
199 
200             rc = Code.NOCHILDRENFOREPHEMERALS;
201             name = null;
202             path = path + "/bar";
203             zk.create(path, data, acl, flags, this, toString());
204 
205             verify();
206         }
207 
208         @Override
toString()209         public String toString() {
210             return super.toString() + name;
211         }
212 
213     }
214 
215     public static class ACLCB extends AsyncCB implements ACLCallback {
216 
217         List<ACL> acl = Ids.CREATOR_ALL_ACL;
218         int version = 0;
219         Stat stat = new Stat();
220         byte[] data = "testing".getBytes();
221 
ACLCB(ZooKeeper zk)222         ACLCB(ZooKeeper zk) {
223             this(zk, new CountDownLatch(1));
224         }
225 
ACLCB(ZooKeeper zk, CountDownLatch latch)226         ACLCB(ZooKeeper zk, CountDownLatch latch) {
227             super(zk, latch);
228             stat.setAversion(0);
229             stat.setCversion(0);
230             stat.setEphemeralOwner(0);
231             stat.setVersion(0);
232         }
233 
processResult(int rc, String path, Object ctx, List<ACL> acl, Stat stat)234         public void processResult(int rc, String path, Object ctx, List<ACL> acl, Stat stat) {
235             this.acl = acl;
236             this.stat = stat;
237             super.processResult(Code.get(rc), path, ctx);
238         }
239 
verifyGetACL()240         public void verifyGetACL() {
241             new StringCB(zk).verifyCreate();
242 
243             zk.getACL(path, stat, this, toString());
244             verify();
245         }
246 
verifyGetACLFailure_NoNode()247         public void verifyGetACLFailure_NoNode() {
248             rc = Code.NONODE;
249             stat = null;
250             acl = null;
251             zk.getACL(path, stat, this, toString());
252 
253             verify();
254         }
255 
toString(List<ACL> acls)256         public String toString(List<ACL> acls) {
257             if (acls == null) {
258                 return "";
259             }
260 
261             StringBuilder result = new StringBuilder();
262             for (ACL acl : acls) {
263                 result.append(acl.getPerms()).append("::");
264             }
265             return result.toString();
266         }
267 
268         @Override
toString()269         public String toString() {
270             return super.toString()
271                    + toString(acl) + ":"
272                    + ":" + version
273                    + ":" + new String(data)
274                    + ":" + (stat == null ? "null" : stat.getAversion()
275                                                     + ":" + stat.getCversion()
276                                                     + ":" + stat.getEphemeralOwner()
277                                                     + ":" + stat.getVersion());
278         }
279 
280     }
281 
282     public static class ChildrenCB extends AsyncCB implements ChildrenCallback {
283 
284         List<String> children = new ArrayList<String>();
285 
ChildrenCB(ZooKeeper zk)286         ChildrenCB(ZooKeeper zk) {
287             this(zk, new CountDownLatch(1));
288         }
289 
ChildrenCB(ZooKeeper zk, CountDownLatch latch)290         ChildrenCB(ZooKeeper zk, CountDownLatch latch) {
291             super(zk, latch);
292         }
293 
processResult(int rc, String path, Object ctx, List<String> children)294         public void processResult(int rc, String path, Object ctx, List<String> children) {
295             this.children = (children == null ? new ArrayList<String>() : children);
296             Collections.sort(this.children);
297             super.processResult(Code.get(rc), path, ctx);
298         }
299 
createNode()300         public StringCB createNode() {
301             StringCB parent = new StringCB(zk);
302             parent.verifyCreate();
303 
304             return parent;
305         }
306 
createNode(StringCB parent)307         public StringCB createNode(StringCB parent) {
308             String childName = "bar";
309 
310             return createNode(parent, childName);
311         }
312 
createNode(StringCB parent, String childName)313         public StringCB createNode(StringCB parent, String childName) {
314             StringCB child = new StringCB(zk);
315             child.setPath(parent.path + "/" + childName);
316             child.verifyCreate();
317 
318             return child;
319         }
320 
verifyGetChildrenEmpty()321         public void verifyGetChildrenEmpty() {
322             StringCB parent = createNode();
323             path = parent.path;
324             verify();
325         }
326 
verifyGetChildrenSingle()327         public void verifyGetChildrenSingle() {
328             StringCB parent = createNode();
329             StringCB child = createNode(parent);
330 
331             path = parent.path;
332             children.add(child.nodeName());
333 
334             verify();
335         }
336 
verifyGetChildrenTwo()337         public void verifyGetChildrenTwo() {
338             StringCB parent = createNode();
339             StringCB child1 = createNode(parent, "child1");
340             StringCB child2 = createNode(parent, "child2");
341 
342             path = parent.path;
343             children.add(child1.nodeName());
344             children.add(child2.nodeName());
345 
346             verify();
347         }
348 
verifyGetChildrenFailure_NoNode()349         public void verifyGetChildrenFailure_NoNode() {
350             rc = KeeperException.Code.NONODE;
351             verify();
352         }
353 
354         @Override
verify()355         public void verify() {
356             zk.getChildren(path, false, this, toString());
357             super.verify();
358         }
359 
360         @Override
toString()361         public String toString() {
362             return super.toString() + children.toString();
363         }
364 
365     }
366 
367     public static class Children2CB extends AsyncCB implements Children2Callback {
368 
369         List<String> children = new ArrayList<String>();
370 
Children2CB(ZooKeeper zk)371         Children2CB(ZooKeeper zk) {
372             this(zk, new CountDownLatch(1));
373         }
374 
Children2CB(ZooKeeper zk, CountDownLatch latch)375         Children2CB(ZooKeeper zk, CountDownLatch latch) {
376             super(zk, latch);
377         }
378 
processResult(int rc, String path, Object ctx, List<String> children, Stat stat)379         public void processResult(int rc, String path, Object ctx, List<String> children, Stat stat) {
380             this.children = (children == null ? new ArrayList<String>() : children);
381             Collections.sort(this.children);
382             super.processResult(Code.get(rc), path, ctx);
383         }
384 
createNode()385         public StringCB createNode() {
386             StringCB parent = new StringCB(zk);
387             parent.verifyCreate();
388 
389             return parent;
390         }
391 
createNode(StringCB parent)392         public StringCB createNode(StringCB parent) {
393             String childName = "bar";
394 
395             return createNode(parent, childName);
396         }
397 
createNode(StringCB parent, String childName)398         public StringCB createNode(StringCB parent, String childName) {
399             StringCB child = new StringCB(zk);
400             child.setPath(parent.path + "/" + childName);
401             child.verifyCreate();
402 
403             return child;
404         }
405 
verifyGetChildrenEmpty()406         public void verifyGetChildrenEmpty() {
407             StringCB parent = createNode();
408             path = parent.path;
409             verify();
410         }
411 
verifyGetChildrenSingle()412         public void verifyGetChildrenSingle() {
413             StringCB parent = createNode();
414             StringCB child = createNode(parent);
415 
416             path = parent.path;
417             children.add(child.nodeName());
418 
419             verify();
420         }
421 
verifyGetChildrenTwo()422         public void verifyGetChildrenTwo() {
423             StringCB parent = createNode();
424             StringCB child1 = createNode(parent, "child1");
425             StringCB child2 = createNode(parent, "child2");
426 
427             path = parent.path;
428             children.add(child1.nodeName());
429             children.add(child2.nodeName());
430 
431             verify();
432         }
433 
verifyGetChildrenFailure_NoNode()434         public void verifyGetChildrenFailure_NoNode() {
435             rc = KeeperException.Code.NONODE;
436             verify();
437         }
438 
439         @Override
verify()440         public void verify() {
441             zk.getChildren(path, false, this, toString());
442             super.verify();
443         }
444 
445         @Override
toString()446         public String toString() {
447             return super.toString() + children.toString();
448         }
449 
450     }
451 
452     public static class Create2CB extends AsyncCB implements Create2Callback {
453 
454         byte[] data = new byte[10];
455         List<ACL> acl = Ids.CREATOR_ALL_ACL;
456         CreateMode flags = CreateMode.PERSISTENT;
457         String name = path;
458         Stat stat = new Stat();
459 
Create2CB(ZooKeeper zk)460         Create2CB(ZooKeeper zk) {
461             this(zk, new CountDownLatch(1));
462         }
463 
Create2CB(ZooKeeper zk, CountDownLatch latch)464         Create2CB(ZooKeeper zk, CountDownLatch latch) {
465             super(zk, latch);
466         }
467 
setPath(String path)468         public void setPath(String path) {
469             super.setPath(path);
470             this.name = path;
471         }
472 
nodeName()473         public String nodeName() {
474             return path.substring(path.lastIndexOf('/') + 1);
475         }
476 
processResult(int rc, String path, Object ctx, String name, Stat stat)477         public void processResult(int rc, String path, Object ctx, String name, Stat stat) {
478             this.name = name;
479             this.stat = stat;
480             super.processResult(Code.get(rc), path, ctx);
481         }
482 
create()483         public AsyncCB create() {
484             zk.create(path, data, acl, flags, this, toString());
485             return this;
486         }
487 
verifyCreate()488         public void verifyCreate() {
489             create();
490             verify();
491         }
492 
verifyCreateFailure_NodeExists()493         public void verifyCreateFailure_NodeExists() {
494             new Create2CB(zk).verifyCreate();
495             rc = Code.NODEEXISTS;
496             name = null;
497             stat = null;
498             zk.create(path, data, acl, flags, this, toString());
499             verify();
500         }
501 
verifyCreateFailure_NoNode()502         public void verifyCreateFailure_NoNode() {
503             rc = Code.NONODE;
504             name = null;
505             stat = null;
506             path = path + "/bar";
507             zk.create(path, data, acl, flags, this, toString());
508 
509             verify();
510         }
511 
verifyCreateFailure_NoChildForEphemeral()512         public void verifyCreateFailure_NoChildForEphemeral() {
513             new StringCB(zk).verifyCreateEphemeral();
514 
515             rc = Code.NOCHILDRENFOREPHEMERALS;
516             name = null;
517             stat = null;
518             path = path + "/bar";
519             zk.create(path, data, acl, flags, this, toString());
520 
521             verify();
522         }
523 
524         @Override
toString()525         public String toString() {
526             return super.toString()
527                     + name + ":"
528                     + (stat == null
529                         ? "null"
530                         : stat.getAversion()
531                             + ":" + stat.getCversion()
532                             + ":" + stat.getEphemeralOwner()
533                             + ":" + stat.getVersion());
534         }
535 
536     }
537 
538     public static class DataCB extends AsyncCB implements DataCallback {
539 
540         byte[] data = new byte[10];
541         Stat stat = new Stat();
542 
DataCB(ZooKeeper zk)543         DataCB(ZooKeeper zk) {
544             this(zk, new CountDownLatch(1));
545         }
546 
DataCB(ZooKeeper zk, CountDownLatch latch)547         DataCB(ZooKeeper zk, CountDownLatch latch) {
548             super(zk, latch);
549             stat.setAversion(0);
550             stat.setCversion(0);
551             stat.setEphemeralOwner(0);
552             stat.setVersion(0);
553         }
554 
processResult(int rc, String path, Object ctx, byte[] data, Stat stat)555         public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
556             this.data = data;
557             this.stat = stat;
558             super.processResult(Code.get(rc), path, ctx);
559         }
560 
verifyGetData()561         public void verifyGetData() {
562             new StringCB(zk).verifyCreate();
563 
564             zk.getData(path, false, this, toString());
565             verify();
566         }
567 
verifyGetDataFailure_NoNode()568         public void verifyGetDataFailure_NoNode() {
569             rc = KeeperException.Code.NONODE;
570             data = null;
571             stat = null;
572             zk.getData(path, false, this, toString());
573             verify();
574         }
575 
576         @Override
toString()577         public String toString() {
578             return super.toString()
579                    + ":" + (data == null ? "null" : new String(data))
580                    + ":" + (stat == null ? "null" : stat.getAversion()
581                                                     + ":" + stat.getCversion()
582                                                     + ":" + stat.getEphemeralOwner()
583                                                     + ":" + stat.getVersion());
584         }
585 
586     }
587 
588     public static class StatCB extends AsyncCB implements StatCallback {
589 
590         List<ACL> acl = Ids.CREATOR_ALL_ACL;
591         int version = 0;
592         Stat stat = new Stat();
593         byte[] data = "testing".getBytes();
594 
StatCB(ZooKeeper zk)595         StatCB(ZooKeeper zk) {
596             this(zk, new CountDownLatch(1));
597         }
598 
StatCB(ZooKeeper zk, CountDownLatch latch)599         StatCB(ZooKeeper zk, CountDownLatch latch) {
600             super(zk, latch);
601             stat.setAversion(0);
602             stat.setCversion(0);
603             stat.setEphemeralOwner(0);
604             stat.setVersion(0);
605         }
606 
processResult(int rc, String path, Object ctx, Stat stat)607         public void processResult(int rc, String path, Object ctx, Stat stat) {
608             this.stat = stat;
609             super.processResult(Code.get(rc), path, ctx);
610         }
611 
verifySetACL()612         public void verifySetACL() {
613             stat.setAversion(1);
614             new StringCB(zk).verifyCreate();
615 
616             zk.setACL(path, acl, version, this, toString());
617             verify();
618         }
619 
verifySetACLFailure_NoNode()620         public void verifySetACLFailure_NoNode() {
621             rc = KeeperException.Code.NONODE;
622             stat = null;
623             zk.setACL(path, acl, version, this, toString());
624             verify();
625         }
626 
verifySetACLFailure_BadVersion()627         public void verifySetACLFailure_BadVersion() {
628             new StringCB(zk).verifyCreate();
629 
630             rc = Code.BADVERSION;
631             stat = null;
632             zk.setACL(path, acl, version + 1, this, toString());
633 
634             verify();
635         }
636 
setData()637         public void setData() {
638             zk.setData(path, data, version, this, toString());
639         }
640 
verifySetData()641         public void verifySetData() {
642             stat.setVersion(1);
643             new StringCB(zk).verifyCreate();
644 
645             setData();
646             verify();
647         }
648 
verifySetDataFailure_NoNode()649         public void verifySetDataFailure_NoNode() {
650             rc = KeeperException.Code.NONODE;
651             stat = null;
652             zk.setData(path, data, version, this, toString());
653             verify();
654         }
655 
verifySetDataFailure_BadVersion()656         public void verifySetDataFailure_BadVersion() {
657             new StringCB(zk).verifyCreate();
658 
659             rc = Code.BADVERSION;
660             stat = null;
661             zk.setData(path, data, version + 1, this, toString());
662 
663             verify();
664         }
665 
verifyExists()666         public void verifyExists() {
667             new StringCB(zk).verifyCreate();
668 
669             zk.exists(path, false, this, toString());
670             verify();
671         }
672 
verifyExistsFailure_NoNode()673         public void verifyExistsFailure_NoNode() {
674             rc = KeeperException.Code.NONODE;
675             stat = null;
676             zk.exists(path, false, this, toString());
677             verify();
678         }
679 
680         @Override
toString()681         public String toString() {
682             return super.toString() + version
683                    + ":" + new String(data)
684                    + ":" + (stat == null ? "null" : stat.getAversion()
685                                                     + ":" + stat.getCversion()
686                                                     + ":" + stat.getEphemeralOwner()
687                                                     + ":" + stat.getVersion());
688         }
689 
690     }
691 
692     public static class VoidCB extends AsyncCB implements VoidCallback {
693 
694         int version = 0;
695 
VoidCB(ZooKeeper zk)696         VoidCB(ZooKeeper zk) {
697             this(zk, new CountDownLatch(1));
698         }
699 
VoidCB(ZooKeeper zk, CountDownLatch latch)700         VoidCB(ZooKeeper zk, CountDownLatch latch) {
701             super(zk, latch);
702         }
703 
processResult(int rc, String path, Object ctx)704         public void processResult(int rc, String path, Object ctx) {
705             super.processResult(Code.get(rc), path, ctx);
706         }
707 
delete()708         public void delete() {
709             zk.delete(path, version, this, toString());
710         }
711 
verifyDelete()712         public void verifyDelete() {
713             new StringCB(zk).verifyCreate();
714 
715             delete();
716             verify();
717         }
718 
verifyDeleteFailure_NoNode()719         public void verifyDeleteFailure_NoNode() {
720             rc = Code.NONODE;
721             zk.delete(path, version, this, toString());
722             verify();
723         }
724 
verifyDeleteFailure_BadVersion()725         public void verifyDeleteFailure_BadVersion() {
726             new StringCB(zk).verifyCreate();
727             rc = Code.BADVERSION;
728             zk.delete(path, version + 1, this, toString());
729             verify();
730         }
731 
verifyDeleteFailure_NotEmpty()732         public void verifyDeleteFailure_NotEmpty() {
733             StringCB scb = new StringCB(zk);
734             scb.create();
735             scb.setPath(path + "/bar");
736             scb.create();
737 
738             rc = Code.NOTEMPTY;
739             zk.delete(path, version, this, toString());
740             verify();
741         }
742 
sync()743         public void sync() {
744             zk.sync(path, this, toString());
745         }
746 
verifySync()747         public void verifySync() {
748             sync();
749             verify();
750         }
751 
752         @Override
toString()753         public String toString() {
754             return super.toString() + version;
755         }
756 
757     }
758 
759     public static class MultiCB implements MultiCallback {
760 
761         ZooKeeper zk;
762         int rc;
763         List<OpResult> opResults;
764         final CountDownLatch latch = new CountDownLatch(1);
765 
MultiCB(ZooKeeper zk)766         MultiCB(ZooKeeper zk) {
767             this.zk = zk;
768         }
769 
processResult(int rc, String path, Object ctx, List<OpResult> opResults)770         public void processResult(int rc, String path, Object ctx, List<OpResult> opResults) {
771             this.rc = rc;
772             this.opResults = opResults;
773             latch.countDown();
774         }
775 
latch_await()776         void latch_await() {
777             try {
778                 latch.await(10000, TimeUnit.MILLISECONDS);
779             } catch (InterruptedException e) {
780                 fail("unexpected interrupt");
781             }
782             assertSame(0L, latch.getCount());
783         }
784 
verifyMulti()785         public void verifyMulti() {
786             List<Op> ops = Arrays.asList(
787                 Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),
788                 Op.delete("/multi", -1));
789             zk.multi(ops, this, null);
790             latch_await();
791 
792             assertEquals(this.rc, KeeperException.Code.OK.intValue());
793             assertTrue(this.opResults.get(0) instanceof OpResult.CreateResult);
794             assertTrue(this.opResults.get(1) instanceof OpResult.DeleteResult);
795         }
796 
verifyMultiFailure_AllErrorResult()797         public void verifyMultiFailure_AllErrorResult() {
798             List<Op> ops = Arrays.asList(
799                 Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),
800                 Op.delete("/nonexist1", -1), Op.setData("/multi", "test".getBytes(), -1));
801             zk.multi(ops, this, null);
802             latch_await();
803 
804             assertTrue(this.opResults.get(0) instanceof OpResult.ErrorResult);
805             assertTrue(this.opResults.get(1) instanceof OpResult.ErrorResult);
806             assertTrue(this.opResults.get(2) instanceof OpResult.ErrorResult);
807         }
808 
verifyMultiFailure_NoSideEffect()809         public void verifyMultiFailure_NoSideEffect() throws KeeperException, InterruptedException {
810             List<Op> ops = Arrays.asList(
811                 Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT),
812                 Op.delete("/nonexist1", -1));
813             zk.multi(ops, this, null);
814             latch_await();
815 
816             assertTrue(this.opResults.get(0) instanceof OpResult.ErrorResult);
817             assertNull(zk.exists("/multi", false));
818         }
819 
verifyMultiSequential_NoSideEffect()820         public void verifyMultiSequential_NoSideEffect() throws Exception {
821             StringCB scb = new StringCB(zk);
822             scb.verifyCreate();
823             String path = scb.path + "-";
824             String seqPath = path + "0000000002";
825 
826             zk.create(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
827             assertNotNull(zk.exists(path + "0000000001", false));
828 
829             List<Op> ops = Arrays.asList(
830                 Op.create(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL),
831                 Op.delete("/nonexist", -1));
832             zk.multi(ops, this, null);
833             latch_await();
834 
835             assertNull(zk.exists(seqPath, false));
836             zk.create(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
837             assertNotNull(zk.exists(seqPath, false));
838         }
839 
840     }
841 
842 }
843