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 2014/03/05 13:08:44 UTC

[1/3] git commit: more testing for rest proxy

Repository: curator
Updated Branches:
  refs/heads/CURATOR-88 cf30ec2f6 -> 6477a2f08


more testing for rest proxy


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

Branch: refs/heads/CURATOR-88
Commit: a798ff82950bd8e00fa598387ce8d487f8fc8885
Parents: cf30ec2
Author: randgalt <ra...@apache.org>
Authored: Tue Mar 4 20:53:38 2014 +0530
Committer: randgalt <ra...@apache.org>
Committed: Tue Mar 4 20:53:38 2014 +0530

----------------------------------------------------------------------
 curator-recipes/pom.xml                         |   1 -
 .../locks/TestInterProcessMutexBase.java        |  28 +++-
 curator-x-rest/pom.xml                          |   1 +
 .../curator/x/rest/api/LeaderResource.java      |   5 +-
 .../apache/curator/x/rest/api/LockResource.java |   5 +-
 .../curator/x/rest/api/NodeCacheResource.java   |   5 +-
 .../x/rest/api/PathChildrenCacheResource.java   |   5 +-
 .../api/PersistentEphemeralNodeResource.java    |   4 +-
 .../x/rest/api/ReadWriteLockResource.java       |   6 +-
 .../curator/x/rest/api/SemaphoreResource.java   |   6 +-
 .../org/apache/curator/x/rest/entities/Id.java  |  48 +++++++
 .../src/site/confluence/apis.confluence         |  16 +--
 .../src/site/confluence/client.confluence       |   2 +-
 .../src/site/confluence/entities.confluence     |   2 +-
 .../apache/curator/x/rest/api/TestClient.java   |  25 +---
 .../apache/curator/x/rest/api/TestLocks.java    | 143 +++++++++++++++++++
 .../x/rest/support/BaseClassForTests.java       |  80 +++++++----
 .../x/rest/support/InterProcessLockBridge.java  |  77 +++++++++-
 .../apache/curator/x/rest/support/UriMaker.java |  65 +++++++++
 .../src/test/resources/test-config.json         |  13 ++
 20 files changed, 453 insertions(+), 84 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-recipes/pom.xml
----------------------------------------------------------------------
diff --git a/curator-recipes/pom.xml b/curator-recipes/pom.xml
index 56ac0c8..576661b 100644
--- a/curator-recipes/pom.xml
+++ b/curator-recipes/pom.xml
@@ -27,7 +27,6 @@
         <version>2.4.1-SNAPSHOT</version>
     </parent>
 
-    <groupId>org.apache.curator</groupId>
     <artifactId>curator-recipes</artifactId>
     <version>2.4.1-SNAPSHOT</version>
     <packaging>bundle</packaging>

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/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 b1373fa..5101d06 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
@@ -20,17 +20,16 @@
 package org.apache.curator.framework.recipes.locks;
 
 import com.google.common.collect.Lists;
-import org.apache.curator.utils.CloseableUtils;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.framework.recipes.BaseClassForTests;
 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.KillSession;
 import org.apache.curator.test.TestingServer;
 import org.apache.curator.test.Timing;
+import org.apache.curator.utils.CloseableUtils;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 import java.util.List;
@@ -395,9 +394,15 @@ public abstract class TestInterProcessMutexBase extends BaseClassForTests
                         {
                             try
                             {
-                                mutexForClient1.acquire(10, TimeUnit.SECONDS);
+                                if ( !mutexForClient1.acquire(10, TimeUnit.SECONDS) )
+                                {
+                                    throw new Exception("mutexForClient1.acquire timed out");
+                                }
                                 acquiredLatchForClient1.countDown();
-                                latchForClient1.await(10, TimeUnit.SECONDS);
+                                if ( !latchForClient1.await(10, TimeUnit.SECONDS) )
+                                {
+                                    throw new Exception("latchForClient1 timed out");
+                                }
                                 mutexForClient1.release();
                             }
                             catch ( Exception e )
@@ -417,9 +422,15 @@ public abstract class TestInterProcessMutexBase extends BaseClassForTests
                         {
                             try
                             {
-                                mutexForClient2.acquire(10, TimeUnit.SECONDS);
+                                if ( !mutexForClient2.acquire(10, TimeUnit.SECONDS) )
+                                {
+                                    throw new Exception("mutexForClient2.acquire timed out");
+                                }
                                 acquiredLatchForClient2.countDown();
-                                latchForClient2.await(10, TimeUnit.SECONDS);
+                                if ( !latchForClient2.await(10, TimeUnit.SECONDS) )
+                                {
+                                    throw new Exception("latchForClient2 timed out");
+                                }
                                 mutexForClient2.release();
                             }
                             catch ( Exception e )
@@ -434,6 +445,11 @@ public abstract class TestInterProcessMutexBase extends BaseClassForTests
             while ( !mutexForClient1.isAcquiredInThisProcess() && !mutexForClient2.isAcquiredInThisProcess() )
             {
                 Thread.sleep(1000);
+                Exception exception = exceptionRef.get();
+                if ( exception != null )
+                {
+                    throw exception;
+                }
                 Assert.assertFalse(future1.isDone() && future2.isDone());
             }
 

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/pom.xml
----------------------------------------------------------------------
diff --git a/curator-x-rest/pom.xml b/curator-x-rest/pom.xml
index affe441..ff53aea 100644
--- a/curator-x-rest/pom.xml
+++ b/curator-x-rest/pom.xml
@@ -37,6 +37,7 @@
         <dependency>
             <groupId>org.apache.curator</groupId>
             <artifactId>curator-recipes</artifactId>
+            <version>${project.parent.version}</version>
             <exclusions>
                 <exclusion>
                     <groupId>org.slf4j</groupId>

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LeaderResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LeaderResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LeaderResource.java
index 43316a1..0f07296 100644
--- a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LeaderResource.java
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LeaderResource.java
@@ -24,10 +24,10 @@ import org.apache.curator.framework.recipes.leader.LeaderLatch;
 import org.apache.curator.framework.recipes.leader.LeaderLatchListener;
 import org.apache.curator.framework.recipes.leader.Participant;
 import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.Id;
 import org.apache.curator.x.rest.entities.LeaderSpec;
 import org.apache.curator.x.rest.entities.ParticipantSpec;
 import org.apache.curator.x.rest.entities.StatusMessage;
-import org.codehaus.jackson.node.ObjectNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import javax.annotation.Nullable;
@@ -98,8 +98,7 @@ public class LeaderResource
         };
         leaderLatch.addListener(listener);
 
-        ObjectNode node = Constants.makeIdNode(context, id);
-        return Response.ok(context.getWriter().writeValueAsString(node)).build();
+        return Response.ok(new Id(id)).build();
     }
 
     @DELETE

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LockResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LockResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LockResource.java
index 8104858..dfb6ebc 100644
--- a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LockResource.java
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LockResource.java
@@ -20,8 +20,8 @@ package org.apache.curator.x.rest.api;
 
 import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
 import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.Id;
 import org.apache.curator.x.rest.entities.LockSpec;
