Repository: curator
Updated Branches:
  refs/heads/persistent-watch 38c766310 -> 6cfd38c25


More testing and refactoring. Wasn't checking for deleted children after a 
refresh. Also, allow for different methods of comparing nodes for change.


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

Branch: refs/heads/persistent-watch
Commit: 6cfd38c25391865503ba4cf35530f1794c777b91
Parents: 38c7663
Author: randgalt <randg...@apache.org>
Authored: Sat Dec 31 17:57:18 2016 -0500
Committer: randgalt <randg...@apache.org>
Committed: Sat Dec 31 17:57:18 2016 -0500

----------------------------------------------------------------------
 .../framework/recipes/watch/CacheFilters.java   |  45 ++++-
 .../recipes/watch/CachedNodeComparator.java     |  24 +++
 .../recipes/watch/CachedNodeComparators.java    |  91 +++++++++
 .../recipes/watch/CuratorCacheBase.java         |   5 +-
 .../recipes/watch/CuratorCacheBuilder.java      |  13 +-
 .../recipes/watch/InternalCuratorCache.java     |  41 +++-
 .../recipes/watch/InternalNodeCache.java        |   2 +-
 .../recipes/watch/BaseTestTreeCache.java        |  10 +
 .../framework/recipes/watch/TestTreeCache.java  | 200 +++++++++++++++++--
 9 files changed, 397 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/6cfd38c2/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CacheFilters.java
----------------------------------------------------------------------
diff --git 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CacheFilters.java
 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CacheFilters.java
index dec16b1..534829e 100644
--- 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CacheFilters.java
+++ 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CacheFilters.java
@@ -24,7 +24,7 @@ public class CacheFilters
     private static final CacheFilter compressedStatAndData = new 
StandardCacheFilter(CacheAction.STAT_AND_COMPRESSED_DATA);
     private static final CacheFilter statOnly = new 
StandardCacheFilter(CacheAction.STAT_ONLY);
     private static final CacheFilter pathOnly = new 
StandardCacheFilter(CacheAction.PATH_ONLY);
-    private static final CacheFilter full = new CacheFilter()
+    private static final CacheFilter fullStatAndData = new CacheFilter()
     {
         @Override
         public CacheAction actionForPath(String mainPath, String checkPath)
@@ -32,6 +32,30 @@ public class CacheFilters
             return CacheAction.STAT_AND_DATA;
         }
     };
+    private static final CacheFilter fullCompressedStatAndData = new 
CacheFilter()
+    {
+        @Override
+        public CacheAction actionForPath(String mainPath, String checkPath)
+        {
+            return CacheAction.STAT_AND_COMPRESSED_DATA;
+        }
+    };
+    private static final CacheFilter fullStatOnly = new CacheFilter()
+    {
+        @Override
+        public CacheAction actionForPath(String mainPath, String checkPath)
+        {
+            return CacheAction.STAT_ONLY;
+        }
+    };
+    private static final CacheFilter fullPathOnly = new CacheFilter()
+    {
+        @Override
+        public CacheAction actionForPath(String mainPath, String checkPath)
+        {
+            return CacheAction.PATH_ONLY;
+        }
+    };
 
     public static CacheFilter statAndData()
     {
@@ -53,9 +77,24 @@ public class CacheFilters
         return pathOnly;
     }
 
-    public static CacheFilter full()
+    public static CacheFilter fullStatAndData()
+    {
+        return fullStatAndData;
+    }
+
+    public static CacheFilter fullCompressedStatAndData()
+    {
+        return fullCompressedStatAndData;
+    }
+
+    public static CacheFilter fullStatOnly()
+    {
+        return fullStatOnly;
+    }
+
+    public static CacheFilter fullPathOnly()
     {
-        return full;
+        return fullPathOnly;
     }
 
     private CacheFilters()

http://git-wip-us.apache.org/repos/asf/curator/blob/6cfd38c2/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CachedNodeComparator.java
----------------------------------------------------------------------
diff --git 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CachedNodeComparator.java
 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CachedNodeComparator.java
