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 2020/03/17 18:02:24 UTC

[curator] 01/02: CURATOR-558

This is an automated email from the ASF dual-hosted git repository.

randgalt pushed a commit to branch CURATOR-549-zk36-persistent-watcher-recipes
in repository https://gitbox.apache.org/repos/asf/curator.git

commit fb55476c80885c909112e05db4332d51b2229a1b
Author: randgalt <ra...@apache.org>
AuthorDate: Sat Nov 2 11:40:44 2019 -0500

    CURATOR-558
    
    Bring Curator up to ZooKeeper 3.5.6 in preparation for supporting persistent recursive watchers while maintaining background compatability with previous versions of ZK. Added a new module to make sure we maintain compatibility with ZK 3.5.x. ZooKeeper 3.6.0 has some significant changes from previous versions. The reconfig APIs have moved into a new class, ZooKeeperAdmin. This class existed in 3.5.x but wasn't required. Now it is. A bunch of little things changed in the ZK server code  [...]
    
    There is a new module, curator-test-zk35. It forces ZooKeeper 3.5.6 and performs selected tests from the other modules to ensure compatibility. Tests annotated with TestNG groups zk35 and zk35Compatibility are tested. Group zk36 is excluded. Note: these tests will only run from Maven. I don't think IntelliJ/Eclipse support the Maven syntax I used.
    Support persistent watchers in ZK 3.6+ while maintaining background compatability with previous versions of ZK. Added a new module to make sure we maintain comaptibility with ZK 3.5.x
---
 .../curator/framework/imps/TestWatchesBuilder.java | 431 +++++++++++----------
 .../recipes/leader/TestLeaderSelectorEdges.java    |   1 +
 curator-test-zk35/pom.xml~3172ccb6... CURATOR-549  | 161 ++++++++
 3 files changed, 384 insertions(+), 209 deletions(-)

diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestWatchesBuilder.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestWatchesBuilder.java
index b30de1d..9ee8fce 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestWatchesBuilder.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestWatchesBuilder.java
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 package org.apache.curator.framework.imps;
 
 import org.apache.curator.framework.CuratorFramework;
@@ -54,7 +55,7 @@ public class TestWatchesBuilder extends CuratorTestBase
         final AtomicReference<ConnectionState> state = new AtomicReference<ConnectionState>();
         client.getConnectionStateListenable().addListener(new ConnectionStateListener()
         {
-            
+
             @Override
             public void stateChanged(CuratorFramework client, ConnectionState newState)
             {
@@ -65,13 +66,13 @@ public class TestWatchesBuilder extends CuratorTestBase
                 }
             }
         });
-        
+
         return state;
     }
-    
+
     private boolean blockUntilDesiredConnectionState(AtomicReference<ConnectionState> stateRef, Timing timing, final ConnectionState desiredState)
     {
-        if(stateRef.get() == desiredState)
+        if ( stateRef.get() == desiredState )
         {
             return true;
         }
@@ -79,55 +80,55 @@ public class TestWatchesBuilder extends CuratorTestBase
         //noinspection SynchronizationOnLocalVariableOrMethodParameter
         synchronized(stateRef)
         {
-            if(stateRef.get() == desiredState)
+            if ( stateRef.get() == desiredState )
             {
                 return true;
             }
-            
+
             try
             {
                 stateRef.wait(timing.milliseconds());
                 return stateRef.get() == desiredState;
             }
-            catch(InterruptedException e)
+            catch ( InterruptedException e )
             {
                 Thread.currentThread().interrupt();
                 return false;
             }
         }
     }
-    
+
     @Test
     public void testRemoveCuratorDefaultWatcher() throws Exception
     {
         Timing timing = new Timing();
         CuratorFramework client = CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             final CountDownLatch removedLatch = new CountDownLatch(1);
-            
-            final String path = "/";            
+
+            final String path = "/";
             client.getCuratorListenable().addListener(new CuratorListener()
-            {                
+            {
                 @Override
-                public void eventReceived(CuratorFramework client, CuratorEvent event)
-                        throws Exception
+                public void eventReceived(CuratorFramework client, CuratorEvent event) throws Exception
                 {
-                    if(event.getType() == CuratorEventType.WATCHED && event.getWatchedEvent().getType() == EventType.DataWatchRemoved) {                        
+                    if ( event.getType() == CuratorEventType.WATCHED && event.getWatchedEvent().getType() == EventType.DataWatchRemoved )
+                    {
                         removedLatch.countDown();
-                    }        
+                    }
                 }
             });
-                        
+
             client.checkExists().watched().forPath(path);
-            
+
             client.watches().removeAll().forPath(path);
-            
+
             Assert.assertTrue(timing.awaitLatch(removedLatch), "Timed out waiting for watch removal");
         }
         finally
@@ -135,34 +136,35 @@ public class TestWatchesBuilder extends CuratorTestBase
             CloseableUtils.closeQuietly(client);
         }
     }
