You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@curator.apache.org by ra...@apache.org on 2017/07/20 07:14:26 UTC

[3/4] curator git commit: Basic concept of zk 3.4.x compatibility proven. The Compatibility class checks for a well-known 3.5 class and sets a static that advertises whether the ZK lib is 3.4.x or 3.5.x. Then, the code "ifs" using this static. The major

Basic concept of zk 3.4.x compatibility proven. The Compatibility class checks for a well-known 3.5 class and sets a static
that advertises whether the ZK lib is 3.4.x or 3.5.x. Then, the code "ifs" using this static. The major work was emulating
the kill session injection (that emulation is done using reflection) and testing. The curator-test-zk module runs
the framework and recipe tests but forces ZooKeeper 3.4.x and uses the Curator 2.x version of curator-test. This
requires a few tricks as the new code uses new methods/classes on the Curator 3.x version of curator-test. I'll write
a readme documenting how this is done.


Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/58bc969f
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/58bc969f
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/58bc969f

Branch: refs/heads/CURATOR-425
Commit: 58bc969fecc01a1947dd272300d4fb305d221ea2
Parents: 0641243
Author: randgalt <ra...@apache.org>
Authored: Thu Jul 20 01:48:40 2017 -0500
Committer: randgalt <ra...@apache.org>
Committed: Thu Jul 20 01:48:40 2017 -0500

----------------------------------------------------------------------
 .../org/apache/curator/utils/Compatibility.java |  76 +++++
 .../curator/utils/InjectSessionExpiration.java  | 107 +++++++
 .../java/org/apache/curator/BasicTests.java     |   4 +-
 .../curator/TestSessionFailRetryLoop.java       |  11 +-
 .../framework/CuratorFrameworkFactory.java      |  30 +-
 .../apache/curator/framework/SafeIsTtlMode.java |   3 +-
 .../framework/imps/CreateBuilderImpl.java       |   9 +-
 .../imps/CuratorMultiTransactionImpl.java       |  18 +-
 .../framework/state/ConnectionStateManager.java |   6 +-
 .../curator/framework/imps/TestCleanState.java  |   7 +
 .../framework/imps/TestCreateReturningStat.java |  13 +-
 .../imps/TestEnabledSessionExpiredState.java    |   8 +-
 .../curator/framework/imps/TestFramework.java   |   3 +-
 .../framework/imps/TestFrameworkEdges.java      |   8 +-
 .../framework/imps/TestReconfiguration.java     |   9 +-
 .../framework/imps/TestRemoveWatches.java       |   6 +-
 .../curator/framework/imps/TestTtlNodes.java    |   5 +-
 .../imps/TestWatcherRemovalManager.java         |   5 +-
 .../recipes/cache/TestEventOrdering.java        |   3 +-
 .../framework/recipes/cache/TestNodeCache.java  |   4 +-
 .../recipes/cache/TestPathChildrenCache.java    |   4 +-
 .../framework/recipes/cache/TestTreeCache.java  |   4 +-
 .../recipes/leader/TestLeaderLatch.java         |   3 +-
 .../recipes/leader/TestLeaderSelector.java      |   9 +-
 .../recipes/locks/TestInterProcessMutex.java    |   5 +-
 .../locks/TestInterProcessMutexBase.java        |   7 +-
 .../nodes/TestPersistentEphemeralNode.java      |  14 +-
 .../recipes/nodes/TestPersistentNode.java       |   3 +-
 curator-test-zk34/pom.xml                       |  44 +++
 .../curator/framework/imps/TestCleanState.java  |  25 --
 .../org/apache/curator/test/Compatibility.java  |  35 +++
 curator-test/pom.xml                            |  19 ++
 .../apache/curator/test/CuratorTestBase.java    |  27 ++
 .../org/apache/curator/test/KillSession2.java   |  39 +++
 .../java/org/apache/curator/test/Timing2.java   | 299 +++++++++++++++++++
 .../curator/test/Zk35MethodInterceptor.java     |  55 ++++
 .../org/apache/curator/test/Compatibility.java  |  34 +++
 .../apache/curator/test/KillServerSession.java  | 122 --------
 .../org/apache/curator/test/KillSession.java    |  67 -----
 .../java/org/apache/curator/test/Timing.java    |  75 +----
 .../x/async/CompletableBaseClassForTests.java   |   3 +-
 .../discovery/details/TestServiceDiscovery.java |   8 +-
 pom.xml                                         |   7 +
 43 files changed, 859 insertions(+), 384 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-client/src/main/java/org/apache/curator/utils/Compatibility.java