-import org.codehaus.jackson.node.ObjectNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import javax.ws.rs.Consumes;
@@ -76,8 +76,7 @@ public class LockResource
             }
         };
         String id = context.getSession().addThing(lock, closer);
-        ObjectNode node = Constants.makeIdNode(context, id);
-        return Response.ok(context.getWriter().writeValueAsString(node)).build();
+        return Response.ok(new Id(id)).build();
     }
 
     @DELETE

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/NodeCacheResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/NodeCacheResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/NodeCacheResource.java
index 4548759..5d2e66e 100644
--- a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/NodeCacheResource.java
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/NodeCacheResource.java
@@ -21,9 +21,9 @@ package org.apache.curator.x.rest.api;
 import org.apache.curator.framework.recipes.cache.NodeCache;
 import org.apache.curator.framework.recipes.cache.NodeCacheListener;
 import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.Id;
 import org.apache.curator.x.rest.entities.NodeCacheSpec;
 import org.apache.curator.x.rest.entities.StatusMessage;
-import org.codehaus.jackson.node.ObjectNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import javax.ws.rs.Consumes;
@@ -84,8 +84,7 @@ public class NodeCacheResource
         };
         cache.getListenable().addListener(listener);
 
-        ObjectNode node = Constants.makeIdNode(context, id);
-        return Response.ok(context.getWriter().writeValueAsString(node)).build();
+        return Response.ok(new Id(id)).build();
     }
 
     @DELETE

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PathChildrenCacheResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PathChildrenCacheResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PathChildrenCacheResource.java
index 4622ac1..a694930 100644
--- a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PathChildrenCacheResource.java
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PathChildrenCacheResource.java
@@ -25,10 +25,10 @@ import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
 import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
 import org.apache.curator.utils.ThreadUtils;
 import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.Id;
 import org.apache.curator.x.rest.entities.PathChildrenCacheSpec;
 import org.apache.curator.x.rest.entities.StatusMessage;
 import org.codehaus.jackson.node.ArrayNode;
-import org.codehaus.jackson.node.ObjectNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import javax.ws.rs.Consumes;
@@ -89,8 +89,7 @@ public class PathChildrenCacheResource
         };
         cache.getListenable().addListener(listener);
 
-        ObjectNode node = Constants.makeIdNode(context, id);
-        return Response.ok(context.getWriter().writeValueAsString(node)).build();
+        return Response.ok(new Id(id)).build();
     }
 
     @DELETE

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PersistentEphemeralNodeResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PersistentEphemeralNodeResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PersistentEphemeralNodeResource.java
index 85d2c3f..d55772e 100644
--- a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PersistentEphemeralNodeResource.java
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PersistentEphemeralNodeResource.java
@@ -20,13 +20,13 @@ package org.apache.curator.x.rest.api;
 
 import org.apache.curator.framework.recipes.nodes.PersistentEphemeralNode;
 import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.Id;
 import org.apache.curator.x.rest.entities.PersistentEphemeralNodeSpec;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -69,7 +69,7 @@ public class PersistentEphemeralNodeResource
             }
         };
         String id = context.getSession().addThing(node, closer);
-        return Response.ok(context.getWriter().writeValueAsString(Constants.makeIdNode(context, id))).build();
+        return Response.ok(new Id(id)).build();
     }
 
     @DELETE

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ReadWriteLockResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ReadWriteLockResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ReadWriteLockResource.java
index fe5e319..b501d0e 100644
--- a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ReadWriteLockResource.java
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ReadWriteLockResource.java
@@ -21,14 +21,13 @@ package org.apache.curator.x.rest.api;
 import org.apache.curator.framework.recipes.locks.InterProcessMutex;
 import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
 import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.Id;
 import org.apache.curator.x.rest.entities.LockSpec;
-import org.codehaus.jackson.node.ObjectNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -103,7 +102,6 @@ public class ReadWriteLockResource
             }
         };
         String id = context.getSession().addThing(actualLock, closer);
-        ObjectNode node = Constants.makeIdNode(context, id);
-        return Response.ok(context.getWriter().writeValueAsString(node)).build();
+        return Response.ok(new Id(id)).build();
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SemaphoreResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SemaphoreResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SemaphoreResource.java
index 41f6e2d..2b6438b 100644
--- a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SemaphoreResource.java
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SemaphoreResource.java
@@ -22,14 +22,13 @@ import com.google.common.collect.Lists;
 import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreV2;
 import org.apache.curator.framework.recipes.locks.Lease;
 import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.Id;
 import org.apache.curator.x.rest.entities.SemaphoreSpec;
-import org.codehaus.jackson.node.ObjectNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -89,8 +88,7 @@ public class SemaphoreResource
             }
         };
         String id = context.getSession().addThing(new LeasesHolder(leases), closer);