-    
+
     @Test
     public void testRemoveCuratorWatch() throws Exception
-    {       
+    {
         Timing timing = new Timing();
         CuratorFrameworkImpl client = (CuratorFrameworkImpl)CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             final CountDownLatch removedLatch = new CountDownLatch(1);
-            
-            final String path = "/";            
+
+            final String path = "/";
             CuratorWatcher watcher = new CuratorWatcher()
             {
-                
+
                 @Override
                 public void process(WatchedEvent event) throws Exception
                 {
-                    if(event.getPath().equals(path) && event.getType() == EventType.DataWatchRemoved) {
+                    if ( event.getPath().equals(path) && event.getType() == EventType.DataWatchRemoved )
+                    {
                         removedLatch.countDown();
                     }
                 }
             };
-                        
+
             client.checkExists().usingWatcher(watcher).forPath(path);
 
             client.watches().remove(watcher).forPath(path);
@@ -173,25 +175,25 @@ public class TestWatchesBuilder extends CuratorTestBase
         {
             CloseableUtils.closeQuietly(client);
         }
-    }    
-    
+    }
+
     @Test
     public void testRemoveWatch() throws Exception
-    {       
+    {
         Timing timing = new Timing();
         CuratorFrameworkImpl client = (CuratorFrameworkImpl)CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             final CountDownLatch removedLatch = new CountDownLatch(1);
-            
-            final String path = "/";    
+
+            final String path = "/";
             Watcher watcher = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);
-            
+
             client.checkExists().usingWatcher(watcher).forPath(path);
 
             client.watches().remove(watcher).forPath(path);
@@ -203,97 +205,97 @@ public class TestWatchesBuilder extends CuratorTestBase
             CloseableUtils.closeQuietly(client);
         }
     }
-    
+
     @Test
     public void testRemoveWatchInBackgroundWithCallback() throws Exception
-    {       
+    {
         Timing timing = new Timing();
         CuratorFrameworkImpl client = (CuratorFrameworkImpl)CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
-        {            
+        {
             client.start();
-         
+
             //Make sure that the event fires on both the watcher and the callback.
             final CountDownLatch removedLatch = new CountDownLatch(2);
             final String path = "/";
             Watcher watcher = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);
-            
+
             BackgroundCallback callback = new BackgroundCallback()
             {
-                
+
                 @Override
-                public void processResult(CuratorFramework client, CuratorEvent event)
-                        throws Exception
+                public void processResult(CuratorFramework client, CuratorEvent event) throws Exception
                 {
-                    if(event.getType() == CuratorEventType.REMOVE_WATCHES && event.getPath().equals(path)) {
+                    if ( event.getType() == CuratorEventType.REMOVE_WATCHES && event.getPath().equals(path) )
+                    {
                         removedLatch.countDown();
                     }
                 }
             };
-            
+
             client.checkExists().usingWatcher(watcher).forPath(path);
 
             client.watches().remove(watcher).ofType(WatcherType.Any).inBackground(callback).forPath(path);
 
             Assert.assertTrue(timing.awaitLatch(removedLatch), "Timed out waiting for watch removal");
-            
+
         }
         finally
         {
             CloseableUtils.closeQuietly(client);
         }
     }
-    
+
     @Test
     public void testRemoveWatchInBackgroundWithNoCallback() throws Exception
-    {       
+    {
         Timing timing = new Timing();
         CuratorFrameworkImpl client = (CuratorFrameworkImpl)CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             final String path = "/";
             final CountDownLatch removedLatch = new CountDownLatch(1);
             Watcher watcher = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);
-            
+
             client.checkExists().usingWatcher(watcher).forPath(path);
 
             client.watches().remove(watcher).inBackground().forPath(path);
 
             Assert.assertTrue(timing.awaitLatch(removedLatch), "Timed out waiting for watch removal");
-            
+
         }
         finally
         {
             CloseableUtils.closeQuietly(client);
         }
-    }        
-    
+    }
+
     @Test
     public void testRemoveAllWatches() throws Exception