----------------------------------------------------------------------
diff --git a/curator-client/src/main/java/org/apache/curator/utils/Compatibility.java b/curator-client/src/main/java/org/apache/curator/utils/Compatibility.java
new file mode 100644
index 0000000..58b62a7
--- /dev/null
+++ b/curator-client/src/main/java/org/apache/curator/utils/Compatibility.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.curator.utils;
+
+import org.apache.zookeeper.ZooKeeper;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utils to help with ZK 3.4.x compatibility
+ */
+public class Compatibility
+{
+    private static final boolean hasZooKeeperAdmin;
+    static
+    {
+        boolean hasIt;
+        try
+        {
+            Class.forName("org.apache.zookeeper.admin.ZooKeeperAdmin");
+            hasIt = true;
+        }
+        catch ( ClassNotFoundException e )
+        {
+            hasIt = false;
+            LoggerFactory.getLogger(Compatibility.class).info("Running in ZooKeeper 3.4.x compatibility mode");
+        }
+        hasZooKeeperAdmin = hasIt;
+    }
+
+    /**
+     * Return true if the classpath ZooKeeper library is 3.4.x
+     *
+     * @return true/false
+     */
+    public static boolean isZK34()
+    {
+        return !hasZooKeeperAdmin;
+    }
+
+    /**
+     * For ZooKeeper 3.5.x, use the supported <code>zooKeeper.getTestable().injectSessionExpiration()</code>.
+     * For ZooKeeper 3.4.x do the equivalent via reflection
+     *
+     * @param zooKeeper client
+     */
+    public static void injectSessionExpiration(ZooKeeper zooKeeper)
+    {
+        if ( isZK34() )
+        {
+            InjectSessionExpiration.injectSessionExpiration(zooKeeper);
+        }
+        else
+        {
+            // LOL - this method was proposed by me (JZ) in 2013 for totally unrelated reasons
+            // it got added to ZK 3.5 and now does exactly what we need
+            // https://issues.apache.org/jira/browse/ZOOKEEPER-1730
+            zooKeeper.getTestable().injectSessionExpiration();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-client/src/main/java/org/apache/curator/utils/InjectSessionExpiration.java
----------------------------------------------------------------------
diff --git a/curator-client/src/main/java/org/apache/curator/utils/InjectSessionExpiration.java b/curator-client/src/main/java/org/apache/curator/utils/InjectSessionExpiration.java
new file mode 100644
index 0000000..996e9a2
--- /dev/null
+++ b/curator-client/src/main/java/org/apache/curator/utils/InjectSessionExpiration.java
@@ -0,0 +1,107 @@
+/**
+ * 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.curator.utils;
+
+import org.apache.zookeeper.ClientCnxn;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooKeeper;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+// reflective version of zooKeeper.getTestable().injectSessionExpiration();
+@SuppressWarnings("JavaReflectionMemberAccess")
+public class InjectSessionExpiration
+{
+    private static final Field cnxnField;
+    private static final Field stateField;
+    private static final Field eventThreadField;
+    private static final Field sendThreadField;
+    private static final Method queueEventMethod;
+    private static final Method queueEventOfDeathMethod;
+    private static final Method getClientCnxnSocketMethod;
+    private static final Method wakeupCnxnMethod;
+    static
+    {
+        Field localCnxnField;
+        Field localStateField;
+        Field localEventThreadField;
+        Field localSendThreadField;
+        Method localQueueEventMethod;
+        Method localEventOfDeathMethod;
+        Method localGetClientCnxnSocketMethod;
+        Method localWakeupCnxnMethod;
+        try
+        {
+            Class<?> eventThreadClass = Class.forName("org.apache.zookeeper.ClientCnxn$EventThread");
+            Class<?> sendThreadClass = Class.forName("org.apache.zookeeper.ClientCnxn$SendThread");
+            Class<?> clientCnxnSocketClass = Class.forName("org.apache.zookeeper.ClientCnxnSocket");
+
+            localCnxnField = ZooKeeper.class.getDeclaredField("cnxn");
+            localCnxnField.setAccessible(true);
+            localStateField = ClientCnxn.class.getDeclaredField("state");
+            localStateField.setAccessible(true);
+            localEventThreadField = ClientCnxn.class.getDeclaredField("eventThread");
+            localEventThreadField.setAccessible(true);
+            localSendThreadField = ClientCnxn.class.getDeclaredField("sendThread");
+            localSendThreadField.setAccessible(true);
+            localQueueEventMethod = eventThreadClass.getDeclaredMethod("queueEvent", WatchedEvent.class);
+            localQueueEventMethod.setAccessible(true);
+            localEventOfDeathMethod = eventThreadClass.getDeclaredMethod("queueEventOfDeath");
+            localEventOfDeathMethod.setAccessible(true);
+            localGetClientCnxnSocketMethod = sendThreadClass.getDeclaredMethod("getClientCnxnSocket");
+            localGetClientCnxnSocketMethod.setAccessible(true);
+            localWakeupCnxnMethod = clientCnxnSocketClass.getDeclaredMethod("wakeupCnxn");
+            localWakeupCnxnMethod.setAccessible(true);
+        }
+        catch ( ReflectiveOperationException e )
+        {
+            throw new RuntimeException("Could not access internal ZooKeeper fields", e);
+        }
+        cnxnField = localCnxnField;
+        stateField = localStateField;
+        eventThreadField = localEventThreadField;
+        sendThreadField = localSendThreadField;
+        queueEventMethod = localQueueEventMethod;
+        queueEventOfDeathMethod = localEventOfDeathMethod;
+        getClientCnxnSocketMethod = localGetClientCnxnSocketMethod;
+        wakeupCnxnMethod = localWakeupCnxnMethod;
+    }
+
+    public static void injectSessionExpiration(ZooKeeper zooKeeper)
+    {
+        try
+        {
+            WatchedEvent event = new WatchedEvent(Watcher.Event.EventType.None, Watcher.Event.KeeperState.Expired, null);
+
+            ClientCnxn clientCnxn = (ClientCnxn)cnxnField.get(zooKeeper);
+            Object eventThread = eventThreadField.get(clientCnxn);
+            queueEventMethod.invoke(eventThread, event);
+            queueEventOfDeathMethod.invoke(eventThread);
+            stateField.set(clientCnxn, ZooKeeper.States.CLOSED);
+            Object sendThread = sendThreadField.get(clientCnxn);
+            Object clientCnxnSocket = getClientCnxnSocketMethod.invoke(sendThread);
+            wakeupCnxnMethod.invoke(clientCnxnSocket);
+        }
+        catch ( ReflectiveOperationException e )
+        {
+            throw new RuntimeException("Could not inject session expiration using reflection", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-client/src/test/java/org/apache/curator/BasicTests.java
----------------------------------------------------------------------
diff --git a/curator-client/src/test/java/org/apache/curator/BasicTests.java b/curator-client/src/test/java/org/apache/curator/BasicTests.java
index eee5047..94d418b 100644
--- a/curator-client/src/test/java/org/apache/curator/BasicTests.java
+++ b/curator-client/src/test/java/org/apache/curator/BasicTests.java
@@ -21,7 +21,7 @@ package org.apache.curator;
 import org.apache.curator.ensemble.fixed.FixedEnsembleProvider;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
-import org.apache.curator.test.KillSession;
+import org.apache.curator.test.KillSession2;
 import org.apache.curator.test.Timing;
 import org.apache.curator.utils.ZookeeperFactory;
 import org.apache.zookeeper.CreateMode;
@@ -100,7 +100,7 @@ public class BasicTests extends BaseClassForTests
                                 // ignore
                             }
 
-                            KillSession.kill(client.getZooKeeper(), server.getConnectString());
+                            KillSession2.kill(client.getZooKeeper());
 
                             Assert.assertTrue(timing.awaitLatch(latch));
                         }

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-client/src/test/java/org/apache/curator/TestSessionFailRetryLoop.java
----------------------------------------------------------------------
diff --git a/curator-client/src/test/java/org/apache/curator/TestSessionFailRetryLoop.java b/curator-client/src/test/java/org/apache/curator/TestSessionFailRetryLoop.java
index b33939f..e56f4d4 100644
--- a/curator-client/src/test/java/org/apache/curator/TestSessionFailRetryLoop.java
+++ b/curator-client/src/test/java/org/apache/curator/TestSessionFailRetryLoop.java
@@ -20,9 +20,8 @@ package org.apache.curator;
 
 import org.apache.curator.retry.ExponentialBackoffRetry;
 import org.apache.curator.test.BaseClassForTests;
+import org.apache.curator.test.KillSession2;
 import org.apache.curator.utils.CloseableUtils;
-import org.apache.curator.retry.RetryOneTime;
-import org.apache.curator.test.KillSession;
 import org.apache.curator.test.Timing;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -58,7 +57,7 @@ public class TestSessionFailRetryLoop extends BaseClassForTests
                                 if ( firstTime.compareAndSet(true, false) )
                                 {
                                     Assert.assertNull(client.getZooKeeper().exists("/foo/bar", false));
-                                    KillSession.kill(client.getZooKeeper(), server.getConnectString());
+                                    KillSession2.kill(client.getZooKeeper());
                                     client.getZooKeeper();
                                     client.blockUntilConnectedOrTimedOut();
                                 }
@@ -132,7 +131,7 @@ public class TestSessionFailRetryLoop extends BaseClassForTests
                                     if ( firstTime.compareAndSet(true, false) )
                                     {
                                         Assert.assertNull(client.getZooKeeper().exists("/foo/bar", false));
-                                        KillSession.kill(client.getZooKeeper(), server.getConnectString());
+                                        KillSession2.kill(client.getZooKeeper());
                                         client.getZooKeeper();
                                         client.blockUntilConnectedOrTimedOut();
                                     }
@@ -197,7 +196,7 @@ public class TestSessionFailRetryLoop extends BaseClassForTests
                                 public Void call() throws Exception
                                 {
                                     Assert.assertNull(client.getZooKeeper().exists("/foo/bar", false));
-                                    KillSession.kill(client.getZooKeeper(), server.getConnectString());
+                                    KillSession2.kill(client.getZooKeeper());
 
                                     timing.sleepABit();
 
@@ -259,7 +258,7 @@ public class TestSessionFailRetryLoop extends BaseClassForTests
                                     public Void call() throws Exception
                                     {
                                         Assert.assertNull(client.getZooKeeper().exists("/foo/bar", false));
-                                        KillSession.kill(client.getZooKeeper(), server.getConnectString());
+                                        KillSession2.kill(client.getZooKeeper());
 
                                         client.getZooKeeper();
                                         client.blockUntilConnectedOrTimedOut();

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java b/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java
index 5ce7762..18011aa 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java
@@ -44,7 +44,6 @@ import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.Watcher;
 import org.apache.zookeeper.ZooKeeper;
-import org.slf4j.LoggerFactory;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
@@ -52,6 +51,8 @@ import java.util.List;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
+import static org.apache.curator.utils.Compatibility.isZK34;
+
 /**
  * Factory methods for creating framework-style clients
  */
@@ -68,33 +69,6 @@ public class CuratorFrameworkFactory
     private static final long DEFAULT_INACTIVE_THRESHOLD_MS = (int)TimeUnit.MINUTES.toMillis(3);
     private static final int DEFAULT_CLOSE_WAIT_MS = (int)TimeUnit.SECONDS.toMillis(1);
 
-    private static final boolean hasZooKeeperAdmin;
-    static
-    {
-        boolean hasIt;
-        try
-        {
-            Class.forName("org.apache.zookeeper.admin.ZooKeeperAdmin");
-            hasIt = true;
-        }
-        catch ( ClassNotFoundException e )
-        {
-            hasIt = false;
-            LoggerFactory.getLogger(CuratorFrameworkFactory.class).info("Running in ZooKeeper 3.4.x compatibility mode");
-        }
-        hasZooKeeperAdmin = hasIt;
-    }
-
-    /**
-     * Return true if the classpath ZooKeeper library is 3.4.x
-     *
-     * @return true/false
-     */
-    public static boolean isZK34()
-    {
-        return !hasZooKeeperAdmin;
-    }
-
     /**
      * Return a new builder that builds a CuratorFramework
      *

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/main/java/org/apache/curator/framework/SafeIsTtlMode.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/SafeIsTtlMode.java b/curator-framework/src/main/java/org/apache/curator/framework/SafeIsTtlMode.java
index 3c4b9e6..e499a7b 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/SafeIsTtlMode.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/SafeIsTtlMode.java
@@ -18,6 +18,7 @@
  */
 package org.apache.curator.framework;
 
+import org.apache.curator.utils.Compatibility;
 import org.apache.zookeeper.CreateMode;
 
 public class SafeIsTtlMode
@@ -34,7 +35,7 @@ public class SafeIsTtlMode
 
     public static boolean isTtl(CreateMode mode)
     {
-        return !CuratorFrameworkFactory.isZK34() && Internal.instance.isTtl(mode);
+        return !Compatibility.isZK34() && Internal.instance.isTtl(mode);
     }
 
     private SafeIsTtlMode()

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
index b58084f..1487d6b 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
@@ -176,7 +176,14 @@ public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, Backgro
                 }
 
                 String fixedPath = client.fixForNamespace(path);
-                transaction.add(Op.create(fixedPath, data, acling.getAclList(path), createMode, ttl), OperationType.CREATE, path);
+                if ( client.isZk34CompatibilityMode() )
+                {
+                    transaction.add(Op.create(fixedPath, data, acling.getAclList(path), createMode), OperationType.CREATE, path);
+                }
+                else
+                {
+                    transaction.add(Op.create(fixedPath, data, acling.getAclList(path), createMode, ttl), OperationType.CREATE, path);
+                }
                 return context;
             }
         };

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java
index bdab158..9057934 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java
@@ -35,6 +35,7 @@ import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
 import org.apache.curator.framework.schema.Schema;
 import org.apache.zookeeper.AsyncCallback;
 import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.OpResult;
 import org.apache.zookeeper.ZooDefs;
 import org.apache.zookeeper.proto.CreateRequest;
