http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/ACLTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ACLTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ACLTest.java new file mode 100644 index 0000000..793265c --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ACLTest.java @@ -0,0 +1,186 @@ +/** + * 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 static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT; + +import java.io.File; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.PortAssignment; +import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.ZKTestCase; +import org.apache.zookeeper.ZooKeeper; +import org.apache.zookeeper.Watcher.Event.KeeperState; +import org.apache.zookeeper.ZooDefs.Ids; +import org.apache.zookeeper.data.ACL; +import org.apache.zookeeper.data.Id; +import org.apache.zookeeper.server.ServerCnxnFactory; +import org.apache.zookeeper.server.SyncRequestProcessor; +import org.apache.zookeeper.server.ZooKeeperServer; +import org.junit.Assert; +import org.junit.Test; + +public class ACLTest extends ZKTestCase implements Watcher { + private static final Logger LOG = LoggerFactory.getLogger(ACLTest.class); + private static final String HOSTPORT = + "127.0.0.1:" + PortAssignment.unique(); + private volatile CountDownLatch startSignal; + + @Test + public void testDisconnectedAddAuth() throws Exception { + File tmpDir = ClientBase.createTmpDir(); + ClientBase.setupTestEnv(); + ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000); + SyncRequestProcessor.setSnapCount(1000); + final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]); + ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1); + f.startup(zks); + try { + LOG.info("starting up the zookeeper server .. waiting"); + Assert.assertTrue("waiting for server being up", + ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT)); + ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this); + try { + zk.addAuthInfo("digest", "pat:test".getBytes()); + zk.setACL("/", Ids.CREATOR_ALL_ACL, -1); + } finally { + zk.close(); + } + } finally { + f.shutdown(); + zks.shutdown(); + Assert.assertTrue("waiting for server down", + ClientBase.waitForServerDown(HOSTPORT, + ClientBase.CONNECTION_TIMEOUT)); + } + } + + /** + * Verify that acl optimization of storing just + * a few acls and there references in the data + * node is actually working. + */ + @Test + public void testAcls() throws Exception { + File tmpDir = ClientBase.createTmpDir(); + ClientBase.setupTestEnv(); + ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000); + SyncRequestProcessor.setSnapCount(1000); + final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]); + ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1); + f.startup(zks); + ZooKeeper zk; + String path; + try { + LOG.info("starting up the zookeeper server .. waiting"); + Assert.assertTrue("waiting for server being up", + ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT)); + zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this); + LOG.info("starting creating acls"); + for (int i = 0; i < 100; i++) { + path = "/" + i; + zk.create(path, path.getBytes(), Ids.OPEN_ACL_UNSAFE, + CreateMode.PERSISTENT); + } + Assert.assertTrue("size of the acl map ", (1 == zks.getZKDatabase().getAclSize())); + for (int j = 100; j < 200; j++) { + path = "/" + j; + ACL acl = new ACL(); + acl.setPerms(0); + Id id = new Id(); + id.setId("1.1.1."+j); + id.setScheme("ip"); + acl.setId(id); + ArrayList<ACL> list = new ArrayList<ACL>(); + list.add(acl); + zk.create(path, path.getBytes(), list, CreateMode.PERSISTENT); + } + Assert.assertTrue("size of the acl map ", (101 == zks.getZKDatabase().getAclSize())); + } finally { + // now shutdown the server and restart it + f.shutdown(); + zks.shutdown(); + Assert.assertTrue("waiting for server down", + ClientBase.waitForServerDown(HOSTPORT, CONNECTION_TIMEOUT)); + } + startSignal = new CountDownLatch(1); + + zks = new ZooKeeperServer(tmpDir, tmpDir, 3000); + f = ServerCnxnFactory.createFactory(PORT, -1); + + f.startup(zks); + try { + Assert.assertTrue("waiting for server up", + ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT)); + + startSignal.await(CONNECTION_TIMEOUT, + TimeUnit.MILLISECONDS); + Assert.assertTrue("count == 0", startSignal.getCount() == 0); + + Assert.assertTrue("acl map ", (101 == zks.getZKDatabase().getAclSize())); + for (int j = 200; j < 205; j++) { + path = "/" + j; + ACL acl = new ACL(); + acl.setPerms(0); + Id id = new Id(); + id.setId("1.1.1."+j); + id.setScheme("ip"); + acl.setId(id); + ArrayList<ACL> list = new ArrayList<ACL>(); + list.add(acl); + zk.create(path, path.getBytes(), list, CreateMode.PERSISTENT); + } + Assert.assertTrue("acl map ", (106 == zks.getZKDatabase().getAclSize())); + + zk.close(); + } finally { + f.shutdown(); + zks.shutdown(); + Assert.assertTrue("waiting for server down", + ClientBase.waitForServerDown(HOSTPORT, + ClientBase.CONNECTION_TIMEOUT)); + } + + } + + /* + * (non-Javadoc) + * + * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatcherEvent) + */ + public void process(WatchedEvent event) { + LOG.info("Event:" + event.getState() + " " + event.getType() + " " + + event.getPath()); + if (event.getState() == KeeperState.SyncConnected) { + if (startSignal != null && startSignal.getCount() > 0) { + LOG.info("startsignal.countDown()"); + startSignal.countDown(); + } else { + LOG.warn("startsignal " + startSignal); + } + } + } +}
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncHammerTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncHammerTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncHammerTest.java new file mode 100644 index 0000000..ebfc963 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncHammerTest.java @@ -0,0 +1,245 @@ +/** + * 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 static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT; +import static org.apache.zookeeper.test.ClientBase.verifyThreadTerminated; + +import java.util.LinkedList; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.TestableZooKeeper; +import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.ZKTestCase; +import org.apache.zookeeper.AsyncCallback.DataCallback; +import org.apache.zookeeper.AsyncCallback.StringCallback; +import org.apache.zookeeper.AsyncCallback.VoidCallback; +import org.apache.zookeeper.ZooDefs.Ids; +import org.apache.zookeeper.data.Stat; +import org.apache.zookeeper.test.ClientBase.CountdownWatcher; +import org.junit.Assert; +import org.junit.Test; + +public class AsyncHammerTest extends ZKTestCase + implements StringCallback, VoidCallback, DataCallback +{ + private static final Logger LOG = LoggerFactory.getLogger(AsyncHammerTest.class); + + private QuorumBase qb = new QuorumBase(); + + private volatile boolean bang; + + public void setUp(boolean withObservers) throws Exception { + qb.setUp(withObservers); + } + + protected void restart() throws Exception { + LOG.info("RESTARTING " + getTestName()); + qb.tearDown(); + + // don't call setup - we don't want to reassign ports/dirs, etc... + JMXEnv.setUp(); + qb.startServers(); + } + + public void tearDown() throws Exception { + LOG.info("Test clients shutting down"); + qb.tearDown(); + } + + /** + * Create /test- sequence nodes asynchronously, max 30 outstanding + */ + class HammerThread extends Thread implements StringCallback, VoidCallback { + private static final int MAX_OUTSTANDING = 30; + + private TestableZooKeeper zk; + private int outstanding; + + private volatile boolean failed = false; + + public HammerThread(String name) { + super(name); + } + + public void run() { + try { + CountdownWatcher watcher = new CountdownWatcher(); + zk = new TestableZooKeeper(qb.hostPort, CONNECTION_TIMEOUT, + watcher); + watcher.waitForConnected(CONNECTION_TIMEOUT); + while(bang) { + incOutstanding(); // before create otw race + zk.create("/test-", new byte[0], Ids.OPEN_ACL_UNSAFE, + CreateMode.PERSISTENT_SEQUENTIAL, this, null); + } + } catch (InterruptedException e) { + if (bang) { + LOG.error("sanity check Assert.failed!!!"); // sanity check + return; + } + } catch (Exception e) { + LOG.error("Client create operation Assert.failed", e); + return; + } finally { + if (zk != null) { + try { + zk.close(); + if (!zk.testableWaitForShutdown(CONNECTION_TIMEOUT)) { + failed = true; + LOG.error("Client did not shutdown"); + } + } catch (InterruptedException e) { + LOG.info("Interrupted", e); + } + } + } + } + + private synchronized void incOutstanding() throws InterruptedException { + outstanding++; + while(outstanding > MAX_OUTSTANDING) { + wait(); + } + } + + private synchronized void decOutstanding() { + outstanding--; + Assert.assertTrue("outstanding >= 0", outstanding >= 0); + notifyAll(); + } + + public void process(WatchedEvent event) { + // ignore for purposes of this test + } + + public void processResult(int rc, String path, Object ctx, String name) { + if (rc != KeeperException.Code.OK.intValue()) { + if (bang) { + failed = true; + LOG.error("Create Assert.failed for 0x" + + Long.toHexString(zk.getSessionId()) + + "with rc:" + rc + " path:" + path); + } + decOutstanding(); + return; + } + try { + decOutstanding(); + zk.delete(name, -1, this, null); + } catch (Exception e) { + if (bang) { + failed = true; + LOG.error("Client delete Assert.failed", e); + } + } + } + + public void processResult(int rc, String path, Object ctx) { + if (rc != KeeperException.Code.OK.intValue()) { + if (bang) { + failed = true; + LOG.error("Delete Assert.failed for 0x" + + Long.toHexString(zk.getSessionId()) + + "with rc:" + rc + " path:" + path); + } + } + } + } + + @Test + public void testHammer() throws Exception { + setUp(false); + bang = true; + LOG.info("Starting hammers"); + HammerThread[] hammers = new HammerThread[100]; + for (int i = 0; i < hammers.length; i++) { + hammers[i] = new HammerThread("HammerThread-" + i); + hammers[i].start(); + } + LOG.info("Started hammers"); + Thread.sleep(5000); // allow the clients to run for max 5sec + bang = false; + LOG.info("Stopping hammers"); + for (int i = 0; i < hammers.length; i++) { + hammers[i].interrupt(); + verifyThreadTerminated(hammers[i], 60000); + Assert.assertFalse(hammers[i].failed); + } + + // before restart + LOG.info("Hammers stopped, verifying consistency"); + qb.verifyRootOfAllServersMatch(qb.hostPort); + + restart(); + + // after restart + LOG.info("Verifying hammers 2"); + qb.verifyRootOfAllServersMatch(qb.hostPort); + tearDown(); + } + + @Test + public void testObserversHammer() throws Exception { + setUp(true); + bang = true; + Thread[] hammers = new Thread[100]; + for (int i = 0; i < hammers.length; i++) { + hammers[i] = new HammerThread("HammerThread-" + i); + hammers[i].start(); + } + Thread.sleep(5000); // allow the clients to run for max 5sec + bang = false; + for (int i = 0; i < hammers.length; i++) { + hammers[i].interrupt(); + verifyThreadTerminated(hammers[i], 60000); + } + // before restart + qb.verifyRootOfAllServersMatch(qb.hostPort); + tearDown(); + } + + @SuppressWarnings("unchecked") + public void processResult(int rc, String path, Object ctx, String name) { + synchronized(ctx) { + ((LinkedList<Integer>)ctx).add(rc); + ctx.notifyAll(); + } + } + + @SuppressWarnings("unchecked") + public void processResult(int rc, String path, Object ctx) { + synchronized(ctx) { + ((LinkedList<Integer>)ctx).add(rc); + ctx.notifyAll(); + } + } + + @SuppressWarnings("unchecked") + public void processResult(int rc, String path, Object ctx, byte[] data, + Stat stat) { + synchronized(ctx) { + ((LinkedList<Integer>)ctx).add(rc); + ctx.notifyAll(); + } + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncOps.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncOps.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncOps.java new file mode 100644 index 0000000..2dbe644 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncOps.java @@ -0,0 +1,655 @@ +/** + * 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.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.ZooKeeper; +import org.apache.zookeeper.AsyncCallback.ACLCallback; +import org.apache.zookeeper.AsyncCallback.Children2Callback; +import org.apache.zookeeper.AsyncCallback.ChildrenCallback; +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.KeeperException.Code; +import org.apache.zookeeper.ZooDefs.Ids; +import org.apache.zookeeper.data.ACL; +import org.apache.zookeeper.data.Stat; +import org.junit.Assert; + +public class AsyncOps { + /** + * This is the base class for all of the async callback classes. It will + * verify the expected value against the actual value. + * + * Basic operation is that the subclasses will generate an "expected" value + * which is defined by the "toString" method of the subclass. This is + * passed through to the verify clause by specifying it as the ctx object + * of each async call (processResult methods get the ctx as part of + * the callback). Additionally the callback will also overwrite any + * instance fields with matching parameter arguments to the processResult + * method. The cb instance can then compare the expected to the + * actual value by again calling toString and comparing the two. + * + * The format of each expected value differs (is defined) by subclass. + * Generally the expected value starts with the result code (rc) and path + * of the node being operated on, followed by the fields specific to + * each operation type (cb subclass). For example ChildrenCB specifies + * a list of the expected children suffixed onto the rc and path. See + * the toString() method of each subclass for details of it's format. + */ + public static abstract class AsyncCB { + protected final ZooKeeper zk; + protected long defaultTimeoutMillis = 30000; + + /** the latch is used to await the results from the server */ + CountDownLatch latch; + + Code rc = Code.OK; + String path = "/foo"; + String expected; + + public AsyncCB(ZooKeeper zk, CountDownLatch latch) { + this.zk = zk; + this.latch = latch; + } + + public void setRC(Code rc) { + this.rc = rc; + } + + public void setPath(String path) { + this.path = path; + } + + public void processResult(Code rc, String path, Object ctx) + { + this.rc = rc; + this.path = path; + this.expected = (String)ctx; + latch.countDown(); + } + + /** String format is rc:path:<suffix> where <suffix> is defined by each + * subclass individually. */ + @Override + public String toString() { + return rc + ":" + path + ":"; + } + + protected void verify() { + try { + latch.await(defaultTimeoutMillis, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Assert.fail("unexpected interrupt"); + } + // on the lookout for timeout + Assert.assertSame(0L, latch.getCount()); + + String actual = toString(); + + Assert.assertEquals(expected, actual); + } + } + + public static class StringCB extends AsyncCB implements StringCallback { + byte[] data = new byte[10]; + List<ACL> acl = Ids.CREATOR_ALL_ACL; + CreateMode flags = CreateMode.PERSISTENT; + String name = path; + + StringCB(ZooKeeper zk) { + this(zk, new CountDownLatch(1)); + } + + StringCB(ZooKeeper zk, CountDownLatch latch) { + super(zk, latch); + } + + public void setPath(String path) { + super.setPath(path); + this.name = path; + } + + public String nodeName() { + return path.substring(path.lastIndexOf('/') + 1); + } + + public void processResult(int rc, String path, Object ctx, String name) + { + this.name = name; + super.processResult(Code.get(rc), path, ctx); + } + + public AsyncCB create() { + 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(); + + rc = Code.NODEEXISTS; + name = null; + 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; + } + } + + public static class ACLCB extends AsyncCB implements ACLCallback { + List<ACL> acl = Ids.CREATOR_ALL_ACL; + int version = 0; + Stat stat = new Stat(); + byte[] data = "testing".getBytes(); + + ACLCB(ZooKeeper zk) { + this(zk, new CountDownLatch(1)); + } + + ACLCB(ZooKeeper zk, CountDownLatch latch) { + super(zk, latch); + stat.setAversion(0); + stat.setCversion(0); + stat.setEphemeralOwner(0); + stat.setVersion(0); + } + + public void processResult(int rc, String path, Object ctx, + List<ACL> acl, Stat stat) + { + this.acl = acl; + this.stat = stat; + super.processResult(Code.get(rc), path, ctx); + } + + public void verifyGetACL() { + new StringCB(zk).verifyCreate(); + + 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() + "::"); + } + return result.toString(); + } + + @Override + public String toString() { + return super.toString() + toString(acl) + ":" + + ":" + version + ":" + new String(data) + + ":" + (stat == null ? "null" : stat.getAversion() + ":" + + stat.getCversion() + ":" + stat.getEphemeralOwner() + + ":" + stat.getVersion()); + } + } + + public static class ChildrenCB extends AsyncCB implements ChildrenCallback { + List<String> children = new ArrayList<String>(); + + ChildrenCB(ZooKeeper zk) { + this(zk, new CountDownLatch(1)); + } + + ChildrenCB(ZooKeeper zk, CountDownLatch latch) { + super(zk, latch); + } + + public void processResult(int rc, String path, Object ctx, + List<String> children) + { + this.children = + (children == null ? new ArrayList<String>() : children); + Collections.sort(this.children); + super.processResult(Code.get(rc), path, ctx); + } + + public StringCB createNode() { + StringCB parent = new StringCB(zk); + parent.verifyCreate(); + + return parent; + } + + public StringCB createNode(StringCB parent) { + String childName = "bar"; + + return createNode(parent, childName); + } + + public StringCB createNode(StringCB parent, String childName) { + StringCB child = new StringCB(zk); + child.setPath(parent.path + "/" + childName); + child.verifyCreate(); + + return child; + } + + public void verifyGetChildrenEmpty() { + StringCB parent = createNode(); + path = parent.path; + verify(); + } + + public void verifyGetChildrenSingle() { + StringCB parent = createNode(); + StringCB child = createNode(parent); + + path = parent.path; + children.add(child.nodeName()); + + verify(); + } + + public void verifyGetChildrenTwo() { + StringCB parent = createNode(); + StringCB child1 = createNode(parent, "child1"); + StringCB child2 = createNode(parent, "child2"); + + path = parent.path; + children.add(child1.nodeName()); + children.add(child2.nodeName()); + + verify(); + } + + public void verifyGetChildrenFailure_NoNode() { + rc = KeeperException.Code.NONODE; + verify(); + } + + @Override + public void verify() { + zk.getChildren(path, false, this, toString()); + super.verify(); + } + + @Override + public String toString() { + return super.toString() + children.toString(); + } + } + + public static class Children2CB extends AsyncCB implements Children2Callback { + List<String> children = new ArrayList<String>(); + + Children2CB(ZooKeeper zk) { + this(zk, new CountDownLatch(1)); + } + + Children2CB(ZooKeeper zk, CountDownLatch latch) { + super(zk, latch); + } + + public void processResult(int rc, String path, Object ctx, + List<String> children, Stat stat) + { + this.children = + (children == null ? new ArrayList<String>() : children); + Collections.sort(this.children); + super.processResult(Code.get(rc), path, ctx); + } + + public StringCB createNode() { + StringCB parent = new StringCB(zk); + parent.verifyCreate(); + + return parent; + } + + public StringCB createNode(StringCB parent) { + String childName = "bar"; + + return createNode(parent, childName); + } + + public StringCB createNode(StringCB parent, String childName) { + StringCB child = new StringCB(zk); + child.setPath(parent.path + "/" + childName); + child.verifyCreate(); + + return child; + } + + public void verifyGetChildrenEmpty() { + StringCB parent = createNode(); + path = parent.path; + verify(); + } + + public void verifyGetChildrenSingle() { + StringCB parent = createNode(); + StringCB child = createNode(parent); + + path = parent.path; + children.add(child.nodeName()); + + verify(); + } + + public void verifyGetChildrenTwo() { + StringCB parent = createNode(); + StringCB child1 = createNode(parent, "child1"); + StringCB child2 = createNode(parent, "child2"); + + path = parent.path; + children.add(child1.nodeName()); + children.add(child2.nodeName()); + + verify(); + } + + public void verifyGetChildrenFailure_NoNode() { + rc = KeeperException.Code.NONODE; + verify(); + } + + @Override + public void verify() { + zk.getChildren(path, false, this, toString()); + super.verify(); + } + + @Override + public String toString() { + return super.toString() + children.toString(); + } + } + + public static class DataCB extends AsyncCB implements DataCallback { + byte[] data = new byte[10]; + Stat stat = new Stat(); + + DataCB(ZooKeeper zk) { + this(zk, new CountDownLatch(1)); + } + + DataCB(ZooKeeper zk, CountDownLatch latch) { + super(zk, latch); + stat.setAversion(0); + stat.setCversion(0); + stat.setEphemeralOwner(0); + stat.setVersion(0); + } + + public void processResult(int rc, String path, Object ctx, byte[] data, + Stat stat) + { + this.data = data; + this.stat = stat; + super.processResult(Code.get(rc), path, ctx); + } + + public void verifyGetData() { + new StringCB(zk).verifyCreate(); + + zk.getData(path, false, this, toString()); + verify(); + } + + public void verifyGetDataFailure_NoNode() { + rc = KeeperException.Code.NONODE; + data = null; + stat = null; + zk.getData(path, false, this, toString()); + verify(); + } + + @Override + public String toString() { + return super.toString() + + ":" + (data == null ? "null" : new String(data)) + + ":" + (stat == null ? "null" : stat.getAversion() + ":" + + stat.getCversion() + ":" + stat.getEphemeralOwner() + + ":" + stat.getVersion()); + } + } + + public static class StatCB extends AsyncCB implements StatCallback { + List<ACL> acl = Ids.CREATOR_ALL_ACL; + int version = 0; + Stat stat = new Stat(); + byte[] data = "testing".getBytes(); + + StatCB(ZooKeeper zk) { + this(zk, new CountDownLatch(1)); + } + + StatCB(ZooKeeper zk, CountDownLatch latch) { + super(zk, latch); + stat.setAversion(0); + stat.setCversion(0); + stat.setEphemeralOwner(0); + stat.setVersion(0); + } + + public void processResult(int rc, String path, Object ctx, Stat stat) { + this.stat = stat; + super.processResult(Code.get(rc), path, ctx); + } + + public void verifySetACL() { + stat.setAversion(1); + new StringCB(zk).verifyCreate(); + + zk.setACL(path, acl, version, this, toString()); + verify(); + } + + public void verifySetACLFailure_NoNode() { + rc = KeeperException.Code.NONODE; + stat = null; + 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()); + } + + public void verifySetData() { + stat.setVersion(1); + new StringCB(zk).verifyCreate(); + + setData(); + verify(); + } + + public void verifySetDataFailure_NoNode() { + rc = KeeperException.Code.NONODE; + stat = null; + 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(); + + zk.exists(path, false, this, toString()); + verify(); + } + + public void verifyExistsFailure_NoNode() { + rc = KeeperException.Code.NONODE; + stat = null; + zk.exists(path, false, this, toString()); + verify(); + } + + @Override + public String toString() { + return super.toString() + version + + ":" + new String(data) + + ":" + (stat == null ? "null" : stat.getAversion() + ":" + + stat.getCversion() + ":" + stat.getEphemeralOwner() + + ":" + stat.getVersion()); + } + } + + public static class VoidCB extends AsyncCB implements VoidCallback { + int version = 0; + + VoidCB(ZooKeeper zk) { + this(zk, new CountDownLatch(1)); + } + + VoidCB(ZooKeeper zk, CountDownLatch latch) { + super(zk, latch); + } + + public void processResult(int rc, String path, Object ctx) { + super.processResult(Code.get(rc), path, ctx); + } + + public void delete() { + zk.delete(path, version, this, toString()); + } + + public void verifyDelete() { + new StringCB(zk).verifyCreate(); + + delete(); + verify(); + } + + public void verifyDeleteFailure_NoNode() { + rc = Code.NONODE; + 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()); + } + + public void verifySync() { + sync(); + verify(); + } + + @Override + public String toString() { + return super.toString() + version; + } + } + + +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncOpsTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncOpsTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncOpsTest.java new file mode 100644 index 0000000..c807d72 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncOpsTest.java @@ -0,0 +1,227 @@ +/** + * 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.util.concurrent.CountDownLatch; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.zookeeper.ZooKeeper; +import org.apache.zookeeper.test.AsyncOps.ACLCB; +import org.apache.zookeeper.test.AsyncOps.Children2CB; +import org.apache.zookeeper.test.AsyncOps.ChildrenCB; +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.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AsyncOpsTest extends ClientBase { + private static final Logger LOG = LoggerFactory.getLogger(AsyncOpsTest.class); + + private ZooKeeper zk; + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + + LOG.info("Creating client " + getTestName()); + + zk = createClient(); + zk.addAuthInfo("digest", "ben:passwd".getBytes()); + } + + @After + @Override + public void tearDown() throws Exception { + zk.close(); + + super.tearDown(); + + LOG.info("Test clients shutting down"); + } + + @Test + public void testAsyncCreate() { + new StringCB(zk).verifyCreate(); + } + + @Test + public void testAsyncCreateThree() { + CountDownLatch latch = new CountDownLatch(3); + + StringCB op1 = new StringCB(zk, latch); + op1.setPath("/op1"); + StringCB op2 = new StringCB(zk, latch); + op2.setPath("/op2"); + StringCB op3 = new StringCB(zk, latch); + op3.setPath("/op3"); + + op1.create(); + op2.create(); + op3.create(); + + op1.verify(); + op2.verify(); + op3.verify(); + } + + @Test + public void testAsyncCreateFailure_NodeExists() { + 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 testAsyncDelete() { + new VoidCB(zk).verifyDelete(); + } + + @Test + public void testAsyncDeleteFailure_NoNode() { + 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(); + } + + @Test + public void testAsyncSetACL() { + new StatCB(zk).verifySetACL(); + } + + @Test + public void testAsyncSetACLFailure_NoNode() { + new StatCB(zk).verifySetACLFailure_NoNode(); + } + + @Test + public void testAsyncSetACLFailure_BadVersion() { + new StatCB(zk).verifySetACLFailure_BadVersion(); + } + + @Test + public void testAsyncSetData() { + new StatCB(zk).verifySetData(); + } + + @Test + public void testAsyncSetDataFailure_NoNode() { + new StatCB(zk).verifySetDataFailure_NoNode(); + } + + @Test + public void testAsyncSetDataFailure_BadVersion() { + new StatCB(zk).verifySetDataFailure_BadVersion(); + } + + @Test + public void testAsyncExists() { + new StatCB(zk).verifyExists(); + } + + @Test + public void testAsyncExistsFailure_NoNode() { + new StatCB(zk).verifyExistsFailure_NoNode(); + } + + @Test + public void testAsyncGetACL() { + new ACLCB(zk).verifyGetACL(); + } + + @Test + public void testAsyncGetACLFailure_NoNode() { + new ACLCB(zk).verifyGetACLFailure_NoNode(); + } + + @Test + public void testAsyncGetChildrenEmpty() { + new ChildrenCB(zk).verifyGetChildrenEmpty(); + } + + @Test + public void testAsyncGetChildrenSingle() { + new ChildrenCB(zk).verifyGetChildrenSingle(); + } + + @Test + public void testAsyncGetChildrenTwo() { + new ChildrenCB(zk).verifyGetChildrenTwo(); + } + + @Test + public void testAsyncGetChildrenFailure_NoNode() { + new ChildrenCB(zk).verifyGetChildrenFailure_NoNode(); + } + + @Test + public void testAsyncGetChildren2Empty() { + new Children2CB(zk).verifyGetChildrenEmpty(); + } + + @Test + public void testAsyncGetChildren2Single() { + new Children2CB(zk).verifyGetChildrenSingle(); + } + + @Test + public void testAsyncGetChildren2Two() { + new Children2CB(zk).verifyGetChildrenTwo(); + } + + @Test + public void testAsyncGetChildren2Failure_NoNode() { + new Children2CB(zk).verifyGetChildrenFailure_NoNode(); + } + + @Test + public void testAsyncGetData() { + new DataCB(zk).verifyGetData(); + } + + @Test + public void testAsyncGetDataFailure_NoNode() { + new DataCB(zk).verifyGetDataFailure_NoNode(); + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncTest.java new file mode 100644 index 0000000..2182032 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AsyncTest.java @@ -0,0 +1,172 @@ +/** + * 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 static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT; + +import java.io.IOException; +import java.util.LinkedList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.ZKTestCase; +import org.apache.zookeeper.ZooKeeper; +import org.apache.zookeeper.AsyncCallback.DataCallback; +import org.apache.zookeeper.AsyncCallback.StringCallback; +import org.apache.zookeeper.AsyncCallback.VoidCallback; +import org.apache.zookeeper.KeeperException.Code; +import org.apache.zookeeper.Watcher.Event.KeeperState; +import org.apache.zookeeper.ZooDefs.Ids; +import org.apache.zookeeper.data.Stat; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class AsyncTest extends ZKTestCase + implements StringCallback, VoidCallback, DataCallback +{ + private static final Logger LOG = LoggerFactory.getLogger(AsyncTest.class); + + private QuorumBase qb = new QuorumBase(); + + @Before + public void setUp() throws Exception { + qb.setUp(); + } + + public void restart() throws Exception { + JMXEnv.setUp(); + qb.startServers(); + } + + @After + public void tearDown() throws Exception { + LOG.info("Test clients shutting down"); + qb.tearDown(); + } + + private static class CountdownWatcher implements Watcher { + volatile CountDownLatch clientConnected = new CountDownLatch(1); + + public void process(WatchedEvent event) { + if (event.getState() == KeeperState.SyncConnected) { + clientConnected.countDown(); + } + } + } + + private ZooKeeper createClient() throws IOException,InterruptedException { + return createClient(qb.hostPort); + } + + private ZooKeeper createClient(String hp) + throws IOException, InterruptedException + { + CountdownWatcher watcher = new CountdownWatcher(); + ZooKeeper zk = new ZooKeeper(hp, CONNECTION_TIMEOUT, watcher); + if(!watcher.clientConnected.await(CONNECTION_TIMEOUT, + TimeUnit.MILLISECONDS)) + { + Assert.fail("Unable to connect to server"); + } + return zk; + } + + LinkedList<Integer> results = new LinkedList<Integer>(); + @Test + public void testAsync() + throws IOException, InterruptedException, KeeperException + { + ZooKeeper zk = null; + zk = createClient(); + try { + zk.addAuthInfo("digest", "ben:passwd".getBytes()); + zk.create("/ben", new byte[0], Ids.READ_ACL_UNSAFE, CreateMode.PERSISTENT, this, results); + zk.create("/ben/2", new byte[0], Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT, this, results); + zk.delete("/ben", -1, this, results); + zk.create("/ben2", new byte[0], Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT, this, results); + zk.getData("/ben2", false, this, results); + synchronized (results) { + while (results.size() < 5) { + results.wait(); + } + } + Assert.assertEquals(0, (int) results.get(0)); + Assert.assertEquals(Code.NOAUTH, Code.get(results.get(1))); + Assert.assertEquals(0, (int) results.get(2)); + Assert.assertEquals(0, (int) results.get(3)); + Assert.assertEquals(0, (int) results.get(4)); + } finally { + zk.close(); + } + + zk = createClient(); + try { + zk.addAuthInfo("digest", "ben:passwd2".getBytes()); + try { + zk.getData("/ben2", false, new Stat()); + Assert.fail("Should have received a permission error"); + } catch (KeeperException e) { + Assert.assertEquals(Code.NOAUTH, e.code()); + } + } finally { + zk.close(); + } + + zk = createClient(); + try { + zk.addAuthInfo("digest", "ben:passwd".getBytes()); + zk.getData("/ben2", false, new Stat()); + } finally { + zk.close(); + } + } + + @SuppressWarnings("unchecked") + public void processResult(int rc, String path, Object ctx, String name) { + synchronized(ctx) { + ((LinkedList<Integer>)ctx).add(rc); + ctx.notifyAll(); + } + } + + @SuppressWarnings("unchecked") + public void processResult(int rc, String path, Object ctx) { + synchronized(ctx) { + ((LinkedList<Integer>)ctx).add(rc); + ctx.notifyAll(); + } + } + + @SuppressWarnings("unchecked") + public void processResult(int rc, String path, Object ctx, byte[] data, + Stat stat) { + synchronized(ctx) { + ((LinkedList<Integer>)ctx).add(rc); + ctx.notifyAll(); + } + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/AtomicFileOutputStreamTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AtomicFileOutputStreamTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AtomicFileOutputStreamTest.java new file mode 100644 index 0000000..cbd2b77 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AtomicFileOutputStreamTest.java @@ -0,0 +1,200 @@ +/** + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.zookeeper.ZKTestCase; +import org.apache.zookeeper.common.AtomicFileOutputStream; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AtomicFileOutputStreamTest extends ZKTestCase { + private static final String TEST_STRING = "hello world"; + private static final String TEST_STRING_2 = "goodbye world"; + + private File testDir; + private File dstFile; + + @Before + public void setupTestDir() throws IOException { + testDir = ClientBase.createEmptyTestDir(); + dstFile = new File(testDir, "test.txt"); + } + @After + public void cleanupTestDir() throws IOException { + ClientBase.recursiveDelete(testDir); + } + + /** + * Test case where there is no existing file + */ + @Test + public void testWriteNewFile() throws IOException { + OutputStream fos = new AtomicFileOutputStream(dstFile); + assertFalse(dstFile.exists()); + fos.write(TEST_STRING.getBytes()); + fos.flush(); + assertFalse(dstFile.exists()); + fos.close(); + assertTrue(dstFile.exists()); + + String readBackData = ClientBase.readFile(dstFile); + assertEquals(TEST_STRING, readBackData); + } + + /** + * Test case where there is no existing file + */ + @Test + public void testOverwriteFile() throws IOException { + assertTrue("Creating empty dst file", dstFile.createNewFile()); + + OutputStream fos = new AtomicFileOutputStream(dstFile); + + assertTrue("Empty file still exists", dstFile.exists()); + fos.write(TEST_STRING.getBytes()); + fos.flush(); + + // Original contents still in place + assertEquals("", ClientBase.readFile(dstFile)); + + fos.close(); + + // New contents replace original file + String readBackData = ClientBase.readFile(dstFile); + assertEquals(TEST_STRING, readBackData); + } + + /** + * Test case where the flush() fails at close time - make sure that we clean + * up after ourselves and don't touch any existing file at the destination + */ + @Test + public void testFailToFlush() throws IOException { + // Create a file at destination + FileOutputStream fos = new FileOutputStream(dstFile); + fos.write(TEST_STRING_2.getBytes()); + fos.close(); + + OutputStream failingStream = createFailingStream(); + failingStream.write(TEST_STRING.getBytes()); + try { + failingStream.close(); + fail("Close didn't throw exception"); + } catch (IOException ioe) { + // expected + } + + // Should not have touched original file + assertEquals(TEST_STRING_2, ClientBase.readFile(dstFile)); + + assertEquals("Temporary file should have been cleaned up", + dstFile.getName(), ClientBase.join(",", testDir.list())); + } + + /** + * Create a stream that fails to flush at close time + */ + private OutputStream createFailingStream() throws FileNotFoundException { + return new AtomicFileOutputStream(dstFile) { + @Override + public void flush() throws IOException { + throw new IOException("injected failure"); + } + }; + } + + /** + * Ensure the tmp file is cleaned up and dstFile is not created when + * aborting a new file. + */ + @Test + public void testAbortNewFile() throws IOException { + AtomicFileOutputStream fos = new AtomicFileOutputStream(dstFile); + + fos.abort(); + + assertEquals(0, testDir.list().length); + } + + /** + * Ensure the tmp file is cleaned up and dstFile is not created when + * aborting a new file. + */ + @Test + public void testAbortNewFileAfterFlush() throws IOException { + AtomicFileOutputStream fos = new AtomicFileOutputStream(dstFile); + fos.write(TEST_STRING.getBytes()); + fos.flush(); + + fos.abort(); + + assertEquals(0, testDir.list().length); + } + + /** + * Ensure the tmp file is cleaned up and dstFile is untouched when + * aborting an existing file overwrite. + */ + @Test + public void testAbortExistingFile() throws IOException { + FileOutputStream fos1 = new FileOutputStream(dstFile); + fos1.write(TEST_STRING.getBytes()); + fos1.close(); + + AtomicFileOutputStream fos2 = new AtomicFileOutputStream(dstFile); + + fos2.abort(); + + // Should not have touched original file + assertEquals(TEST_STRING, ClientBase.readFile(dstFile)); + assertEquals(1, testDir.list().length); + } + + /** + * Ensure the tmp file is cleaned up and dstFile is untouched when + * aborting an existing file overwrite. + */ + @Test + public void testAbortExistingFileAfterFlush() throws IOException { + FileOutputStream fos1 = new FileOutputStream(dstFile); + fos1.write(TEST_STRING.getBytes()); + fos1.close(); + + AtomicFileOutputStream fos2 = new AtomicFileOutputStream(dstFile); + fos2.write(TEST_STRING_2.getBytes()); + fos2.flush(); + + fos2.abort(); + + // Should not have touched original file + assertEquals(TEST_STRING, ClientBase.readFile(dstFile)); + assertEquals(1, testDir.list().length); + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthTest.java new file mode 100644 index 0000000..60e3453 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthTest.java @@ -0,0 +1,174 @@ +/** + * 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.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.TestableZooKeeper; +import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.Watcher.Event.KeeperState; +import org.apache.zookeeper.ZooDefs.Ids; +import org.apache.zookeeper.ZooKeeper; +import org.junit.Assert; +import org.junit.Test; + +public class AuthTest extends ClientBase { + static { + // password is test + System.setProperty("zookeeper.DigestAuthenticationProvider.superDigest", + "super:D/InIHSb7yEEbrWz8b9l71RjZJU="); + System.setProperty("zookeeper.authProvider.1", "org.apache.zookeeper.test.InvalidAuthProvider"); + } + + private final CountDownLatch authFailed = new CountDownLatch(1); + + @Override + protected TestableZooKeeper createClient(String hp) + throws IOException, InterruptedException + { + MyWatcher watcher = new MyWatcher(); + return createClient(watcher, hp); + } + + private class MyWatcher extends CountdownWatcher { + @Override + public synchronized void process(WatchedEvent event) { + if (event.getState() == KeeperState.AuthFailed) { + authFailed.countDown(); + } + else { + super.process(event); + } + } + } + + @Test + public void testBadAuthNotifiesWatch() throws Exception { + ZooKeeper zk = createClient(); + try { + zk.addAuthInfo("FOO", "BAR".getBytes()); + zk.getData("/path1", false, null); + Assert.fail("Should get auth state error"); + } catch(KeeperException.AuthFailedException e) { + if(!authFailed.await(CONNECTION_TIMEOUT, + TimeUnit.MILLISECONDS)) + { + Assert.fail("Should have called my watcher"); + } + } + finally { + zk.close(); + } + } + + @Test + public void testBadAuthThenSendOtherCommands() throws Exception { + ZooKeeper zk = createClient(); + try { + zk.addAuthInfo("INVALID", "BAR".getBytes()); + zk.exists("/foobar", false); + zk.getData("/path1", false, null); + Assert.fail("Should get auth state error"); + } catch(KeeperException.AuthFailedException e) { + if(!authFailed.await(CONNECTION_TIMEOUT, + TimeUnit.MILLISECONDS)) + { + Assert.fail("Should have called my watcher"); + } + } + finally { + zk.close(); + } + } + + + @Test + public void testSuper() throws Exception { + ZooKeeper zk = createClient(); + try { + zk.addAuthInfo("digest", "pat:pass".getBytes()); + zk.create("/path1", null, Ids.CREATOR_ALL_ACL, + CreateMode.PERSISTENT); + zk.close(); + // verify no auth + zk = createClient(); + try { + zk.getData("/path1", false, null); + Assert.fail("auth verification"); + } catch (KeeperException.NoAuthException e) { + // expected + } + zk.close(); + // verify bad pass Assert.fails + zk = createClient(); + zk.addAuthInfo("digest", "pat:pass2".getBytes()); + try { + zk.getData("/path1", false, null); + Assert.fail("auth verification"); + } catch (KeeperException.NoAuthException e) { + // expected + } + zk.close(); + // verify super with bad pass Assert.fails + zk = createClient(); + zk.addAuthInfo("digest", "super:test2".getBytes()); + try { + zk.getData("/path1", false, null); + Assert.fail("auth verification"); + } catch (KeeperException.NoAuthException e) { + // expected + } + zk.close(); + // verify super with correct pass success + zk = createClient(); + zk.addAuthInfo("digest", "super:test".getBytes()); + zk.getData("/path1", false, null); + } finally { + zk.close(); + } + } + + @Test + public void testSuperACL() throws Exception { + ZooKeeper zk = createClient(); + try { + zk.addAuthInfo("digest", "pat:pass".getBytes()); + zk.create("/path1", null, Ids.CREATOR_ALL_ACL, + CreateMode.PERSISTENT); + zk.close(); + // verify super can do anything and ignores ACLs + zk = createClient(); + zk.addAuthInfo("digest", "super:test".getBytes()); + zk.getData("/path1", false, null); + + zk.setACL("/path1", Ids.READ_ACL_UNSAFE, -1); + zk.create("/path1/foo", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT); + + + zk.setACL("/path1", Ids.OPEN_ACL_UNSAFE, -1); + + } finally { + zk.close(); + } + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/BufferSizeTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/BufferSizeTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/BufferSizeTest.java new file mode 100644 index 0000000..6d74e54 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/BufferSizeTest.java @@ -0,0 +1,132 @@ +/** + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; + +import org.apache.jute.BinaryInputArchive; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.ZooDefs.Ids; +import org.apache.zookeeper.ZooKeeper; +import org.junit.Before; +import org.junit.Test; + +public class BufferSizeTest extends ClientBase { + public static final int TEST_MAXBUFFER = 100; + private static final File TEST_DATA = new File( + System.getProperty("test.data.dir", "build/test/data"), + "buffersize"); + + private ZooKeeper zk; + + @Before + public void setMaxBuffer() throws IOException, InterruptedException { + System.setProperty("jute.maxbuffer", "" + TEST_MAXBUFFER); + assertEquals("Can't set jute.maxbuffer!", TEST_MAXBUFFER, BinaryInputArchive.maxBuffer); + zk = createClient(); + } + + @Test + public void testCreatesReqs() throws Exception { + testRequests(new ClientOp() { + @Override + public void execute(byte[] data) throws Exception { + zk.create("/create_test", data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); + } + }); + } + + @Test + public void testSetReqs() throws Exception { + final String path = "/set_test"; + zk.create(path, new byte[1], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); + testRequests(new ClientOp() { + @Override + public void execute(byte[] data) throws Exception { + zk.setData(path, data, -1); + } + }); + } + + /** Issues requests containing data smaller, equal, and greater than TEST_MAXBUFFER. */ + private void testRequests(ClientOp clientOp) throws Exception { + clientOp.execute(new byte[TEST_MAXBUFFER - 60]); + try { + // This should fail since the buffer size > the data size due to extra fields + clientOp.execute(new byte[TEST_MAXBUFFER]); + fail("Request exceeding jute.maxbuffer succeeded!"); + } catch (KeeperException.ConnectionLossException e) {} + try { + clientOp.execute(new byte[TEST_MAXBUFFER + 10]); + fail("Request exceeding jute.maxbuffer succeeded!"); + } catch (KeeperException.ConnectionLossException e) {} + } + + private interface ClientOp { + void execute(byte[] data) throws Exception; + } + + @Test + public void testStartup() throws Exception { + final String path = "/test_node"; + zk.create(path, new byte[TEST_MAXBUFFER - 60], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); + zk.setData(path, new byte[TEST_MAXBUFFER - 50], -1); + + stopServer(); + startServer(); + } + + @Test + public void testStartupFailureCreate() throws Exception { + // Empty snapshot and logfile containing a 5000-byte create + testStartupFailure(new File(TEST_DATA, "create"), + "Server started despite create exceeding jute.maxbuffer!"); + } + + @Test + public void testStartupFailureSet() throws Exception { + // Empty snapshot and logfile containing a 1-byte create and 5000-byte set + testStartupFailure(new File(TEST_DATA, "set"), + "Server started despite set exceeding jute.maxbuffer!"); + } + + @Test + public void testStartupFailureSnapshot() throws Exception { + // Snapshot containing 5000-byte znode and logfile containing create txn + testStartupFailure(new File(TEST_DATA, "snapshot"), + "Server started despite znode exceeding jute.maxbuffer!"); + } + + private void testStartupFailure(File testDir, String failureMsg) throws Exception { + stopServer(); + // Point server at testDir + tmpDir = testDir; + try { + startServer(); + fail(failureMsg); + } catch (IOException e) { + LOG.info("Successfully caught IOException: " + e); + } + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootAsyncTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootAsyncTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootAsyncTest.java new file mode 100644 index 0000000..e60ea04 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootAsyncTest.java @@ -0,0 +1,47 @@ +/** + * 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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.ZooKeeper; +import org.apache.zookeeper.ZooDefs.Ids; + +public class ChrootAsyncTest extends AsyncOpsTest { + private static final Logger LOG = LoggerFactory.getLogger(ChrootAsyncTest.class); + + @Override + public void setUp() throws Exception { + String hp = hostPort; + hostPort = hostPort + "/chrootasynctest"; + + super.setUp(); + + LOG.info("Creating client " + getTestName()); + + ZooKeeper zk = createClient(hp); + try { + zk.create("/chrootasynctest", null, Ids.OPEN_ACL_UNSAFE, + CreateMode.PERSISTENT); + } finally { + zk.close(); + } + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootClientTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootClientTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootClientTest.java new file mode 100644 index 0000000..e0286e1 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootClientTest.java @@ -0,0 +1,54 @@ +/** + * 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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.ZooKeeper; +import org.apache.zookeeper.ZooDefs.Ids; +import org.junit.Test; + +public class ChrootClientTest extends ClientTest { + private static final Logger LOG = LoggerFactory.getLogger(ChrootClientTest.class); + + @Override + public void setUp() throws Exception { + String hp = hostPort; + hostPort = hostPort + "/chrootclienttest"; + + System.out.println(hostPort); + super.setUp(); + + LOG.info("STARTING " + getTestName()); + + ZooKeeper zk = createClient(hp); + try { + zk.create("/chrootclienttest", null, Ids.OPEN_ACL_UNSAFE, + CreateMode.PERSISTENT); + } finally { + zk.close(); + } + } + + @Test + public void testPing() throws Exception { + // not necessary to repeat this, expensive and not chroot related + } +} http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootTest.java ---------------------------------------------------------------------- diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootTest.java new file mode 100644 index 0000000..3df068b --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ChrootTest.java @@ -0,0 +1,136 @@ +/** + * 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.Arrays; +import java.util.concurrent.CountDownLatch; +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.ZooDefs.Ids; +import org.junit.Assert; +import org.junit.Test; + +public class ChrootTest extends ClientBase { + private class MyWatcher implements Watcher { + private final String path; + private String eventPath; + private CountDownLatch latch = new CountDownLatch(1); + + public MyWatcher(String path) { + this.path = path; + } + public void process(WatchedEvent event) { + System.out.println("latch:" + path + " " + event.getPath()); + this.eventPath = event.getPath(); + latch.countDown(); + } + public boolean matches() throws InterruptedException { + if (!latch.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)) { + Assert.fail("No watch received within timeout period " + path); + } + return path.equals(eventPath); + } + } + + @Test + public void testChrootSynchronous() + throws IOException, InterruptedException, KeeperException + { + ZooKeeper zk1 = createClient(); + try { + zk1.create("/ch1", null, Ids.OPEN_ACL_UNSAFE, + CreateMode.PERSISTENT); + } finally { + if(zk1 != null) + zk1.close(); + } + ZooKeeper zk2 = createClient(hostPort + "/ch1"); + try { + Assert.assertEquals("/ch2", + zk2.create("/ch2", null, Ids.OPEN_ACL_UNSAFE, + CreateMode.PERSISTENT)); + } finally { + if(zk2 != null) + zk2.close(); + } + + zk1 = createClient(); + zk2 = createClient(hostPort + "/ch1"); + try { + // check get + MyWatcher w1 = new MyWatcher("/ch1"); + Assert.assertNotNull(zk1.exists("/ch1", w1)); + MyWatcher w2 = new MyWatcher("/ch1/ch2"); + Assert.assertNotNull(zk1.exists("/ch1/ch2", w2)); + + MyWatcher w3 = new MyWatcher("/ch2"); + Assert.assertNotNull(zk2.exists("/ch2", w3)); + + // set watches on child + MyWatcher w4 = new MyWatcher("/ch1"); + zk1.getChildren("/ch1",w4); + MyWatcher w5 = new MyWatcher("/"); + zk2.getChildren("/",w5); + + // check set + zk1.setData("/ch1", "1".getBytes(), -1); + zk2.setData("/ch2", "2".getBytes(), -1); + + // check watches + Assert.assertTrue(w1.matches()); + Assert.assertTrue(w2.matches()); + Assert.assertTrue(w3.matches()); + + // check exceptions + try { + zk2.setData("/ch3", "3".getBytes(), -1); + } catch (KeeperException.NoNodeException e) { + Assert.assertEquals("/ch3", e.getPath()); + } + + Assert.assertTrue(Arrays.equals("1".getBytes(), + zk1.getData("/ch1", false, null))); + Assert.assertTrue(Arrays.equals("2".getBytes(), + zk1.getData("/ch1/ch2", false, null))); + Assert.assertTrue(Arrays.equals("2".getBytes(), + zk2.getData("/ch2", false, null))); + + // check delete + zk2.delete("/ch2", -1); + Assert.assertTrue(w4.matches()); + Assert.assertTrue(w5.matches()); + + zk1.delete("/ch1", -1); + Assert.assertNull(zk1.exists("/ch1", false)); + Assert.assertNull(zk1.exists("/ch1/ch2", false)); + Assert.assertNull(zk2.exists("/ch2", false)); + } finally { + if(zk1 != null) + zk1.close(); + if(zk2 != null) + zk2.close(); + } + } +}