-    {       
+    {
         Timing timing = new Timing();
         CuratorFrameworkImpl client = (CuratorFrameworkImpl)CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             final String path = "/";
             final CountDownLatch removedLatch = new CountDownLatch(2);
-            
-            Watcher watcher1 = new CountDownWatcher(path, removedLatch, EventType.ChildWatchRemoved);            
-            Watcher watcher2 = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);                        
-            
+
+            Watcher watcher1 = new CountDownWatcher(path, removedLatch, EventType.ChildWatchRemoved);
+            Watcher watcher2 = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);
+
             client.getChildren().usingWatcher(watcher1).forPath(path);
             client.checkExists().usingWatcher(watcher2).forPath(path);
 
@@ -305,32 +307,32 @@ public class TestWatchesBuilder extends CuratorTestBase
         {
             CloseableUtils.closeQuietly(client);
         }
-    }  
-    
+    }
+
     @Test
     public void testRemoveAllDataWatches() throws Exception
-    {       
+    {
         Timing timing = new Timing();
         CuratorFramework client = CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             final String path = "/";
             final AtomicBoolean removedFlag = new AtomicBoolean(false);
             final CountDownLatch removedLatch = new CountDownLatch(1);
-            
-            Watcher watcher1 = new BooleanWatcher(path, removedFlag, EventType.ChildWatchRemoved);            
-            Watcher watcher2 = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);                        
-            
+
+            Watcher watcher1 = new BooleanWatcher(path, removedFlag, EventType.ChildWatchRemoved);
+            Watcher watcher2 = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);
+
             client.getChildren().usingWatcher(watcher1).forPath(path);
             client.checkExists().usingWatcher(watcher2).forPath(path);
-            
+
             client.watches().removeAll().ofType(WatcherType.Data).forPath(path);
-            
+
             Assert.assertTrue(timing.awaitLatch(removedLatch), "Timed out waiting for watch removal");
             Assert.assertEquals(removedFlag.get(), false);
         }
@@ -339,31 +341,31 @@ public class TestWatchesBuilder extends CuratorTestBase
             CloseableUtils.closeQuietly(client);
         }
     }
-    
+
     @Test
     public void testRemoveAllChildWatches() throws Exception
-    {       
+    {
         Timing timing = new Timing();
         CuratorFramework client = CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             final String path = "/";
             final AtomicBoolean removedFlag = new AtomicBoolean(false);
             final CountDownLatch removedLatch = new CountDownLatch(1);
-            
-            Watcher watcher1 = new BooleanWatcher(path, removedFlag, EventType.DataWatchRemoved);            
-            Watcher watcher2 = new CountDownWatcher(path, removedLatch, EventType.ChildWatchRemoved);                        
-                        
+
+            Watcher watcher1 = new BooleanWatcher(path, removedFlag, EventType.DataWatchRemoved);
+            Watcher watcher2 = new CountDownWatcher(path, removedLatch, EventType.ChildWatchRemoved);
+
             client.checkExists().usingWatcher(watcher1).forPath(path);
             client.getChildren().usingWatcher(watcher2).forPath(path);
-            
+
             client.watches().removeAll().ofType(WatcherType.Children).forPath(path);
-            
+
             Assert.assertTrue(timing.awaitLatch(removedLatch), "Timed out waiting for watch removal");
             Assert.assertEquals(removedFlag.get(), false);
         }
@@ -371,34 +373,35 @@ public class TestWatchesBuilder extends CuratorTestBase
         {
             CloseableUtils.closeQuietly(client);
         }
-    }     
-    
+    }
+
     @Test
-    public void testRemoveLocalWatch() throws Exception {
+    public void testRemoveLocalWatch() throws Exception
+    {
         Timing timing = new Timing();
         CuratorFrameworkImpl client = (CuratorFrameworkImpl)CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             AtomicReference<ConnectionState> stateRef = registerConnectionStateListener(client);
-            
+
             final String path = "/";
-            
+
             final CountDownLatch removedLatch = new CountDownLatch(1);
-            
-            Watcher watcher = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);        
-            
+
+            Watcher watcher = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);
+
             client.checkExists().usingWatcher(watcher).forPath(path);
 
             //Stop the server so we can check if we can remove watches locally when offline
             server.stop();