@@ -135,7 +136,22 @@ public class CuratorMultiTransactionImpl implements
             if ( (curatorOp.get().getType() == ZooDefs.OpCode.create) || (curatorOp.get().getType() == ZooDefs.OpCode.createContainer) )
             {
                 CreateRequest createRequest = (CreateRequest)curatorOp.get().toRequestRecord();
-                CreateMode createMode = CreateMode.fromFlag(createRequest.getFlags(), CreateMode.PERSISTENT);
+                CreateMode createMode;
+                if ( client.isZk34CompatibilityMode() )
+                {
+                    try
+                    {
+                        createMode = CreateMode.fromFlag(createRequest.getFlags());
+                    }
+                    catch ( KeeperException.BadArgumentsException dummy )
+                    {
+                        createMode = CreateMode.PERSISTENT;
+                    }
+                }
+                else
+                {
+                    createMode = CreateMode.fromFlag(createRequest.getFlags(), CreateMode.PERSISTENT);
+                }
                 schema.validateCreate(createMode, createRequest.getPath(), createRequest.getData(), createRequest.getAcl());
             }
             else if ( (curatorOp.get().getType() == ZooDefs.OpCode.delete) || (curatorOp.get().getType() == ZooDefs.OpCode.deleteContainer) )

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/main/java/org/apache/curator/framework/state/ConnectionStateManager.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/state/ConnectionStateManager.java b/curator-framework/src/main/java/org/apache/curator/framework/state/ConnectionStateManager.java
index 56c2250..251baa9 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/state/ConnectionStateManager.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/state/ConnectionStateManager.java
@@ -23,6 +23,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.listen.ListenerContainer;
+import org.apache.curator.utils.Compatibility;
 import org.apache.curator.utils.ThreadUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -306,10 +307,7 @@ public class ConnectionStateManager implements Closeable
                 log.warn(String.format("Session timeout has elapsed while SUSPENDED. Injecting a session expiration. Elapsed ms: %d. Adjusted session timeout ms: %d", elapsedMs, useSessionTimeoutMs));
                 try
                 {
-                    // LOL - this method was proposed by me (JZ) in 2013 for totally unrelated reasons
-                    // it got added to ZK 3.5 and now does exactly what we need
-                    // https://issues.apache.org/jira/browse/ZOOKEEPER-1730
-                    client.getZookeeperClient().getZooKeeper().getTestable().injectSessionExpiration();
+                    Compatibility.injectSessionExpiration(client.getZookeeperClient().getZooKeeper());
                 }
                 catch ( Exception e )
                 {

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCleanState.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCleanState.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCleanState.java
index 9d90616..7a61eea 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCleanState.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCleanState.java
@@ -21,6 +21,7 @@ package org.apache.curator.framework.imps;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.test.WatchersDebug;
 import org.apache.curator.utils.CloseableUtils;
+import org.apache.curator.utils.Compatibility;
 import org.apache.zookeeper.ZooKeeper;
 import java.util.concurrent.Callable;
 
@@ -33,6 +34,12 @@ public class TestCleanState
             return;
         }
 