new file mode 100644
index 0000000..34d86ad
--- /dev/null
+++ 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CachedNodeComparator.java
@@ -0,0 +1,24 @@
+/**
+ * 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.framework.recipes.watch;
+
+public interface CachedNodeComparator
+{
+    boolean isSame(CachedNode n1, CachedNode n2);
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/6cfd38c2/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CachedNodeComparators.java
----------------------------------------------------------------------
diff --git 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CachedNodeComparators.java
 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CachedNodeComparators.java
new file mode 100644
index 0000000..b54d443
--- /dev/null
+++ 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CachedNodeComparators.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.curator.framework.recipes.watch;
+
+import java.util.Arrays;
+
+public class CachedNodeComparators
+{
+    private static final CachedNodeComparator dataOnly = new 
CachedNodeComparator()
+    {
+        @Override
+        public boolean isSame(CachedNode n1, CachedNode n2)
+        {
+            return firstCheck(n1, n2) && Arrays.equals(n1.getData(), 
n2.getData());
+        }
+    };
+
+    private static final CachedNodeComparator dataAndType = new 
CachedNodeComparator()
+    {
+        @Override
+        public boolean isSame(CachedNode n1, CachedNode n2)
+        {
+            return firstCheck(n1, n2) && Arrays.equals(n1.getData(), 
n2.getData()) && sameType(n1.getStat().getEphemeralOwner(), 
n2.getStat().getEphemeralOwner());
+        }
+    };
+
+    private static final CachedNodeComparator deep = new CachedNodeComparator()
+    {
+        @Override
+        public boolean isSame(CachedNode n1, CachedNode n2)
+        {
+            return n1.equals(n2);
+        }
+    };
+
+    private static boolean sameType(long e1, long e2)
+    {
+        boolean e1Is = (e1 > 0);
+        boolean e2Is = (e2 > 0);
+        return e1Is == e2Is;
+    }
+
+    private static boolean firstCheck(CachedNode n1, CachedNode n2)
+    {
+        if ( n1 == n2 )
+        {
+            return true;
+        }
+        //noinspection RedundantIfStatement
+        if ( (n1 == null) || (n2 == null) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    public static CachedNodeComparator dataOnly()
+    {
+        return dataOnly;
+    }
+
+    public static CachedNodeComparator deep()
+    {
+        return deep;
+    }
+
+    public static CachedNodeComparator dataAndType()
+    {
+        return dataAndType;
+    }
+
+    private CachedNodeComparators()
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/6cfd38c2/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBase.java
----------------------------------------------------------------------
diff --git 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBase.java
 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBase.java
index 1362679..4cc46e8 100644
--- 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBase.java
+++ 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBase.java
@@ -42,7 +42,6 @@ abstract class CuratorCacheBase implements CuratorCache
     private final AtomicReference<CountDownLatch> initialRefreshLatch = new 
AtomicReference<>(new CountDownLatch(1));
     private final boolean sendRefreshEvents;
     private final AtomicInteger refreshCount = new AtomicInteger(0);
-    private Function<String, String> function;
 
     protected boolean isStarted()
     {
@@ -107,13 +106,13 @@ abstract class CuratorCacheBase implements CuratorCache
     @Override
     public Collection<String> childNamesAtPath(final String basePath)
     {
-        function = new Function<String, String>()
+        Function<String, String> function = new Function<String, String>()
         {
             @Override
             public String apply(String path)
             {
                 ZKPaths.PathAndNode pathAndNode = ZKPaths.getPathAndNode(path);
-                return pathAndNode.getPath().equals(basePath) ? 
pathAndNode.getNode() : null;
+                return (pathAndNode.getPath().equals(basePath) && 
!path.equals(basePath)) ? pathAndNode.getNode() : null;   // must special case 
"root" as parent of root is root
             }
         };
         return Collections2.filter(Collections2.transform(paths(), function), 
Predicates.notNull());

http://git-wip-us.apache.org/repos/asf/curator/blob/6cfd38c2/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBuilder.java
----------------------------------------------------------------------
diff --git 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBuilder.java
 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBuilder.java
index 31633f0..fa26b07 100644
--- 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBuilder.java
+++ 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/CuratorCacheBuilder.java
@@ -35,6 +35,7 @@ public class CuratorCacheBuilder
     private boolean refreshOnStart = true;
     private CacheFilter cacheFilter = CacheFilters.statAndData();
     private boolean sortChildren = true;
+    private CachedNodeComparator nodeComparator = 
CachedNodeComparators.dataAndType();
 
     public static CuratorCacheBuilder builder(CuratorFramework client, String 
path)
     {
@@ -47,9 +48,9 @@ public class CuratorCacheBuilder
         if ( singleNode )
         {
             Preconditions.checkState(refreshFilter == null, "Single node 
caches do not use RefreshFilters");
-            return new InternalNodeCache(client, path, cacheFilter, 
cacheBuilder.<String, CachedNode>build(), sendRefreshEvents, refreshOnStart);
+            return new InternalNodeCache(client, path, nodeComparator, 
cacheFilter, cacheBuilder.<String, CachedNode>build(), sendRefreshEvents, 
refreshOnStart);
         }
-        return new InternalCuratorCache(client, path, cacheFilter, 
refreshFilter, cacheBuilder.<String, CachedNode>build(), sendRefreshEvents, 
refreshOnStart, sortChildren);
+        return new InternalCuratorCache(client, path, nodeComparator, 
cacheFilter, refreshFilter, cacheBuilder.<String, CachedNode>build(), 
sendRefreshEvents, refreshOnStart, sortChildren);
     }
 
     public CuratorCacheBuilder forSingleNode()
@@ -72,7 +73,7 @@ public class CuratorCacheBuilder
     {
         singleNode = false;
         refreshFilter = RefreshFilters.tree();
-        cacheFilter = CacheFilters.full();
+        cacheFilter = CacheFilters.fullStatAndData();
         return this;
     }
 
@@ -130,6 +131,12 @@ public class CuratorCacheBuilder
         return this;
     }
 
+    public CuratorCacheBuilder nodeComparator(CachedNodeComparator 
nodeComparator)
+    {
+        this.nodeComparator = Objects.requireNonNull(nodeComparator, 
"nodeComparator cannot be null");
+        return this;
+    }
+
     private CuratorCacheBuilder(CuratorFramework client, String path)
     {
         this.client = Objects.requireNonNull(client, "client cannot be null");

http://git-wip-us.apache.org/repos/asf/curator/blob/6cfd38c2/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalCuratorCache.java
----------------------------------------------------------------------
diff --git 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalCuratorCache.java
 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalCuratorCache.java
index 750545b..bff8b2a 100644
--- 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalCuratorCache.java
+++ 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalCuratorCache.java
@@ -20,6 +20,7 @@ package org.apache.curator.framework.recipes.watch;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.cache.Cache;
+import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.SettableFuture;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.api.BackgroundCallback;
@@ -27,8 +28,10 @@ import org.apache.curator.framework.api.CuratorEvent;
 import org.apache.curator.framework.api.CuratorEventType;
 import org.apache.curator.utils.ThreadUtils;
 import org.apache.curator.utils.ZKPaths;
+import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -41,6 +44,7 @@ class InternalCuratorCache extends CuratorCacheBase 
implements Watcher
     private final PersistentWatcher watcher;
     private final CuratorFramework client;
     private final String basePath;
+    private final CachedNodeComparator nodeComparator;
     private final CacheFilter cacheFilter;
     private final RefreshFilter refreshFilter;
     private final boolean sortChildren;
@@ -54,11 +58,12 @@ class InternalCuratorCache extends CuratorCacheBase 
implements Watcher
         }
     };
 
-    InternalCuratorCache(CuratorFramework client, String path, CacheFilter 
cacheFilter, final RefreshFilter refreshFilter, Cache<String, CachedNode> 
cache, boolean sendRefreshEvents, final boolean refreshOnStart, boolean 
sortChildren)
+    InternalCuratorCache(CuratorFramework client, String path, 
CachedNodeComparator nodeComparator, CacheFilter cacheFilter, final 
RefreshFilter refreshFilter, Cache<String, CachedNode> cache, boolean 
sendRefreshEvents, final boolean refreshOnStart, boolean sortChildren)
     {
         super(cache, sendRefreshEvents);
         this.client = Objects.requireNonNull(client, "client cannot be null");
-        basePath = Objects.requireNonNull(path, "path cannot be null");
+        this.basePath = Objects.requireNonNull(path, "path cannot be null");
+        this.nodeComparator = Objects.requireNonNull(nodeComparator, 
"nodeComparator cannot be null");
         this.cacheFilter = Objects.requireNonNull(cacheFilter, "cacheFilter 
cannot be null");
         this.refreshFilter = Objects.requireNonNull(refreshFilter, 
"primingFilter cannot be null");
         this.sortChildren = sortChildren;
@@ -102,11 +107,7 @@ class InternalCuratorCache extends CuratorCacheBase 
implements Watcher
 
             case NodeDeleted:
             {
-                CachedNode removed = cache.asMap().remove(event.getPath());
-                if ( removed != null )
-                {
-                    notifyListeners(CacheEvent.NODE_DELETED, event.getPath(), 
removed);
-                }
+                remove(event.getPath());
                 break;
             }
 
@@ -164,7 +165,7 @@ class InternalCuratorCache extends CuratorCacheBase 
implements Watcher
                         {
                             notifyListeners(CacheEvent.NODE_CREATED, path, 
newNode);
                         }
-                        else if ( !newNode.equals(oldNode) )
+                        else if ( !nodeComparator.isSame(newNode, oldNode) )
                         {
                             notifyListeners(CacheEvent.NODE_CHANGED, path, 
newNode);
                         }
@@ -172,6 +173,7 @@ class InternalCuratorCache extends CuratorCacheBase 
implements Watcher
                     else if ( event.getType() == CuratorEventType.CHILDREN )
                     {
                         List<String> children = event.getChildren();
+                        checkDeletedChildren(path, children);
                         if ( sortChildren )
                         {
                             Collections.sort(children);
@@ -182,6 +184,10 @@ class InternalCuratorCache extends CuratorCacheBase 
implements Watcher
                         }
                     }
                 }
+                else if ( (event.getType() == CuratorEventType.CHILDREN) && 
(event.getResultCode() == KeeperException.Code.NONODE.intValue()) )
+                {
+                    checkDeletedChildren(path, 
Collections.<String>emptyList());
+                }
                 else
                 {
                     // TODO
@@ -250,6 +256,16 @@ class InternalCuratorCache extends CuratorCacheBase 
implements Watcher
         }
     }
 
+    private void checkDeletedChildren(String path, List<String> children)
+    {
+        Collection<String> namesAtPath = childNamesAtPath(path);
+        Sets.SetView<String> deleted = 
Sets.difference(Sets.newHashSet(namesAtPath), Sets.newHashSet(children));
+        for ( String deletedName : deleted )
+        {
+            remove(ZKPaths.makePath(path, deletedName));
+        }
+    }
+
     private CachedNode putNewNode(String path, CacheAction cacheAction, 
CachedNode newNode)
     {
         CachedNode putNode;
@@ -290,4 +306,13 @@ class InternalCuratorCache extends CuratorCacheBase 
implements Watcher
             task.set(true);
         }
     }
+
+    private void remove(String path)
+    {
+        CachedNode removed = cache.asMap().remove(path);
+        if ( removed != null )
+        {
+            notifyListeners(CacheEvent.NODE_DELETED, path, removed);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/6cfd38c2/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalNodeCache.java
----------------------------------------------------------------------
diff --git 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalNodeCache.java
 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalNodeCache.java
index b4a7b16..0968e7a 100644
--- 
a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalNodeCache.java
+++ 
b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/watch/InternalNodeCache.java
@@ -94,7 +94,7 @@ class InternalNodeCache extends CuratorCacheBase
         }
     };
 
-    InternalNodeCache(CuratorFramework client, String path, CacheFilter 
cacheFilter, Cache<String, CachedNode> cache, boolean sendRefreshEvents, 
boolean refreshOnStart)
+    InternalNodeCache(CuratorFramework client, String path, 
CachedNodeComparator nodeComparator, CacheFilter cacheFilter, Cache<String, 
CachedNode> cache, boolean sendRefreshEvents, boolean refreshOnStart)
     {
         super(cache, sendRefreshEvents);
         this.client = client.newWatcherRemoveCuratorFramework();

http://git-wip-us.apache.org/repos/asf/curator/blob/6cfd38c2/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/BaseTestTreeCache.java
----------------------------------------------------------------------
diff --git 
a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/BaseTestTreeCache.java
 
b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/BaseTestTreeCache.java
index ab2e999..c866a81 100644
--- 
a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/BaseTestTreeCache.java
+++ 
b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/BaseTestTreeCache.java
@@ -18,6 +18,7 @@
  */
 package org.apache.curator.framework.recipes.watch;
 
