From commits-return-7265-archive-asf-public=cust-asf.ponee.io@zookeeper.apache.org Wed Oct 24 11:31:02 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 109B11807A5 for ; Wed, 24 Oct 2018 11:30:58 +0200 (CEST) Received: (qmail 69523 invoked by uid 500); 24 Oct 2018 09:30:57 -0000 Mailing-List: contact commits-help@zookeeper.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zookeeper.apache.org Delivered-To: mailing list commits@zookeeper.apache.org Received: (qmail 69142 invoked by uid 99); 24 Oct 2018 09:30:57 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 24 Oct 2018 09:30:57 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 57D03E11BC; Wed, 24 Oct 2018 09:30:56 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: andor@apache.org To: commits@zookeeper.apache.org Date: Wed, 24 Oct 2018 09:31:06 -0000 Message-Id: <7722ee4bcb6e45b885ca54a51d7f305b@git.apache.org> In-Reply-To: <25d338a3641d4672b9e83437148d061f@git.apache.org> References: <25d338a3641d4672b9e83437148d061f@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [11/51] [partial] zookeeper git commit: ZOOKEEPER-3032: MAVEN MIGRATION - branch-3.5 - zookeeper-server 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 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 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 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 expected = new ArrayList(); + 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 expected = new ArrayList(); + 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 expected = new ArrayList(); + 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 expected = new ArrayList(); + 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()); + 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 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 e : properties.entrySet()) { + System.setProperty(e.getKey(), e.getValue()); + } + /** + * ZKClientConfig should get initialized with system properties + */ + ZKClientConfig conf = new ZKClientConfig(); + for (Map.Entry e : properties.entrySet()) { + assertEquals(e.getValue(), conf.getProperty(e.getKey())); + } + /** + * clear properties + */ + for (Map.Entry e : properties.entrySet()) { + System.clearProperty(e.getKey()); + } + + conf = new ZKClientConfig(); + /** + * test that all the properties are null + */ + for (Map.Entry 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. + *

+ * 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 + *

+ * After test program starts, in another window, do commands: + * date -s '+1hour' + * date -s '-1hour' + *

+ * 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 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 CREATOR_ALL_AND_WORLD_READABLE = + new ArrayList() { { + 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 acls = zk.getACL("/path", new Stat()); + Assert.assertEquals(2,acls.size()); + } + catch (Exception e) { + // test failed somehow. + Assert.assertTrue(false); + } + + f.shutdown(); + zks.shutdown(); + } +}