zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From an...@apache.org
Subject [04/36] zookeeper git commit: ZOOKEEPER-3032: MAVEN MIGRATION - branch-3.4 - zookeeper-server
Date Wed, 24 Oct 2018 09:32:20 GMT
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/ReadOnlyModeTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ReadOnlyModeTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ReadOnlyModeTest.java
new file mode 100644
index 0000000..6f281d9
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ReadOnlyModeTest.java
@@ -0,0 +1,291 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import java.util.regex.Pattern;
+
+import junit.framework.Assert;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.WriterAppender;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.NotReadOnlyException;
+import org.apache.zookeeper.Transaction;
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.ZooKeeper.States;
+import org.apache.zookeeper.common.Time;
+import org.apache.zookeeper.test.ClientBase.CountdownWatcher;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.slf4j.LoggerFactory;
+
+
+public class ReadOnlyModeTest extends ZKTestCase {
+    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ReadOnlyModeTest.class);
+    private static int CONNECTION_TIMEOUT = QuorumBase.CONNECTION_TIMEOUT;
+    private QuorumUtil qu = new QuorumUtil(1);
+
+    @Before
+    public void setUp() throws Exception {
+        System.setProperty("readonlymode.enabled", "true");
+        qu.startQuorum();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        System.setProperty("readonlymode.enabled", "false");
+        qu.tearDown();
+    }
+
+    /**
+     * Test write operations using multi request.
+     */
+    @Test(timeout = 90000)
+    public void testMultiTransaction() throws Exception {
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(qu.getConnString(), CONNECTION_TIMEOUT,
+                watcher, true);
+        watcher.waitForConnected(CONNECTION_TIMEOUT); // ensure zk got connected
+
+        final String data = "Data to be read in RO mode";
+        final String node1 = "/tnode1";
+        final String node2 = "/tnode2";
+        zk.create(node1, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        watcher.reset();
+        qu.shutdown(2);
+        watcher.waitForConnected(CONNECTION_TIMEOUT);
+        Assert.assertEquals("Should be in r-o mode", States.CONNECTEDREADONLY,
+                zk.getState());
+
+        // read operation during r/o mode
+        String remoteData = new String(zk.getData(node1, false, null));
+        Assert.assertEquals("Failed to read data in r-o mode", data, remoteData);
+
+        try {
+            Transaction transaction = zk.transaction();
+            transaction.setData(node1, "no way".getBytes(), -1);
+            transaction.create(node2, data.getBytes(),
+                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+            transaction.commit();
+            Assert.fail("Write operation using multi-transaction"
+                    + " api has succeeded during RO mode");
+        } catch (NotReadOnlyException e) {
+            // ok
+        }
+
+        Assert.assertNull("Should have created the znode:" + node2,
+                zk.exists(node2, false));
+    }
+
+    /**
+     * Basic test of read-only client functionality. Tries to read and write
+     * during read-only mode, then regains a quorum and tries to write again.
+     */
+    @Test(timeout = 90000)
+    public void testReadOnlyClient() throws Exception {
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(qu.getConnString(), CONNECTION_TIMEOUT,
+                watcher, true);
+        watcher.waitForConnected(CONNECTION_TIMEOUT); // ensure zk got connected
+
+        final String data = "Data to be read in RO mode";
+        final String node = "/tnode";
+        zk.create(node, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+
+        watcher.reset();
+        qu.shutdown(2);
+        watcher.waitForConnected(CONNECTION_TIMEOUT);
+
+        // read operation during r/o mode
+        String remoteData = new String(zk.getData(node, false, null));
+        Assert.assertEquals(data, remoteData);
+
+        try {
+            zk.setData(node, "no way".getBytes(), -1);
+            Assert.fail("Write operation has succeeded during RO mode");
+        } catch (NotReadOnlyException e) {
+            // ok
+        }
+
+        watcher.reset();
+        qu.start(2);
+        Assert.assertTrue("waiting for server up", ClientBase.waitForServerUp(
+                "127.0.0.1:" + qu.getPeer(2).clientPort, CONNECTION_TIMEOUT));
+        watcher.waitForConnected(CONNECTION_TIMEOUT);
+        zk.setData(node, "We're in the quorum now".getBytes(), -1);
+
+        zk.close();
+    }
+
+    /**
+     * Ensures that upon connection to a read-only server client receives
+     * ConnectedReadOnly state notification.
+     */
+    @Test(timeout = 90000)
+    public void testConnectionEvents() throws Exception {
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(qu.getConnString(), CONNECTION_TIMEOUT,
+                watcher, true);
+        boolean success = false;
+        for (int i = 0; i < 30; i++) {
+            try {
+                zk.create("/test", "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
+                        CreateMode.PERSISTENT);
+                success=true;
+                break;
+            } catch(KeeperException.ConnectionLossException e) {
+                Thread.sleep(1000);               
+            }            
+        }
+        Assert.assertTrue("Did not succeed in connecting in 30s", success);
+        Assert.assertFalse("The connection should not be read-only yet", watcher.readOnlyConnected);
+
+        // kill peer and wait no more than 5 seconds for read-only server
+        // to be started (which should take one tickTime (2 seconds))
+        qu.shutdown(2);
+        long start = Time.currentElapsedTime();
+        while (!(zk.getState() == States.CONNECTEDREADONLY)) {
+            Thread.sleep(200);
+            // FIXME this was originally 5 seconds, but realistically, on random/slow/virt hosts, there is no way to guarantee this
+            Assert.assertTrue("Can't connect to the server",
+                              Time.currentElapsedTime() - start < 30000);
+        }
+
+        watcher.waitForReadOnlyConnected(5000);
+        zk.close();
+    }
+
+    /**
+     * Tests a situation when client firstly connects to a read-only server and
+     * then connects to a majority server. Transition should be transparent for
+     * the user.
+     */
+    @Test(timeout = 90000)
+    public void testSessionEstablishment() throws Exception {
+        qu.shutdown(2);
+
+        CountdownWatcher watcher = new CountdownWatcher();
+        LOG.debug("Connection string: {}", qu.getConnString());
+        ZooKeeper zk = new ZooKeeper(qu.getConnString(), CONNECTION_TIMEOUT,
+                watcher, true);
+        watcher.waitForConnected(CONNECTION_TIMEOUT);
+        Assert.assertSame("should be in r/o mode", States.CONNECTEDREADONLY, zk
+                .getState());
+        long fakeId = zk.getSessionId();
+        LOG.info("Connected as r/o mode with state {} and session id {}",
+                zk.getState(), fakeId);
+
+        watcher.reset();
+        qu.start(2);
+        Assert.assertTrue("waiting for server up", ClientBase.waitForServerUp(
+                "127.0.0.1:" + qu.getPeer(2).clientPort, CONNECTION_TIMEOUT));
+        LOG.info("Server 127.0.0.1:{} is up", qu.getPeer(2).clientPort);
+        // ZOOKEEPER-2722: wait until we can connect to a read-write server after the quorum
+        // is formed. Otherwise, it is possible that client first connects to a read-only server,
+        // then drops the connection because of shutting down of the read-only server caused
+        // by leader election / quorum forming between the read-only server and the newly started
+        // server. If we happen to execute the zk.create after the read-only server is shutdown and
+        // before the quorum is formed, we will get a ConnectLossException.
+        watcher.waitForSyncConnected(CONNECTION_TIMEOUT);
+        Assert.assertEquals("Should be in read-write mode", States.CONNECTED,
+                zk.getState());
+        LOG.info("Connected as rw mode with state {} and session id {}",
+                zk.getState(), zk.getSessionId());
+        zk.create("/test", "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+        Assert.assertFalse("fake session and real session have same id", zk
+                .getSessionId() == fakeId);
+        zk.close();
+    }
+
+    /**
+     * Ensures that client seeks for r/w servers while it's connected to r/o
+     * server.
+     */
+    @SuppressWarnings("deprecation")
+    @Test(timeout = 90000)
+    public void testSeekForRwServer() throws Exception {
+
+        // setup the logger to capture all logs
+        Layout layout = Logger.getRootLogger().getAppender("CONSOLE")
+                .getLayout();
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        WriterAppender appender = new WriterAppender(layout, os);
+        appender.setImmediateFlush(true);
+        appender.setThreshold(Level.INFO);
+        Logger zlogger = Logger.getLogger("org.apache.zookeeper");
+        zlogger.addAppender(appender);
+
+        try {
+            qu.shutdown(2);
+            CountdownWatcher watcher = new CountdownWatcher();
+            ZooKeeper zk = new ZooKeeper(qu.getConnString(),
+                    CONNECTION_TIMEOUT, watcher, true);
+            watcher.waitForConnected(CONNECTION_TIMEOUT);
+
+            // if we don't suspend a peer it will rejoin a quorum
+            qu.getPeer(1).peer.suspend();
+
+            // start two servers to form a quorum; client should detect this and
+            // connect to one of them
+            watcher.reset();
+            qu.start(2);
+            qu.start(3);
+            ClientBase.waitForServerUp(qu.getConnString(), 2000);
+            watcher.waitForConnected(CONNECTION_TIMEOUT);
+            zk.create("/test", "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
+                    CreateMode.PERSISTENT);
+
+            // resume poor fellow
+            qu.getPeer(1).peer.resume();
+        } finally {
+            zlogger.removeAppender(appender);
+        }
+
+        os.close();
+        LineNumberReader r = new LineNumberReader(new StringReader(os
+                .toString()));
+        String line;
+        Pattern p = Pattern.compile(".*Majority server found.*");
+        boolean found = false;
+        while ((line = r.readLine()) != null) {
+            if (p.matcher(line).matches()) {
+                found = true;
+                break;
+            }
+        }
+        Assert.assertTrue(
+                "Majority server wasn't found while connected to r/o server",
+                found);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/RecoveryTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/RecoveryTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/RecoveryTest.java
new file mode 100644
index 0000000..c084a68
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/RecoveryTest.java
@@ -0,0 +1,209 @@
+/**
+ * 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.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.data.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 RecoveryTest extends ZKTestCase implements Watcher {
+    protected static final Logger LOG = LoggerFactory.getLogger(RecoveryTest.class);
+
+    private static final String HOSTPORT =
+        "127.0.0.1:" + PortAssignment.unique();
+
+    private volatile CountDownLatch startSignal;
+
+    /**
+     * Verify that if a server goes down that clients will reconnect
+     * automatically after the server is restarted. Note that this requires the
+     * server to restart within the connection timeout period.
+     *
+     * Also note that the client latches are used to eliminate any chance
+     * of spurrious connectionloss exceptions on the read ops. Specifically
+     * a sync operation will throw this exception if the server goes down
+     * (as recognized by the client) during the operation. If the operation
+     * occurs after the server is down, but before the client recognizes
+     * that the server is down (ping) then the op will throw connectionloss.
+     */
+    @Test
+    public void testRecovery() throws Exception {
+        File tmpDir = ClientBase.createTmpDir();
+
+        ClientBase.setupTestEnv();
+        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
+
+        int oldSnapCount = SyncRequestProcessor.getSnapCount();
+        SyncRequestProcessor.setSnapCount(1000);
+        try {
+            final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]);
+            ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);
+            f.startup(zks);
+            LOG.info("starting up the the server, waiting");
+
+            Assert.assertTrue("waiting for server up",
+                       ClientBase.waitForServerUp(HOSTPORT,
+                                       CONNECTION_TIMEOUT));
+
+            startSignal = new CountDownLatch(1);
+            ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);
+            startSignal.await(CONNECTION_TIMEOUT,
+                    TimeUnit.MILLISECONDS);
+            Assert.assertTrue("count == 0", startSignal.getCount() == 0);
+            String path;
+            LOG.info("starting creating nodes");
+            for (int i = 0; i < 10; i++) {
+                path = "/" + i;
+                zk.create(path,
+                          (path + "!").getBytes(),
+                          Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+                for (int j = 0; j < 10; j++) {
+                    String subpath = path + "/" + j;
+                    zk.create(subpath, (subpath + "!").getBytes(),
+                            Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+                    for (int k = 0; k < 20; k++) {
+                        String subsubpath = subpath + "/" + k;
+                        zk.create(subsubpath, (subsubpath + "!").getBytes(),
+                                Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+                    }
+                }
+            }
+
+            f.shutdown();
+            zks.shutdown();
+            Assert.assertTrue("waiting for server down",
+                       ClientBase.waitForServerDown(HOSTPORT,
+                                          CONNECTION_TIMEOUT));
+
+            zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
+            f = ServerCnxnFactory.createFactory(PORT, -1);
+
+            startSignal = new CountDownLatch(1);
+
+            f.startup(zks);
+
+            Assert.assertTrue("waiting for server up",
+                       ClientBase.waitForServerUp(HOSTPORT,
+                                           CONNECTION_TIMEOUT));
+
+            startSignal.await(CONNECTION_TIMEOUT,
+                    TimeUnit.MILLISECONDS);
+            Assert.assertTrue("count == 0", startSignal.getCount() == 0);
+
+            Stat stat = new Stat();
+            for (int i = 0; i < 10; i++) {
+                path = "/" + i;
+                LOG.info("Checking " + path);
+                Assert.assertEquals(new String(zk.getData(path, false, stat)), path
+                        + "!");
+                for (int j = 0; j < 10; j++) {
+                    String subpath = path + "/" + j;
+                    Assert.assertEquals(new String(zk.getData(subpath, false, stat)),
+                            subpath + "!");
+                    for (int k = 0; k < 20; k++) {
+                        String subsubpath = subpath + "/" + k;
+                        Assert.assertEquals(new String(zk.getData(subsubpath, false,
+                                stat)), subsubpath + "!");
+                    }
+                }
+            }
+            f.shutdown();
+            zks.shutdown();
+
+            Assert.assertTrue("waiting for server down",
+                       ClientBase.waitForServerDown(HOSTPORT,
+                                          ClientBase.CONNECTION_TIMEOUT));
+
+            zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
+            f = ServerCnxnFactory.createFactory(PORT, -1);
+
+            startSignal = new CountDownLatch(1);
+
+            f.startup(zks);
+
+            Assert.assertTrue("waiting for server up",
+                       ClientBase.waitForServerUp(HOSTPORT,
+                               CONNECTION_TIMEOUT));
+
+            startSignal.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);
+            Assert.assertTrue("count == 0", startSignal.getCount() == 0);
+
+            stat = new Stat();
+            LOG.info("Check 2");
+            for (int i = 0; i < 10; i++) {
+                path = "/" + i;
+                Assert.assertEquals(new String(zk.getData(path, false, stat)),
+                             path + "!");
+                for (int j = 0; j < 10; j++) {
+                    String subpath = path + "/" + j;
+                    Assert.assertEquals(new String(zk.getData(subpath, false, stat)),
+                            subpath + "!");
+                    for (int k = 0; k < 20; k++) {
+                        String subsubpath = subpath + "/" + k;
+                        Assert.assertEquals(new String(zk.getData(subsubpath, false,
+                                stat)), subsubpath + "!");
+                    }
+                }
+            }
+            zk.close();
+
+            f.shutdown();
+            zks.shutdown();
+
+            Assert.assertTrue("waiting for server down",
+                       ClientBase.waitForServerDown(HOSTPORT,
+                                                    CONNECTION_TIMEOUT));
+        } finally {
+            SyncRequestProcessor.setSnapCount(oldSnapCount);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatcherEvent)
+     */
+    public void process(WatchedEvent event) {
+        LOG.info("Event:" + event.getState() + " " + event.getType() + " " + event.getPath());
+        if (event.getState() == KeeperState.SyncConnected
+                && startSignal != null && startSignal.getCount() > 0)
+        {
+            startSignal.countDown();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/RepeatStartupTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/RepeatStartupTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/RepeatStartupTest.java
new file mode 100644
index 0000000..f714a2c
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/RepeatStartupTest.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.server.ServerCnxnFactory;
+import org.apache.zookeeper.server.ZooKeeperServer;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class RepeatStartupTest extends ZKTestCase {
+
+    /** bring up 5 quorum peers and then shut them down
+     * and then bring one of the nodes as server
+     *
+     * @throws Exception might be thrown here
+     */
+    @Test
+    public void testFail() throws Exception {
+        QuorumBase qb = new QuorumBase();
+        qb.setUp();
+
+        System.out.println("Comment: the servers are at " + qb.hostPort);
+        ZooKeeper zk = qb.createClient();
+        zk.create("/test", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+        zk.close();
+        qb.shutdown(qb.s1);
+        qb.shutdown(qb.s2);
+        qb.shutdown(qb.s3);
+        qb.shutdown(qb.s4);
+        qb.shutdown(qb.s5);
+        String hp = qb.hostPort.split(",")[0];
+        ZooKeeperServer zks = new ZooKeeperServer(qb.s1.getTxnFactory().getSnapDir(),
+                qb.s1.getTxnFactory().getDataDir(), 3000);
+        final int PORT = Integer.parseInt(hp.split(":")[1]);
+        ServerCnxnFactory factory = ServerCnxnFactory.createFactory(PORT, -1);
+
+        factory.startup(zks);
+        System.out.println("Comment: starting factory");
+        Assert.assertTrue("waiting for server up",
+                   ClientBase.waitForServerUp("127.0.0.1:" + PORT,
+                           QuorumTest.CONNECTION_TIMEOUT));
+        factory.shutdown();
+        zks.shutdown();
+        Assert.assertTrue("waiting for server down",
+                   ClientBase.waitForServerDown("127.0.0.1:" + PORT,
+                                                QuorumTest.CONNECTION_TIMEOUT));
+        System.out.println("Comment: shutting down standalone");
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/RestoreCommittedLogTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/RestoreCommittedLogTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/RestoreCommittedLogTest.java
new file mode 100644
index 0000000..65cc0e2
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/RestoreCommittedLogTest.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.File;
+import java.util.List;
+import java.util.LinkedList;
+
+import org.apache.log4j.Logger;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.server.quorum.Leader.Proposal;
+import org.apache.zookeeper.server.ServerCnxnFactory;
+import org.apache.zookeeper.server.SyncRequestProcessor;
+import org.apache.zookeeper.server.ZooKeeperServer;
+import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
+import org.junit.Assert;
+import org.junit.Test;
+
+/** After a replica starts, it should load commits in its committedLog list. 
+ *  This test checks if committedLog != 0 after replica restarted.
+ */
+public class RestoreCommittedLogTest extends ZKTestCase implements  Watcher {
+    private static final Logger LOG = Logger.getLogger(RestoreCommittedLogTest.class);
+    private static String HOSTPORT = "127.0.0.1:" + PortAssignment.unique();
+    private static final int CONNECTION_TIMEOUT = 3000;
+    /**
+     * test the purge
+     * @throws Exception an exception might be thrown here
+     */
+    @Test
+    public void testRestoreCommittedLog() throws Exception {
+        File tmpDir = ClientBase.createTmpDir();
+        ClientBase.setupTestEnv();
+        ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
+        SyncRequestProcessor.setSnapCount(100);
+        final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]);
+        ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);
+        f.startup(zks);
+        Assert.assertTrue("waiting for server being up ",
+                ClientBase.waitForServerUp(HOSTPORT,CONNECTION_TIMEOUT));
+        ZooKeeper zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);
+        try {
+            for (int i = 0; i< 2000; i++) {
+                zk.create("/invalidsnap-" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,
+                        CreateMode.PERSISTENT);
+            }
+        } finally {
+            zk.close();
+        }
+        f.shutdown();
+        zks.shutdown();
+        Assert.assertTrue("waiting for server to shutdown",
+                ClientBase.waitForServerDown(HOSTPORT, CONNECTION_TIMEOUT));
+
+        // start server again
+        zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
+        zks.startdata();
+        LinkedList<Proposal> committedLog = zks.getZKDatabase().getCommittedLog();
+        int logsize = committedLog.size();
+        LOG.info("committedLog size = " + logsize);
+        Assert.assertTrue("log size != 0", (logsize != 0));
+        zks.shutdown();
+    }
+
+    public void process(WatchedEvent event) {
+        // do nothing
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthDesignatedClientTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthDesignatedClientTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthDesignatedClientTest.java
new file mode 100644
index 0000000..9e28278
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthDesignatedClientTest.java
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SaslAuthDesignatedClientTest extends ClientBase {
+    static {
+        System.setProperty("zookeeper.authProvider.1","org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
+        System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, "MyZookeeperClient");
+
+        try {
+            File tmpDir = createTmpDir();
+            File saslConfFile = new File(tmpDir, "jaas.conf");
+            FileWriter fwriter = new FileWriter(saslConfFile);
+
+            fwriter.write("" +
+                "Server {\n" +
+                "          org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                "          user_myuser=\"mypassword\";\n" +
+                "};\n" +
+                "Client {\n" + /* this 'Client' section has an incorrect password, but we're not configured
+                                  to  use it (we're configured by the above System.setProperty(...LOGIN_CONTEXT_NAME_KEY...) to 
+                                  use the 'MyZookeeperClient' section below, which has the correct password).*/
+                "       org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                "       username=\"myuser\"\n" +
+                "       password=\"wrongpassword\";\n" +
+                "};" +
+                "MyZookeeperClient {\n" +
+                "       org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                "       username=\"myuser\"\n" +
+                "       password=\"mypassword\";\n" +
+                "};" + "\n");
+            fwriter.close();
+            System.setProperty("java.security.auth.login.config",saslConfFile.getAbsolutePath());
+        }
+        catch (IOException e) {
+            // could not create tmp directory to hold JAAS conf file : test will fail now.
+        }
+    }
+
+    @Test
+    public void testAuth() throws Exception {
+        ZooKeeper zk = createClient();
+        try {
+            zk.create("/path1", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
+            Thread.sleep(1000);
+        } catch (KeeperException e) {
+          Assert.fail("test failed :" + e);
+        }
+        finally {
+            zk.close();
+        }
+    }
+
+    @Test
+    public void testSaslConfig() throws Exception {
+        ZooKeeper zk = createClient();
+        try {
+            zk.getChildren("/", false);
+            Assert.assertFalse(zk.getSaslClient().
+                clientTunneledAuthenticationInProgress());
+            Assert.assertEquals(zk.getSaslClient().getSaslState(),
+                ZooKeeperSaslClient.SaslState.COMPLETE);
+            Assert.assertNotNull(
+                javax.security.auth.login.Configuration.getConfiguration().
+                    getAppConfigurationEntry("MyZookeeperClient"));
+            Assert.assertSame(zk.getSaslClient().getLoginContext(),
+                "MyZookeeperClient");
+        } catch (KeeperException e) {
+            Assert.fail("test failed :" + e);
+        } finally {
+            zk.close();
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthDesignatedServerTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthDesignatedServerTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthDesignatedServerTest.java
new file mode 100644
index 0000000..aa30870
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthDesignatedServerTest.java
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.server.ZooKeeperSaslServer;
+import org.apache.zookeeper.JaasConfiguration;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SaslAuthDesignatedServerTest extends ClientBase {
+    public static int AUTHENTICATION_TIMEOUT = 30000;
+
+    static {
+        System.setProperty("zookeeper.authProvider.1","org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
+        System.setProperty(ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY, "MyZookeeperServer");
+
+        JaasConfiguration conf = new JaasConfiguration();
+
+        /* this 'Server' section has an incorrect password, but we're not configured
+         * to  use it (we're configured by the above System.setProperty(...LOGIN_CONTEXT_NAME_KEY...)
+         * to use the 'MyZookeeperServer' section below, which has the correct password).
+         */
+        conf.addSection("Server", "org.apache.zookeeper.server.auth.DigestLoginModule",
+                        "user_myuser", "wrongpassword");
+
+        conf.addSection("MyZookeeperServer", "org.apache.zookeeper.server.auth.DigestLoginModule",
+                        "user_myuser", "mypassword");
+
+        conf.addSection("Client", "org.apache.zookeeper.server.auth.DigestLoginModule",
+                        "username", "myuser", "password", "mypassword");
+
+        javax.security.auth.login.Configuration.setConfiguration(conf);
+    }
+
+    private AtomicInteger authFailed = new AtomicInteger(0);
+
+    private class MyWatcher extends CountdownWatcher {
+        volatile CountDownLatch authCompleted;
+
+        @Override
+        synchronized public void reset() {
+            authCompleted = new CountDownLatch(1);
+            super.reset();
+        }
+
+        @Override
+        public synchronized void process(WatchedEvent event) {
+            if (event.getState() == KeeperState.AuthFailed) {
+                authFailed.incrementAndGet();
+                authCompleted.countDown();
+            } else if (event.getState() == KeeperState.SaslAuthenticated) {
+                authCompleted.countDown();
+            } else {
+                super.process(event);
+            }
+        }
+    }
+
+    @Test
+    public void testAuth() throws Exception {
+        MyWatcher watcher = new MyWatcher();
+        ZooKeeper zk = createClient(watcher);
+        watcher.authCompleted.await(AUTHENTICATION_TIMEOUT, TimeUnit.MILLISECONDS);
+        Assert.assertEquals(authFailed.get(), 0);
+
+        try {
+            zk.create("/path1", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
+        } catch (KeeperException e) {
+          Assert.fail("test failed :" + e);
+        }
+        finally {
+            zk.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailDesignatedClientTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailDesignatedClientTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailDesignatedClientTest.java
new file mode 100644
index 0000000..5291141
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailDesignatedClientTest.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.TestableZooKeeper;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SaslAuthFailDesignatedClientTest extends ClientBase {
+    static {
+        System.setProperty("zookeeper.authProvider.1","org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
+        System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, "MyZookeeperClient");
+
+        try {
+            File tmpDir = createTmpDir();
+            File saslConfFile = new File(tmpDir, "jaas.conf");
+            FileWriter fwriter = new FileWriter(saslConfFile);
+
+            fwriter.write("" +
+                "Server {\n" +
+                "          org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                "          user_myuser=\"mypassword\";\n" +
+                "};\n" +
+                "Client {\n" + /* this 'Client' section has the correct password, but we're not configured
+                                  to  use it (we're configured by the above System.setProperty(...LOGIN_CONTEXT_NAME_KEY...) to 
+                                  use the 'MyZookeeperClient' section, which has an incorrect password).*/
+                "       org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                "       username=\"myuser\"\n" +
+                "       password=\"mypassword\";\n" +
+                "};" +
+                "MyZookeeperClient {\n" +
+                "       org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                "       username=\"myuser\"\n" +
+                "       password=\"wrongpassword\";\n" +
+                "};" + "\n");
+            fwriter.close();
+            System.setProperty("java.security.auth.login.config",saslConfFile.getAbsolutePath());
+        }
+        catch (IOException e) {
+            // could not create tmp directory to hold JAAS conf file : test will fail now.
+        }
+    }
+
+    private AtomicInteger authFailed = new AtomicInteger(0);
+
+    private class MyWatcher extends CountdownWatcher {
+        @Override
+        public synchronized void process(WatchedEvent event) {
+            if (event.getState() == KeeperState.AuthFailed) {
+                authFailed.incrementAndGet();
+            }
+            else {
+                super.process(event);
+            }
+        }
+    }
+
+    @Test
+    public void testAuth() throws Exception {
+        // Cannot use createClient here because server may close session before 
+        // JMXEnv.ensureAll is called which will fail the test case
+        CountdownWatcher watcher = new CountdownWatcher();
+        TestableZooKeeper zk = new TestableZooKeeper(hostPort, CONNECTION_TIMEOUT, watcher);
+        if (!watcher.clientConnected.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS))
+        {
+            Assert.fail("Unable to connect to server");
+        }
+        try {
+            zk.create("/path1", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
+            Assert.fail("Should have gotten exception.");
+        } catch (KeeperException e) {
+            // ok, exception as expected.
+            LOG.info("Got exception as expected: " + e);
+        }
+        finally {
+            zk.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailNotifyTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailNotifyTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailNotifyTest.java
new file mode 100644
index 0000000..2b00d86
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailNotifyTest.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.TestableZooKeeper;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.junit.Test;
+import org.junit.Assert;
+
+public class SaslAuthFailNotifyTest extends ClientBase {
+    static {
+        System.setProperty("zookeeper.authProvider.1","org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
+        System.setProperty("zookeeper.allowSaslFailedClients","true");
+
+        try {
+            File tmpDir = createTmpDir();
+            File saslConfFile = new File(tmpDir, "jaas.conf");
+            FileWriter fwriter = new FileWriter(saslConfFile);
+
+            fwriter.write("" +
+                    "Server {\n" +
+                    "          org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                    "          user_super=\"test\";\n" +
+                    "};\n" +
+                    "Client {\n" +
+                    "       org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                    "       username=\"super\"\n" +
+                    "       password=\"test1\";\n" + // NOTE: wrong password ('test' != 'test1') : this is to test SASL authentication failure.
+                    "};" + "\n");
+            fwriter.close();
+            System.setProperty("java.security.auth.login.config",saslConfFile.getAbsolutePath());
+        }
+        catch (IOException e) {
+            // could not create tmp directory to hold JAAS conf file.
+        }
+    }
+
+    private AtomicInteger authFailed = new AtomicInteger(0);
+    
+    @Override
+    protected TestableZooKeeper createClient(String hp)
+    throws IOException, InterruptedException
+    {
+        MyWatcher watcher = new MyWatcher();
+        return createClient(watcher, hp);
+    }
+
+    private class MyWatcher extends CountdownWatcher {
+        @Override
+        public synchronized void process(WatchedEvent event) {
+            if (event.getState() == KeeperState.AuthFailed) {
+                synchronized(authFailed) {
+                    authFailed.incrementAndGet();
+                    authFailed.notify();
+                }
+            }
+            else {
+                super.process(event);
+            }
+        }
+    }
+
+    @Test
+    public void testBadSaslAuthNotifiesWatch() throws Exception {
+        ZooKeeper zk = createClient();
+        // wait for authFailed event from client's EventThread.
+        synchronized(authFailed) {
+            authFailed.wait();
+        }
+        Assert.assertEquals(authFailed.get(),1);
+        zk.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailTest.java
new file mode 100644
index 0000000..33a505e
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailTest.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.TestableZooKeeper;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.junit.Test;
+import org.junit.Assert;
+
+public class SaslAuthFailTest extends ClientBase {
+    static {
+        System.setProperty("zookeeper.authProvider.1","org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
+        System.setProperty("zookeeper.allowSaslFailedClients","true");
+
+        try {
+            File tmpDir = createTmpDir();
+            File saslConfFile = new File(tmpDir, "jaas.conf");
+            FileWriter fwriter = new FileWriter(saslConfFile);
+
+            fwriter.write("" +
+                    "Server {\n" +
+                    "          org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                    "          user_super=\"test\";\n" +
+                    "};\n" +
+                    "Client {\n" +
+                    "       org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                    "       username=\"super\"\n" +
+                    "       password=\"test1\";\n" + // NOTE: wrong password ('test' != 'test1') : this is to test SASL authentication failure.
+                    "};" + "\n");
+            fwriter.close();
+            System.setProperty("java.security.auth.login.config",saslConfFile.getAbsolutePath());
+        }
+        catch (IOException e) {
+            // could not create tmp directory to hold JAAS conf file.
+        }
+    }
+    
+    @Test
+    public void testAuthFail() throws Exception {
+        ZooKeeper zk = createClient();
+        try {
+            zk.create("/path1", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
+            Assert.fail("Should have gotten exception.");
+        } catch(Exception e ) {
+            // ok, exception as expected.
+            LOG.info("Got exception as expected: " + e);
+        } finally {
+            zk.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthMissingClientConfigTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthMissingClientConfigTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthMissingClientConfigTest.java
new file mode 100644
index 0000000..98be0be
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthMissingClientConfigTest.java
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SaslAuthMissingClientConfigTest extends ClientBase {
+    static {
+        System.setProperty("zookeeper.authProvider.1","org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
+        // This configuration section 'MyZookeeperClient', is missing from the JAAS configuration.
+        // As a result, SASL authentication should fail, which is tested by this test (testAuth()).
+        System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, "MyZookeeperClient");
+
+        try {
+            File tmpDir = createTmpDir();
+            File saslConfFile = new File(tmpDir, "jaas.conf");
+            FileWriter fwriter = new FileWriter(saslConfFile);
+
+            fwriter.write("" +
+                "Server {\n" +
+                "          org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                "          user_myuser=\"mypassword\";\n" +
+                "};\n" +
+                "Client {\n" + /* this 'Client' section has the correct password, but we're not configured
+                                  to  use it - we're configured instead by the above
+                                  System.setProperty(...LOGIN_CONTEXT_NAME_KEY...) to
+                                  use the (nonexistent) 'MyZookeeperClient' section. */
+                "       org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
+                "       username=\"myuser\"\n" +
+                "       password=\"mypassword\";\n" +
+                "};\n");
+            fwriter.close();
+            System.setProperty("java.security.auth.login.config",saslConfFile.getAbsolutePath());
+        }
+        catch (IOException e) {
+            // could not create tmp directory to hold JAAS conf file : test will fail now.
+        }
+    }
+
+    private AtomicInteger authFailed = new AtomicInteger(0);
+
+    private class MyWatcher extends CountdownWatcher {
+        @Override
+        public synchronized void process(WatchedEvent event) {
+            if (event.getState() == KeeperState.AuthFailed) {
+                authFailed.incrementAndGet();
+            }
+            else {
+                super.process(event);
+            }
+        }
+    }
+
+    @Test
+    public void testAuth() throws Exception {
+        ZooKeeper zk = createClient();
+        try {
+            zk.create("/path1", null, Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
+            Assert.fail("Should have gotten exception.");
+        } catch (KeeperException e) {
+            // ok, exception as expected.
+            LOG.info("Got exception as expected: " + e);
+        }
+        finally {
+            zk.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslClientTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslClientTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslClientTest.java
new file mode 100644
index 0000000..8213abc
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslClientTest.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class SaslClientTest extends ZKTestCase {
+
+    private String existingPropertyValue = null;
+
+    @Before
+    public void setUp() {
+        existingPropertyValue = System.getProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY);
+    }
+
+    @After
+    public void tearDown() {
+        // Restore the System property if it was set previously
+        if (existingPropertyValue != null) {
+            System.setProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY, existingPropertyValue);
+        }
+    }
+
+    @Test
+    public void testSaslClientDisabled() {
+        System.clearProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY);
+        Assert.assertTrue("SASL client disabled", ZooKeeperSaslClient.isEnabled());
+
+        for (String value : Arrays.asList("true", "TRUE")) {
+            System.setProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY, value);
+            Assert.assertTrue("SASL client disabled", ZooKeeperSaslClient.isEnabled());
+        }
+
+        for (String value : Arrays.asList("false", "FALSE")) {
+            System.setProperty(ZooKeeperSaslClient.ENABLE_CLIENT_SASL_KEY, value);
+            Assert.assertFalse("SASL client disabled", ZooKeeperSaslClient.isEnabled());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionInvalidationTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionInvalidationTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionInvalidationTest.java
new file mode 100644
index 0000000..3a0b2ee
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionInvalidationTest.java
@@ -0,0 +1,105 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+import junit.framework.Assert;
+
+import org.apache.jute.BinaryOutputArchive;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooDefs.OpCode;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.proto.ConnectRequest;
+import org.apache.zookeeper.proto.CreateRequest;
+import org.apache.zookeeper.proto.RequestHeader;
+import org.junit.Test;
+
+public class SessionInvalidationTest extends ClientBase {
+    /**
+     * Test solution for ZOOKEEPER-1208. Verify that operations are not
+     * accepted after a close session.
+     * 
+     * We're using our own marshalling here in order to force an operation
+     * after the session is closed (ZooKeeper.class will not allow this). Also
+     * by filling the pipe with operations it increases the likelyhood that
+     * the server will process the create before FinalRequestProcessor
+     * removes the session from the tracker.
+     */
+    @Test
+    public void testCreateAfterCloseShouldFail() throws Exception {
+        for (int i = 0; i < 10; i++) {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
+
+            // open a connection
+            boa.writeInt(44, "len");
+            ConnectRequest conReq = new ConnectRequest(0, 0, 30000, 0, new byte[16]);
+            conReq.serialize(boa, "connect");
+
+            // close connection
+            boa.writeInt(8, "len");
+            RequestHeader h = new RequestHeader(1, ZooDefs.OpCode.closeSession);
+            h.serialize(boa, "header");
+
+            // create ephemeral znode
+            boa.writeInt(52, "len"); // We'll fill this in later
+            RequestHeader header = new RequestHeader(2, OpCode.create);
+            header.serialize(boa, "header");
+            CreateRequest createReq = new CreateRequest("/foo" + i, new byte[0],
+                    Ids.OPEN_ACL_UNSAFE, 1);
+            createReq.serialize(boa, "request");
+            baos.close();
+            
+            System.out.println("Length:" + baos.toByteArray().length);
+            
+            String hp[] = hostPort.split(":");
+            Socket sock = new Socket(hp[0], Integer.parseInt(hp[1]));
+            InputStream resultStream = null;
+            try {
+                OutputStream outstream = sock.getOutputStream();
+                byte[] data = baos.toByteArray();
+                outstream.write(data);
+                outstream.flush();
+                
+                resultStream = sock.getInputStream();
+                byte[] b = new byte[10000];
+                int len;
+                while ((len = resultStream.read(b)) >= 0) {
+                    // got results
+                    System.out.println("gotlen:" + len);
+                }
+            } finally {
+                if (resultStream != null) {
+                    resultStream.close();
+                }
+                sock.close();
+            }
+        }
+        
+        ZooKeeper zk = createClient();
+        Assert.assertEquals(1, zk.getChildren("/", false).size());
+
+        zk.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionTest.java
new file mode 100644
index 0000000..891b0f0
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionTest.java
@@ -0,0 +1,394 @@
+/**
+ * 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.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.zookeeper.AsyncCallback;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.Watcher.Event.EventType;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.server.ServerCnxnFactory;
+import org.apache.zookeeper.server.ZooKeeperServer;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class SessionTest extends ZKTestCase {
+    protected static final Logger LOG = LoggerFactory.getLogger(SessionTest.class);
+
+    private static final String HOSTPORT = "127.0.0.1:" +
+            PortAssignment.unique();
+    
+    private ServerCnxnFactory serverFactory;
+    private ZooKeeperServer zs;
+
+    private CountDownLatch startSignal;
+
+    File tmpDir;
+
+    private final int TICK_TIME = 3000;
+
+    @Before
+    public void setUp() throws Exception {
+        if (tmpDir == null) {
+            tmpDir = ClientBase.createTmpDir();
+        }
+
+        ClientBase.setupTestEnv();
+        zs = new ZooKeeperServer(tmpDir, tmpDir, TICK_TIME);
+
+        final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]);
+        serverFactory = ServerCnxnFactory.createFactory(PORT, -1);
+        serverFactory.startup(zs);
+
+        Assert.assertTrue("waiting for server up",
+                   ClientBase.waitForServerUp(HOSTPORT,
+                                              CONNECTION_TIMEOUT));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        serverFactory.shutdown();
+        zs.shutdown();
+        Assert.assertTrue("waiting for server down",
+                   ClientBase.waitForServerDown(HOSTPORT,
+                                                CONNECTION_TIMEOUT));
+    }
+
+    private static class CountdownWatcher implements Watcher {
+        volatile CountDownLatch clientConnected = new CountDownLatch(1);
+
+        public void process(WatchedEvent event) {
+            if (event.getState() == KeeperState.SyncConnected) {
+                clientConnected.countDown();
+            }
+        }
+    }
+
+    private DisconnectableZooKeeper createClient()
+        throws IOException, InterruptedException
+    {
+        CountdownWatcher watcher = new CountdownWatcher();
+        return createClient(CONNECTION_TIMEOUT, watcher);
+    }
+
+    private DisconnectableZooKeeper createClient(int timeout)
+        throws IOException, InterruptedException
+    {
+        CountdownWatcher watcher = new CountdownWatcher();
+        return createClient(timeout, watcher);
+    }
+
+    private DisconnectableZooKeeper createClient(int timeout,
+            CountdownWatcher watcher)
+        throws IOException, InterruptedException
+    {
+        DisconnectableZooKeeper zk =
+                new DisconnectableZooKeeper(HOSTPORT, timeout, watcher);
+        if(!watcher.clientConnected.await(timeout, TimeUnit.MILLISECONDS)) {
+            Assert.fail("Unable to connect to server");
+        }
+
+        return zk;
+    }
+
+// FIXME this test is Assert.failing due to client close race condition fixing in separate patch for ZOOKEEPER-63
+//    /**
+//     * this test checks to see if the sessionid that was created for the
+//     * first zookeeper client can be reused for the second one immidiately
+//     * after the first client closes and the new client resues them.
+//     * @throws IOException
+//     * @throws InterruptedException
+//     * @throws KeeperException
+//     */
+//    public void testSessionReuse() throws IOException, InterruptedException {
+//        ZooKeeper zk = createClient();
+//
+//        long sessionId = zk.getSessionId();
+//        byte[] passwd = zk.getSessionPasswd();
+//        zk.close();
+//
+//        zk.close();
+//
+//        LOG.info("Closed first session");
+//
+//        startSignal = new CountDownLatch(1);
+//        zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this,
+//                sessionId, passwd);
+//        startSignal.await();
+//
+//        LOG.info("Opened reuse");
+//
+//        Assert.assertEquals(sessionId, zk.getSessionId());
+//
+//        zk.close();
+//    }
+
+    private class MyWatcher implements Watcher {
+        private String name;
+        public MyWatcher(String name) {
+            this.name = name;
+        }
+        public void process(WatchedEvent event) {
+            LOG.info(name + " event:" + event.getState() + " "
+                    + event.getType() + " " + event.getPath());
+            if (event.getState() == KeeperState.SyncConnected
+                    && startSignal != null && startSignal.getCount() > 0)
+            {
+                startSignal.countDown();
+            }
+        }
+    }
+
+    /**
+     * This test verifies that when the session id is reused, and the original
+     * client is disconnected, but not session closed, that the server
+     * will remove ephemeral nodes created by the original session.
+     */
+    @Test
+    public void testSession()
+        throws IOException, InterruptedException, KeeperException
+    {
+        DisconnectableZooKeeper zk = createClient();
+        zk.create("/e", new byte[0], Ids.OPEN_ACL_UNSAFE,
+                        CreateMode.EPHEMERAL);
+        LOG.info("zk with session id 0x" + Long.toHexString(zk.getSessionId())
+                + " was destroyed!");
+
+        // disconnect the client by killing the socket, not sending the
+        // session disconnect to the server as usual. This allows the test
+        // to verify disconnect handling
+        zk.disconnect();
+
+        Stat stat = new Stat();
+        startSignal = new CountDownLatch(1);
+        zk = new DisconnectableZooKeeper(HOSTPORT, CONNECTION_TIMEOUT,
+                new MyWatcher("testSession"), zk.getSessionId(),
+                zk.getSessionPasswd());
+        startSignal.await();
+
+        LOG.info("zk with session id 0x" + Long.toHexString(zk.getSessionId())
+                 + " was created!");
+        zk.getData("/e", false, stat);
+        LOG.info("After get data /e");
+        zk.close();
+
+        zk = createClient();
+        Assert.assertEquals(null, zk.exists("/e", false));
+        LOG.info("before close zk with session id 0x"
+                + Long.toHexString(zk.getSessionId()) + "!");
+        zk.close();
+        try {
+            zk.getData("/e", false, stat);
+            Assert.fail("Should have received a SessionExpiredException");
+        } catch(KeeperException.SessionExpiredException e) {}
+        
+        AsyncCallback.DataCallback cb = new AsyncCallback.DataCallback() {
+            String status = "not done";
+            public void processResult(int rc, String p, Object c, byte[] b, Stat s) {
+                synchronized(this) { status = KeeperException.Code.get(rc).toString(); this.notify(); }
+            }
+           public String toString() { return status; }
+        };
+        zk.getData("/e", false, cb, null);
+        synchronized(cb) {
+            if (cb.toString().equals("not done")) {
+                cb.wait(1000);
+            }
+        }
+        Assert.assertEquals(KeeperException.Code.SESSIONEXPIRED.toString(), cb.toString());        
+    }
+
+    /**
+     * Make sure that we cannot have two connections with the same
+     * session id.
+     *
+     * @throws IOException
+     * @throws InterruptedException
+     * @throws KeeperException
+     */
+    @Test
+    public void testSessionMove() throws Exception {
+        String hostPorts[] = HOSTPORT.split(",");
+        DisconnectableZooKeeper zk = new DisconnectableZooKeeper(hostPorts[0],
+                CONNECTION_TIMEOUT, new MyWatcher("0"));
+        zk.create("/sessionMoveTest", new byte[0], Ids.OPEN_ACL_UNSAFE,
+                CreateMode.EPHEMERAL);
+        // we want to loop through the list twice
+        for(int i = 0; i < hostPorts.length*2; i++) {
+            zk.dontReconnect();
+            // This should stomp the zk handle
+            DisconnectableZooKeeper zknew = new DisconnectableZooKeeper(
+                    hostPorts[(i+1)%hostPorts.length],
+                    CONNECTION_TIMEOUT,
+                    new MyWatcher(Integer.toString(i+1)),
+                    zk.getSessionId(),
+                    zk.getSessionPasswd());
+            final int result[] = new int[1];
+            result[0] = Integer.MAX_VALUE;
+            zknew.sync("/", new AsyncCallback.VoidCallback() {
+                    public void processResult(int rc, String path, Object ctx) {
+                        synchronized(result) { result[0] = rc; result.notify(); }
+                    }
+                }, null);
+            synchronized(result) {
+                if(result[0] == Integer.MAX_VALUE) {
+                    result.wait(5000);
+                }
+            }
+            LOG.info(hostPorts[(i+1)%hostPorts.length] + " Sync returned " + result[0]);
+            Assert.assertTrue(result[0] == KeeperException.Code.OK.intValue());
+            zknew.setData("/", new byte[1], -1);
+            try {
+                zk.setData("/", new byte[1], -1);
+                Assert.fail("Should have lost the connection");
+            } catch(KeeperException.ConnectionLossException e) {
+                LOG.info("Got connection loss exception as expected");
+            }
+            //zk.close();
+            zk = zknew;
+        }
+        zk.close();
+    }
+    /**
+     * This test makes sure that duplicate state changes are not communicated
+     * to the client watcher. For example we should not notify state as
+     * "disconnected" if the watch has already been disconnected. In general
+     * we don't consider a dup state notification if the event type is
+     * not "None" (ie non-None communicates an event).
+     */
+    @Test
+    public void testSessionStateNoDupStateReporting()
+        throws IOException, InterruptedException, KeeperException
+    {
+        final int TIMEOUT = 3000;
+        DupWatcher watcher = new DupWatcher();
+        ZooKeeper zk = createClient(TIMEOUT, watcher);
+
+        // shutdown the server
+        serverFactory.shutdown();
+
+        try {
+            Thread.sleep(10000);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        // verify that the size is just 2 - ie connect then disconnect
+        // if the client attempts reconnect and we are not handling current
+        // state correctly (ie eventing on duplicate disconnects) then we'll
+        // see a disconnect for each Assert.failed connection attempt
+        Assert.assertEquals(2, watcher.states.size());
+
+        zk.close();
+    }
+
+    /**
+     * Verify access to the negotiated session timeout.
+     */
+    @Test
+    public void testSessionTimeoutAccess() throws Exception {
+        // validate typical case - requested == negotiated
+        DisconnectableZooKeeper zk = createClient(TICK_TIME * 4);
+        Assert.assertEquals(TICK_TIME * 4, zk.getSessionTimeout());
+        // make sure tostring works in both cases
+        LOG.info(zk.toString());
+        zk.close();
+        LOG.info(zk.toString());
+
+        // validate lower limit
+        zk = createClient(TICK_TIME);
+        Assert.assertEquals(TICK_TIME * 2, zk.getSessionTimeout());
+        LOG.info(zk.toString());
+        zk.close();
+        LOG.info(zk.toString());
+
+        // validate upper limit
+        zk = createClient(TICK_TIME * 30);
+        Assert.assertEquals(TICK_TIME * 20, zk.getSessionTimeout());
+        LOG.info(zk.toString());
+        zk.close();
+        LOG.info(zk.toString());
+    }
+
+    private class DupWatcher extends CountdownWatcher {
+        public LinkedList<WatchedEvent> states = new LinkedList<WatchedEvent>();
+        public void process(WatchedEvent event) {
+            super.process(event);
+            if (event.getType() == EventType.None) {
+                states.add(event);
+            }
+        }
+    }
+
+    @Test
+    public void testMinMaxSessionTimeout() throws Exception {
+        // override the defaults
+        final int MINSESS = 20000;
+        final int MAXSESS = 240000;
+        {
+            ZooKeeperServer zs = ClientBase.getServer(serverFactory);
+            zs.setMinSessionTimeout(MINSESS);
+            zs.setMaxSessionTimeout(MAXSESS);
+        }
+
+        // validate typical case - requested == negotiated
+        int timeout = 120000;
+        DisconnectableZooKeeper zk = createClient(timeout);
+        Assert.assertEquals(timeout, zk.getSessionTimeout());
+        // make sure tostring works in both cases
+        LOG.info(zk.toString());
+        zk.close();
+        LOG.info(zk.toString());
+
+        // validate lower limit
+        zk = createClient(MINSESS/2);
+        Assert.assertEquals(MINSESS, zk.getSessionTimeout());
+        LOG.info(zk.toString());
+        zk.close();
+        LOG.info(zk.toString());
+
+        // validate upper limit
+        zk = createClient(MAXSESS * 2);
+        Assert.assertEquals(MAXSESS, zk.getSessionTimeout());
+        LOG.info(zk.toString());
+        zk.close();
+        LOG.info(zk.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionTimeoutTest.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionTimeoutTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionTimeoutTest.java
new file mode 100644
index 0000000..09badae
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionTimeoutTest.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.test;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.TestableZooKeeper;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.Stat;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class SessionTimeoutTest extends ClientBase {
+    protected static final Logger LOG = LoggerFactory.getLogger(SessionTimeoutTest.class);
+
+    private TestableZooKeeper zk;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        zk = createClient();
+    }
+
+    @Test
+    public void testSessionExpiration() throws InterruptedException,
+            KeeperException {
+        final CountDownLatch expirationLatch = new CountDownLatch(1);
+        Watcher watcher = new Watcher() {
+            @Override
+            public void process(WatchedEvent event) {
+                if ( event.getState() == Event.KeeperState.Expired ) {
+                    expirationLatch.countDown();
+                }
+            }
+        };
+        zk.exists("/foo", watcher);
+
+        zk.getTestable().injectSessionExpiration();
+        Assert.assertTrue(expirationLatch.await(5, TimeUnit.SECONDS));
+
+        boolean gotException = false;
+        try {
+            zk.exists("/foo", false);
+            Assert.fail("Should have thrown a SessionExpiredException");
+        } catch (KeeperException.SessionExpiredException e) {
+            // correct
+            gotException = true;
+        }
+        Assert.assertTrue(gotException);
+    }
+
+    /**
+     * Make sure ephemerals get cleaned up when session disconnects.
+     */
+    @Test
+    public void testSessionDisconnect() throws KeeperException, InterruptedException, IOException {
+        zk.create("/sdisconnect", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,
+                CreateMode.EPHEMERAL);
+        assertNotNull("Ephemeral node has not been created", zk.exists("/sdisconnect", null));
+
+        zk.close();
+
+        zk = createClient();
+        assertNull("Ephemeral node shouldn't exist after client disconnect", zk.exists("/sdisconnect", null));
+    }
+
+    /**
+     * Make sure ephemerals are kept when session restores.
+     */
+    @Test
+    public void testSessionRestore() throws KeeperException, InterruptedException, IOException {
+        zk.create("/srestore", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,
+                CreateMode.EPHEMERAL);
+        assertNotNull("Ephemeral node has not been created", zk.exists("/srestore", null));
+
+        zk.disconnect();
+        zk.close();
+
+        zk = createClient();
+        assertNotNull("Ephemeral node should be present when session is restored", zk.exists("/srestore", null));
+    }
+
+    /**
+     * Make sure ephemerals are kept when server restarts.
+     */
+    @Test
+    public void testSessionSurviveServerRestart() throws Exception {
+        zk.create("/sdeath", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,
+                CreateMode.EPHEMERAL);
+        assertNotNull("Ephemeral node has not been created", zk.exists("/sdeath", null));
+
+        zk.disconnect();
+        stopServer();
+        startServer();
+        zk = createClient();
+
+        assertNotNull("Ephemeral node should be present when server restarted", zk.exists("/sdeath", null));
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/test/java/org/apache/zookeeper/test/SledgeHammer.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SledgeHammer.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SledgeHammer.java
new file mode 100644
index 0000000..614a93d
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SledgeHammer.java
@@ -0,0 +1,115 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.data.Stat;
+
+public class SledgeHammer extends Thread implements Watcher {
+    ZooKeeper zk;
+
+    int count;
+
+    int readsPerWrite;
+
+    public SledgeHammer(String hosts, int count, int readsPerWrite)
+            throws IOException {
+        zk = new ZooKeeper(hosts, 10000, this);
+        this.count = count;
+        this.readsPerWrite = readsPerWrite;
+    }
+
+    public void run() {
+        try {
+            Stat stat = new Stat();
+            String path = zk.create("/hammers/hammer-", new byte[0],
+                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
+            byte tag[] = (path + " was here!").getBytes();
+            synchronized (this) {
+                String startPath = "/hammers/start";
+                System.out.println("Waiting for " + startPath);
+                while (zk.exists(startPath, true) == null) {
+                    wait();
+                }
+                System.out.println("Running");
+            }
+            for (int i = 0; i < count; i++) {
+                try {
+                    System.out.print(i + "\r");
+                    List<String> childs =
+                        zk.getChildren("/hammers", false);
+                    Collections.shuffle(childs);
+                    for (String s : childs) {
+                        if (s.startsWith("hammer-")) {
+                            s = "/hammers/" + s;
+                            zk.setData(s, tag, -1);
+                            for (int j = 0; j < readsPerWrite; j++) {
+                                zk.getData(s, false, stat);
+                            }
+                            break;
+                        }
+                    }
+                } catch (KeeperException.ConnectionLossException e) {
+                    // ignore connection loss
+                } catch (KeeperException e) {
+                    e.printStackTrace();
+                }
+            }
+            System.out.println();
+            zk.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * @param args
+     * @throws IOException
+     * @throws KeeperException
+     * @throws NumberFormatException
+     */
+    public static void main(String[] args) throws NumberFormatException,
+            IOException {
+        if (args.length != 3) {
+            System.err
+                    .println("USAGE: SledgeHammer zookeeper_server reps reads_per_rep");
+            System.exit(3);
+        }
+        SledgeHammer h = new SledgeHammer(args[0], Integer.parseInt(args[1]),
+                Integer.parseInt(args[2]));
+        h.start();
+        System.exit(0);
+    }
+
+    public void process(WatchedEvent event) {
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+}


Mime
View raw message