+        if ( Compatibility.isZK34() )
+        {
+            CloseableUtils.closeQuietly(client);
+            return;
+        }
+
         try
         {
             CuratorFrameworkImpl internalClient = (CuratorFrameworkImpl)client;

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCreateReturningStat.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCreateReturningStat.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCreateReturningStat.java
index 4e9e78c..bef143f 100755
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCreateReturningStat.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCreateReturningStat.java
@@ -18,25 +18,24 @@
  */
 package org.apache.curator.framework.imps;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicReference;
-
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.framework.api.BackgroundCallback;
 import org.apache.curator.framework.api.CuratorEvent;
 import org.apache.curator.framework.api.CuratorEventType;
-import org.apache.curator.framework.api.ExistsBuilder;
-import org.apache.curator.framework.api.PathAndBytesable;
 import org.apache.curator.retry.RetryOneTime;
-import org.apache.curator.test.BaseClassForTests;
+import org.apache.curator.test.CuratorTestBase;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Zk35MethodInterceptor;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.zookeeper.data.Stat;
 import org.testng.Assert;
 import org.testng.annotations.Test;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
 
-public class TestCreateReturningStat extends BaseClassForTests
+@Test(groups = Zk35MethodInterceptor.zk35Group)
+public class TestCreateReturningStat extends CuratorTestBase
 {
     private CuratorFramework createClient()
     {

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/test/java/org/apache/curator/framework/imps/TestEnabledSessionExpiredState.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestEnabledSessionExpiredState.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestEnabledSessionExpiredState.java
index f96592a..63fd36e 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestEnabledSessionExpiredState.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestEnabledSessionExpiredState.java
@@ -25,8 +25,8 @@ import org.apache.curator.framework.state.ConnectionState;
 import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
-import org.apache.curator.test.KillSession;
-import org.apache.curator.test.Timing;
+import org.apache.curator.test.KillSession2;
+import org.apache.curator.test.Timing2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.WatchedEvent;
@@ -41,7 +41,7 @@ import java.util.concurrent.TimeUnit;
 
 public class TestEnabledSessionExpiredState extends BaseClassForTests
 {
-    private final Timing timing = new Timing();
+    private final Timing2 timing = new Timing2();
 
     private CuratorFramework client;
     private BlockingQueue<ConnectionState> states;
@@ -127,7 +127,7 @@ public class TestEnabledSessionExpiredState extends BaseClassForTests
     {
         Assert.assertEquals(states.poll(timing.milliseconds(), TimeUnit.MILLISECONDS), ConnectionState.CONNECTED);
 
-        KillSession.kill(client.getZookeeperClient().getZooKeeper(), server.getConnectString());
+        KillSession2.kill(client.getZookeeperClient().getZooKeeper());
 
         Assert.assertEquals(states.poll(timing.forSessionSleep().milliseconds(), TimeUnit.MILLISECONDS), ConnectionState.LOST);
         Assert.assertEquals(states.poll(timing.milliseconds(), TimeUnit.MILLISECONDS), ConnectionState.RECONNECTED);

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java
index 5d0c5ed..70ae2ea 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java
@@ -31,6 +31,7 @@ import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Timing2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.curator.utils.EnsurePath;
 import org.apache.curator.utils.ZKPaths;
@@ -261,7 +262,7 @@ public class TestFramework extends BaseClassForTests
             client.getChildren().usingWatcher(watcher).forPath("/base");
             client.create().forPath("/base/child");
 
-            String path = new Timing().takeFromQueue(queue);
+            String path = new Timing2().takeFromQueue(queue);
             Assert.assertEquals(path, "/base");
         }
         finally

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkEdges.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkEdges.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkEdges.java
index 8fee2d3..42e9afa 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkEdges.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkEdges.java
@@ -33,9 +33,9 @@ import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.retry.RetryNTimes;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
-import org.apache.curator.test.KillSession;
+import org.apache.curator.test.KillSession2;
 import org.apache.curator.test.TestingServer;
-import org.apache.curator.test.Timing;
+import org.apache.curator.test.Timing2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.curator.utils.ZKPaths;
 import org.apache.zookeeper.CreateMode;
@@ -57,7 +57,7 @@ import org.apache.curator.framework.api.CreateBuilder;
 
 public class TestFrameworkEdges extends BaseClassForTests
 {
-    private final Timing timing = new Timing();
+    private final Timing2 timing = new Timing2();
 
     @Test
     public void testCreateContainersForBadConnect() throws Exception
@@ -391,7 +391,7 @@ public class TestFrameworkEdges extends BaseClassForTests
                 }
             };
             client.checkExists().usingWatcher(watcher).forPath("/sessionTest");
-            KillSession.kill(client.getZookeeperClient().getZooKeeper(), server.getConnectString());
+            KillSession2.kill(client.getZookeeperClient().getZooKeeper());
             Assert.assertNotNull(client.checkExists().forPath("/sessionTest"));
             Assert.assertTrue(sessionDied.get());
         }

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/test/java/org/apache/curator/framework/imps/TestReconfiguration.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestReconfiguration.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestReconfiguration.java
index ef2faed..567d71d 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestReconfiguration.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestReconfiguration.java
@@ -27,11 +27,13 @@ import org.apache.curator.framework.api.BackgroundCallback;
 import org.apache.curator.framework.api.CuratorEvent;
 import org.apache.curator.framework.api.CuratorEventType;
 import org.apache.curator.retry.ExponentialBackoffRetry;
-import org.apache.curator.test.BaseClassForTests;
+import org.apache.curator.test.CuratorTestBase;
 import org.apache.curator.test.InstanceSpec;
 import org.apache.curator.test.TestingCluster;
 import org.apache.curator.test.TestingZooKeeperServer;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Timing2;
+import org.apache.curator.test.Zk35MethodInterceptor;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
@@ -56,9 +58,10 @@ import java.util.Properties;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicReference;
 
-public class TestReconfiguration extends BaseClassForTests
+@Test(groups = Zk35MethodInterceptor.zk35Group)
+public class TestReconfiguration extends CuratorTestBase
 {
-    private final Timing timing = new Timing();
+    private final Timing2 timing = new Timing2();
     private TestingCluster cluster;
     private EnsembleProvider ensembleProvider;
 

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/test/java/org/apache/curator/framework/imps/TestRemoveWatches.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestRemoveWatches.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestRemoveWatches.java
index 4ac68d3..66f5703 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestRemoveWatches.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestRemoveWatches.java
@@ -30,8 +30,9 @@ import org.apache.curator.framework.state.ConnectionState;
 import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.retry.ExponentialBackoffRetry;
 import org.apache.curator.retry.RetryOneTime;
-import org.apache.curator.test.BaseClassForTests;
+import org.apache.curator.test.CuratorTestBase;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Zk35MethodInterceptor;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.WatchedEvent;
@@ -44,7 +45,8 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
-public class TestRemoveWatches extends BaseClassForTests
+@Test(groups = Zk35MethodInterceptor.zk35Group)
+public class TestRemoveWatches extends CuratorTestBase
 {
     private AtomicReference<ConnectionState> registerConnectionStateListener(CuratorFramework client)
     {

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/test/java/org/apache/curator/framework/imps/TestTtlNodes.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestTtlNodes.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestTtlNodes.java
index c544474..297399d 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestTtlNodes.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestTtlNodes.java
@@ -24,7 +24,9 @@ import org.apache.curator.framework.api.BackgroundCallback;
 import org.apache.curator.framework.api.CuratorEvent;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
+import org.apache.curator.test.CuratorTestBase;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Zk35MethodInterceptor;
 import org.apache.zookeeper.CreateMode;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
@@ -32,7 +34,8 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 import java.util.concurrent.CountDownLatch;
 
-public class TestTtlNodes extends BaseClassForTests
+@Test(groups = Zk35MethodInterceptor.zk35Group)
+public class TestTtlNodes extends CuratorTestBase
 {
     @BeforeMethod
     @Override

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-framework/src/test/java/org/apache/curator/framework/imps/TestWatcherRemovalManager.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestWatcherRemovalManager.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestWatcherRemovalManager.java
index 9c405a2..d3ad66f 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestWatcherRemovalManager.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestWatcherRemovalManager.java
@@ -25,8 +25,10 @@ import org.apache.curator.framework.api.BackgroundCallback;
 import org.apache.curator.framework.api.CuratorEvent;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
+import org.apache.curator.test.CuratorTestBase;
 import org.apache.curator.test.Timing;
 import org.apache.curator.test.WatchersDebug;
+import org.apache.curator.test.Zk35MethodInterceptor;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
@@ -36,7 +38,8 @@ import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 
-public class TestWatcherRemovalManager extends BaseClassForTests
+@Test(groups = Zk35MethodInterceptor.zk35Group)
+public class TestWatcherRemovalManager extends CuratorTestBase
 {
     @Test
     public void testSameWatcherDifferentPaths1Triggered() throws Exception

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestEventOrdering.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestEventOrdering.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestEventOrdering.java
index 7b3a07e..c50474d 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestEventOrdering.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestEventOrdering.java
@@ -25,6 +25,7 @@ import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Timing2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.zookeeper.KeeperException;
 import org.testng.Assert;
@@ -41,7 +42,7 @@ import java.util.concurrent.TimeUnit;
 
 public abstract class TestEventOrdering<T extends Closeable> extends BaseClassForTests
 {
-    private final Timing timing = new Timing();
+    private final Timing2 timing = new Timing2();
     private final long start = System.currentTimeMillis();
     private static final int THREAD_QTY = 100;
     private static final int ITERATIONS = 100;

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestNodeCache.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestNodeCache.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestNodeCache.java
index d6d495a..52c76ad 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestNodeCache.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestNodeCache.java
@@ -20,12 +20,12 @@ package org.apache.curator.framework.recipes.cache;
 
 import org.apache.curator.framework.imps.TestCleanState;
 import org.apache.curator.test.BaseClassForTests;
+import org.apache.curator.test.KillSession2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.framework.api.UnhandledErrorListener;
 import org.apache.curator.retry.RetryOneTime;
-import org.apache.curator.test.KillSession;
 import org.apache.curator.test.Timing;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -194,7 +194,7 @@ public class TestNodeCache extends BaseClassForTests
                 }
             );
 
-            KillSession.kill(client.getZookeeperClient().getZooKeeper(), server.getConnectString());
+            KillSession2.kill(client.getZookeeperClient().getZooKeeper());
             Thread.sleep(timing.multiple(1.5).session());
 
             Assert.assertEquals(cache.getCurrentData().getData(), "start".getBytes());

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestPathChildrenCache.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestPathChildrenCache.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestPathChildrenCache.java
index a09c878..f24b846 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestPathChildrenCache.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestPathChildrenCache.java
@@ -29,7 +29,7 @@ import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
 import org.apache.curator.test.ExecuteCalledWatchingExecutorService;
-import org.apache.curator.test.KillSession;
+import org.apache.curator.test.KillSession2;
 import org.apache.curator.test.TestingServer;
 import org.apache.curator.test.Timing;
 import org.apache.curator.utils.CloseableUtils;
@@ -715,7 +715,7 @@ public class TestPathChildrenCache extends BaseClassForTests
             client.create().withMode(CreateMode.EPHEMERAL).forPath("/test/me", "data".getBytes());
             Assert.assertTrue(timing.awaitLatch(childAddedLatch));
 
-            KillSession.kill(client.getZookeeperClient().getZooKeeper());
+            KillSession2.kill(client.getZookeeperClient().getZooKeeper());
             Assert.assertTrue(timing.awaitLatch(lostLatch));
             Assert.assertTrue(timing.awaitLatch(reconnectedLatch));
             Assert.assertTrue(timing.awaitLatch(removedLatch));

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java
index c9c22dd..1e203b7 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java
@@ -21,9 +21,9 @@ package org.apache.curator.framework.recipes.cache;
 
 import com.google.common.collect.ImmutableSet;
 import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.test.KillServerSession;
 import org.apache.curator.framework.api.UnhandledErrorListener;
 import org.apache.curator.framework.recipes.cache.TreeCacheEvent.Type;
+import org.apache.curator.test.KillSession2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.zookeeper.CreateMode;
 import org.testng.Assert;
@@ -423,7 +423,7 @@ public class TestTreeCache extends BaseTestTreeCache
         client.create().withMode(CreateMode.EPHEMERAL).forPath("/test/me", "data".getBytes());
         assertEvent(TreeCacheEvent.Type.NODE_ADDED, "/test/me");
 
-        KillServerSession.kill(client.getZookeeperClient().getZooKeeper(), server.getConnectString());
+        KillSession2.kill(client.getZookeeperClient().getZooKeeper());
         assertEvent(TreeCacheEvent.Type.CONNECTION_SUSPENDED);
         assertEvent(TreeCacheEvent.Type.CONNECTION_LOST);
         assertEvent(TreeCacheEvent.Type.CONNECTION_RECONNECTED);

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderLatch.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderLatch.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderLatch.java
index 991e6fc..93c955b 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderLatch.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderLatch.java
@@ -35,6 +35,7 @@ import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
 import org.apache.curator.test.TestingServer;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Timing2;
 import org.apache.curator.utils.CloseableUtils;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -136,7 +137,7 @@ public class TestLeaderLatch extends BaseClassForTests
     @Test
     public void testErrorPolicies() throws Exception
     {
-        Timing timing = new Timing();
+        Timing2 timing = new Timing2();
         LeaderLatch latch = null;
         CuratorFramework client = CuratorFrameworkFactory.builder()
             .connectString(server.getConnectString())

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderSelector.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderSelector.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderSelector.java
index 60619d0..79fcdb3 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderSelector.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderSelector.java
@@ -30,9 +30,10 @@ import org.apache.curator.framework.state.SessionConnectionStateErrorPolicy;
 import org.apache.curator.framework.state.StandardConnectionStateErrorPolicy;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
-import org.apache.curator.test.KillSession;
+import org.apache.curator.test.KillSession2;
 import org.apache.curator.test.TestingServer;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Timing2;
 import org.apache.curator.utils.CloseableUtils;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -56,7 +57,7 @@ public class TestLeaderSelector extends BaseClassForTests
     @Test
     public void testErrorPolicies() throws Exception
     {
-        Timing timing = new Timing();
+        Timing2 timing = new Timing2();
         LeaderSelector selector = null;
         CuratorFramework client = CuratorFrameworkFactory
             .builder()
@@ -147,7 +148,7 @@ public class TestLeaderSelector extends BaseClassForTests
     @Test
     public void testLeaderNodeDeleteOnInterrupt() throws Exception
     {
-        Timing timing = new Timing();
+        Timing2 timing = new Timing2();
         LeaderSelector selector = null;
         CuratorFramework client = null;
         try
@@ -486,7 +487,7 @@ public class TestLeaderSelector extends BaseClassForTests
 
             Assert.assertTrue(timing.acquireSemaphore(semaphore, 1));
 
-            KillSession.kill(client.getZookeeperClient().getZooKeeper(), server.getConnectString());
+            KillSession2.kill(client.getZookeeperClient().getZooKeeper());
 
             Assert.assertTrue(timing.awaitLatch(interruptedLatch));
             timing.sleepABit();

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutex.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutex.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutex.java
index 68daeb7..cf82c57 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutex.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutex.java
@@ -26,7 +26,7 @@ import org.apache.curator.framework.imps.TestCleanState;
 import org.apache.curator.framework.schema.Schema;
 import org.apache.curator.framework.schema.SchemaSet;
 import org.apache.curator.retry.RetryOneTime;
-import org.apache.curator.test.KillSession;
+import org.apache.curator.test.KillSession2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.zookeeper.CreateMode;
 import org.testng.Assert;
@@ -38,7 +38,6 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
 
 public class TestInterProcessMutex extends TestInterProcessMutexBase
 {
@@ -173,7 +172,7 @@ public class TestInterProcessMutex extends TestInterProcessMutexBase
             Assert.assertTrue(lock.isAcquiredInThisProcess());
 
             // Kill the session, check that lock node still exists
-            KillSession.kill(client.getZookeeperClient().getZooKeeper(), server.getConnectString());
+            KillSession2.kill(client.getZookeeperClient().getZooKeeper());
             Assert.assertNotNull(client.checkExists().forPath(LOCK_PATH));
 
             // Release the lock and verify that the actual lock node created no longer exists

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutexBase.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutexBase.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutexBase.java
index febf499..43ded2e 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutexBase.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/locks/TestInterProcessMutexBase.java
@@ -27,9 +27,10 @@ import org.apache.curator.framework.state.ConnectionState;
 import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.retry.ExponentialBackoffRetry;
 import org.apache.curator.test.BaseClassForTests;
-import org.apache.curator.test.KillSession;
+import org.apache.curator.test.KillSession2;
 import org.apache.curator.test.TestingServer;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Timing2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.curator.utils.ZKPaths;
 import org.testng.Assert;
@@ -149,7 +150,7 @@ public abstract class TestInterProcessMutexBase extends BaseClassForTests
     @Test
     public void testKilledSession() throws Exception
     {
-        final Timing timing = new Timing();
+        final Timing2 timing = new Timing2();
 
         CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new ExponentialBackoffRetry(100, 3));
         client.start();
@@ -191,7 +192,7 @@ public abstract class TestInterProcessMutexBase extends BaseClassForTests
                 );
 
             Assert.assertTrue(timing.acquireSemaphore(semaphore, 1));
-            KillSession.kill(client.getZookeeperClient().getZooKeeper(), server.getConnectString());
+            KillSession2.kill(client.getZookeeperClient().getZooKeeper());
             Assert.assertTrue(timing.forSessionSleep().acquireSemaphore(semaphore, 1));
         }
         finally

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
index 7d52b58..0ce61d5 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
@@ -31,8 +31,8 @@ import org.apache.curator.framework.state.ConnectionState;
 import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
-import org.apache.curator.test.KillSession;
-import org.apache.curator.test.Timing;
+import org.apache.curator.test.KillSession2;
+import org.apache.curator.test.Timing2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.curator.utils.ZKPaths;
 import org.apache.zookeeper.CreateMode;
@@ -69,7 +69,7 @@ public class TestPersistentEphemeralNode extends BaseClassForTests
     private final Collection<CuratorFramework> curatorInstances = Lists.newArrayList();
     private final Collection<PersistentEphemeralNode> createdNodes = Lists.newArrayList();
 
-    private final Timing timing = new Timing();
+    private final Timing2 timing = new Timing2();
 
     @AfterMethod
     @Override
@@ -329,7 +329,7 @@ public class TestPersistentEphemeralNode extends BaseClassForTests
             observer.checkExists().usingWatcher(deletedTrigger).forPath(node.getActualPath());
 
             node.debugCreateNodeLatch = new CountDownLatch(1);
-            KillSession.kill(curator.getZookeeperClient().getZooKeeper());
+            KillSession2.kill(curator.getZookeeperClient().getZooKeeper());
 
             // Make sure the node got deleted
             assertTrue(deletedTrigger.firedWithin(timing.forSessionSleep().seconds(), TimeUnit.SECONDS));
@@ -359,7 +359,7 @@ public class TestPersistentEphemeralNode extends BaseClassForTests
             observer.checkExists().usingWatcher(deletedTrigger).forPath(node.getActualPath());
 
             node.debugCreateNodeLatch = new CountDownLatch(1);
-            KillSession.kill(curator.getZookeeperClient().getZooKeeper());
+            KillSession2.kill(curator.getZookeeperClient().getZooKeeper());
 
             // Make sure the node got deleted...
             assertTrue(deletedTrigger.firedWithin(timing.forSessionSleep().seconds(), TimeUnit.SECONDS));
@@ -400,7 +400,7 @@ public class TestPersistentEphemeralNode extends BaseClassForTests
 
                 node.debugCreateNodeLatch = new CountDownLatch(1);
                 // Kill the session, thus cleaning up the node...
-                KillSession.kill(curator.getZookeeperClient().getZooKeeper());
+                KillSession2.kill(curator.getZookeeperClient().getZooKeeper());
 
                 // Make sure the node ended up getting deleted...
                 assertTrue(deletionTrigger.firedWithin(timing.multiple(1.5).forSessionSleep().seconds(), TimeUnit.SECONDS));
@@ -443,7 +443,7 @@ public class TestPersistentEphemeralNode extends BaseClassForTests
             Trigger deletedTrigger = Trigger.deletedOrSetData();
             observer.checkExists().usingWatcher(deletedTrigger).forPath(node.getActualPath());
 
-            KillSession.kill(nodeCreator.getZookeeperClient().getZooKeeper());
+            KillSession2.kill(nodeCreator.getZookeeperClient().getZooKeeper());
 
             // Make sure the node got deleted...
             assertTrue(deletedTrigger.firedWithin(timing.forWaiting().seconds(), TimeUnit.SECONDS));

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentNode.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentNode.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentNode.java
index 07d9083..b848fe4 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentNode.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentNode.java
@@ -23,6 +23,7 @@ import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
 import org.apache.curator.test.Timing;
+import org.apache.curator.test.Timing2;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.zookeeper.CreateMode;
 import org.testng.Assert;
@@ -67,7 +68,7 @@ public class TestPersistentNode extends BaseClassForTests
     {
         final byte[] TEST_DATA = "hey".getBytes();
 
-        Timing timing = new Timing();
+        Timing2 timing = new Timing2();
         PersistentNode pen = null;
         CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1));
         try

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test-zk34/pom.xml
----------------------------------------------------------------------
diff --git a/curator-test-zk34/pom.xml b/curator-test-zk34/pom.xml
index fe5e216..8d2f073 100644
--- a/curator-test-zk34/pom.xml
+++ b/curator-test-zk34/pom.xml
@@ -58,6 +58,31 @@
 
         <dependency>
             <groupId>org.apache.curator</groupId>
+            <artifactId>curator-framework</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.zookeeper</groupId>
+                    <artifactId>zookeeper</artifactId>
+                </exclusion>
+            </exclusions>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-framework</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.zookeeper</groupId>
+                    <artifactId>zookeeper</artifactId>
+                </exclusion>
+            </exclusions>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.curator</groupId>
             <artifactId>curator-recipes</artifactId>
             <exclusions>
                 <exclusion>
@@ -122,6 +147,25 @@
                     </dependenciesToScan>
                 </configuration>
             </plugin>
+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>add-compatibility</id>
+                        <goals>
+                            <goal>add-test-source</goal>
+                        </goals>
+                        <phase>generate-test-sources</phase>
+                        <configuration>
+                            <sources>
+                                <source>../curator-test/src/compatibility/java</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 </project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test-zk34/src/test/java/org/apache/curator/framework/imps/TestCleanState.java
----------------------------------------------------------------------
diff --git a/curator-test-zk34/src/test/java/org/apache/curator/framework/imps/TestCleanState.java b/curator-test-zk34/src/test/java/org/apache/curator/framework/imps/TestCleanState.java
deleted file mode 100644
index 9efeb90..0000000
--- a/curator-test-zk34/src/test/java/org/apache/curator/framework/imps/TestCleanState.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.apache.curator.framework.imps;
-
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.utils.CloseableUtils;
-import java.util.concurrent.Callable;
-
-public class TestCleanState
-{
-    public static void closeAndTestClean(CuratorFramework client)
-    {
-        CloseableUtils.closeQuietly(client);
-    }
-
-    public static void test(CuratorFramework client, Callable<Void> proc) throws Exception
-    {
-        try
-        {
-            proc.call();
-        }
-        finally
-        {
-            CloseableUtils.closeQuietly(client);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test-zk34/src/test/java/org/apache/curator/test/Compatibility.java
----------------------------------------------------------------------
diff --git a/curator-test-zk34/src/test/java/org/apache/curator/test/Compatibility.java b/curator-test-zk34/src/test/java/org/apache/curator/test/Compatibility.java
new file mode 100644
index 0000000..77ddf2c
--- /dev/null
+++ b/curator-test-zk34/src/test/java/org/apache/curator/test/Compatibility.java
@@ -0,0 +1,35 @@
+/**
+ * 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.curator.test;
+
+import org.apache.curator.utils.InjectSessionExpiration;
+import org.apache.zookeeper.ZooKeeper;
+
+class Compatibility
+{
+    static boolean isZK34()
+    {
+        return true;
+    }
+
+    static void injectSessionExpiration(ZooKeeper zooKeeper)
+    {
+        InjectSessionExpiration.injectSessionExpiration(zooKeeper);
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test/pom.xml
----------------------------------------------------------------------
diff --git a/curator-test/pom.xml b/curator-test/pom.xml
index fb28d53..0ffe023 100644
--- a/curator-test/pom.xml
+++ b/curator-test/pom.xml
@@ -95,6 +95,25 @@
                     </execution>
                 </executions>
             </plugin>
+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>add-compatibility</id>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <phase>generate-sources</phase>
+                        <configuration>
+                            <sources>
+                                <source>src/compatibility/java</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 </project>

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test/src/compatibility/java/org/apache/curator/test/CuratorTestBase.java
----------------------------------------------------------------------
diff --git a/curator-test/src/compatibility/java/org/apache/curator/test/CuratorTestBase.java b/curator-test/src/compatibility/java/org/apache/curator/test/CuratorTestBase.java
new file mode 100644
index 0000000..efa94a3
--- /dev/null
+++ b/curator-test/src/compatibility/java/org/apache/curator/test/CuratorTestBase.java
@@ -0,0 +1,27 @@
+/**
+ * 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.curator.test;
+
+import org.testng.annotations.Listeners;
+
+@Listeners(Zk35MethodInterceptor.class)
+public class CuratorTestBase extends BaseClassForTests
+{
+    protected final Timing2 timing = new Timing2();
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test/src/compatibility/java/org/apache/curator/test/KillSession2.java
----------------------------------------------------------------------
diff --git a/curator-test/src/compatibility/java/org/apache/curator/test/KillSession2.java b/curator-test/src/compatibility/java/org/apache/curator/test/KillSession2.java
new file mode 100644
index 0000000..52ab168
--- /dev/null
+++ b/curator-test/src/compatibility/java/org/apache/curator/test/KillSession2.java
@@ -0,0 +1,39 @@
+/**
+ * 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.curator.test;
+
+import org.apache.zookeeper.ZooKeeper;
+
+/**
+ * <p>
+ *     Utility to simulate a ZK session dying.
+ * </p>
+ */
+public class KillSession2
+{
+    /**
+     * Kill the given ZK session
+     *
+     * @param client the client to kill
+     */
+    public static void     kill(ZooKeeper client)
+    {
+        Compatibility.injectSessionExpiration(client);
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test/src/compatibility/java/org/apache/curator/test/Timing2.java
----------------------------------------------------------------------
diff --git a/curator-test/src/compatibility/java/org/apache/curator/test/Timing2.java b/curator-test/src/compatibility/java/org/apache/curator/test/Timing2.java
new file mode 100644
index 0000000..02b71c4
--- /dev/null
+++ b/curator-test/src/compatibility/java/org/apache/curator/test/Timing2.java
@@ -0,0 +1,299 @@
+/**
+ * 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.curator.test;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Utility to get various testing times.
+ *
+ * Copied from the old Timing class which is now deprecated. Needed this to support ZK 3.4 compatibility
+ */
+public class Timing2
+{
+    private final long value;
+    private final TimeUnit unit;
+    private final int waitingMultiple;
+
+    private static final int DEFAULT_SECONDS = 10;
+    private static final int DEFAULT_WAITING_MULTIPLE = 5;
+    private static final double SESSION_MULTIPLE = 1.5;
+    private static final double SESSION_SLEEP_MULTIPLE = SESSION_MULTIPLE * 1.75;  // has to be at least session + 2/3 of a session to account for missed heartbeat then session expiration
+
+    /**
+     * Use the default base time
+     */
+    public Timing2()
+    {
+        this(Integer.getInteger("timing-multiple", 1), getWaitingMultiple());
+    }
+
+    /**
+     * Use a multiple of the default base time
+     *
+     * @param multiple the multiple
+     */
+    public Timing2(double multiple)
+    {
+        this((long)(DEFAULT_SECONDS * multiple), TimeUnit.SECONDS, getWaitingMultiple());
+    }
+
+    /**
+     * Use a multiple of the default base time
+     *
+     * @param multiple the multiple
+     * @param waitingMultiple multiple of main timing to use when waiting
+     */
+    public Timing2(double multiple, int waitingMultiple)
+    {
+        this((long)(DEFAULT_SECONDS * multiple), TimeUnit.SECONDS, waitingMultiple);
+    }
+
+    /**
+     * @param value base time
+     * @param unit  base time unit
+     */
+    public Timing2(long value, TimeUnit unit)
+    {
+        this(value, unit, getWaitingMultiple());
+    }
+
+    /**
+     * @param value base time
+     * @param unit  base time unit
+     * @param waitingMultiple multiple of main timing to use when waiting
+     */
+    public Timing2(long value, TimeUnit unit, int waitingMultiple)
+    {
+        this.value = value;
+        this.unit = unit;
+        this.waitingMultiple = waitingMultiple;
+    }
+
+    /**
+     * Return the base time in milliseconds
+     *
+     * @return time ms
+     */
+    public int milliseconds()
+    {
+        return (int)TimeUnit.MILLISECONDS.convert(value, unit);
+    }
+
+    /**
+     * Return the base time in seconds
+     *
+     * @return time secs
+     */
+    public int seconds()
+    {
+        return (int)value;
+    }
+
+    /**
+     * Wait on the given latch
+     *
+     * @param latch latch to wait on
+     * @return result of {@link java.util.concurrent.CountDownLatch#await(long, java.util.concurrent.TimeUnit)}
+     */
+    public boolean awaitLatch(CountDownLatch latch)
+    {
+        Timing2 m = forWaiting();
+        try
+        {
+            return latch.await(m.value, m.unit);
+        }
+        catch ( InterruptedException e )
+        {
+            Thread.currentThread().interrupt();
+        }
+        return false;
+    }
+
+    /**
+     * Try to take an item from the given queue
+     *
+     * @param queue queue
+     * @return item
+     * @throws Exception interrupted or timed out
+     */
+    public <T> T takeFromQueue(BlockingQueue<T> queue) throws Exception
+    {
+        Timing2 m = forWaiting();
+        try
+        {
+            T value = queue.poll(m.value, m.unit);
+            if ( value == null )
+            {
+                throw new TimeoutException("Timed out trying to take from queue");
+            }
+            return value;
+        }
+        catch ( InterruptedException e )
+        {
+            Thread.currentThread().interrupt();
+            throw e;
+        }
+    }
+
+    /**
+     * Wait on the given semaphore
+     *
+     * @param semaphore the semaphore
+     * @return result of {@link java.util.concurrent.Semaphore#tryAcquire()}
+     */
+    public boolean acquireSemaphore(Semaphore semaphore)
+    {
+        Timing2 m = forWaiting();
+        try
+        {
+            return semaphore.tryAcquire(m.value, m.unit);
+        }
+        catch ( InterruptedException e )
+        {
+            Thread.currentThread().interrupt();
+        }
+        return false;
+    }
+
+    /**
+     * Wait on the given semaphore
+     *
+     * @param semaphore the semaphore
+     * @param n         number of permits to acquire
+     * @return result of {@link java.util.concurrent.Semaphore#tryAcquire(int, long, java.util.concurrent.TimeUnit)}
+     */
+    public boolean acquireSemaphore(Semaphore semaphore, int n)
+    {
+        Timing2 m = forWaiting();
+        try
+        {
+            return semaphore.tryAcquire(n, m.value, m.unit);
+        }
+        catch ( InterruptedException e )
+        {
+            Thread.currentThread().interrupt();
+        }
+        return false;
+    }
+
+    /**
+     * Return a new timing that is a multiple of the this timing
+     *
+     * @param n the multiple
+     * @return this timing times the multiple
+     */
+    public Timing2 multiple(double n)
+    {
+        return new Timing2((int)(value * n), unit);
+    }
+
+    /**
+     * Return a new timing that is a multiple of the this timing
+     *
+     * @param n the multiple
+     * @param waitingMultiple new waitingMultiple
+     * @return this timing times the multiple
+     */
+    public Timing2 multiple(double n, int waitingMultiple)
+    {
+        return new Timing2((int)(value * n), unit, waitingMultiple);
+    }
+
+    /**
+     * Return a new timing with the standard multiple for waiting on latches, etc.
+     *
+     * @return this timing multiplied
+     */
+    @SuppressWarnings("PointlessArithmeticExpression")
+    public Timing2 forWaiting()
+    {
+        return multiple(waitingMultiple);
+    }
+
+    /**
+     * Return a new timing with a multiple that ensures a ZK session timeout
+     *
+     * @return this timing multiplied
+     */
+    public Timing2 forSessionSleep()
+    {
+        return multiple(SESSION_SLEEP_MULTIPLE, 1);
+    }
+
+    /**
+     * Return a new timing with a multiple for sleeping a smaller amount of time
+     *
+     * @return this timing multiplied
+     */
+    public Timing2 forSleepingABit()
+    {
+        return multiple(.25);
+    }
+
+    /**
+     * Sleep for a small amount of time
+     *
+     * @throws InterruptedException if interrupted
+     */
+    public void sleepABit() throws InterruptedException
+    {
+        forSleepingABit().sleep();
+    }
+
+    /**
+     * Sleep for a the full amount of time
+     *
+     * @throws InterruptedException if interrupted
+     */
+    public void sleep() throws InterruptedException
+    {
+        unit.sleep(value);
+    }
+
+    /**
+     * Return the value to use for ZK session timeout
+     *
+     * @return session timeout
+     */
+    public int session()
+    {
+        return multiple(SESSION_MULTIPLE).milliseconds();
+    }
+
+    /**
+     * Return the value to use for ZK connection timeout
+     *
+     * @return connection timeout
+     */
+    public int connection()
+    {
+        return milliseconds();
+    }
+
+    private static Integer getWaitingMultiple()
+    {
+        return Integer.getInteger("timing-waiting-multiple", DEFAULT_WAITING_MULTIPLE);
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test/src/compatibility/java/org/apache/curator/test/Zk35MethodInterceptor.java
----------------------------------------------------------------------
diff --git a/curator-test/src/compatibility/java/org/apache/curator/test/Zk35MethodInterceptor.java b/curator-test/src/compatibility/java/org/apache/curator/test/Zk35MethodInterceptor.java
new file mode 100644
index 0000000..290910c
--- /dev/null
+++ b/curator-test/src/compatibility/java/org/apache/curator/test/Zk35MethodInterceptor.java
@@ -0,0 +1,55 @@
+/**
+ * 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.curator.test;
+
+import org.testng.IMethodInstance;
+import org.testng.IMethodInterceptor;
+import org.testng.ITestContext;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Zk35MethodInterceptor implements IMethodInterceptor
+{
+    public static final String zk35Group = "zk35";
+
+    @Override
+    public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context)
+    {
+        if ( !Compatibility.isZK34() )
+        {
+            return methods;
+        }
+
+        List<IMethodInstance> filteredMethods = new ArrayList<>();
+        for ( IMethodInstance method : methods )
+        {
+            if ( !isInGroup(method.getMethod().getGroups()) )
+            {
+                filteredMethods.add(method);
+            }
+        }
+        return filteredMethods;
+    }
+
+    private boolean isInGroup(String[] groups)
+    {
+        return (groups != null) && Arrays.asList(groups).contains(zk35Group);
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test/src/main/java/org/apache/curator/test/Compatibility.java
----------------------------------------------------------------------
diff --git a/curator-test/src/main/java/org/apache/curator/test/Compatibility.java b/curator-test/src/main/java/org/apache/curator/test/Compatibility.java
new file mode 100644
index 0000000..87eb33e
--- /dev/null
+++ b/curator-test/src/main/java/org/apache/curator/test/Compatibility.java
@@ -0,0 +1,34 @@
+/**
+ * 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.curator.test;
+
+import org.apache.zookeeper.ZooKeeper;
+
+class Compatibility
+{
+    static boolean isZK34()
+    {
+        return false;
+    }
+
+    static void injectSessionExpiration(ZooKeeper zooKeeper)
+    {
+        zooKeeper.getTestable().injectSessionExpiration();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/58bc969f/curator-test/src/main/java/org/apache/curator/test/KillServerSession.java
----------------------------------------------------------------------
diff --git a/curator-test/src/main/java/org/apache/curator/test/KillServerSession.java b/curator-test/src/main/java/org/apache/curator/test/KillServerSession.java
deleted file mode 100644
index ab5fa32..0000000
--- a/curator-test/src/main/java/org/apache/curator/test/KillServerSession.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * 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.curator.test;
-
-import org.apache.zookeeper.WatchedEvent;
-import org.apache.zookeeper.Watcher;
-import org.apache.zookeeper.ZooKeeper;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * <p>
- *     Utility to simulate a ZK session dying. See: <a href="http://wiki.apache.org/hadoop/ZooKeeper/FAQ#A4">ZooKeeper FAQ</a>
- * </p>
- *
- * <blockquote>
- *     In the case of testing we want to cause a problem, so to explicitly expire a session an
- *     application connects to ZooKeeper, saves the session id and password, creates another
- *     ZooKeeper handle with that id and password, and then closes the new handle. Since both
- *     handles reference the same session, the close on second handle will invalidate the session
- *     causing a SESSION_EXPIRED on the first handle.
- * </blockquote>
- */
-public class KillServerSession
-{
-    /**
-     * Kill the given ZK session
-     *
-     * @param client the client to kill
-     * @param connectString server connection string
-     * @throws Exception errors
-     */
-    public static void     kill(ZooKeeper client, String connectString) throws Exception
-    {
-        kill(client, connectString, new Timing().forWaiting().milliseconds());
-    }
-
-    /**
-     * Kill the given ZK session
-     *
-     * @param client the client to kill
-     * @param connectString server connection string
-     * @param maxMs max time ms to wait for kill
-     * @throws Exception errors
-     */
-    public static void     kill(ZooKeeper client, String connectString, int maxMs) throws Exception
-    {
-        long                    startTicks = System.currentTimeMillis();
-
-        final CountDownLatch    sessionLostLatch = new CountDownLatch(1);
-        Watcher                 sessionLostWatch = new Watcher()
-        {
-            @Override
-            public void process(WatchedEvent event)
-            {
-                sessionLostLatch.countDown();
-            }
-        };
-        client.exists("/___CURATOR_KILL_SESSION___" + System.nanoTime(), sessionLostWatch);
-
-        final CountDownLatch    connectionLatch = new CountDownLatch(1);
-        Watcher                 connectionWatcher = new Watcher()
-        {
-            @Override
-            public void process(WatchedEvent event)
-            {
-                if ( event.getState() == Event.KeeperState.SyncConnected )
-                {
-                    connectionLatch.countDown();
-                }
-            }
-        };
-        ZooKeeper zk = new ZooKeeper(connectString, maxMs, connectionWatcher, client.getSessionId(), client.getSessionPasswd());
-        try
-        {
-            if ( !connectionLatch.await(maxMs, TimeUnit.MILLISECONDS) )
-            {
-                throw new Exception("KillSession could not establish duplicate session");
-            }
-            try
-            {
-                zk.close();
-            }
-            finally
-            {
-                zk = null;
-            }
-
-            while ( client.getState().isConnected() && !sessionLostLatch.await(100, TimeUnit.MILLISECONDS) )
-            {
-                long        elapsed = System.currentTimeMillis() - startTicks;
-                if ( elapsed > maxMs )
-                {
-                    throw new Exception("KillSession timed out waiting for session to expire");
-                }
-            }
-        }
-        finally
-        {
-            if ( zk != null )
-            {
-                zk.close();
-            }
-        }
-    }
-}