+import com.google.common.collect.Sets;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.framework.imps.TestCleanState;
@@ -164,4 +165,13 @@ public class BaseTestTreeCache extends BaseClassForTests
         }
         return event;
     }
+
+    void assertChildNodeNames(String path, String... names)
+    {
+        if ( names == null )
+        {
+            names = new String[0];
+        }
+        Assert.assertEquals(Sets.newHashSet(cache.childNamesAtPath(path)), 
Sets.newHashSet(names));
+    }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/6cfd38c2/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/TestTreeCache.java
----------------------------------------------------------------------
diff --git 
a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/TestTreeCache.java
 
b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/TestTreeCache.java
index b4c5765..fe3a681 100644
--- 
a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/TestTreeCache.java
+++ 
b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/watch/TestTreeCache.java
@@ -18,8 +18,8 @@
  */
 package org.apache.curator.framework.recipes.watch;
 
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
+import org.apache.curator.test.KillServerSession;
+import org.apache.zookeeper.CreateMode;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -89,9 +89,9 @@ public class TestTreeCache extends BaseTestTreeCache
         assertEvent(CacheEvent.CACHE_REFRESHED);
         assertNoMoreEvents();
 
-        Assert.assertEquals(Sets.newHashSet(cache.childNamesAtPath("/test")), 
Sets.newHashSet("1", "2", "3"));
-        
Assert.assertEquals(Sets.newHashSet(cache.childNamesAtPath("/test/1")), 
Sets.newHashSet());
-        
Assert.assertEquals(Sets.newHashSet(cache.childNamesAtPath("/test/2")), 
Sets.newHashSet("sub"));
+        assertChildNodeNames("/test", "1", "2", "3");
+        assertChildNodeNames("/test/1");
+        assertChildNodeNames("/test/2", "sub");
         Assert.assertNull(cache.get("/test/non_exist"));
     }
 
