zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From an...@apache.org
Subject [11/51] [partial] zookeeper git commit: ZOOKEEPER-3032: MAVEN MIGRATION - branch-3.5 - zookeeper-server
Date Wed, 24 Oct 2018 09:31:06 GMT
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/43d71c2e/zookeeper-server/src/test/java/org/apache/zookeeper/ZooKeeperTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/ZooKeeperTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/ZooKeeperTest.java
new file mode 100644
index 0000000..f8be441
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/ZooKeeperTest.java
@@ -0,0 +1,594 @@
+/**
+ * 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;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.zookeeper.AsyncCallback.VoidCallback;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.cli.*;
+import org.apache.zookeeper.common.StringUtils;
+import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.test.ClientBase;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ * Testing ZooKeeper public methods
+ *
+ */
+public class ZooKeeperTest extends ClientBase {
+
+    private static final String LINE_SEPARATOR = System.getProperty("line.separator", "\n");
+
+    @Test
+    public void testDeleteRecursive() throws IOException, InterruptedException, CliException, KeeperException {
+        final ZooKeeper zk = createClient();
+        // making sure setdata works on /
+        zk.setData("/", "some".getBytes(), -1);
+        zk.create("/a", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/b", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/b/v", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/b/v/1", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/c", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/c/v", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        List<String> children = zk.getChildren("/a", false);
+
+        Assert.assertEquals("2 children - b & c should be present ", children
+                .size(), 2);
+        Assert.assertTrue(children.contains("b"));
+        Assert.assertTrue(children.contains("c"));
+
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        // 'rmr' is deprecated, so the test here is just for backwards
+        // compatibility.
+        String cmdstring0 = "rmr /a/b/v";
+        String cmdstring1 = "deleteall /a";
+        zkMain.cl.parseCommand(cmdstring0);
+        Assert.assertFalse(zkMain.processZKCmd(zkMain.cl));
+        Assert.assertEquals(null, zk.exists("/a/b/v", null));
+        zkMain.cl.parseCommand(cmdstring1);
+        Assert.assertFalse(zkMain.processZKCmd(zkMain.cl));
+        Assert.assertNull(zk.exists("/a", null));
+    }
+
+    @Test
+    public void testDeleteRecursiveAsync() throws IOException,
+            InterruptedException, KeeperException {
+        final ZooKeeper zk = createClient();
+        // making sure setdata works on /
+        zk.setData("/", "some".getBytes(), -1);
+        zk.create("/a", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/b", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/b/v", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/b/v/1", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/c", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        zk.create("/a/c/v", "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        for (int i = 0; i < 50; ++i) {
+            zk.create("/a/c/" + i, "some".getBytes(), Ids.OPEN_ACL_UNSAFE,
+                    CreateMode.PERSISTENT);
+        }
+        List<String> children = zk.getChildren("/a", false);
+
+        Assert.assertEquals("2 children - b & c should be present ", children
+                .size(), 2);
+        Assert.assertTrue(children.contains("b"));
+        Assert.assertTrue(children.contains("c"));
+
+        VoidCallback cb = new VoidCallback() {
+
+            @Override
+            public void processResult(int rc, String path, Object ctx) {
+                synchronized (ctx) {
+                    ((AtomicInteger) ctx).set(4);
+                    ctx.notify();
+                }
+            }
+
+        };
+        final AtomicInteger ctx = new AtomicInteger(3);
+        ZKUtil.deleteRecursive(zk, "/a", cb, ctx);
+        synchronized (ctx) {
+            ctx.wait();
+        }
+        Assert.assertEquals(4, ((AtomicInteger) ctx).get());
+    }
+
+    @Test
+    public void testStatWhenPathDoesNotExist() throws IOException,
+    		InterruptedException, MalformedCommandException {
+    	final ZooKeeper zk = createClient();
+    	ZooKeeperMain main = new ZooKeeperMain(zk);
+    	String cmdstring = "stat /invalidPath";
+    	main.cl.parseCommand(cmdstring);
+    	try {
+    		main.processZKCmd(main.cl);
+    		Assert.fail("As Node does not exist, command should fail by throwing No Node Exception.");
+    	} catch (CliException e) {
+    		Assert.assertEquals("Node does not exist: /invalidPath", e.getMessage());
+    	}
+    }
+
+    @Test
+    public void testParseWithExtraSpaces() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmdstring = "      ls       /  ";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertEquals("Spaces also considered as characters", zkMain.cl.getNumArguments(), 2);
+        Assert.assertEquals("ls is not taken as first argument", zkMain.cl.getCmdArgument(0), "ls");
+        Assert.assertEquals("/ is not taken as second argument", zkMain.cl.getCmdArgument(1), "/");
+    }
+
+    @Test
+    public void testParseWithQuotes() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        for (String quoteChar : new String[] {"'", "\""}) {
+            String cmdstring = String.format("create /node %1$squoted data%1$s", quoteChar);
+            zkMain.cl.parseCommand(cmdstring);
+            Assert.assertEquals("quotes combine arguments", zkMain.cl.getNumArguments(), 3);
+            Assert.assertEquals("create is not taken as first argument", zkMain.cl.getCmdArgument(0), "create");
+            Assert.assertEquals("/node is not taken as second argument", zkMain.cl.getCmdArgument(1), "/node");
+            Assert.assertEquals("quoted data is not taken as third argument", zkMain.cl.getCmdArgument(2), "quoted data");
+        }
+    }
+
+    @Test
+    public void testParseWithMixedQuotes() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        for (String[] quoteChars : new String[][] {{"'", "\""}, {"\"", "'"}}) {
+            String outerQuotes = quoteChars[0];
+            String innerQuotes = quoteChars[1];
+            String cmdstring = String.format("create /node %1$s%2$squoted data%2$s%1$s", outerQuotes, innerQuotes);
+            zkMain.cl.parseCommand(cmdstring);
+            Assert.assertEquals("quotes combine arguments", zkMain.cl.getNumArguments(), 3);
+            Assert.assertEquals("create is not taken as first argument", zkMain.cl.getCmdArgument(0), "create");
+            Assert.assertEquals("/node is not taken as second argument", zkMain.cl.getCmdArgument(1), "/node");
+            Assert.assertEquals("quoted data is not taken as third argument", zkMain.cl.getCmdArgument(2), innerQuotes + "quoted data" + innerQuotes);
+        }
+    }
+
+    @Test
+    public void testParseWithEmptyQuotes() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmdstring = "create /node ''";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertEquals("empty quotes should produce arguments", zkMain.cl.getNumArguments(), 3);
+        Assert.assertEquals("create is not taken as first argument", zkMain.cl.getCmdArgument(0), "create");
+        Assert.assertEquals("/node is not taken as second argument", zkMain.cl.getCmdArgument(1), "/node");
+        Assert.assertEquals("empty string is not taken as third argument", zkMain.cl.getCmdArgument(2), "");
+    }
+
+    @Test
+    public void testParseWithMultipleQuotes() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmdstring = "create /node '' ''";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertEquals("expected 5 arguments", zkMain.cl.getNumArguments(), 4);
+        Assert.assertEquals("create is not taken as first argument", zkMain.cl.getCmdArgument(0), "create");
+        Assert.assertEquals("/node is not taken as second argument", zkMain.cl.getCmdArgument(1), "/node");
+        Assert.assertEquals("empty string is not taken as third argument", zkMain.cl.getCmdArgument(2), "");
+        Assert.assertEquals("empty string is not taken as fourth argument", zkMain.cl.getCmdArgument(3), "");
+    }
+
+    @Test
+    public void testNonexistantCommand() throws Exception {
+      testInvalidCommand("cret -s /node1", 127);
+    }
+
+    @Test
+    public void testCreateCommandWithoutPath() throws Exception {
+        testInvalidCommand("create", 1);
+    }
+
+    @Test
+    public void testCreateEphemeralCommandWithoutPath() throws Exception {
+        testInvalidCommand("create -e ", 1);
+    }
+
+    @Test
+    public void testCreateSequentialCommandWithoutPath() throws Exception {
+        testInvalidCommand("create -s ", 1);
+    }
+
+    @Test
+    public void testCreateEphemeralSequentialCommandWithoutPath() throws Exception {
+        testInvalidCommand("create -s -e ", 1);
+    }
+
+    private void testInvalidCommand(String cmdString, int exitCode) throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        zkMain.cl.parseCommand(cmdString);
+
+        // Verify that the exit code is set properly
+        zkMain.processCmd(zkMain.cl);
+        Assert.assertEquals(exitCode, zkMain.exitCode);
+
+        // Verify that the correct exception is thrown
+        try {
+          zkMain.processZKCmd(zkMain.cl);
+          Assert.fail();
+        } catch (CliException e) {
+          return;
+        }
+        Assert.fail("invalid command should throw CliException");
+    }
+
+    @Test
+    public void testCreateNodeWithoutData() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        // create persistent sequential node
+        String cmdstring = "create -s /node ";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertTrue("Doesn't create node without data", zkMain
+                .processZKCmd(zkMain.cl));
+        // create ephemeral node
+        cmdstring = "create  -e /node ";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertTrue("Doesn't create node without data", zkMain
+                .processZKCmd(zkMain.cl));
+        // create ephemeral sequential node
+        cmdstring = "create -s -e /node ";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertTrue("Doesn't create node without data", zkMain
+                .processZKCmd(zkMain.cl));
+        // creating ephemeral with wrong option.
+        cmdstring = "create -s y /node";
+        zkMain.cl.parseCommand(cmdstring);
+        try {
+            Assert.assertTrue("Created node with wrong option", zkMain
+                    .processZKCmd(zkMain.cl));
+            Assert.fail("Created the node with wrong option should "
+                    + "throw Exception.");
+        } catch (MalformedPathException e) {
+            Assert.assertEquals("Path must start with / character", e
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void testACLWithExtraAgruments() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        // create persistent sequential node
+        String cmdstring = "create -s /l data ip:10.18.52.144:cdrwa f g h";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertTrue(
+                "Not considering the extra arguments after the acls.", zkMain
+                        .processZKCmd(zkMain.cl));
+    }
+
+    @Test
+    public void testCreatePersistentNode() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmdstring = "create /node2";
+        zkMain.cl.parseCommand(cmdstring);
+        Assert.assertTrue("Not creating Persistent node.", zkMain
+                .processZKCmd(zkMain.cl));
+    }
+
+    @Test
+    public void testDelete() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmdstring1 = "create -e /node2 data";
+        String cmdstring2 = "delete /node2";
+        String cmdstring3 = "ls /node2";
+        zkMain.cl.parseCommand(cmdstring1);
+        Assert.assertTrue(zkMain.processZKCmd(zkMain.cl));
+        zkMain.cl.parseCommand(cmdstring2);
+        Assert.assertFalse(zkMain.processZKCmd(zkMain.cl));
+        zkMain.cl.parseCommand(cmdstring3);
+        Assert.assertFalse("", zkMain.processCmd(zkMain.cl));
+    }
+
+    @Test
+    public void testDeleteNonexistantNode() throws Exception {
+        testInvalidCommand("delete /blahblahblah", 1);
+    }
+
+    @Test
+    public void testStatCommand() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmdstring1 = "create -e /node3 data";
+        String cmdstring2 = "stat /node3";
+        String cmdstring3 = "delete /node3";
+        zkMain.cl.parseCommand(cmdstring1);
+        Assert.assertTrue(zkMain.processZKCmd(zkMain.cl));
+        zkMain.cl.parseCommand(cmdstring2);
+        Assert.assertFalse(zkMain.processZKCmd(zkMain.cl));
+        zkMain.cl.parseCommand(cmdstring3);
+        Assert.assertFalse(zkMain.processZKCmd(zkMain.cl));
+    }
+
+    @Test
+    public void testInvalidStatCommand() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        // node doesn't exists
+        String cmdstring1 = "stat /node123";
+        zkMain.cl.parseCommand(cmdstring1);
+        try {
+            Assert.assertFalse(zkMain.processZKCmd(zkMain.cl));
+            Assert.fail("Path doesn't exists so, command should fail.");
+        } catch (CliWrapperException e) {
+            Assert.assertEquals(KeeperException.Code.NONODE, ((KeeperException)e.getCause()).code());
+        }
+    }
+
+    @Test
+    public void testSetData() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmdstring1 = "create -e /node4 data";
+        String cmdstring2 = "set /node4 " + "data";
+        String cmdstring3 = "delete /node4";
+        Stat stat = new Stat();
+        int version = 0;
+        zkMain.cl.parseCommand(cmdstring1);
+        Assert.assertTrue(zkMain.processZKCmd(zkMain.cl));
+        stat = zk.exists("/node4", true);
+        version = stat.getVersion();
+        zkMain.cl.parseCommand(cmdstring2);
+        Assert.assertFalse(zkMain.processZKCmd(zkMain.cl));
+        stat = zk.exists("/node4", true);
+        Assert.assertEquals(version + 1, stat.getVersion());
+        zkMain.cl.parseCommand(cmdstring3);
+        Assert.assertFalse(zkMain.processZKCmd(zkMain.cl));
+    }
+
+    @Test
+    public void testCheckInvalidAcls() throws Exception {
+         final ZooKeeper zk = createClient();
+            ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+            String cmdstring = "create -s -e /node data ip:scheme:gggsd"; //invalid acl's
+
+            // For Invalid ACls should not throw exception
+            zkMain.executeLine(cmdstring);
+    }
+
+    @Test
+    public void testDeleteWithInvalidVersionNo() throws Exception {
+         final ZooKeeper zk = createClient();
+            ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+            String cmdstring = "create -s -e /node1 data ";
+            String cmdstring1 = "delete /node1 2";//invalid dataversion no
+                 zkMain.executeLine(cmdstring);
+
+            // For Invalid dataversion number should not throw exception
+            zkMain.executeLine(cmdstring1);
+    }
+
+    @Test
+    public void testCliCommandsNotEchoingUsage() throws Exception {
+        // setup redirect out/err streams to get System.in/err, use this judiciously!
+        final PrintStream systemErr = System.err; // get current err
+        final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
+        System.setErr(new PrintStream(errContent));
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmd1 = "printwatches";
+        zkMain.executeLine(cmd1);
+        String cmd2 = "history";
+        zkMain.executeLine(cmd2);
+        String cmd3 = "redo";
+        zkMain.executeLine(cmd3);
+        // revert redirect of out/err streams - important step!
+        System.setErr(systemErr);
+        if (errContent.toString().contains("ZooKeeper -server host:port cmd args")) {
+            fail("CLI commands (history, redo, connect, printwatches) display usage info!");
+        }
+    }
+
+    // ZOOKEEPER-2467 : Testing negative number for redo command
+    @Test
+    public void testRedoWithNegativeCmdNumber() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String cmd1 = "redo -1";
+
+        // setup redirect out/err streams to get System.in/err, use this
+        // judiciously!
+        final PrintStream systemErr = System.err; // get current err
+        final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
+        System.setErr(new PrintStream(errContent));
+        try {
+            zkMain.executeLine(cmd1);
+            Assert.assertEquals("Command index out of range", errContent
+                    .toString().trim());
+        } finally {
+            // revert redirect of out/err streams - important step!
+            System.setErr(systemErr);
+        }
+    }
+
+    private static void runCommandExpect(CliCommand command, List<String> expectedResults)
+            throws Exception {
+        // call command and put result in byteStream
+        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+        PrintStream out = new PrintStream(byteStream);
+        command.setOut(out);
+        command.exec();
+
+        String result = byteStream.toString();
+        assertTrue(result, result.contains(
+                StringUtils.joinStrings(expectedResults, LINE_SEPARATOR)));
+    }
+
+    @Test
+    public void testSortedLs() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+
+        zkMain.executeLine("create /aa1");
+        zkMain.executeLine("create /aa2");
+        zkMain.executeLine("create /aa3");
+        zkMain.executeLine("create /test1");
+        zkMain.executeLine("create /zk1");
+
+        LsCommand cmd = new LsCommand();
+        cmd.setZk(zk);
+        cmd.parse("ls /".split(" "));
+        List<String> expected = new ArrayList<String>();
+        expected.add("[aa1, aa2, aa3, test1, zk1, zookeeper]");
+        runCommandExpect(cmd, expected);
+    }
+
+    @Test
+    public void testLsrCommand() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+
+        zkMain.executeLine("create /a");
+        zkMain.executeLine("create /a/b");
+        zkMain.executeLine("create /a/c");
+        zkMain.executeLine("create /a/b/d");
+        zkMain.executeLine("create /a/c/e");
+        zkMain.executeLine("create /a/f");
+
+        LsCommand cmd = new LsCommand();
+        cmd.setZk(zk);
+        cmd.parse("ls -R /a".split(" "));
+
+        List<String> expected = new ArrayList<String>();
+        expected.add("/a");
+        expected.add("/a/b");
+        expected.add("/a/c");
+        expected.add("/a/f");
+        expected.add("/a/b/d");
+        expected.add("/a/c/e");
+        runCommandExpect(cmd, expected);
+    }
+
+    @Test
+    public void testLsrRootCommand() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+
+        LsCommand cmd = new LsCommand();
+        cmd.setZk(zk);
+        cmd.parse("ls -R /".split(" "));
+
+        List<String> expected = new ArrayList<String>();
+        expected.add("/");
+        expected.add("/zookeeper");
+        runCommandExpect(cmd, expected);
+    }
+
+    @Test
+    public void testLsrLeafCommand() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+
+        zkMain.executeLine("create /b");
+        zkMain.executeLine("create /b/c");
+
+        LsCommand cmd = new LsCommand();
+        cmd.setZk(zk);
+        cmd.parse("ls -R /b/c".split(" "));
+
+        List<String> expected = new ArrayList<String>();
+        expected.add("/b/c");
+        runCommandExpect(cmd, expected);
+    }
+
+    @Test
+    public void testLsrNonexistantZnodeCommand() throws Exception {
+        final ZooKeeper zk = createClient();
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+
+        zkMain.executeLine("create /b");
+        zkMain.executeLine("create /b/c");
+
+        LsCommand cmd = new LsCommand();
+        cmd.setZk(zk);
+        cmd.parse("ls -R /b/c/d".split(" "));
+
+        try {
+            runCommandExpect(cmd, new ArrayList<String>());
+            Assert.fail("Path doesn't exists so, command should fail.");
+        } catch (CliWrapperException e) {
+            Assert.assertEquals(KeeperException.Code.NONODE, ((KeeperException)e.getCause()).code());
+        }
+    }
+
+    @Test
+    public void testSetAclRecursive() throws Exception {
+        final ZooKeeper zk = createClient();
+        final byte[] EMPTY = new byte[0];
+
+        zk.setData("/", EMPTY, -1);
+        zk.create("/a", EMPTY, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+        zk.create("/a/b", EMPTY, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+        zk.create("/a/b/c", EMPTY, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+        zk.create("/a/d", EMPTY, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+        zk.create("/e", EMPTY, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+
+        ZooKeeperMain zkMain = new ZooKeeperMain(zk);
+        String setAclCommand = "setAcl -R /a world:anyone:r";
+        zkMain.cl.parseCommand(setAclCommand);
+        Assert.assertFalse(zkMain.processZKCmd(zkMain.cl));
+
+        Assert.assertEquals(Ids.READ_ACL_UNSAFE, zk.getACL("/a", new Stat()));
+        Assert.assertEquals(Ids.READ_ACL_UNSAFE, zk.getACL("/a/b", new Stat()));
+        Assert.assertEquals(Ids.READ_ACL_UNSAFE, zk.getACL("/a/b/c", new Stat()));
+        Assert.assertEquals(Ids.READ_ACL_UNSAFE, zk.getACL("/a/d", new Stat()));
+        // /e is unset, its acl should remain the same.
+        Assert.assertEquals(Ids.OPEN_ACL_UNSAFE, zk.getACL("/e", new Stat()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/43d71c2e/zookeeper-server/src/test/java/org/apache/zookeeper/client/ZKClientConfigTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/client/ZKClientConfigTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/client/ZKClientConfigTest.java
new file mode 100644
index 0000000..98f7c51
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/client/ZKClientConfigTest.java
@@ -0,0 +1,191 @@
+/**
+ * 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.client;
+
+import static org.apache.zookeeper.client.ZKClientConfig.DISABLE_AUTO_WATCH_RESET;
+import static org.apache.zookeeper.client.ZKClientConfig.ENABLE_CLIENT_SASL_KEY;
+import static org.apache.zookeeper.client.ZKClientConfig.LOGIN_CONTEXT_NAME_KEY;
+import static org.apache.zookeeper.client.ZKClientConfig.SECURE_CLIENT;
+import static org.apache.zookeeper.client.ZKClientConfig.ZK_SASL_CLIENT_USERNAME;
+import static org.apache.zookeeper.client.ZKClientConfig.ZOOKEEPER_CLIENT_CNXN_SOCKET;
+import static org.apache.zookeeper.client.ZKClientConfig.ZOOKEEPER_SERVER_REALM;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.zookeeper.common.ZKConfig;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.Timeout;
+
+public class ZKClientConfigTest {
+    private static final File testData = new File(System.getProperty("test.data.dir", "build/test/data"));
+    @Rule
+    public Timeout timeout = new Timeout(10, TimeUnit.SECONDS);
+
+    @BeforeClass
+    public static void init() {
+        if (!testData.exists()) {
+            testData.mkdirs();
+        }
+    }
+
+    @Test
+    public void testDefaultConfiguration() {
+        Map<String, String> properties = new HashMap<>();
+        properties.put(ZK_SASL_CLIENT_USERNAME, "zookeeper1");
+        properties.put(LOGIN_CONTEXT_NAME_KEY, "Client1");
+        properties.put(ENABLE_CLIENT_SASL_KEY, "true");
+        properties.put(ZOOKEEPER_SERVER_REALM, "zookeeper/hadoop.hadoop.com");
+        properties.put(DISABLE_AUTO_WATCH_RESET, "true");
+        properties.put(ZOOKEEPER_CLIENT_CNXN_SOCKET, "ClientCnxnSocketNetty");
+        properties.put(SECURE_CLIENT, "true");
+
+        for (Map.Entry<String, String> e : properties.entrySet()) {
+            System.setProperty(e.getKey(), e.getValue());
+        }
+        /**
+         * ZKClientConfig should get initialized with system properties
+         */
+        ZKClientConfig conf = new ZKClientConfig();
+        for (Map.Entry<String, String> e : properties.entrySet()) {
+            assertEquals(e.getValue(), conf.getProperty(e.getKey()));
+        }
+        /**
+         * clear properties
+         */
+        for (Map.Entry<String, String> e : properties.entrySet()) {
+            System.clearProperty(e.getKey());
+        }
+
+        conf = new ZKClientConfig();
+        /**
+         * test that all the properties are null
+         */
+        for (Map.Entry<String, String> e : properties.entrySet()) {
+            String result = conf.getProperty(e.getKey());
+            assertNull(result);
+        }
+    }
+
+    @Test
+    public void testSystemPropertyValue() {
+        String clientName = "zookeeper1";
+        System.setProperty(ZK_SASL_CLIENT_USERNAME, clientName);
+
+        ZKClientConfig conf = new ZKClientConfig();
+        assertEquals(conf.getProperty(ZK_SASL_CLIENT_USERNAME), clientName);
+
+        String newClientName = "zookeeper2";
+        conf.setProperty(ZK_SASL_CLIENT_USERNAME, newClientName);
+
+        assertEquals(conf.getProperty(ZK_SASL_CLIENT_USERNAME), newClientName);
+    }
+
+    @Test
+    public void testReadConfigurationFile() throws IOException, ConfigException {
+        File file = File.createTempFile("clientConfig", ".conf", testData);
+        file.deleteOnExit();
+        Properties clientConfProp = new Properties();
+        clientConfProp.setProperty(ENABLE_CLIENT_SASL_KEY, "true");
+        clientConfProp.setProperty(ZK_SASL_CLIENT_USERNAME, "ZK");
+        clientConfProp.setProperty(LOGIN_CONTEXT_NAME_KEY, "MyClient");
+        clientConfProp.setProperty(ZOOKEEPER_SERVER_REALM, "HADOOP.COM");
+        clientConfProp.setProperty("dummyProperty", "dummyValue");
+        OutputStream io = new FileOutputStream(file);
+        try {
+            clientConfProp.store(io, "Client Configurations");
+        } finally {
+            io.close();
+        }
+
+        ZKClientConfig conf = new ZKClientConfig();
+        conf.addConfiguration(file.getAbsolutePath());
+        assertEquals(conf.getProperty(ENABLE_CLIENT_SASL_KEY), "true");
+        assertEquals(conf.getProperty(ZK_SASL_CLIENT_USERNAME), "ZK");
+        assertEquals(conf.getProperty(LOGIN_CONTEXT_NAME_KEY), "MyClient");
+        assertEquals(conf.getProperty(ZOOKEEPER_SERVER_REALM), "HADOOP.COM");
+        assertEquals(conf.getProperty("dummyProperty"), "dummyValue");
+
+        // try to delete it now as we have done with the created file, why to
+        // wait for deleteOnExit() deletion
+        file.delete();
+
+    }
+
+    @Test
+    public void testSetConfiguration() {
+        ZKClientConfig conf = new ZKClientConfig();
+        String defaultValue = conf.getProperty(ZKClientConfig.ENABLE_CLIENT_SASL_KEY,
+                ZKClientConfig.ENABLE_CLIENT_SASL_DEFAULT);
+        if (defaultValue.equals("true")) {
+            conf.setProperty(ENABLE_CLIENT_SASL_KEY, "false");
+        } else {
+            conf.setProperty(ENABLE_CLIENT_SASL_KEY, "true");
+        }
+        assertTrue(conf.getProperty(ENABLE_CLIENT_SASL_KEY) != defaultValue);
+    }
+
+    @Test
+    public void testIntegerRetrievalFromProperty() {
+        ZKClientConfig conf = new ZKClientConfig();
+        String prop = "UnSetProperty" + System.currentTimeMillis();
+        int defaultValue = 100;
+        // property is not set we should get the default value
+        int result = conf.getInt(prop, defaultValue);
+        assertEquals(defaultValue, result);
+
+        // property is set but can not be parsed to int, we should get the
+        // NumberFormatException
+        conf.setProperty(ZKConfig.JUTE_MAXBUFFER, "InvlaidIntValue123");
+        try {
+            result = conf.getInt(ZKConfig.JUTE_MAXBUFFER, defaultValue);
+            fail("NumberFormatException is expected");
+        } catch (NumberFormatException exception) {
+            // do nothing
+        }
+        assertEquals(defaultValue, result);
+
+        // property is set to an valid int, we should get the set value
+        int value = ZKClientConfig.CLIENT_MAX_PACKET_LENGTH_DEFAULT;
+        conf.setProperty(ZKConfig.JUTE_MAXBUFFER, Integer.toString(value));
+        result = conf.getInt(ZKConfig.JUTE_MAXBUFFER, defaultValue);
+        assertEquals(value, result);
+
+        // property is set but with white spaces
+        value = 12345;
+        conf.setProperty(ZKConfig.JUTE_MAXBUFFER,
+                " " + Integer.toString(value) + " ");
+        result = conf.getInt(ZKConfig.JUTE_MAXBUFFER, defaultValue);
+        assertEquals(value, result);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/43d71c2e/zookeeper-server/src/test/java/org/apache/zookeeper/common/AtomicFileWritingIdiomTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/common/AtomicFileWritingIdiomTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/common/AtomicFileWritingIdiomTest.java
new file mode 100644
index 0000000..477ac8e
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/common/AtomicFileWritingIdiomTest.java
@@ -0,0 +1,360 @@
+/**
+ * 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.common;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.common.AtomicFileWritingIdiom.OutputStreamStatement;
+import org.apache.zookeeper.common.AtomicFileWritingIdiom.WriterStatement;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class AtomicFileWritingIdiomTest extends ZKTestCase {
+
+    private static File tmpdir;
+
+    @BeforeClass
+    public static void createTmpDir() {
+        tmpdir = new File("build/test/tmp");
+        tmpdir.mkdirs();
+    }
+
+    @Test
+    public void testOutputStreamSuccess() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        createFile(target, "before");
+        assertEquals("before", getContent(target));
+        new AtomicFileWritingIdiom(target, new OutputStreamStatement() {
+            @Override
+            public void write(OutputStream os) throws IOException {
+                os.write("after".getBytes("ASCII"));
+                assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+            }
+        });
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        // content changed
+        assertEquals("after", getContent(target));
+        target.delete();
+    }
+
+    @Test
+    public void testWriterSuccess() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        createFile(target, "before");
+        assertEquals("before", getContent(target));
+        new AtomicFileWritingIdiom(target, new WriterStatement() {
+            @Override
+            public void write(Writer os) throws IOException {
+                os.write("after");
+                assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+            }
+        });
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        // content changed
+        assertEquals("after", getContent(target));
+        target.delete();
+    }
+
+    @Test
+    public void testOutputStreamFailure() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        createFile(target, "before");
+        assertEquals("before", getContent(target));
+        boolean exception = false;
+        try {
+            new AtomicFileWritingIdiom(target, new OutputStreamStatement() {
+                @Override
+                public void write(OutputStream os) throws IOException {
+                    os.write("after".getBytes("ASCII"));
+                    os.flush();
+                    assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+                    throw new RuntimeException();
+                }
+            });
+        } catch (RuntimeException ex) {
+            exception = true;
+        }
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        assertTrue("should have raised an exception", exception);
+        // content preserved
+        assertEquals("before", getContent(target));
+        target.delete();
+    }
+
+    @Test
+    public void testWriterFailure() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        createFile(target, "before");
+        assertEquals("before", getContent(target));
+        boolean exception = false;
+        try {
+            new AtomicFileWritingIdiom(target, new WriterStatement() {
+                @Override
+                public void write(Writer os) throws IOException {
+                    os.write("after");
+                    os.flush();
+                    assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+                    throw new RuntimeException();
+                }
+            });
+        } catch (RuntimeException ex) {
+            exception = true;
+        }
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        assertTrue("should have raised an exception", exception);
+        // content preserved
+        assertEquals("before", getContent(target));
+        target.delete();
+    }
+
+    @Test
+    public void testOutputStreamFailureIOException() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        createFile(target, "before");
+        assertEquals("before", getContent(target));
+        boolean exception = false;
+        try {
+            new AtomicFileWritingIdiom(target, new OutputStreamStatement() {
+                @Override
+                public void write(OutputStream os) throws IOException {
+                    os.write("after".getBytes("ASCII"));
+                    os.flush();
+                    assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+                    throw new IOException();
+                }
+            });
+        } catch (IOException ex) {
+            exception = true;
+        }
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        assertTrue("should have raised an exception", exception);
+        // content preserved
+        assertEquals("before", getContent(target));
+        target.delete();
+    }
+
+    @Test
+    public void testWriterFailureIOException() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        createFile(target, "before");
+        assertEquals("before", getContent(target));
+        boolean exception = false;
+        try {
+            new AtomicFileWritingIdiom(target, new WriterStatement() {
+                @Override
+                public void write(Writer os) throws IOException {
+                    os.write("after");
+                    os.flush();
+                    assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+                    throw new IOException();
+                }
+            });
+        } catch (IOException ex) {
+            exception = true;
+        }
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        assertTrue("should have raised an exception", exception);
+        // content preserved
+        assertEquals("before", getContent(target));
+        target.delete();
+    }
+
+    @Test
+    public void testOutputStreamFailureError() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        createFile(target, "before");
+        assertEquals("before", getContent(target));
+        boolean exception = false;
+        try {
+            new AtomicFileWritingIdiom(target, new OutputStreamStatement() {
+                @Override
+                public void write(OutputStream os) throws IOException {
+                    os.write("after".getBytes("ASCII"));
+                    os.flush();
+                    assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+                    throw new Error();
+                }
+            });
+        } catch (Error ex) {
+            exception = true;
+        }
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        assertTrue("should have raised an exception", exception);
+        // content preserved
+        assertEquals("before", getContent(target));
+        target.delete();
+    }
+
+    @Test
+    public void testWriterFailureError() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        createFile(target, "before");
+        assertEquals("before", getContent(target));
+        boolean exception = false;
+        try {
+            new AtomicFileWritingIdiom(target, new WriterStatement() {
+                @Override
+                public void write(Writer os) throws IOException {
+                    os.write("after");
+                    os.flush();
+                    assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+                    throw new Error();
+                }
+            });
+        } catch (Error ex) {
+            exception = true;
+        }
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        assertTrue("should have raised an exception", exception);
+        // content preserved
+        assertEquals("before", getContent(target));
+        target.delete();
+    }
+
+    // ************** target file does not exist
+
+    @Test
+    public void testOutputStreamSuccessNE() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        target.delete();
+        assertFalse("file should not exist", target.exists());
+        new AtomicFileWritingIdiom(target, new OutputStreamStatement() {
+            @Override
+            public void write(OutputStream os) throws IOException {
+                os.write("after".getBytes("ASCII"));
+                assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+            }
+        });
+        // content changed
+        assertEquals("after", getContent(target));
+        target.delete();
+    }
+
+    @Test
+    public void testWriterSuccessNE() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        target.delete();
+        assertFalse("file should not exist", target.exists());
+        new AtomicFileWritingIdiom(target, new WriterStatement() {
+            @Override
+            public void write(Writer os) throws IOException {
+                os.write("after");
+                assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+            }
+        });
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        // content changed
+        assertEquals("after", getContent(target));
+        target.delete();
+    }
+
+    @Test
+    public void testOutputStreamFailureNE() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        target.delete();
+        assertFalse("file should not exist", target.exists());
+        boolean exception = false;
+        try {
+            new AtomicFileWritingIdiom(target, new OutputStreamStatement() {
+                @Override
+                public void write(OutputStream os) throws IOException {
+                    os.write("after".getBytes("ASCII"));
+                    os.flush();
+                    assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+                    throw new RuntimeException();
+                }
+            });
+        } catch (RuntimeException ex) {
+            exception = true;
+        }
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        assertTrue("should have raised an exception", exception);
+        // file should not exist
+        assertFalse("file should not exist", target.exists());
+    }
+
+    @Test
+    public void testWriterFailureNE() throws IOException {
+        File target = new File(tmpdir, "target.txt");
+        final File tmp = new File(tmpdir, "target.txt.tmp");
+        target.delete();
+        assertFalse("file should not exist", target.exists());
+        boolean exception = false;
+        try {
+            new AtomicFileWritingIdiom(target, new WriterStatement() {
+                @Override
+                public void write(Writer os) throws IOException {
+                    os.write("after");
+                    os.flush();
+                    assertTrue("implementation of AtomicFileOutputStream has changed, update the test", tmp.exists());
+                    throw new RuntimeException();
+                }
+            });
+        } catch (RuntimeException ex) {
+            exception = true;
+        }
+        assertFalse("tmp file should have been deleted", tmp.exists());
+        assertTrue("should have raised an exception", exception);
+        // file should not exist
+        assertFalse("file should not exist", target.exists());
+    }
+
+    private String getContent(File file, String encoding) throws IOException {
+        StringBuilder result = new StringBuilder();
+        FileInputStream fis = new FileInputStream(file);
+        byte[] b = new byte[20];
+        int nb;
+        while ((nb = fis.read(b)) != -1) {
+               result.append(new String(b, 0, nb, encoding));
+        }
+        fis.close();
+        return result.toString();
+    }
+
+    private String getContent(File file) throws IOException {
+        return getContent(file, "ASCII");
+    }
+
+    private void createFile(File file, String content) throws IOException {
+        FileOutputStream fos = new FileOutputStream(file);
+        fos.write(content.getBytes("ASCII"));
+        fos.close();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/43d71c2e/zookeeper-server/src/test/java/org/apache/zookeeper/common/PathUtilsTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/common/PathUtilsTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/common/PathUtilsTest.java
new file mode 100644
index 0000000..5804456
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/common/PathUtilsTest.java
@@ -0,0 +1,129 @@
+/**
+ * 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.common;
+
+import org.apache.zookeeper.ZKTestCase;
+import org.junit.Test;
+
+public class PathUtilsTest extends ZKTestCase {
+
+    @Test
+    public void testValidatePath_ValidPath() {
+        PathUtils.validatePath("/this is / a valid/path");
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_Null() {
+        PathUtils.validatePath(null);
+    }
+    
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_EmptyString() {
+        PathUtils.validatePath("");
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_NotAbsolutePath() {
+        PathUtils.validatePath("not/valid");
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_EndsWithSlash() {
+        PathUtils.validatePath("/ends/with/slash/");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_ContainsNullCharacter() {
+        PathUtils.validatePath("/test\u0000");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_DoubleSlash() {
+        PathUtils.validatePath("/double//slash");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_SinglePeriod() {
+        PathUtils.validatePath("/single/./period");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_DoublePeriod() {
+        PathUtils.validatePath("/double/../period");
+    }
+    
+    @Test
+    public void testValidatePath_NameContainingPeriod() {
+        // A period that isn't on its own is ok
+        PathUtils.validatePath("/name/with.period.");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_0x01() {
+        PathUtils.validatePath("/test\u0001");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_0x1F() {
+        PathUtils.validatePath("/test\u001F");
+    }
+    
+    @Test // The first allowable character
+    public void testValidatePath_0x20() {
+        PathUtils.validatePath("/test\u0020");
+    }
+    
+    @Test 
+    public void testValidatePath_0x7e() {
+        // The last valid ASCII character
+        PathUtils.validatePath("/test\u007e");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_0x7f() {
+        PathUtils.validatePath("/test\u007f");
+    }
+    
+    @Test(expected=IllegalArgumentException.class) 
+    public void testValidatePath_0x9f() {
+        PathUtils.validatePath("/test\u009f");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_ud800() {
+        PathUtils.validatePath("/test\ud800");
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_uf8ff() {
+        PathUtils.validatePath("/test\uf8ff");
+    }
+    
+    @Test
+    public void testValidatePath_HighestAllowableChar() {
+        PathUtils.validatePath("/test\uffef");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testValidatePath_SupplementaryChar() {
+        PathUtils.validatePath("/test\ufff0");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/43d71c2e/zookeeper-server/src/test/java/org/apache/zookeeper/common/TimeTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/common/TimeTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/common/TimeTest.java
new file mode 100644
index 0000000..d938556
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/common/TimeTest.java
@@ -0,0 +1,109 @@
+/**
+ * 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.common;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.test.ClientBase;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Command line program for demonstrating robustness to clock
+ * changes.
+ * <p/>
+ * How to run:
+ * ant clean compile-test
+ * echo build/test/lib/*.jar build/lib/*.jar build/classes build/test/classes | sed -e 's/ /:/g' > cp
+ * java -cp $(cat cp) org.apache.zookeeper.common.TimeTest | tee log-without-patch
+ * <p/>
+ * After test program starts, in another window, do commands:
+ * date -s '+1hour'
+ * date -s '-1hour'
+ * <p/>
+ * As long as there isn't any expired event, the experiment is successful.
+ */
+public class TimeTest extends ClientBase {
+    private static final long mt0 = System.currentTimeMillis();
+    private static final long nt0 = Time.currentElapsedTime();
+
+    private static AtomicInteger watchCount = new AtomicInteger(0);
+
+
+    public static void main(String[] args) throws Exception {
+        System.out.printf("Starting\n");
+        final TimeTest test = new TimeTest();
+        System.out.printf("After construct\n");
+        test.setUp();
+        ZooKeeper zk = test.createClient();
+        zk.create("/ephemeral", new byte[]{1, 2, 3},
+                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
+        while (Time.currentElapsedTime() - nt0 < 100000) {
+            System.out.printf("%d\t%s\n", discrepancy(),
+                    zk.exists("/ephemeral",
+                            watchCount.get() == 0 ? createWatcher() : null) != null);
+            waitByYielding(500);
+        }
+    }
+
+    private static Watcher createWatcher() {
+        watchCount.incrementAndGet();
+        return new Watcher() {
+            @Override
+            public void process(WatchedEvent event) {
+                watchCount.decrementAndGet();
+                System.out.printf("%d event = %s\n", discrepancy(), event);
+            }
+        };
+
+    }
+
+    private static void waitByYielding(long delay) {
+        long t0 = Time.currentElapsedTime();
+        while (Time.currentElapsedTime() < t0 + delay) {
+            Thread.yield();
+        }
+    }
+
+    private static long discrepancy() {
+        return (System.currentTimeMillis() - mt0) - (Time.currentElapsedTime() - nt0);
+    }
+
+    @Test
+    public void testElapsedTimeToDate() throws Exception {
+        long walltime = Time.currentWallTime();
+        long elapsedTime = Time.currentElapsedTime();
+        Thread.sleep(200);
+
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(Time.elapsedTimeToDate(elapsedTime));
+        int calculatedDate = cal.get(Calendar.HOUR_OF_DAY);
+        cal.setTime(new Date(walltime));
+        int realDate = cal.get(Calendar.HOUR_OF_DAY);
+
+        Assert.assertEquals(calculatedDate, realDate);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/43d71c2e/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java
new file mode 100644
index 0000000..e726caa
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java
@@ -0,0 +1,264 @@
+/**
+ * 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.common;
+
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.client.ZKClientConfig;
+import org.apache.zookeeper.server.ServerCnxnFactory;
+import org.bouncycastle.asn1.x500.X500NameBuilder;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.KeyUsage;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+import java.io.FileOutputStream;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Random;
+
+import static org.apache.zookeeper.test.ClientBase.createTmpDir;
+
+public class X509UtilTest extends ZKTestCase {
+
+    private static final char[] PASSWORD = "password".toCharArray();
+    private X509Certificate rootCertificate;
+
+    private String truststorePath;
+    private String keystorePath;
+    private static KeyPair rootKeyPair;
+
+    private X509Util x509Util;
+    private String[] customCipherSuites = new String[]{"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"};
+
+    @BeforeClass
+    public static void createKeyPair() throws Exception {
+        Security.addProvider(new BouncyCastleProvider());
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
+        keyPairGenerator.initialize(4096);
+        rootKeyPair = keyPairGenerator.genKeyPair();
+    }
+
+    @AfterClass
+    public static void removeBouncyCastleProvider() throws Exception {
+        Security.removeProvider("BC");
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        rootCertificate = createSelfSignedCertifcate(rootKeyPair);
+
+        String tmpDir = createTmpDir().getAbsolutePath();
+        truststorePath = tmpDir + "/truststore.jks";
+        keystorePath = tmpDir + "/keystore.jks";
+
+        x509Util = new ClientX509Util();
+
+        writeKeystore(rootCertificate, rootKeyPair, keystorePath);
+
+        System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY, "org.apache.zookeeper.server.NettyServerCnxnFactory");
+        System.setProperty(ZKClientConfig.ZOOKEEPER_CLIENT_CNXN_SOCKET, "org.apache.zookeeper.ClientCnxnSocketNetty");
+        System.setProperty(x509Util.getSslKeystoreLocationProperty(), keystorePath);
+        System.setProperty(x509Util.getSslKeystorePasswdProperty(), new String(PASSWORD));
+        System.setProperty(x509Util.getSslTruststoreLocationProperty(), truststorePath);
+        System.setProperty(x509Util.getSslTruststorePasswdProperty(), new String(PASSWORD));
+        System.setProperty(x509Util.getSslHostnameVerificationEnabledProperty(), "false");
+
+        writeTrustStore(PASSWORD);
+    }
+
+    private void writeKeystore(X509Certificate certificate, KeyPair keyPair, String path) throws Exception {
+        KeyStore keyStore = KeyStore.getInstance("JKS");
+        keyStore.load(null, PASSWORD);
+        keyStore.setKeyEntry("alias", keyPair.getPrivate(), PASSWORD, new Certificate[] { certificate });
+        FileOutputStream outputStream = new FileOutputStream(path);
+        keyStore.store(outputStream, PASSWORD);
+        outputStream.flush();
+        outputStream.close();
+    }
+
+    private void writeTrustStore(char[] password) throws Exception {
+        KeyStore trustStore = KeyStore.getInstance("JKS");
+        trustStore.load(null, password);
+        trustStore.setCertificateEntry(rootCertificate.getSubjectDN().toString(), rootCertificate);
+        FileOutputStream outputStream = new FileOutputStream(truststorePath);
+        if (password == null) {
+            trustStore.store(outputStream, new char[0]);
+        } else {
+            trustStore.store(outputStream, password);
+        }
+        outputStream.flush();
+        outputStream.close();
+    }
+
+    private X509Certificate createSelfSignedCertifcate(KeyPair keyPair) throws Exception {
+        X500NameBuilder nameBuilder = new X500NameBuilder(BCStyle.INSTANCE);
+        nameBuilder.addRDN(BCStyle.CN, "localhost");
+        Date notBefore = new Date();
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(notBefore);
+        cal.add(Calendar.YEAR, 1);
+        Date notAfter = cal.getTime();
+        BigInteger serialNumber = new BigInteger(128, new Random());
+
+        X509v3CertificateBuilder certificateBuilder =
+                new JcaX509v3CertificateBuilder(nameBuilder.build(), serialNumber, notBefore, notAfter, nameBuilder.build(), keyPair.getPublic())
+                        .addExtension(Extension.basicConstraints, true, new BasicConstraints(0))
+                        .addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign));
+
+        ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate());
+
+        return new JcaX509CertificateConverter().getCertificate(certificateBuilder.build(contentSigner));
+    }
+
+    @After
+    public void cleanUp() throws Exception {
+        System.clearProperty(x509Util.getSslKeystoreLocationProperty());
+        System.clearProperty(x509Util.getSslKeystorePasswdProperty());
+        System.clearProperty(x509Util.getSslTruststoreLocationProperty());
+        System.clearProperty(x509Util.getSslTruststorePasswdProperty());
+        System.clearProperty(x509Util.getSslHostnameVerificationEnabledProperty());
+        System.clearProperty(x509Util.getSslOcspEnabledProperty());
+        System.clearProperty(x509Util.getSslCrlEnabledProperty());
+        System.clearProperty(x509Util.getCipherSuitesProperty());
+        System.clearProperty("com.sun.net.ssl.checkRevocation");
+        System.clearProperty("com.sun.security.enableCRLDP");
+        Security.setProperty("com.sun.security.enableCRLDP", "false");
+    }
+
+    @Test(timeout = 5000)
+    public void testCreateSSLContextWithoutCustomProtocol() throws Exception {
+        SSLContext sslContext = x509Util.getDefaultSSLContext();
+        Assert.assertEquals(X509Util.DEFAULT_PROTOCOL, sslContext.getProtocol());
+    }
+
+    @Test(timeout = 5000)
+    public void testCreateSSLContextWithCustomProtocol() throws Exception {
+        final String protocol = "TLSv1.1";
+        System.setProperty(x509Util.getSslProtocolProperty(), protocol);
+        SSLContext sslContext = x509Util.getDefaultSSLContext();
+        Assert.assertEquals(protocol, sslContext.getProtocol());
+    }
+
+    @Test(timeout = 5000)
+    public void testCreateSSLContextWithoutTrustStorePassword() throws Exception {
+        writeTrustStore(null);
+        System.clearProperty(x509Util.getSslTruststorePasswdProperty());
+        x509Util.getDefaultSSLContext();
+    }
+
+    @Test(timeout = 5000, expected = X509Exception.SSLContextException.class)
+    public void testCreateSSLContextWithoutKeyStoreLocation() throws Exception {
+        System.clearProperty(x509Util.getSslKeystoreLocationProperty());
+        x509Util.getDefaultSSLContext();
+    }
+
+    @Test(timeout = 5000, expected = X509Exception.SSLContextException.class)
+    public void testCreateSSLContextWithoutKeyStorePassword() throws Exception {
+        System.clearProperty(x509Util.getSslKeystorePasswdProperty());
+        x509Util.getDefaultSSLContext();
+    }
+
+    @Test(timeout = 5000)
+    public void testCreateSSLContextWithCustomCipherSuites() throws Exception {
+        setCustomCipherSuites();
+        SSLSocket sslSocket = x509Util.createSSLSocket();
+        Assert.assertArrayEquals(customCipherSuites, sslSocket.getEnabledCipherSuites());
+    }
+
+    // It would be great to test the value of PKIXBuilderParameters#setRevocationEnabled but it does not appear to be
+    // possible
+    @Test(timeout = 5000)
+    public void testCRLEnabled() throws Exception {
+        System.setProperty(x509Util.getSslCrlEnabledProperty(), "true");
+        x509Util.getDefaultSSLContext();
+        Assert.assertTrue(Boolean.valueOf(System.getProperty("com.sun.net.ssl.checkRevocation")));
+        Assert.assertTrue(Boolean.valueOf(System.getProperty("com.sun.security.enableCRLDP")));
+        Assert.assertFalse(Boolean.valueOf(Security.getProperty("ocsp.enable")));
+    }
+
+    @Test(timeout = 5000)
+    public void testCRLDisabled() throws Exception {
+        x509Util.getDefaultSSLContext();
+        Assert.assertFalse(Boolean.valueOf(System.getProperty("com.sun.net.ssl.checkRevocation")));
+        Assert.assertFalse(Boolean.valueOf(System.getProperty("com.sun.security.enableCRLDP")));
+        Assert.assertFalse(Boolean.valueOf(Security.getProperty("ocsp.enable")));
+    }
+
+    @Test(timeout = 5000)
+    public void testOCSPEnabled() throws Exception {
+        System.setProperty(x509Util.getSslOcspEnabledProperty(), "true");
+        x509Util.getDefaultSSLContext();
+        Assert.assertTrue(Boolean.valueOf(System.getProperty("com.sun.net.ssl.checkRevocation")));
+        Assert.assertTrue(Boolean.valueOf(System.getProperty("com.sun.security.enableCRLDP")));
+        Assert.assertTrue(Boolean.valueOf(Security.getProperty("ocsp.enable")));
+    }
+
+    @Test(timeout = 5000)
+    public void testCreateSSLSocket() throws Exception {
+        setCustomCipherSuites();
+        SSLSocket sslSocket = x509Util.createSSLSocket();
+        Assert.assertArrayEquals(customCipherSuites, sslSocket.getEnabledCipherSuites());
+    }
+
+    @Test(timeout = 5000)
+    public void testCreateSSLServerSocketWithoutPort() throws Exception {
+        setCustomCipherSuites();
+        SSLServerSocket sslServerSocket = x509Util.createSSLServerSocket();
+        Assert.assertArrayEquals(customCipherSuites, sslServerSocket.getEnabledCipherSuites());
+        Assert.assertTrue(sslServerSocket.getNeedClientAuth());
+    }
+
+    @Test(timeout = 5000)
+    public void testCreateSSLServerSocketWithPort() throws Exception {
+        int port = PortAssignment.unique();
+        setCustomCipherSuites();
+        SSLServerSocket sslServerSocket = x509Util.createSSLServerSocket(port);
+        Assert.assertEquals(sslServerSocket.getLocalPort(), port);
+        Assert.assertArrayEquals(customCipherSuites, sslServerSocket.getEnabledCipherSuites());
+        Assert.assertTrue(sslServerSocket.getNeedClientAuth());
+    }
+
+    // Warning: this will reset the x509Util
+    private void setCustomCipherSuites() {
+        System.setProperty(x509Util.getCipherSuitesProperty(), customCipherSuites[0] + "," + customCipherSuites[1]);
+        x509Util = new ClientX509Util();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/43d71c2e/zookeeper-server/src/test/java/org/apache/zookeeper/common/ZKTrustManagerTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/common/ZKTrustManagerTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/common/ZKTrustManagerTest.java
new file mode 100644
index 0000000..32f250b
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/common/ZKTrustManagerTest.java
@@ -0,0 +1,248 @@
+/**
+ * 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.common;
+
+import org.apache.zookeeper.ZKTestCase;
+import org.bouncycastle.asn1.x500.X500NameBuilder;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.KeyUsage;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import javax.net.ssl.X509ExtendedTrustManager;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Random;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+// We can only test calls to ZKTrustManager using Sockets (not SSLEngines). This can be fine since the logic is the same.
+public class ZKTrustManagerTest extends ZKTestCase {
+
+    private static KeyPair keyPair;
+
+    private X509ExtendedTrustManager mockX509ExtendedTrustManager;
+    private static final String IP_ADDRESS = "127.0.0.1";
+    private static final String HOSTNAME = "localhost";
+
+    private InetAddress mockInetAddress;
+    private Socket mockSocket;
+
+    @BeforeClass
+    public static void createKeyPair() throws Exception {
+        Security.addProvider(new BouncyCastleProvider());
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
+        keyPairGenerator.initialize(4096);
+        keyPair = keyPairGenerator.genKeyPair();
+    }
+
+    @AfterClass
+    public static void removeBouncyCastleProvider() throws Exception {
+        Security.removeProvider("BC");
+    }
+
+    @Before
+    public void setup() throws Exception {
+        mockX509ExtendedTrustManager = mock(X509ExtendedTrustManager.class);
+
+        mockInetAddress = mock(InetAddress.class);
+        when(mockInetAddress.getHostAddress()).thenAnswer(new Answer() {
+            @Override
+            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
+                return IP_ADDRESS;
+            }
+        });
+
+        when(mockInetAddress.getHostName()).thenAnswer(new Answer() {
+            @Override
+            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
+                return HOSTNAME;
+            }
+        });
+
+        mockSocket = mock(Socket.class);
+        when(mockSocket.getInetAddress()).thenAnswer(new Answer() {
+            @Override
+            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
+                return mockInetAddress;
+            }
+        });
+    }
+
+    private X509Certificate[] createSelfSignedCertifcateChain(String ipAddress, String hostname) throws Exception {
+        X500NameBuilder nameBuilder = new X500NameBuilder(BCStyle.INSTANCE);
+        nameBuilder.addRDN(BCStyle.CN, "NOT_LOCALHOST");
+        Date notBefore = new Date();
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(notBefore);
+        cal.add(Calendar.YEAR, 1);
+        Date notAfter = cal.getTime();
+        BigInteger serialNumber = new BigInteger(128, new Random());
+
+        X509v3CertificateBuilder certificateBuilder =
+                new JcaX509v3CertificateBuilder(nameBuilder.build(), serialNumber, notBefore, notAfter, nameBuilder.build(), keyPair.getPublic())
+                        .addExtension(Extension.basicConstraints, true, new BasicConstraints(0))
+                        .addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign));
+
+        List<GeneralName> generalNames = new ArrayList<>();
+        if (ipAddress != null) {
+            generalNames.add(new GeneralName(GeneralName.iPAddress, ipAddress));
+        }
+        if (hostname != null) {
+            generalNames.add(new GeneralName(GeneralName.dNSName, hostname));
+        }
+
+        if (!generalNames.isEmpty()) {
+            certificateBuilder.addExtension(Extension.subjectAlternativeName,  true,  new GeneralNames(generalNames.toArray(new GeneralName[] {})));
+        }
+
+        ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate());
+
+        return new X509Certificate[] { new JcaX509CertificateConverter().getCertificate(certificateBuilder.build(contentSigner)) };
+    }
+
+    @Test
+    public void testServerHostnameVerificationWithHostnameVerificationDisabled() throws Exception {
+        ZKTrustManager zkTrustManager = new ZKTrustManager(mockX509ExtendedTrustManager, false, false);
+
+        X509Certificate[] certificateChain = createSelfSignedCertifcateChain(IP_ADDRESS, HOSTNAME);
+        zkTrustManager.checkServerTrusted(certificateChain, null, mockSocket);
+
+        verify(mockInetAddress, times(0)).getHostAddress();
+        verify(mockInetAddress, times(0)).getHostName();
+
+        verify(mockX509ExtendedTrustManager, times(1)).checkServerTrusted(certificateChain, null, mockSocket);
+    }
+
+    @Test
+    public void testServerHostnameVerificationWithHostnameVerificationDisabledAndClientHostnameVerificationEnabled() throws Exception {
+        ZKTrustManager zkTrustManager = new ZKTrustManager(mockX509ExtendedTrustManager, false, true);
+
+        X509Certificate[] certificateChain = createSelfSignedCertifcateChain(IP_ADDRESS, HOSTNAME);
+        zkTrustManager.checkServerTrusted(certificateChain, null, mockSocket);
+
+        verify(mockInetAddress, times(0)).getHostAddress();
+        verify(mockInetAddress, times(0)).getHostName();
+
+        verify(mockX509ExtendedTrustManager, times(1)).checkServerTrusted(certificateChain, null, mockSocket);
+    }
+
+    @Test
+    public void testServerHostnameVerificationWithIPAddress() throws Exception {
+        ZKTrustManager zkTrustManager = new ZKTrustManager(mockX509ExtendedTrustManager, true, false);
+
+        X509Certificate[] certificateChain = createSelfSignedCertifcateChain(IP_ADDRESS, null);
+        zkTrustManager.checkServerTrusted(certificateChain, null, mockSocket);
+
+        verify(mockInetAddress, times(1)).getHostAddress();
+        verify(mockInetAddress, times(0)).getHostName();
+
+        verify(mockX509ExtendedTrustManager, times(1)).checkServerTrusted(certificateChain, null, mockSocket);
+    }
+
+    @Test
+    public void testServerHostnameVerificationWithHostname() throws Exception {
+        ZKTrustManager zkTrustManager = new ZKTrustManager(mockX509ExtendedTrustManager, true, false);
+
+        X509Certificate[] certificateChain = createSelfSignedCertifcateChain(null, HOSTNAME);
+        zkTrustManager.checkServerTrusted(certificateChain, null, mockSocket);
+
+        verify(mockInetAddress, times(1)).getHostAddress();
+        verify(mockInetAddress, times(1)).getHostName();
+
+        verify(mockX509ExtendedTrustManager, times(1)).checkServerTrusted(certificateChain, null, mockSocket);
+    }
+
+    @Test
+    public void testClientHostnameVerificationWithHostnameVerificationDisabled() throws Exception {
+        ZKTrustManager zkTrustManager = new ZKTrustManager(mockX509ExtendedTrustManager, false, true);
+
+        X509Certificate[] certificateChain = createSelfSignedCertifcateChain(null, HOSTNAME);
+        zkTrustManager.checkClientTrusted(certificateChain, null, mockSocket);
+
+        verify(mockInetAddress, times(1)).getHostAddress();
+        verify(mockInetAddress, times(1)).getHostName();
+
+        verify(mockX509ExtendedTrustManager, times(1)).checkClientTrusted(certificateChain, null, mockSocket);
+    }
+
+    @Test
+    public void testClientHostnameVerificationWithClientHostnameVerificationDisabled() throws Exception {
+        ZKTrustManager zkTrustManager = new ZKTrustManager(mockX509ExtendedTrustManager, true, false);
+
+        X509Certificate[] certificateChain = createSelfSignedCertifcateChain(null, HOSTNAME);
+        zkTrustManager.checkClientTrusted(certificateChain, null, mockSocket);
+
+        verify(mockInetAddress, times(0)).getHostAddress();
+        verify(mockInetAddress, times(0)).getHostName();
+
+        verify(mockX509ExtendedTrustManager, times(1)).checkClientTrusted(certificateChain, null, mockSocket);
+    }
+
+    @Test
+    public void testClientHostnameVerificationWithIPAddress() throws Exception {
+        ZKTrustManager zkTrustManager = new ZKTrustManager(mockX509ExtendedTrustManager, true, true);
+
+        X509Certificate[] certificateChain = createSelfSignedCertifcateChain(IP_ADDRESS, null);
+        zkTrustManager.checkClientTrusted(certificateChain, null, mockSocket);
+
+        verify(mockInetAddress, times(1)).getHostAddress();
+        verify(mockInetAddress, times(0)).getHostName();
+
+        verify(mockX509ExtendedTrustManager, times(1)).checkClientTrusted(certificateChain, null, mockSocket);
+    }
+
+    @Test
+    public void testClientHostnameVerificationWithHostname() throws Exception {
+        ZKTrustManager zkTrustManager = new ZKTrustManager(mockX509ExtendedTrustManager, true, true);
+
+        X509Certificate[] certificateChain = createSelfSignedCertifcateChain(null, HOSTNAME);
+        zkTrustManager.checkClientTrusted(certificateChain, null, mockSocket);
+
+        verify(mockInetAddress, times(1)).getHostAddress();
+        verify(mockInetAddress, times(1)).getHostName();
+
+        verify(mockX509ExtendedTrustManager, times(1)).checkClientTrusted(certificateChain, null, mockSocket);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/43d71c2e/zookeeper-server/src/test/java/org/apache/zookeeper/test/ACLCountTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ACLCountTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ACLCountTest.java
new file mode 100644
index 0000000..6c876cb
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ACLCountTest.java
@@ -0,0 +1,111 @@
+/**
+ * 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.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+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 ACLCountTest extends ZKTestCase{
+    private static final Logger LOG = LoggerFactory.getLogger(ACLCountTest.class);
+    private static final String HOSTPORT =
+        "127.0.0.1:" + PortAssignment.unique();
+
+    /**
+     *
+     * Create a node and add 4 ACL values to it, but there are only 2 unique ACL values,
+     * and each is repeated once:
+     *
+     *   ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE);
+     *   ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS);
+     *   ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE);
+     *   ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS);
+     *
+     * Even though we've added 4 ACL values, there should only be 2 ACLs for that node,
+     * since there are only 2 *unique* ACL values.
+     */
+    @Test
+    public void testAclCount() 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;
+
+        final ArrayList<ACL> CREATOR_ALL_AND_WORLD_READABLE =
+          new ArrayList<ACL>() { {
+            add(new ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE));
+            add(new ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS));
+            add(new ACL(ZooDefs.Perms.READ,ZooDefs.Ids.ANYONE_ID_UNSAFE));
+            add(new ACL(ZooDefs.Perms.ALL,ZooDefs.Ids.AUTH_IDS));
+        }};
+
+        try {
+            LOG.info("starting up the zookeeper server .. waiting");
+            Assert.assertTrue("waiting for server being up",
+                    ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));
+            zk = ClientBase.createZKClient(HOSTPORT);
+
+            zk.addAuthInfo("digest", "pat:test".getBytes());
+            zk.setACL("/", Ids.CREATOR_ALL_ACL, -1);
+
+            String path = "/path";
+
+            try {
+              Assert.assertEquals(4,CREATOR_ALL_AND_WORLD_READABLE.size());
+            }
+            catch (Exception e) {
+              LOG.error("Something is fundamentally wrong with ArrayList's add() method. add()ing four times to an empty ArrayList should result in an ArrayList with 4 members.");
+              throw e;
+            }
+
+            zk.create(path,path.getBytes(),CREATOR_ALL_AND_WORLD_READABLE,CreateMode.PERSISTENT);
+            List<ACL> acls = zk.getACL("/path", new Stat());
+            Assert.assertEquals(2,acls.size());
+        }
+        catch (Exception e) {
+          // test failed somehow.
+          Assert.assertTrue(false);
+        }
+
+        f.shutdown();
+        zks.shutdown();
+    }
+}


Mime
View raw message