-        ObjectNode node = Constants.makeIdNode(context, id);
-        return Response.ok(context.getWriter().writeValueAsString(node)).build();
+        return Response.ok(new Id(id)).build();
     }
 
     @DELETE

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/Id.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/Id.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/Id.java
new file mode 100644
index 0000000..1e7ca79
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/Id.java
@@ -0,0 +1,48 @@
+/**
+ * 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.x.rest.entities;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class Id
+{
+    private String id;
+
+    public Id()
+    {
+        this("");
+    }
+
+    public Id(String id)
+    {
+        this.id = id;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public void setId(String id)
+    {
+        this.id = id;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/site/confluence/apis.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/site/confluence/apis.confluence b/curator-x-rest/src/site/confluence/apis.confluence
index da6ac1a..74e880f 100644
--- a/curator-x-rest/src/site/confluence/apis.confluence
+++ b/curator-x-rest/src/site/confluence/apis.confluence
@@ -38,30 +38,30 @@ h2. Recipe APIs
 
 ||URL||Method||Request Entity||Response Entity||Description||
 | *Leader* | | | | |
-|/curator/v1/recipes/leader|POST|LeaderSpec|IdSpec|Start a LeaderLatch instance. When you gain leadership, it will be notified via status.|
+|/curator/v1/recipes/leader|POST|LeaderSpec|Id|Start a LeaderLatch instance. When you gain leadership, it will be notified via status.|
 |/curator/v1/recipes/leader/{leader-id}|DELETE|n/a|n/a|Release/delete leadership.|
 |/curator/v1/recipes/leader/{leader-id}|GET|n/a|array of ParticipantSpecs|List of participants in the leader election.|
 | *Lock* | | | | |
-|/curator/v1/recipes/lock|POST|LockSpec|IdSpec|An InterProcessSemaphoreMutex. On successful return, your client will be holding the specified lock until you delete the lock via the delete API.|
+|/curator/v1/recipes/lock|POST|LockSpec|Id|An InterProcessSemaphoreMutex. On successful return, your client will be holding the specified lock until you delete the lock via the delete API.|
 |/curator/v1/recipes/lock/{lock-id}|DELETE|n/a|n/a|Release and delete a lock.|
 | *Read/Write Lock* | | | | |
-|/curator/v1/recipes/read-write-lock/read|POST|LockSpec|IdSpec|An InterProcessReadWriteLock. On successful return, your client will be holding the specified read lock until you delete the lock via the delete API.|
-|/curator/v1/recipes/read-write-lock/write|POST|LockSpec|IdSpec|An InterProcessReadWriteLock. On successful return, your client will be holding the specified write lock until you delete the lock via the delete API.|
+|/curator/v1/recipes/read-write-lock/read|POST|LockSpec|Id|An InterProcessReadWriteLock. On successful return, your client will be holding the specified read lock until you delete the lock via the delete API.|
+|/curator/v1/recipes/read-write-lock/write|POST|LockSpec|Id|An InterProcessReadWriteLock. On successful return, your client will be holding the specified write lock until you delete the lock via the delete API.|
 |/curator/v1/recipes/read-write-lock/{lock-id}|DELETE|n/a|n/a|Release and delete the read/write lock.|
 | *Semaphore* | | | | |
-|/curator/v1/recipes/semaphore|POST|SemaphoreSpec|IdSpec|An InterProcessSemaphoreV2. On successful return, your client will be holding the specified number of leases until you delete them via the delete API.|
+|/curator/v1/recipes/semaphore|POST|SemaphoreSpec|Id|An InterProcessSemaphoreV2. On successful return, your client will be holding the specified number of leases until you delete them via the delete API.|
 |/curator/v1/recipes/semaphore/{lock-id}/{release-qty}|DELETE|n/a|n/a|Release the specified number of leases.|
 | *Node Cache* | | | | |
-|/curator/v1/recipes/node-cache|POST|NodeCacheSpec|IdSpec|Start a NodeCache instance. NodeCache updates will be notified via status.|
+|/curator/v1/recipes/node-cache|POST|NodeCacheSpec|Id|Start a NodeCache instance. NodeCache updates will be notified via status.|
 |/curator/v1/recipes/node-cache/{cache-id}|GET|n/a|NodeData|Stop and delete a node cache.|
 |/curator/v1/recipes/node-cache/{cache-id}|DELETE|n/a|n/a|Stop and delete a node cache.|
 | *Path Cache* | | | | |
-|/curator/v1/recipes/path-cache|POST|PathChildrenCacheSpec|IdSpec|Start a PathChildrenCache instance. PathChildrenCache updates will be notified via status.|
+|/curator/v1/recipes/path-cache|POST|PathChildrenCacheSpec|Id|Start a PathChildrenCache instance. PathChildrenCache updates will be notified via status.|
 |/curator/v1/recipes/path-cache/{cache-id}|GET|n/a|array of NodeData|Return the current cached values.|
 |/curator/v1/recipes/path-cache/{cache-id}/{full-path}|GET|n/a|NodeData|Return the current cached value for the node at the specified full path.|
 |/curator/v1/recipes/path-cache/{cache-id}|DELETE|n/a|n/a|Stop and delete a path cache.|
 | *Persistent Ephemeral Node* | | | | |
-|/curator/v1/recipes/persistent-ephemeral-node|POST|PersistentEphemeralNodeSpec|IdSpec|Start a PersistentEphemeralNode instance.|
+|/curator/v1/recipes/persistent-ephemeral-node|POST|PersistentEphemeralNodeSpec|Id|Start a PersistentEphemeralNode instance.|
 |/curator/v1/recipes/persistent-ephemeral-node/{node-id}|DELETE|n/a|n/a|Stop and delete a persistent ephemeral node.|
 
 h2. Entities

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/site/confluence/client.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/site/confluence/client.confluence b/curator-x-rest/src/site/confluence/client.confluence
index c34502a..a4639e0 100644
--- a/curator-x-rest/src/site/confluence/client.confluence
+++ b/curator-x-rest/src/site/confluence/client.confluence
@@ -42,7 +42,7 @@ Here is pseudo-code for doing a distributed lock using the Curator REST Proxy:
 {code}
 Address address = ... # host and port of the Curator REST Proxy instance
 LockSpec lock = {path: "/lock/path", maxWaitMs: 5000}
-IdSpec lockId = restClient.post(address, "/curator/v1/recipes/lock", lock)
+Id lockId = restClient.post(address, "/curator/v1/recipes/lock", lock)
 statusMaintainer.add(address, lockId)
 
     ... do work here while in the acquired mutex ...

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/site/confluence/entities.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/site/confluence/entities.confluence b/curator-x-rest/src/site/confluence/entities.confluence
index b8f686b..4606919 100644
--- a/curator-x-rest/src/site/confluence/entities.confluence
+++ b/curator-x-rest/src/site/confluence/entities.confluence
@@ -73,7 +73,7 @@ Here are the entity descriptions for the entities used in the APIs:
 |watched|boolean|if true, set a watch|
 |watchId|string|if watched, a user-defined ID to return in the status when the watch triggers|
 | | | |
-| *IdSpec* | | |
+| *Id* | | |
 |id|string|The ID of the created recipe, etc. Used for subsequent calls to delete, close, etc. the instance.|
 | | | |
 | *LockSpec* | | |

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestClient.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestClient.java b/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestClient.java
index e6bb391..5cc8160 100644
--- a/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestClient.java
+++ b/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestClient.java
@@ -36,9 +36,6 @@ import org.apache.zookeeper.CreateMode;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.UriBuilder;
-import java.net.InetSocketAddress;
-import java.net.URI;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -50,7 +47,7 @@ public class TestClient extends BaseClassForTests
         boolean connected = false;
         for ( int i = 0; i < 10; ++i )
         {
-            Status status = restClient.resource(getStatusUri()).get(Status.class);
+            Status status = restClient.resource(uriMaker.getStatusUri()).get(Status.class);
             if ( status.getState().equals("connected") )
             {
                 connected = true;
@@ -74,7 +71,7 @@ public class TestClient extends BaseClassForTests
             createSpec.setPath(path);
             createSpec.setCreatingParentsIfNeeded(true);
             createSpec.setMode(CreateMode.EPHEMERAL);
-            PathAndId pathAndId = restClient.resource(getMethodUri("create")).type(MediaType.APPLICATION_JSON).post(PathAndId.class, createSpec);
+            PathAndId pathAndId = restClient.resource(uriMaker.getMethodUri("create")).type(MediaType.APPLICATION_JSON).post(PathAndId.class, createSpec);
 
             final AtomicReference<String> expiredId = new AtomicReference<String>();
             StatusListener listener = new StatusListener()
@@ -103,7 +100,7 @@ public class TestClient extends BaseClassForTests
                 {
                 }
             };
-            sessionManager.addEntry(new InetSocketAddress("localhost", PORT), pathAndId.getId(), listener);
+            sessionManager.addEntry(uriMaker.getLocalhost(), pathAndId.getId(), listener);
 
             Thread.sleep(2 * curatorConfiguration.getSessionLengthMs());
 
@@ -111,7 +108,7 @@ public class TestClient extends BaseClassForTests
             client.start();
             Assert.assertNotNull(client.checkExists().forPath(path));
 
-            sessionManager.removeEntry(new InetSocketAddress("localhost", PORT), pathAndId.getId());
+            sessionManager.removeEntry(uriMaker.getLocalhost(), pathAndId.getId());
             Thread.sleep(2 * curatorConfiguration.getSessionLengthMs());
             Assert.assertNull(client.checkExists().forPath(path));
             Assert.assertEquals(pathAndId.getId(), expiredId.get());
@@ -133,7 +130,7 @@ public class TestClient extends BaseClassForTests
         existsSpec.setPath(path);
         existsSpec.setWatched(true);
         existsSpec.setWatchId(watchId);
-        restClient.resource(getMethodUri("exists")).type(MediaType.APPLICATION_JSON).post(existsSpec);
+        restClient.resource(uriMaker.getMethodUri("exists")).type(MediaType.APPLICATION_JSON).post(existsSpec);
 
         CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), new RetryOneTime(1));
         try
@@ -148,7 +145,7 @@ public class TestClient extends BaseClassForTests
 
         new Timing().sleepABit();
 
-        Status status = restClient.resource(getStatusUri()).get(Status.class);
+        Status status = restClient.resource(uriMaker.getStatusUri()).get(Status.class);
         boolean foundWatch = false;
         boolean foundWatchId = false;
         boolean foundMessage = false;
@@ -173,14 +170,4 @@ public class TestClient extends BaseClassForTests
         Assert.assertTrue(foundWatchId);
         Assert.assertTrue(foundMessage);
     }
-
-    private URI getMethodUri(String method)
-    {
-        return UriBuilder.fromUri("http://localhost:" + PORT).path(ClientResource.class).path(ClientResource.class, method).build();
-    }
-
-    private URI getStatusUri()
-    {
-        return getMethodUri("getStatus");
-    }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java b/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
new file mode 100644
index 0000000..4a7eaf0
--- /dev/null
+++ b/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
@@ -0,0 +1,143 @@
+/**
+ * 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.x.rest.api;
+
+import org.apache.curator.framework.recipes.locks.InterProcessLock;
+import org.apache.curator.x.rest.support.BaseClassForTests;
+import org.apache.curator.x.rest.support.InterProcessLockBridge;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class TestLocks extends BaseClassForTests
+{
+    @Test
+    public void test2Clients() throws Exception
+    {
+        final InterProcessLock mutexForClient1 = new InterProcessLockBridge(restClient, sessionManager, uriMaker);
+        final InterProcessLock mutexForClient2 = new InterProcessLockBridge(restClient, sessionManager, uriMaker);
+
+        final CountDownLatch latchForClient1 = new CountDownLatch(1);
+        final CountDownLatch latchForClient2 = new CountDownLatch(1);
+        final CountDownLatch acquiredLatchForClient1 = new CountDownLatch(1);
+        final CountDownLatch acquiredLatchForClient2 = new CountDownLatch(1);
+
+        final AtomicReference<Exception> exceptionRef = new AtomicReference<Exception>();
+
+        ExecutorService service = Executors.newCachedThreadPool();
+        Future<Object> future1 = service.submit
+            (
+                new Callable<Object>()
+                {
+                    @Override
+                    public Object call() throws Exception
+                    {
+                        try
+                        {
+                            if ( !mutexForClient1.acquire(10, TimeUnit.SECONDS) )
+                            {
+                                throw new Exception("mutexForClient1.acquire timed out");
+                            }
+                            acquiredLatchForClient1.countDown();
+                            if ( !latchForClient1.await(10, TimeUnit.SECONDS) )
+                            {
+                                throw new Exception("latchForClient1 timed out");
+                            }
+                            mutexForClient1.release();
+                        }
+                        catch ( Exception e )
+                        {
+                            exceptionRef.set(e);
+                        }
+                        return null;
+                    }
+                }
+            );
+        Future<Object> future2 = service.submit
+            (
+                new Callable<Object>()
+                {
+                    @Override
+                    public Object call() throws Exception
+                    {
+                        try
+                        {
+                            if ( !mutexForClient2.acquire(10, TimeUnit.SECONDS) )
+                            {
+                                throw new Exception("mutexForClient2.acquire timed out");
+                            }
+                            acquiredLatchForClient2.countDown();
+                            if ( !latchForClient2.await(10, TimeUnit.SECONDS) )
+                            {
+                                throw new Exception("latchForClient2 timed out");
+                            }
+                            mutexForClient2.release();
+                        }
+                        catch ( Exception e )
+                        {
+                            exceptionRef.set(e);
+                        }
+                        return null;
+                    }
+                }
+            );
+
+        while ( !mutexForClient1.isAcquiredInThisProcess() && !mutexForClient2.isAcquiredInThisProcess() )
+        {
+            Thread.sleep(1000);
+            Exception exception = exceptionRef.get();
+            if ( exception != null )
+            {
+                throw exception;
+            }
+            Assert.assertFalse(future1.isDone() && future2.isDone());
+        }
+
+        Assert.assertTrue(mutexForClient1.isAcquiredInThisProcess() != mutexForClient2.isAcquiredInThisProcess());
+        Thread.sleep(1000);
+        Assert.assertTrue(mutexForClient1.isAcquiredInThisProcess() || mutexForClient2.isAcquiredInThisProcess());
+        Assert.assertTrue(mutexForClient1.isAcquiredInThisProcess() != mutexForClient2.isAcquiredInThisProcess());
+
+        Exception exception = exceptionRef.get();
+        if ( exception != null )
+        {
+            throw exception;
+        }
+
+        if ( mutexForClient1.isAcquiredInThisProcess() )
+        {
+            latchForClient1.countDown();
+            Assert.assertTrue(acquiredLatchForClient2.await(10, TimeUnit.SECONDS));
+            Assert.assertTrue(mutexForClient2.isAcquiredInThisProcess());
+        }
+        else
+        {
+            latchForClient2.countDown();
+            Assert.assertTrue(acquiredLatchForClient1.await(10, TimeUnit.SECONDS));
+            Assert.assertTrue(mutexForClient1.isAcquiredInThisProcess());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java
index ea0a1a5..2690559 100644
--- a/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java
+++ b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java
@@ -19,12 +19,15 @@
 
 package org.apache.curator.x.rest.support;
 
+import ch.qos.logback.core.util.CloseUtil;
 import com.google.common.io.CharStreams;
 import com.google.common.io.Files;
+import com.google.common.io.Resources;
 import com.sun.jersey.api.client.Client;
 import io.dropwizard.Application;
 import io.dropwizard.setup.Bootstrap;
 import io.dropwizard.setup.Environment;
+import org.apache.curator.test.InstanceSpec;
 import org.apache.curator.test.TestingServer;
 import org.apache.curator.utils.DebugUtils;
 import org.apache.curator.x.rest.dropwizard.CuratorApplication;
@@ -37,6 +40,7 @@ import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import java.io.File;
+import java.io.IOException;
 import java.nio.charset.Charset;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
@@ -50,25 +54,60 @@ public class BaseClassForTests
     protected Application<CuratorConfiguration> application;
     protected Client restClient;
     protected CuratorConfiguration curatorConfiguration;
-
-    protected static final int PORT = 8080;
+    protected SessionManager sessionManager;
+    protected UriMaker uriMaker;
 
     private File configFile;
 
     @BeforeMethod
     public void     setup() throws Exception
     {
+        setup(5000);
+    }
+
+    protected void setup(int sessionLengthMs) throws Exception
+    {
+        int port = InstanceSpec.getRandomPort();
         restClient = Client.create();
 
         System.setProperty(DebugUtils.PROPERTY_DONT_LOG_CONNECTION_ISSUES, "true");
         server = new TestingServer();
 
-        configFile = File.createTempFile("temp", ".tmp");
-        CharStreams.write("{\"connection-string\": \"" + server.getConnectString() + "\", \"session-length-ms\":5000}", Files.newWriterSupplier(configFile, Charset.defaultCharset()));
+        configFile = makeConfigFile(server.getConnectString(), sessionLengthMs, port);
 
-        final CountDownLatch startedLatch = new CountDownLatch(1);
         final AtomicReference<CuratorConfiguration> curatorConfigurationAtomicReference = new AtomicReference<CuratorConfiguration>();
-        application = new Application<CuratorConfiguration>()
+        makeAndStartApplication(curatorConfigurationAtomicReference, configFile);
+
+        curatorConfiguration = curatorConfigurationAtomicReference.get();
+        sessionManager = new SessionManager(restClient, curatorConfiguration.getSessionLengthMs());
+        uriMaker = new UriMaker(port);
+    }
+
+    @AfterMethod
+    public void     teardown() throws Exception
+    {
+        if ( configFile != null )
+        {
+            //noinspection ResultOfMethodCallIgnored
+            configFile.delete();
+        }
+
+        CloseUtil.closeQuietly(sessionManager);
+
+        ShutdownThread.getInstance().run();
+
+        CloseUtil.closeQuietly(server);
+
+        if ( restClient != null )
+        {
+            restClient.destroy();
+        }
+    }
+
+    private Application<CuratorConfiguration> makeAndStartApplication(final AtomicReference<CuratorConfiguration> curatorConfigurationRef, final File configFile) throws InterruptedException
+    {
+        final CountDownLatch startedLatch = new CountDownLatch(1);
+        final Application<CuratorConfiguration> application = new Application<CuratorConfiguration>()
         {
             @Override
             public void initialize(Bootstrap<CuratorConfiguration> bootstrap)
@@ -79,7 +118,7 @@ public class BaseClassForTests
             @Override
             public void run(CuratorConfiguration configuration, Environment environment) throws Exception
             {
-                curatorConfigurationAtomicReference.set(configuration);
+                curatorConfigurationRef.set(configuration);
                 LifeCycle.Listener listener = new AbstractLifeCycle.AbstractLifeCycleListener()
                 {
                     @Override
@@ -107,26 +146,17 @@ public class BaseClassForTests
         );
 
         Assert.assertTrue(startedLatch.await(5, TimeUnit.SECONDS));
-
-        curatorConfiguration = curatorConfigurationAtomicReference.get();
+        return application;
     }
 
-    @AfterMethod
-    public void     teardown() throws Exception
+    private static File makeConfigFile(String connectString, int sessionLengthMs, int port) throws IOException
     {
-        if ( configFile != null )
-        {
-            //noinspection ResultOfMethodCallIgnored
-            configFile.delete();
-        }
-
-        if ( restClient != null )
-        {
-            restClient.destroy();
-        }
-
-        ShutdownThread.getInstance().run();
-
-        server.close();
+        String config = Resources.toString(Resources.getResource("test-config.json"), Charset.defaultCharset());
+        config = config.replace("$CONNECT$", connectString);
+        config = config.replace("$SESSION$", Integer.toString(sessionLengthMs));
+        config = config.replace("$PORT$", Integer.toString(port));
+        File configFile = File.createTempFile("temp", ".tmp");
+        CharStreams.write(config, Files.newWriterSupplier(configFile, Charset.defaultCharset()));
+        return configFile;
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/InterProcessLockBridge.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/InterProcessLockBridge.java b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/InterProcessLockBridge.java
index 7fdd8b3..15a7a5c 100644
--- a/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/InterProcessLockBridge.java
+++ b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/InterProcessLockBridge.java
@@ -19,6 +19,81 @@
 
 package org.apache.curator.x.rest.support;
 
-public class InterProcessLockBridge
+import com.google.common.base.Preconditions;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import org.apache.curator.framework.recipes.locks.InterProcessLock;
+import org.apache.curator.x.rest.api.LockResource;
+import org.apache.curator.x.rest.entities.Id;
+import org.apache.curator.x.rest.entities.LockSpec;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+public class InterProcessLockBridge implements InterProcessLock
 {
+    private final Client restClient;
+    private final SessionManager sessionManager;
+    private final UriMaker uriMaker;
+
+    private volatile String id = null;
+
+    private static final String PATH = "/lock";
+
+    public InterProcessLockBridge(Client restClient, SessionManager sessionManager, UriMaker uriMaker)
+    {
+        this.restClient = restClient;
+        this.sessionManager = sessionManager;
+        this.uriMaker = uriMaker;
+    }
+
+    @Override
+    public void acquire() throws Exception
+    {
+        acquire(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+    public boolean acquire(long time, TimeUnit unit) throws Exception
+    {
+        Preconditions.checkArgument(id == null, "Lock already acquired");
+
+        URI uri = uriMaker.getMethodUri(LockResource.class, null);
+        LockSpec lockSpec = new LockSpec();
+        lockSpec.setPath(PATH);
+        lockSpec.setMaxWaitMs((int)unit.toMillis(time));
+        try
+        {
+            id = restClient.resource(uri).type(MediaType.APPLICATION_JSON_TYPE).post(Id.class, lockSpec).getId();
+        }
+        catch ( UniformInterfaceException e )
+        {
+            if ( e.getResponse().getStatus() == Response.Status.SERVICE_UNAVAILABLE.getStatusCode() )
+            {
+                return false;
+            }
+            throw e;
+        }
+        sessionManager.addEntry(uriMaker.getLocalhost(), id, null);
+        return true;
+    }
+
+    @Override
+    public void release() throws Exception
+    {
+        Preconditions.checkArgument(id != null, "Lock not acquired");
+
+        URI uri = uriMaker.getMethodUri(LockResource.class, null);
+        restClient.resource(uri).path(id).delete();
+
+        sessionManager.removeEntry(uriMaker.getLocalhost(), id);
+        id = null;
+    }
+
+    @Override
+    public boolean isAcquiredInThisProcess()
+    {
+        return (id != null);
+    }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/UriMaker.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/UriMaker.java b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/UriMaker.java
new file mode 100644
index 0000000..0466839
--- /dev/null
+++ b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/UriMaker.java
@@ -0,0 +1,65 @@
+/**
+ * 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.x.rest.support;
+
+import org.apache.curator.x.rest.api.ClientResource;
+import javax.ws.rs.core.UriBuilder;
+import java.net.InetSocketAddress;
+import java.net.URI;
+
+public class UriMaker
+{
+    private final int port;
+
+    public UriMaker(int port)
+    {
+        this.port = port;
+    }
+
+    public InetSocketAddress getLocalhost()
+    {
+        return new InetSocketAddress("localhost", port);
+    }
+
+    public int getPort()
+    {
+        return port;
+    }
+
+    public URI getMethodUri(Class resource, String method)
+    {
+        UriBuilder builder = UriBuilder.fromUri("http://localhost:" + port).path(resource);
+        if ( method != null )
+        {
+            builder = builder.path(resource, method);
+        }
+        return builder.build();
+    }
+
+    public URI getMethodUri(String method)
+    {
+        return getMethodUri(ClientResource.class, method);
+    }
+
+    public URI getStatusUri()
+    {
+        return getMethodUri("getStatus");
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/a798ff82/curator-x-rest/src/test/resources/test-config.json
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/resources/test-config.json b/curator-x-rest/src/test/resources/test-config.json
new file mode 100644
index 0000000..2269fe1
--- /dev/null
+++ b/curator-x-rest/src/test/resources/test-config.json
@@ -0,0 +1,13 @@
+{
+    "connection-string": "$CONNECT$",
+    "session-length-ms": $SESSION$,
+
+    "server": {
+        "applicationConnectors": [
+            {
+                "type": "http",
+                "port": $PORT$
+            }
+        ]
+    }
+}
\ No newline at end of file


[3/3] git commit: more tests copied from TestInterProcessMutexBase

Posted by ra...@apache.org.
more tests copied from TestInterProcessMutexBase


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

Branch: refs/heads/CURATOR-88
Commit: 6477a2f08d9e88dd3d934d18051e1193e44a1274
Parents: 0dcba0f
Author: randgalt <ra...@apache.org>
Authored: Tue Mar 4 21:14:46 2014 +0530
Committer: randgalt <ra...@apache.org>
Committed: Tue Mar 4 21:14:46 2014 +0530

----------------------------------------------------------------------
 .../apache/curator/x/rest/api/TestLocks.java    | 58 ++++++++++++++++++++
 1 file changed, 58 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/6477a2f0/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java b/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
index 6625388..7aa4585 100644
--- a/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
+++ b/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
@@ -19,6 +19,7 @@
 
 package org.apache.curator.x.rest.api;
 
+import com.google.common.collect.Lists;
 import org.apache.curator.framework.recipes.locks.InterProcessLock;
 import org.apache.curator.test.KillSession;
 import org.apache.curator.test.TestingServer;
@@ -266,4 +267,61 @@ public class TestLocks extends BaseClassForTests
         KillSession.kill(getCuratorRestContext().getClient().getZookeeperClient().getZooKeeper(), server.getConnectString());
         Assert.assertTrue(timing.acquireSemaphore(semaphore, 1));
     }
+
+    @Test
+    public void testThreading() throws Exception
+    {
+        final int THREAD_QTY = 10;
+
+        final AtomicBoolean hasLock = new AtomicBoolean(false);
+        final AtomicBoolean isFirst = new AtomicBoolean(true);
+        final Semaphore semaphore = new Semaphore(1);
+
+        List<Future<Object>> threads = Lists.newArrayList();
+        ExecutorService service = Executors.newCachedThreadPool();
+        for ( int i = 0; i < THREAD_QTY; ++i )
+        {
+            final InterProcessLock mutex = new InterProcessLockBridge(restClient, sessionManager, uriMaker);
+            Future<Object> t = service.submit
+                (
+                    new Callable<Object>()
+                    {
+                        @Override
+                        public Object call() throws Exception
+                        {
+                            semaphore.acquire();
+                            mutex.acquire();
+                            Assert.assertTrue(hasLock.compareAndSet(false, true));
+                            try
+                            {
+                                if ( isFirst.compareAndSet(true, false) )
+                                {
+                                    semaphore.release(THREAD_QTY - 1);
+                                    while ( semaphore.availablePermits() > 0 )
+                                    {
+                                        Thread.sleep(100);
+                                    }
+                                }
+                                else
+                                {
+                                    Thread.sleep(100);
+                                }
+                            }
+                            finally
+                            {
+                                mutex.release();
+                                hasLock.set(false);
+                            }
+                            return null;
+                        }
+                    }
+                );
+            threads.add(t);
+        }
+
+        for ( Future<Object> t : threads )
+        {
+            t.get();
+        }
+    }
 }


[2/3] git commit: more testing for rest proxy

Posted by ra...@apache.org.
more testing for rest proxy


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

Branch: refs/heads/CURATOR-88
Commit: 0dcba0f47bc439ce506037512ab835238c2f320d
Parents: a798ff8
Author: randgalt <ra...@apache.org>
Authored: Tue Mar 4 21:06:08 2014 +0530
Committer: randgalt <ra...@apache.org>
Committed: Tue Mar 4 21:06:08 2014 +0530

----------------------------------------------------------------------
 .../x/rest/dropwizard/CuratorRestBundle.java    |  14 ++-
 .../apache/curator/x/rest/api/TestLocks.java    | 126 +++++++++++++++++++
 .../x/rest/support/BaseClassForTests.java       |  16 ++-
 .../curator/x/rest/support/SessionManager.java  |  30 ++++-
 4 files changed, 173 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/0dcba0f4/curator-x-rest/src/main/java/org/apache/curator/x/rest/dropwizard/CuratorRestBundle.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/dropwizard/CuratorRestBundle.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/dropwizard/CuratorRestBundle.java
index 6ad93b3..80f3e23 100644
--- a/curator-x-rest/src/main/java/org/apache/curator/x/rest/dropwizard/CuratorRestBundle.java
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/dropwizard/CuratorRestBundle.java
@@ -19,6 +19,7 @@
 
 package org.apache.curator.x.rest.dropwizard;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.sun.jersey.spi.inject.SingletonTypeInjectableProvider;
 import io.dropwizard.ConfiguredBundle;
 import io.dropwizard.setup.Bootstrap;
@@ -34,6 +35,13 @@ import javax.ws.rs.core.Context;
 
 public class CuratorRestBundle implements ConfiguredBundle<CuratorConfiguration>
 {
+    private volatile CuratorRestContext curatorRestContext;
+
+    public CuratorRestContext getCuratorRestContext()
+    {
+        return curatorRestContext;
+    }
+
     @Override
     public void initialize(Bootstrap<?> bootstrap)
     {
@@ -43,15 +51,15 @@ public class CuratorRestBundle implements ConfiguredBundle<CuratorConfiguration>
     @Override
     public void run(CuratorConfiguration configuration, Environment environment) throws Exception
     {
-        final CuratorRestContext context = newCuratorRestContext(configuration);
-        runFromContext(environment, context);
+        curatorRestContext = newCuratorRestContext(configuration);
+        runFromContext(environment, curatorRestContext);
 
         LifeCycle.Listener listener = new AbstractLifeCycle.AbstractLifeCycleListener()
         {
             @Override
             public void lifeCycleStopping(LifeCycle event)
             {
-                closeCuratorClient(context.getClient());
+                closeCuratorClient(curatorRestContext.getClient());
             }
         };
         environment.lifecycle().addLifeCycleListener(listener);

http://git-wip-us.apache.org/repos/asf/curator/blob/0dcba0f4/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java b/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
index 4a7eaf0..6625388 100644
--- a/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
+++ b/curator-x-rest/src/test/java/org/apache/curator/x/rest/api/TestLocks.java
@@ -20,16 +20,26 @@
 package org.apache.curator.x.rest.api;
 
 import org.apache.curator.framework.recipes.locks.InterProcessLock;
+import org.apache.curator.test.KillSession;
+import org.apache.curator.test.TestingServer;
+import org.apache.curator.test.Timing;
+import org.apache.curator.x.rest.entities.Status;
+import org.apache.curator.x.rest.entities.StatusMessage;
 import org.apache.curator.x.rest.support.BaseClassForTests;
 import org.apache.curator.x.rest.support.InterProcessLockBridge;
+import org.apache.curator.x.rest.support.StatusListener;
 import org.testng.Assert;
 import org.testng.annotations.Test;
+import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorCompletionService;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
 public class TestLocks extends BaseClassForTests
@@ -140,4 +150,120 @@ public class TestLocks extends BaseClassForTests
             Assert.assertTrue(mutexForClient1.isAcquiredInThisProcess());
         }
     }
+
+    @Test
+    public void testWaitingProcessKilledServer() throws Exception
+    {
+        final Timing timing = new Timing();
+        final CountDownLatch latch = new CountDownLatch(1);
+        StatusListener statusListener = new StatusListener()
+        {
+            @Override
+            public void statusUpdate(List<StatusMessage> messages)
+            {
+                // NOP
+            }
+
+            @Override
+            public void errorState(Status status)
+            {
+                if ( status.getState().equals("lost") )
+                {
+                    latch.countDown();
+                }
+            }
+        };
+        sessionManager.setStatusListener(statusListener);
+
+        final AtomicBoolean isFirst = new AtomicBoolean(true);
+        ExecutorCompletionService<Object> service = new ExecutorCompletionService<Object>(Executors.newFixedThreadPool(2));
+        for ( int i = 0; i < 2; ++i )
+        {
+            service.submit
+                (
+                    new Callable<Object>()
+                    {
+                        @Override
+                        public Object call() throws Exception
+                        {
+                            InterProcessLock lock = new InterProcessLockBridge(restClient, sessionManager, uriMaker);
+                            lock.acquire();
+                            try
+                            {
+                                if ( isFirst.compareAndSet(true, false) )
+                                {
+                                    timing.sleepABit();
+
+                                    server.stop();
+                                    Assert.assertTrue(timing.awaitLatch(latch));
+                                    server = new TestingServer(server.getPort(), server.getTempDirectory());
+                                }
+                            }
+                            finally
+                            {
+                                try
+                                {
+                                    lock.release();
+                                }
+                                catch ( Exception e )
+                                {
+                                    // ignore
+                                }
+                            }
+                            return null;
+                        }
+                    }
+                );
+        }
+
+        for ( int i = 0; i < 2; ++i )
+        {
+            service.take().get(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS);
+        }
+    }
+
+    @Test
+    public void testKilledSession() throws Exception
+    {
+        final Timing timing = new Timing();
+
+        final InterProcessLock mutex1 = new InterProcessLockBridge(restClient, sessionManager, uriMaker);
+        final InterProcessLock mutex2 = new InterProcessLockBridge(restClient, sessionManager, uriMaker);
+
+        final Semaphore semaphore = new Semaphore(0);
+        ExecutorCompletionService<Object> service = new ExecutorCompletionService<Object>(Executors.newFixedThreadPool(2));
+        service.submit
+            (
+                new Callable<Object>()
+                {
+                    @Override
+                    public Object call() throws Exception
+                    {
+                        mutex1.acquire();
+                        semaphore.release();
+                        Thread.sleep(1000000);
+                        return null;
+                    }
+                }
+            );
+
+        service.submit
+            (
+                new Callable<Object>()
+                {
+                    @Override
+                    public Object call() throws Exception
+                    {
+                        mutex2.acquire();
+                        semaphore.release();
+                        Thread.sleep(1000000);
+                        return null;
+                    }
+                }
+            );
+
+        Assert.assertTrue(timing.acquireSemaphore(semaphore, 1));
+        KillSession.kill(getCuratorRestContext().getClient().getZookeeperClient().getZooKeeper(), server.getConnectString());
+        Assert.assertTrue(timing.acquireSemaphore(semaphore, 1));
+    }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/0dcba0f4/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java
index 2690559..53b8b36 100644
--- a/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java
+++ b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/BaseClassForTests.java
@@ -30,6 +30,7 @@ import io.dropwizard.setup.Environment;
 import org.apache.curator.test.InstanceSpec;
 import org.apache.curator.test.TestingServer;
 import org.apache.curator.utils.DebugUtils;
+import org.apache.curator.x.rest.CuratorRestContext;
 import org.apache.curator.x.rest.dropwizard.CuratorApplication;
 import org.apache.curator.x.rest.dropwizard.CuratorConfiguration;
 import org.apache.curator.x.rest.dropwizard.CuratorRestBundle;
@@ -58,22 +59,20 @@ public class BaseClassForTests
     protected UriMaker uriMaker;
 
     private File configFile;
+    private CuratorRestBundle bundle;
 
     @BeforeMethod
     public void     setup() throws Exception
     {
-        setup(5000);
-    }
+        bundle = new CuratorRestBundle();
 
-    protected void setup(int sessionLengthMs) throws Exception
-    {
         int port = InstanceSpec.getRandomPort();
         restClient = Client.create();
 
         System.setProperty(DebugUtils.PROPERTY_DONT_LOG_CONNECTION_ISSUES, "true");
         server = new TestingServer();
 
-        configFile = makeConfigFile(server.getConnectString(), sessionLengthMs, port);
+        configFile = makeConfigFile(server.getConnectString(), 5000, port);
 
         final AtomicReference<CuratorConfiguration> curatorConfigurationAtomicReference = new AtomicReference<CuratorConfiguration>();
         makeAndStartApplication(curatorConfigurationAtomicReference, configFile);
@@ -104,6 +103,11 @@ public class BaseClassForTests
         }
     }
 
+    protected CuratorRestContext getCuratorRestContext()
+    {
+        return bundle.getCuratorRestContext();
+    }
+
     private Application<CuratorConfiguration> makeAndStartApplication(final AtomicReference<CuratorConfiguration> curatorConfigurationRef, final File configFile) throws InterruptedException
     {
         final CountDownLatch startedLatch = new CountDownLatch(1);
@@ -112,7 +116,7 @@ public class BaseClassForTests
             @Override
             public void initialize(Bootstrap<CuratorConfiguration> bootstrap)
             {
-                bootstrap.addBundle(new CuratorRestBundle());
+                bootstrap.addBundle(bundle);
             }
 
             @Override

http://git-wip-us.apache.org/repos/asf/curator/blob/0dcba0f4/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/SessionManager.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/SessionManager.java b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/SessionManager.java
index 69cfc76..140569e 100644
--- a/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/SessionManager.java
+++ b/curator-x-rest/src/test/java/org/apache/curator/x/rest/support/SessionManager.java
@@ -49,6 +49,8 @@ public class SessionManager implements Closeable
     private final Future<?> task;
     private final ConcurrentMap<InetSocketAddress, Entry> entries = Maps.newConcurrentMap();
 
+    private volatile StatusListener statusListener;
+
     private static class Entry
     {
         private final StatusListener listener;
@@ -104,6 +106,12 @@ public class SessionManager implements Closeable
         task.cancel(true);
     }
 
+    public void setStatusListener(StatusListener statusListener)
+    {
+        Preconditions.checkState(this.statusListener == null, "statusListener already set");
+        this.statusListener = statusListener;
+    }
+
     private void processEntries()
     {
         for ( Map.Entry<InetSocketAddress, Entry> mapEntry : entries.entrySet() )
@@ -122,14 +130,28 @@ public class SessionManager implements Closeable
             if ( status.getState().equals("connected") )
             {
                 List<StatusMessage> messages = status.getMessages();
-                if ( (messages.size() > 0) && (entry.listener != null) )
+                if ( messages.size() > 0 )
                 {
-                    entry.listener.statusUpdate(status.getMessages());
+                    if ( statusListener != null )
+                    {
+                        statusListener.statusUpdate(status.getMessages());
+                    }
+                    if ( entry.listener != null )
+                    {
+                        entry.listener.statusUpdate(status.getMessages());
+                    }
                 }
             }
-            else if ( entry.listener != null )
+            else
             {
-                entry.listener.errorState(status);
+                if ( statusListener != null )
+                {
+                    statusListener.errorState(status);
+                }
+                if ( entry.listener != null )
+                {
+                    entry.listener.errorState(status);
+                }
             }
         }
     }