@@ -136,9 +136,9 @@ public class TestTreeCache extends BaseTestTreeCache
         assertEvent(CacheEvent.CACHE_REFRESHED);
         assertNoMoreEvents();
 
-        Assert.assertEquals(cache.childNamesAtPath("/test"), 
ImmutableSet.of());
+        assertChildNodeNames("/test");
         Assert.assertNull(cache.get("/test/1"));
-        Assert.assertEquals(cache.childNamesAtPath("/test/1").size(), 0);
+        assertChildNodeNames("/test/1");
         Assert.assertNull(cache.get("/test/non_exist"));
     }
 
@@ -160,12 +160,12 @@ public class TestTreeCache extends BaseTestTreeCache
         assertEvent(CacheEvent.CACHE_REFRESHED);
         assertNoMoreEvents();
 
-        Assert.assertEquals(Sets.newHashSet(cache.childNamesAtPath("/test")), 
Sets.newHashSet("1", "2", "3"));
-        
Assert.assertEquals(Sets.newHashSet(cache.childNamesAtPath("/test/1")), 
Sets.newHashSet());
-        
Assert.assertEquals(Sets.newHashSet(cache.childNamesAtPath("/test/2")), 
Sets.newHashSet());
+        assertChildNodeNames("/test", "1", "2", "3");
+        assertChildNodeNames("/test/1");
+        assertChildNodeNames("/test/2");
         Assert.assertNull(cache.get("/test/2/sub"));