-            
+
             Assert.assertTrue(blockUntilDesiredConnectionState(stateRef, timing, ConnectionState.SUSPENDED));
-                       
+
             client.watches().removeAll().locally().forPath(path);
 
             Assert.assertTrue(timing.awaitLatch(removedLatch), "Timed out waiting for watch removal");
@@ -408,33 +411,34 @@ public class TestWatchesBuilder extends CuratorTestBase
             CloseableUtils.closeQuietly(client);
         }
     }
-    
+
     @Test
-    public void testRemoveLocalWatchInBackground() throws Exception {
+    public void testRemoveLocalWatchInBackground() throws Exception
+    {
         Timing timing = new Timing();
         CuratorFrameworkImpl client = (CuratorFrameworkImpl)CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             AtomicReference<ConnectionState> stateRef = registerConnectionStateListener(client);
-            
+
             final String path = "/";
-            
+
             final CountDownLatch removedLatch = new CountDownLatch(1);
-            
-            Watcher watcher = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);        
-            
+
+            Watcher watcher = new CountDownWatcher(path, removedLatch, EventType.DataWatchRemoved);
+
             client.checkExists().usingWatcher(watcher).forPath(path);
 
             //Stop the server so we can check if we can remove watches locally when offline
             server.stop();
-            
+
             Assert.assertTrue(blockUntilDesiredConnectionState(stateRef, timing, ConnectionState.SUSPENDED));
-                       
+
             client.watches().removeAll().locally().inBackground().forPath(path);
 
             Assert.assertTrue(timing.awaitLatch(removedLatch), "Timed out waiting for watch removal");
@@ -443,8 +447,8 @@ public class TestWatchesBuilder extends CuratorTestBase
         {
             CloseableUtils.closeQuietly(client);
         }
-    }    
-    
+    }
+
     /**
      * Test the case where we try and remove an unregistered watcher. In this case we expect a NoWatcherException to
      * be thrown. 
@@ -454,21 +458,22 @@ public class TestWatchesBuilder extends CuratorTestBase
     public void testRemoveUnregisteredWatcher() throws Exception
     {
         CuratorFramework client = CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
-            final String path = "/";            
-            Watcher watcher = new Watcher() {
+
+            final String path = "/";
+            Watcher watcher = new Watcher()
+            {
                 @Override
                 public void process(WatchedEvent event)
                 {
-                }                
+                }
             };
-            
+
             try
             {
                 client.watches().remove(watcher).forPath(path);
@@ -484,7 +489,7 @@ public class TestWatchesBuilder extends CuratorTestBase
             CloseableUtils.closeQuietly(client);
         }
     }
-    
+
     /**
      * Test the case where we try and remove an unregistered watcher but have the quietly flag set. In this case we expect success. 
      * @throws Exception
@@ -494,22 +499,22 @@ public class TestWatchesBuilder extends CuratorTestBase
     {
         Timing timing = new Timing();
         CuratorFramework client = CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             final AtomicBoolean watcherRemoved = new AtomicBoolean(false);
-            
-            final String path = "/";            
+
+            final String path = "/";
             Watcher watcher = new BooleanWatcher(path, watcherRemoved, EventType.DataWatchRemoved);
-            
+
             client.watches().remove(watcher).quietly().forPath(path);
-            
+
             timing.sleepABit();
-            
+
             //There should be no watcher removed as none were registered.
             Assert.assertEquals(watcherRemoved.get(), false);
         }
@@ -518,94 +523,94 @@ public class TestWatchesBuilder extends CuratorTestBase
             CloseableUtils.closeQuietly(client);
         }
     }
-    
+
     @Test
-    public void testGuaranteedRemoveWatch() throws Exception {
+    public void testGuaranteedRemoveWatch() throws Exception
+    {
         Timing timing = new Timing();
         CuratorFramework client = CuratorFrameworkFactory.builder().
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
         try
         {
             client.start();
-            
+
             AtomicReference<ConnectionState> stateRef = registerConnectionStateListener(client);
-                       
+
             String path = "/";
-            
+
             CountDownLatch removeLatch = new CountDownLatch(1);
-            
-            Watcher watcher = new CountDownWatcher(path, removeLatch, EventType.DataWatchRemoved);            
+
+            Watcher watcher = new CountDownWatcher(path, removeLatch, EventType.DataWatchRemoved);
             client.checkExists().usingWatcher(watcher).forPath(path);
-            
-            server.stop();           
-            
+
+            server.stop();
+
             Assert.assertTrue(blockUntilDesiredConnectionState(stateRef, timing, ConnectionState.SUSPENDED));
-            
+
             //Remove the watch while we're not connected
-            try 
+            try
             {
                 client.watches().remove(watcher).guaranteed().forPath(path);
                 Assert.fail();
             }
-            catch(KeeperException.ConnectionLossException e)
+            catch ( KeeperException.ConnectionLossException e )
             {
                 //Expected
             }
-            
+
             server.restart();
-            
-            timing.awaitLatch(removeLatch);            
+
+            timing.awaitLatch(removeLatch);
         }
         finally
         {
             CloseableUtils.closeQuietly(client);
         }
     }
-    
+
     @Test
-    public void testGuaranteedRemoveWatchInBackground() throws Exception {
+    public void testGuaranteedRemoveWatchInBackground() throws Exception
+    {
         Timing timing = new Timing();
-        CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(),
-                                                                    new ExponentialBackoffRetry(100, 3));
+        CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new ExponentialBackoffRetry(100, 3));
         try
         {
             client.start();
-            
+
             AtomicReference<ConnectionState> stateRef = registerConnectionStateListener(client);
-                        
+
             final CountDownLatch guaranteeAddedLatch = new CountDownLatch(1);
-            
+
             ((CuratorFrameworkImpl)client).getFailedRemoveWatcherManager().debugListener = new FailedOperationManager.FailedOperationManagerListener<FailedRemoveWatchManager.FailedRemoveWatchDetails>()
             {
 
                 @Override
-                public void pathAddedForGuaranteedOperation(
-                        FailedRemoveWatchDetails detail)
+                public void pathAddedForGuaranteedOperation(FailedRemoveWatchDetails detail)
                 {
                     guaranteeAddedLatch.countDown();
                 }
             };
-            
+
             String path = "/";
-            
+
             CountDownLatch removeLatch = new CountDownLatch(1);
-            
-            Watcher watcher = new CountDownWatcher(path, removeLatch, EventType.DataWatchRemoved);            
+
+            Watcher watcher = new CountDownWatcher(path, removeLatch, EventType.DataWatchRemoved);
             client.checkExists().usingWatcher(watcher).forPath(path);
-            
-            server.stop();           
+
+            server.stop();
             Assert.assertTrue(blockUntilDesiredConnectionState(stateRef, timing, ConnectionState.SUSPENDED));
-            
+
             //Remove the watch while we're not connected
             client.watches().remove(watcher).guaranteed().inBackground().forPath(path);
-            
+
             timing.awaitLatch(guaranteeAddedLatch);
-            
+
             server.restart();
-            
-            timing.awaitLatch(removeLatch);            
+
+            timing.awaitLatch(removeLatch);
         }
         finally
         {
@@ -658,7 +663,7 @@ public class TestWatchesBuilder extends CuratorTestBase
     @Test(groups = CuratorTestBase.zk36Group)
     public void testPersistentRecursiveWatch() throws Exception
     {
-        try ( CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), new RetryOneTime(1)) )
+        try (CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), new RetryOneTime(1)))
         {
             client.start();
             client.blockUntilConnected();
@@ -712,7 +717,7 @@ public class TestWatchesBuilder extends CuratorTestBase
             };
             return new ZooKeeper(connectString, sessionTimeout, actualWatcher);
         };
-        try (CuratorFramework client = CuratorFrameworkFactory.builder().connectString(server.getConnectString()).retryPolicy(new RetryOneTime(1)).zookeeperFactory(zookeeperFactory).build() )
+        try (CuratorFramework client = CuratorFrameworkFactory.builder().connectString(server.getConnectString()).retryPolicy(new RetryOneTime(1)).zookeeperFactory(zookeeperFactory).build())
         {
             client.start();
             client.blockUntilConnected();
@@ -729,51 +734,59 @@ public class TestWatchesBuilder extends CuratorTestBase
         }
     }
 
-    private static class CountDownWatcher implements Watcher {
+    private static class CountDownWatcher implements Watcher
+    {
         private String path;
         private EventType eventType;
         private CountDownLatch removeLatch;
-        
-        public CountDownWatcher(String path, CountDownLatch removeLatch, EventType eventType) {
+
+        public CountDownWatcher(String path, CountDownLatch removeLatch, EventType eventType)
+        {
             this.path = path;
             this.eventType = eventType;
-            this.removeLatch = removeLatch;            
+            this.removeLatch = removeLatch;
         }
-        
+
         @Override
         public void process(WatchedEvent event)
         {
-            if(event.getPath() == null || event.getType() == null) {
+            if ( event.getPath() == null || event.getType() == null )
+            {
                 return;
             }
-            
-            if(event.getPath().equals(path) && event.getType() == eventType) {
+
+            if ( event.getPath().equals(path) && event.getType() == eventType )
+            {
                 removeLatch.countDown();
             }
-        }  
+        }
     }
-    
-    private static class BooleanWatcher implements Watcher {
+
+    private static class BooleanWatcher implements Watcher
+    {
         private String path;
         private EventType eventType;
         private AtomicBoolean removedFlag;
-        
-        public BooleanWatcher(String path, AtomicBoolean removedFlag, EventType eventType) {
+
+        public BooleanWatcher(String path, AtomicBoolean removedFlag, EventType eventType)
+        {
             this.path = path;
             this.eventType = eventType;
-            this.removedFlag = removedFlag;            
+            this.removedFlag = removedFlag;
         }
-        
+
         @Override
         public void process(WatchedEvent event)
         {
-            if(event.getPath() == null || event.getType() == null) {
+            if ( event.getPath() == null || event.getType() == null )
+            {
                 return;
             }
-            
-            if(event.getPath().equals(path) && event.getType() == eventType) {
+
+            if ( event.getPath().equals(path) && event.getType() == eventType )
+            {
                 removedFlag.set(true);
             }
-        }  
-    }    
+        }
+    }
 }
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderSelectorEdges.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderSelectorEdges.java
index 9841677..9969b05 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderSelectorEdges.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/leader/TestLeaderSelectorEdges.java
@@ -42,6 +42,7 @@ import java.util.concurrent.TimeUnit;
 /**
  * Test cases designed after CURATOR-45
  */
