/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zookeeper.test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.junit.Assert;
import org.junit.Test;
public class WatcherFuncTest extends ClientBase {
private static class SimpleWatcher implements Watcher {
private LinkedBlockingQueue<WatchedEvent> events =
new LinkedBlockingQueue<WatchedEvent>();
private CountDownLatch latch;
public SimpleWatcher(CountDownLatch latch) {
this.latch = latch;
}
public void process(WatchedEvent event) {
if (event.getState() == KeeperState.SyncConnected) {
if (latch != null) {
latch.countDown();
}
}
if (event.getType() == EventType.None) {
return;
}
try {
events.put(event);
} catch (InterruptedException e) {
Assert.assertTrue("interruption unexpected", false);
}
}
public void verify(List<EventType> expected) throws InterruptedException{
WatchedEvent event;
int count = 0;
while (count < expected.size()
&& (event = events.poll(30, TimeUnit.SECONDS)) != null)
{
Assert.assertEquals(expected.get(count), event.getType());
count++;
}
Assert.assertEquals(expected.size(), count);
events.clear();
}
}
private SimpleWatcher client_dwatch;
private volatile CountDownLatch client_latch;
private ZooKeeper client;
private SimpleWatcher lsnr_dwatch;
private volatile CountDownLatch lsnr_latch;
private ZooKeeper lsnr;
private List<EventType> expected;
@Override
public void setUp() throws Exception {
super.setUp();
client_latch = new CountDownLatch(1);
client_dwatch = new SimpleWatcher(client_latch);
client = createClient(client_dwatch, client_latch);
lsnr_latch = new CountDownLatch(1);
lsnr_dwatch = new SimpleWatcher(lsnr_latch);
lsnr = createClient(lsnr_dwatch, lsnr_latch);
expected = new ArrayList<EventType>();
}
@Override
public void tearDown() throws Exception {
client.close();
lsnr.close();
super.tearDown();
}
protected ZooKeeper createClient(Watcher watcher, CountDownLatch latch)
throws IOException, InterruptedException
{
ZooKeeper zk = new ZooKeeper(hostPort, CONNECTION_TIMEOUT, watcher);
if(!latch.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)){
Assert.fail("Unable to connect to server");
}
return zk;
}
private void verify() throws InterruptedException {
lsnr_dwatch.verify(expected);
expected.clear();
}
@Test
public void testExistsSync()
throws IOException, InterruptedException, KeeperException
{
Assert.assertNull(lsnr.exists("/foo", true));
Assert.assertNull(lsnr.exists("/foo/bar", true));
client.create("/foo", "parent".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
expected.add(EventType.NodeCreated);
client.create("/foo/bar", "child".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
expected.add(EventType.NodeCreated);
verify();
Assert.assertNotNull(lsnr.exists("/foo", true));
Assert.assertNotNull(lsnr.exists("/foo/bar", true));
try {
Assert.assertNull(lsnr.exists("/car", true));
client.setData("/car", "missing".getBytes(), -1);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/car", e.getPath());
}
try {
Assert.assertNull(lsnr.exists("/foo/car", true));
client.setData("/foo/car", "missing".getBytes(), -1);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/foo/car", e.getPath());
}
client.setData("/foo", "parent".getBytes(), -1);
expected.add(EventType.NodeDataChanged);
client.setData("/foo/bar", "child".getBytes(), -1);
expected.add(EventType.NodeDataChanged);
verify();
Assert.assertNotNull(lsnr.exists("/foo", true));
Assert.assertNotNull(lsnr.exists("/foo/bar", true));
client.delete("/foo/bar", -1);
expected.add(EventType.NodeDeleted);
client.delete("/foo", -1);
expected.add(EventType.NodeDeleted);
verify();
}
@Test
public void testGetDataSync()
throws IOException, InterruptedException, KeeperException
{
try {
lsnr.getData("/foo", true, null);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/foo", e.getPath());
}
try {
lsnr.getData("/foo/bar", true, null);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/foo/bar", e.getPath());
}
client.create("/foo", "parent".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
Assert.assertNotNull(lsnr.getData("/foo", true, null));
client.create("/foo/bar", "child".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
Assert.assertNotNull(lsnr.getData("/foo/bar", true, null));
client.setData("/foo", "parent".getBytes(), -1);
expected.add(EventType.NodeDataChanged);
client.setData("/foo/bar", "child".getBytes(), -1);
expected.add(EventType.NodeDataChanged);
verify();
Assert.assertNotNull(lsnr.getData("/foo", true, null));
Assert.assertNotNull(lsnr.getData("/foo/bar", true, null));
client.delete("/foo/bar", -1);
expected.add(EventType.NodeDeleted);
client.delete("/foo", -1);
expected.add(EventType.NodeDeleted);
verify();
}
@Test
public void testGetChildrenSync()
throws IOException, InterruptedException, KeeperException
{
try {
lsnr.getChildren("/foo", true);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/foo", e.getPath());
}
try {
lsnr.getChildren("/foo/bar", true);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/foo/bar", e.getPath());
}
client.create("/foo", "parent".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
Assert.assertNotNull(lsnr.getChildren("/foo", true));
client.create("/foo/bar", "child".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
expected.add(EventType.NodeChildrenChanged); // /foo
Assert.assertNotNull(lsnr.getChildren("/foo/bar", true));
client.setData("/foo", "parent".getBytes(), -1);
client.setData("/foo/bar", "child".getBytes(), -1);
Assert.assertNotNull(lsnr.exists("/foo", true));
Assert.assertNotNull(lsnr.getChildren("/foo", true));
Assert.assertNotNull(lsnr.getChildren("/foo/bar", true));
client.delete("/foo/bar", -1);
expected.add(EventType.NodeDeleted); // /foo/bar childwatch
expected.add(EventType.NodeChildrenChanged); // /foo
client.delete("/foo", -1);
expected.add(EventType.NodeDeleted);
verify();
}
@Test
public void testExistsSyncWObj()
throws IOException, InterruptedException, KeeperException
{
SimpleWatcher w1 = new SimpleWatcher(null);
SimpleWatcher w2 = new SimpleWatcher(null);
SimpleWatcher w3 = new SimpleWatcher(null);
SimpleWatcher w4 = new SimpleWatcher(null);
List<EventType> e2 = new ArrayList<EventType>();
Assert.assertNull(lsnr.exists("/foo", true));
Assert.assertNull(lsnr.exists("/foo", w1));
Assert.assertNull(lsnr.exists("/foo/bar", w2));
Assert.assertNull(lsnr.exists("/foo/bar", w3));
Assert.assertNull(lsnr.exists("/foo/bar", w3));
Assert.assertNull(lsnr.exists("/foo/bar", w4));
client.create("/foo", "parent".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
expected.add(EventType.NodeCreated);
client.create("/foo/bar", "child".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
e2.add(EventType.NodeCreated);
lsnr_dwatch.verify(expected);
w1.verify(expected);
w2.verify(e2);
w3.verify(e2);
w4.verify(e2);
expected.clear();
e2.clear();
// default not registered
Assert.assertNotNull(lsnr.exists("/foo", w1));
Assert.assertNotNull(lsnr.exists("/foo/bar", w2));
Assert.assertNotNull(lsnr.exists("/foo/bar", w3));
Assert.assertNotNull(lsnr.exists("/foo/bar", w4));
Assert.assertNotNull(lsnr.exists("/foo/bar", w4));
client.setData("/foo", "parent".getBytes(), -1);
expected.add(EventType.NodeDataChanged);
client.setData("/foo/bar", "child".getBytes(), -1);
e2.add(EventType.NodeDataChanged);
lsnr_dwatch.verify(new ArrayList<EventType>()); // not reg so should = 0
w1.verify(expected);
w2.verify(e2);
w3.verify(e2);
w4.verify(e2);
expected.clear();
e2.clear();
Assert.assertNotNull(lsnr.exists("/foo", true));
Assert.assertNotNull(lsnr.exists("/foo", w1));
Assert.assertNotNull(lsnr.exists("/foo", w1));
Assert.assertNotNull(lsnr.exists("/foo/bar", w2));
Assert.assertNotNull(lsnr.exists("/foo/bar", w2));
Assert.assertNotNull(lsnr.exists("/foo/bar", w3));
Assert.assertNotNull(lsnr.exists("/foo/bar", w4));
client.delete("/foo/bar", -1);
expected.add(EventType.NodeDeleted);
client.delete("/foo", -1);
e2.add(EventType.NodeDeleted);
lsnr_dwatch.verify(expected);
w1.verify(expected);
w2.verify(e2);
w3.verify(e2);
w4.verify(e2);
expected.clear();
e2.clear();
}
@Test
public void testGetDataSyncWObj()
throws IOException, InterruptedException, KeeperException
{
SimpleWatcher w1 = new SimpleWatcher(null);
SimpleWatcher w2 = new SimpleWatcher(null);
SimpleWatcher w3 = new SimpleWatcher(null);
SimpleWatcher w4 = new SimpleWatcher(null);
List<EventType> e2 = new ArrayList<EventType>();
try {
lsnr.getData("/foo", w1, null);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/foo", e.getPath());
}
try {
lsnr.getData("/foo/bar", w2, null);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/foo/bar", e.getPath());
}
client.create("/foo", "parent".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
Assert.assertNotNull(lsnr.getData("/foo", true, null));
Assert.assertNotNull(lsnr.getData("/foo", w1, null));
client.create("/foo/bar", "child".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
Assert.assertNotNull(lsnr.getData("/foo/bar", w2, null));
Assert.assertNotNull(lsnr.getData("/foo/bar", w3, null));
Assert.assertNotNull(lsnr.getData("/foo/bar", w4, null));
Assert.assertNotNull(lsnr.getData("/foo/bar", w4, null));
client.setData("/foo", "parent".getBytes(), -1);
expected.add(EventType.NodeDataChanged);
client.setData("/foo/bar", "child".getBytes(), -1);
e2.add(EventType.NodeDataChanged);
lsnr_dwatch.verify(expected);
w1.verify(expected);
w2.verify(e2);
w3.verify(e2);
w4.verify(e2);
expected.clear();
e2.clear();
Assert.assertNotNull(lsnr.getData("/foo", true, null));
Assert.assertNotNull(lsnr.getData("/foo", w1, null));
Assert.assertNotNull(lsnr.getData("/foo/bar", w2, null));
Assert.assertNotNull(lsnr.getData("/foo/bar", w3, null));
Assert.assertNotNull(lsnr.getData("/foo/bar", w3, null));
Assert.assertNotNull(lsnr.getData("/foo/bar", w4, null));
client.delete("/foo/bar", -1);
expected.add(EventType.NodeDeleted);
client.delete("/foo", -1);
e2.add(EventType.NodeDeleted);
lsnr_dwatch.verify(expected);
w1.verify(expected);
w2.verify(e2);
w3.verify(e2);
w4.verify(e2);
expected.clear();
e2.clear();
}
@Test
public void testGetChildrenSyncWObj()
throws IOException, InterruptedException, KeeperException
{
SimpleWatcher w1 = new SimpleWatcher(null);
SimpleWatcher w2 = new SimpleWatcher(null);
SimpleWatcher w3 = new SimpleWatcher(null);
SimpleWatcher w4 = new SimpleWatcher(null);
List<EventType> e2 = new ArrayList<EventType>();
try {
lsnr.getChildren("/foo", true);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/foo", e.getPath());
}
try {
lsnr.getChildren("/foo/bar", true);
Assert.fail();
} catch (KeeperException e) {
Assert.assertEquals(KeeperException.Code.NONODE, e.code());
Assert.assertEquals("/foo/bar", e.getPath());
}
client.create("/foo", "parent".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
Assert.assertNotNull(lsnr.getChildren("/foo", true));
Assert.assertNotNull(lsnr.getChildren("/foo", w1));
client.create("/foo/bar", "child".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
expected.add(EventType.NodeChildrenChanged); // /foo
Assert.assertNotNull(lsnr.getChildren("/foo/bar", w2));
Assert.assertNotNull(lsnr.getChildren("/foo/bar", w2));
Assert.assertNotNull(lsnr.getChildren("/foo/bar", w3));
Assert.assertNotNull(lsnr.getChildren("/foo/bar", w4));
client.setData("/foo", "parent".getBytes(), -1);
client.setData("/foo/bar", "child".getBytes(), -1);
Assert.assertNotNull(lsnr.exists("/foo", true));
Assert.assertNotNull(lsnr.exists("/foo", w1));
Assert.assertNotNull(lsnr.exists("/foo", true));
Assert.assertNotNull(lsnr.exists("/foo", w1));
Assert.assertNotNull(lsnr.getChildren("/foo", true));
Assert.assertNotNull(lsnr.getChildren("/foo", w1));
Assert.assertNotNull(lsnr.getChildren("/foo/bar", w2));
Assert.assertNotNull(lsnr.getChildren("/foo/bar", w3));
Assert.assertNotNull(lsnr.getChildren("/foo/bar", w4));
Assert.assertNotNull(lsnr.getChildren("/foo/bar", w4));
client.delete("/foo/bar", -1);
e2.add(EventType.NodeDeleted); // /foo/bar childwatch
expected.add(EventType.NodeChildrenChanged); // /foo
client.delete("/foo", -1);
expected.add(EventType.NodeDeleted);
lsnr_dwatch.verify(expected);
w1.verify(expected);
w2.verify(e2);
w3.verify(e2);
w4.verify(e2);
expected.clear();
e2.clear();
}
}