-        Assert.assertEquals(cache.childNamesAtPath("/test/2/sub").size(), 0);
-        Assert.assertEquals(cache.childNamesAtPath("/test/non_exist").size(), 
0);
+        assertChildNodeNames("/test/2/sub");
+        assertChildNodeNames("/test/non_exist");
     }
 
     @Test
@@ -218,8 +218,8 @@ public class TestTreeCache extends BaseTestTreeCache
         assertNoMoreEvents();
 
         Assert.assertTrue(cache.childNamesAtPath("/").contains("test"));
-        Assert.assertEquals(cache.childNamesAtPath("/test"), 
ImmutableSet.of("one"));
-        Assert.assertEquals(cache.childNamesAtPath("/test/one"), 
ImmutableSet.of());
+        assertChildNodeNames("/test", "one");
+        assertChildNodeNames("/test/one");
         Assert.assertEquals(new String(cache.get("/test/one").getData()), "hey 
there");
     }
 
@@ -237,8 +237,176 @@ public class TestTreeCache extends BaseTestTreeCache
         assertNoMoreEvents();
 
         Assert.assertTrue(cache.childNamesAtPath("/").contains("test"));
-        Assert.assertEquals(cache.childNamesAtPath("/test"), 
ImmutableSet.of());
+        assertChildNodeNames("/test");
         Assert.assertNull(cache.get("/test/one"));