+@Test(groups = CuratorTestBase.zk35Group)
 public class TestLeaderSelectorEdges extends BaseClassForTests
 {
     private final Logger log = LoggerFactory.getLogger(getClass());
diff --git a/curator-test-zk35/pom.xml~3172ccb6... CURATOR-549 b/curator-test-zk35/pom.xml~3172ccb6... CURATOR-549
new file mode 100644
index 0000000..8d0d220
--- /dev/null
+++ b/curator-test-zk35/pom.xml~3172ccb6... CURATOR-549	
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.curator</groupId>
+        <artifactId>apache-curator</artifactId>
+        <version>4.2.1-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>curator-test-zk35</artifactId>
+
+    <properties>
+        <zookeeper-35-version>3.5.6</zookeeper-35-version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-framework</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.zookeeper</groupId>
+                    <artifactId>zookeeper</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-x-async</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.zookeeper</groupId>
+                    <artifactId>zookeeper</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-recipes</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.zookeeper</groupId>
+                    <artifactId>zookeeper</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.zookeeper</groupId>
+            <artifactId>zookeeper</artifactId>
+            <version>${zookeeper-35-version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.sun.jmx</groupId>
+                    <artifactId>jmxri</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.sun.jdmk</groupId>
+                    <artifactId>jmxtools</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>javax.jms</groupId>
+                    <artifactId>jms</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>junit</groupId>
+                    <artifactId>junit</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-test</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-recipes</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-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.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>deploy</phase>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                        <goals>
+                            <goal>deploy</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <dependenciesToScan>
+                        <dependency>org.apache.curator:curator-framework</dependency>
+                        <dependency>org.apache.curator:curator-recipes</dependency>
+                    </dependenciesToScan>
+                    <groups>zk35,zk35TestCompatibility</groups>
+                    <excludedGroups>zk36</excludedGroups>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>