-        Assert.assertEquals(cache.childNamesAtPath("/test/one").size(), 0);
+        assertChildNodeNames("/test/one");
+    }
+
+    @Test
+    public void testWithNamespace() throws Exception
+    {
+        client.create().forPath("/outer");
+        client.create().forPath("/outer/foo");
+        client.create().forPath("/outer/test");
+        client.create().forPath("/outer/test/one", "hey there".getBytes());
+
+        cache = newTreeCacheWithListeners(client.usingNamespace("outer"), 
"/test");
+        cache.start();
+        assertEvent(CacheEvent.NODE_CREATED, "/test");
+        assertEvent(CacheEvent.NODE_CREATED, "/test/one");
+        assertEvent(CacheEvent.CACHE_REFRESHED);
+        assertNoMoreEvents();
+
+        assertChildNodeNames("/test", "one");
+        assertChildNodeNames("/test/one");
+        Assert.assertEquals(new String(cache.get("/test/one").getData()), "hey 
there");
+    }
+
+    @Test
+    public void testWithNamespaceAtRoot() throws Exception
+    {
+        client.create().forPath("/outer");
+        client.create().forPath("/outer/foo");
+        client.create().forPath("/outer/test");
+        client.create().forPath("/outer/test/one", "hey there".getBytes());
+
+        cache = newTreeCacheWithListeners(client.usingNamespace("outer"), "/");
+        cache.start();
+        assertEvent(CacheEvent.NODE_CREATED, "/");
+        assertEvent(CacheEvent.NODE_CREATED, "/foo");
+        assertEvent(CacheEvent.NODE_CREATED, "/test");
+        assertEvent(CacheEvent.NODE_CREATED, "/test/one");
+        assertEvent(CacheEvent.CACHE_REFRESHED);
+        assertNoMoreEvents();
+        assertChildNodeNames("/", "foo", "test");
+        assertChildNodeNames("/foo");
+        assertChildNodeNames("/test", "one");
+        assertChildNodeNames("/test/one");
+        Assert.assertEquals(new String(cache.get("/test/one").getData()), "hey 
there");
+    }
+
+    @Test
+    public void testSyncInitialPopulation() throws Exception
+    {
+        cache = newTreeCacheWithListeners(client, "/test");
+        cache.start();
+        assertEvent(CacheEvent.CACHE_REFRESHED);
+
+        client.create().forPath("/test");
+        client.create().forPath("/test/one", "hey there".getBytes());
+        assertEvent(CacheEvent.NODE_CREATED, "/test");
+        assertEvent(CacheEvent.NODE_CREATED, "/test/one");
+        assertNoMoreEvents();
+    }
+
+    @Test
+    public void testChildrenInitialized() throws Exception
+    {
+        client.create().forPath("/test", "".getBytes());
+        client.create().forPath("/test/1", "1".getBytes());
+        client.create().forPath("/test/2", "2".getBytes());
+        client.create().forPath("/test/3", "3".getBytes());
+
+        cache = newTreeCacheWithListeners(client, "/test");
+        cache.start();
+        assertEvent(CacheEvent.NODE_CREATED, "/test");
+        assertEvent(CacheEvent.NODE_CREATED, "/test/1");
+        assertEvent(CacheEvent.NODE_CREATED, "/test/2");
+        assertEvent(CacheEvent.NODE_CREATED, "/test/3");
+        assertEvent(CacheEvent.CACHE_REFRESHED);
+        assertNoMoreEvents();
+    }
+
+    @Test
+    public void testUpdateWhenNotCachingData() throws Exception
+    {
+        client.create().forPath("/test");
+
+        cache = buildWithListeners(CuratorCacheBuilder.builder(client, 
"/test").forTree().withCacheFilter(CacheFilters.fullStatOnly()));
+        cache.start();
+        assertEvent(CacheEvent.NODE_CREATED, "/test");
+        assertEvent(CacheEvent.CACHE_REFRESHED);
+
+        client.create().forPath("/test/foo", "first".getBytes());
+        assertEvent(CacheEvent.NODE_CREATED, "/test/foo");
+
+        client.setData().forPath("/test/foo", "something new".getBytes());
+        assertEvent(CacheEvent.NODE_CHANGED, "/test/foo");
+        assertNoMoreEvents();
+
+        Assert.assertNotNull(cache.get("/test/foo"));
+        // No byte data querying the tree because we're not caching data.
+        Assert.assertEquals(cache.get("/test/foo").getData().length, 0);
+    }
+
+    @Test
+    public void testDeleteThenCreate() throws Exception
+    {
+        client.create().forPath("/test");
+        client.create().forPath("/test/foo", "one".getBytes());
+
+        cache = newTreeCacheWithListeners(client, "/test");
+        cache.start();
+        assertEvent(CacheEvent.NODE_CREATED, "/test");
+        assertEvent(CacheEvent.NODE_CREATED, "/test/foo");
+        assertEvent(CacheEvent.CACHE_REFRESHED);
+
+        client.delete().forPath("/test/foo");
+        assertEvent(CacheEvent.NODE_DELETED, "/test/foo", "one".getBytes());
+        client.create().forPath("/test/foo", "two".getBytes());
+        assertEvent(CacheEvent.NODE_CREATED, "/test/foo");
+
+        client.delete().forPath("/test/foo");
+        assertEvent(CacheEvent.NODE_DELETED, "/test/foo", "two".getBytes());
+        client.create().forPath("/test/foo", "two".getBytes());
+        assertEvent(CacheEvent.NODE_CREATED, "/test/foo");
+
+        assertNoMoreEvents();
+    }
+
+    @Test
+    public void testDeleteThenCreateRoot() throws Exception
+    {
+        client.create().forPath("/test");
+        client.create().forPath("/test/foo", "one".getBytes());
+
+        cache = newTreeCacheWithListeners(client, "/test/foo");
+        cache.start();
+        assertEvent(CacheEvent.NODE_CREATED, "/test/foo");
+        assertEvent(CacheEvent.CACHE_REFRESHED);
+
+        client.delete().forPath("/test/foo");
+        assertEvent(CacheEvent.NODE_DELETED, "/test/foo");
+        client.create().forPath("/test/foo", "two".getBytes());
+        assertEvent(CacheEvent.NODE_CREATED, "/test/foo");
+
+        client.delete().forPath("/test/foo");
+        assertEvent(CacheEvent.NODE_DELETED, "/test/foo");
+        client.create().forPath("/test/foo", "two".getBytes());
+        assertEvent(CacheEvent.NODE_CREATED, "/test/foo");
+
+        assertNoMoreEvents();
+    }
+
+    @Test
+    public void testKilledSession() throws Exception
+    {
+        client.create().forPath("/test");
+
+        cache = newTreeCacheWithListeners(client, "/test");
+        cache.start();
+        assertEvent(CacheEvent.NODE_CREATED, "/test");
+        assertEvent(CacheEvent.CACHE_REFRESHED);
+
+        client.create().forPath("/test/foo", "foo".getBytes());
+        assertEvent(CacheEvent.NODE_CREATED, "/test/foo");
+        client.create().withMode(CreateMode.EPHEMERAL).forPath("/test/me", 
"data".getBytes());
+        assertEvent(CacheEvent.NODE_CREATED, "/test/me");
+
+        KillServerSession.kill(client.getZookeeperClient().getZooKeeper(), 
server.getConnectString());
+        assertEvent(CacheEvent.NODE_DELETED, "/test/me", "data".getBytes());
+        assertEvent(CacheEvent.CACHE_REFRESHED);
+
+        assertNoMoreEvents();
     }
 }

Reply via email to