You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ev...@apache.org on 2013/10/18 18:24:00 UTC

git commit: The Queue API for OpenStack Marconi.

Updated Branches:
  refs/heads/master 2e92538b1 -> 60fd86d3c


The Queue API for OpenStack Marconi.


Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/commit/60fd86d3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/tree/60fd86d3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/diff/60fd86d3

Branch: refs/heads/master
Commit: 60fd86d3cd09ad2e76ed6cfc5c3874e48278336a
Parents: 2e92538
Author: Everett Toews <ev...@rackspace.com>
Authored: Thu Oct 17 15:30:27 2013 -0500
Committer: Everett Toews <ev...@rackspace.com>
Committed: Fri Oct 18 11:23:43 2013 -0500

----------------------------------------------------------------------
 .../openstack/marconi/v1/domain/Aged.java       | 123 ++++++++++++
 .../marconi/v1/domain/MessagesStats.java        | 187 +++++++++++++++++++
 .../openstack/marconi/v1/domain/QueueStats.java |  67 +++++++
 .../openstack/marconi/v1/features/QueueApi.java |  85 ++++++++-
 .../v1/handlers/MarconiErrorHandler.java        |  12 +-
 .../marconi/v1/features/QueueApiLiveTest.java   |  73 +++++++-
 .../marconi/v1/features/QueueApiMockTest.java   | 140 ++++++++++++++
 .../us/CloudQueuesUSProviderMetadata.java       |   2 +-
 8 files changed, 679 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/60fd86d3/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/Aged.java
----------------------------------------------------------------------
diff --git a/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/Aged.java b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/Aged.java
new file mode 100644
index 0000000..84ac899
--- /dev/null
+++ b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/Aged.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds 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.jclouds.openstack.marconi.v1.domain;
+
+import com.google.common.base.Objects;
+
+import java.util.Date;
+
+/**
+ * The age of messages in a queue.
+ *
+ * @author Everett Toews
+ */
+public class Aged {
+
+   private int age;
+   private Date created;
+
+   protected Aged(int age, Date created) {
+      this.age = age;
+      this.created = created;
+   }
+
+   /**
+    * @return Age of the oldest/newest message in seconds.
+    */
+   public int getAge() {
+      return age;
+   }
+
+   /**
+    * @return Date/Time of the oldest/newest message.
+    */
+   public Date getCreated() {
+      return created;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(age, created);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      Aged that = Aged.class.cast(obj);
+      return Objects.equal(this.age, that.age) && Objects.equal(this.created, that.created);
+   }
+
+   protected Objects.ToStringHelper string() {
+      return Objects.toStringHelper(this)
+         .add("age", age).add("created", created);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder toBuilder() {
+      return new ConcreteBuilder().fromAged(this);
+   }
+
+   public static abstract class Builder {
+      protected abstract Builder self();
+
+      protected int age;
+      protected Date created;
+
+      /**
+       * @see Aged#age
+       */
+      public Builder age(int age) {
+         this.age = age;
+         return self();
+      }
+
+      /**
+       * @see Aged#created
+       */
+      public Builder created(Date created) {
+         this.created = created;
+         return self();
+      }
+
+      public Aged build() {
+         return new Aged(age, created);
+      }
+
+      public Builder fromAged(Aged in) {
+         return this.age(in.getAge()).created(in.getCreated());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/60fd86d3/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/MessagesStats.java
----------------------------------------------------------------------
diff --git a/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/MessagesStats.java b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/MessagesStats.java
new file mode 100644
index 0000000..1440592
--- /dev/null
+++ b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/MessagesStats.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds 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.jclouds.openstack.marconi.v1.domain;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import org.jclouds.javax.annotation.Nullable;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * Statistics on messages in this queue.
+ *
+ * @author Everett Toews
+ */
+public class MessagesStats {
+
+   private int claimed;
+   private int free;
+   private int total;
+   private Aged oldest;
+   private Aged newest;
+
+   @ConstructorProperties({
+         "claimed", "free", "total", "oldest", "newest"
+   })
+   protected MessagesStats(int claimed, int free, int total, @Nullable Aged oldest, @Nullable Aged newest) {
+      this.claimed = claimed;
+      this.free = free;
+      this.total = total;
+      this.oldest = oldest;
+      this.newest = newest;
+   }
+
+   /**
+    * @return The number of claimed messages in this queue.
+    */
+   public int getClaimed() {
+      return claimed;
+   }
+
+   /**
+    * @return The number of free messages in this queue.
+    */
+   public int getFree() {
+      return free;
+   }
+
+   /**
+    * @return The total number of messages in this queue.
+    */
+   public int getTotal() {
+      return total;
+   }
+
+   /**
+    * @return Statistics on the oldest messages in this queue. If the value of total is 0, then oldest is not present.
+    */
+   public Optional<Aged> getOldest() {
+      return Optional.fromNullable(oldest);
+   }
+
+   /**
+    * @return Statistics on the newest messages in this queue. If the value of total is 0, then newest is not present.
+    */
+   public Optional<Aged> getNewest() {
+      return Optional.fromNullable(newest);
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(claimed, free, total, oldest, newest);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      MessagesStats that = MessagesStats.class.cast(obj);
+      return Objects.equal(this.claimed, that.claimed) 
+            && Objects.equal(this.free, that.free)
+            && Objects.equal(this.total, that.total)
+            && Objects.equal(this.oldest, that.oldest)
+            && Objects.equal(this.newest, that.newest);
+   }
+
+   protected Objects.ToStringHelper string() {
+      return Objects.toStringHelper(this).omitNullValues()
+         .add("claimed", claimed).add("free", free).add("total", total).add("oldest", oldest).add("newest", newest);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder toBuilder() {
+      return new ConcreteBuilder().fromMessagesStats(this);
+   }
+
+   public static abstract class Builder {
+      protected abstract Builder self();
+
+      protected int claimed;
+      protected int free;
+      protected int total;
+      protected Aged oldest;
+      protected Aged newest;
+
+      /**
+       * @see MessagesStats#claimed
+       */
+      public Builder claimed(int claimed) {
+         this.claimed = claimed;
+         return self();
+      }
+
+      /**
+       * @see MessagesStats#free
+       */
+      public Builder free(int free) {
+         this.free = free;
+         return self();
+      }
+
+      /**
+       * @see MessagesStats#total
+       */
+      public Builder total(int total) {
+         this.total = total;
+         return self();
+      }
+
+      /**
+       * @see MessagesStats#oldest
+       */
+      public Builder oldest(Aged oldest) {
+         this.oldest = oldest;
+         return self();
+      }
+
+      /**
+       * @see MessagesStats#newest
+       */
+      public Builder newest(Aged newest) {
+         this.newest = newest;
+         return self();
+      }
+
+      public MessagesStats build() {
+         return new MessagesStats(claimed, free, total, oldest, newest);
+      }
+
+      public Builder fromMessagesStats(MessagesStats in) {
+         return this.claimed(in.getClaimed()).free(in.getFree()).total(in.getTotal()).oldest(in.getOldest().orNull())
+               .newest(in.getNewest().orNull());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/60fd86d3/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/QueueStats.java
----------------------------------------------------------------------
diff --git a/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/QueueStats.java b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/QueueStats.java
new file mode 100644
index 0000000..492f432
--- /dev/null
+++ b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/domain/QueueStats.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds 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.jclouds.openstack.marconi.v1.domain;
+
+import com.google.common.base.Objects;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * Queue statistics, including how many messages are in the queue.
+ *
+ * @author Everett Toews
+ */
+public class QueueStats {
+
+   private MessagesStats messages;
+
+   protected QueueStats(MessagesStats messages) {
+      this.messages = messages;
+   }
+
+   /**
+    * @return The statistics of the messages in this queue.
+    */
+   public MessagesStats getMessagesStats() {
+      return messages;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(messages);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      QueueStats that = QueueStats.class.cast(obj);
+      return Objects.equal(this.messages, that.messages);
+   }
+
+   protected Objects.ToStringHelper string() {
+      return Objects.toStringHelper(this)
+         .add("messagesStats", messages);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/60fd86d3/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/features/QueueApi.java
----------------------------------------------------------------------
diff --git a/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/features/QueueApi.java b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/features/QueueApi.java
index e620002..aca5782 100644
--- a/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/features/QueueApi.java
+++ b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/features/QueueApi.java
@@ -18,35 +18,112 @@ package org.jclouds.openstack.marconi.v1.features;
 
 import org.jclouds.Fallbacks;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.marconi.v1.domain.QueueStats;
+import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SkipEncoding;
+import org.jclouds.rest.binders.BindToJsonPayload;
 
 import javax.inject.Named;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
+import java.util.Map;
 
 /**
  * Provides access to Queues via their REST API.
- * 
+ *
  * @author Everett Toews
  */
 @SkipEncoding({'/', '='})
 @RequestFilters(AuthenticateRequest.class)
 public interface QueueApi {
    /**
-    * Creates a new Queue
+    * Create a queue.
     *
-    * @param name Name of the Queue. The name must not exceed 64 bytes in length, and it is limited to US-ASCII
+    * @param name Name of the queue. The name must not exceed 64 bytes in length, and it is limited to US-ASCII
     *             letters, digits, underscores, and hyphens.
     */
    @Named("queue:create")
    @PUT
    @Path("queues/{name}")
-   @Consumes(MediaType.APPLICATION_JSON)
    @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
    boolean create(@PathParam("name") String name);
+
+   /**
+    * Delete a queue.
+    *
+    * @param name Name of the queue. The name must not exceed 64 bytes in length, and it is limited to US-ASCII
+    *             letters, digits, underscores, and hyphens.
+    */
+   @Named("queue:delete")
+   @DELETE
+   @Path("queues/{name}")
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("name") String name);
+
+   /**
+    * Check for a queue's existence.
+    *
+    * @param name Name of the queue. The name must not exceed 64 bytes in length, and it is limited to US-ASCII
+    *             letters, digits, underscores, and hyphens.
+    */
+   @Named("queue:get")
+   @GET
+   @Path("queues/{name}")
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean exists(@PathParam("name") String name);
+
+   /**
+    * Sets metadata for the specified queue.
+    * <p/>
+    * The request body has a limit of 256 KB, excluding whitespace.
+    * <p/>
+    * This operation replaces any existing metadata document in its entirety. Ensure that you do not accidentally
+    * overwrite existing metadata that you want to retain.
+    *
+    * @param name Name of the queue. The name must not exceed 64 bytes in length, and it is limited to US-ASCII
+    *             letters, digits, underscores, and hyphens.
+    * @param metadata Metadata in key/value pairs.
+    */
+   @Named("queue:setMetadata")
+   @PUT
+   @Path("queues/{name}/metadata")
+   @Produces(MediaType.APPLICATION_JSON)
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean setMetadata(@PathParam("name") String name,
+                       @BinderParam(BindToJsonPayload.class) Map<String, String> metadata);
+
+   /**
+    * Gets metadata for the specified queue.
+    *
+    * @param name Name of the queue. The name must not exceed 64 bytes in length, and it is limited to US-ASCII
+    *             letters, digits, underscores, and hyphens.
+    */
+   @Named("queue:getMetadata")
+   @GET
+   @Path("queues/{name}/metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   Map<String, String> getMetadata(@PathParam("name") String name);
+
+
+   /**
+    * Gets stats for the specified queue.
+    *
+    * @param name Name of the queue. The name must not exceed 64 bytes in length, and it is limited to US-ASCII
+    *             letters, digits, underscores, and hyphens.
+    */
+   @Named("queue:getStats")
+   @GET
+   @Path("queues/{name}/stats")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   QueueStats getStats(@PathParam("name") String name);
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/60fd86d3/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/handlers/MarconiErrorHandler.java
----------------------------------------------------------------------
diff --git a/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/handlers/MarconiErrorHandler.java b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/handlers/MarconiErrorHandler.java
index dd6c603..098fa17 100644
--- a/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/handlers/MarconiErrorHandler.java
+++ b/openstack-marconi/src/main/java/org/jclouds/openstack/marconi/v1/handlers/MarconiErrorHandler.java
@@ -29,11 +29,14 @@ public class MarconiErrorHandler implements HttpErrorHandler {
    public void handleError(HttpCommand command, HttpResponse response) {
       // it is important to always read fully and close streams
       byte[] data = closeClientButKeepContentStream(response);
-      String message = (data != null) ? new String(data) : null;
+      Exception exception;
 
-      Exception exception = (message != null) ?
-            new HttpResponseException(command, response, message) :
-            new HttpResponseException(command, response);
+      if (data == null) {
+         exception = new HttpResponseException(command, response);
+      }
+      else {
+         exception = new HttpResponseException(command, response, new String(data));
+      }
 
       switch (response.getStatusCode()) {
          case 401:
@@ -43,6 +46,7 @@ public class MarconiErrorHandler implements HttpErrorHandler {
             exception = new IllegalStateException(exception.getMessage(), exception);
             break;
       }
+
       command.setException(exception);
    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/60fd86d3/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiLiveTest.java b/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiLiveTest.java
index 86f1f0d..7c1341f 100644
--- a/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiLiveTest.java
+++ b/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiLiveTest.java
@@ -16,12 +16,18 @@
  */
 package org.jclouds.openstack.marconi.v1.features;
 
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.openstack.marconi.v1.domain.QueueStats;
 import org.jclouds.openstack.marconi.v1.internal.BaseMarconiApiLiveTest;
 import org.testng.annotations.Test;
 
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
-@Test(groups = "live", testName = "QueueApiLiveTest")
+@Test(groups = "live", testName = "QueueApiLiveTest", singleThreaded = true)
 public class QueueApiLiveTest extends BaseMarconiApiLiveTest {
 
    public void create() throws Exception {
@@ -32,4 +38,69 @@ public class QueueApiLiveTest extends BaseMarconiApiLiveTest {
          assertTrue(success);
       }
    }
+
+   @Test(dependsOnMethods = { "create" })
+   public void exists() throws Exception {
+      for (String zoneId : api.getConfiguredZones()) {
+         QueueApi queueApi = api.getQueueApiForZone(zoneId);
+         boolean success = queueApi.exists("jclouds-test");
+
+         assertTrue(success);
+      }
+   }
+
+   @Test(dependsOnMethods = { "exists" })
+   public void setMetadata() throws Exception {
+      for (String zoneId : api.getConfiguredZones()) {
+         QueueApi queueApi = api.getQueueApiForZone(zoneId);
+         Map<String, String> metadata = ImmutableMap.of("key1", "value1");
+         boolean success = queueApi.setMetadata("jclouds-test", metadata);
+
+         assertTrue(success);
+      }
+   }
+
+   @Test(dependsOnMethods = { "setMetadata" })
+   public void getMetadata() throws Exception {
+      for (String zoneId : api.getConfiguredZones()) {
+         QueueApi queueApi = api.getQueueApiForZone(zoneId);
+         Map<String, String> metadata = queueApi.getMetadata("jclouds-test");
+
+         assertEquals(metadata.get("key1"), "value1");
+      }
+   }
+
+   @Test(dependsOnMethods = { "getMetadata" })
+   public void getStatsWithoutTotal() throws Exception {
+      for (String zoneId : api.getConfiguredZones()) {
+         QueueApi queueApi = api.getQueueApiForZone(zoneId);
+         QueueStats stats = queueApi.getStats("jclouds-test");
+
+         assertEquals(stats.getMessagesStats().getClaimed(), 0);
+         assertEquals(stats.getMessagesStats().getFree(), 0);
+         assertEquals(stats.getMessagesStats().getTotal(), 0);
+         assertFalse(stats.getMessagesStats().getOldest().isPresent());
+         assertFalse(stats.getMessagesStats().getNewest().isPresent());
+      }
+   }
+
+   @Test(dependsOnMethods = { "getStatsWithoutTotal" })
+   public void delete() throws Exception {
+      for (String zoneId : api.getConfiguredZones()) {
+         QueueApi queueApi = api.getQueueApiForZone(zoneId);
+         boolean success = queueApi.delete("jclouds-test");
+
+         assertTrue(success);
+      }
+   }
+
+   @Test(dependsOnMethods = { "delete" })
+   public void doesNotExist() throws Exception {
+      for (String zoneId : api.getConfiguredZones()) {
+         QueueApi queueApi = api.getQueueApiForZone(zoneId);
+         boolean success = queueApi.exists("jclouds-test");
+
+         assertFalse(success);
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/60fd86d3/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiMockTest.java b/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiMockTest.java
index db0caf0..02e0488 100644
--- a/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiMockTest.java
+++ b/openstack-marconi/src/test/java/org/jclouds/openstack/marconi/v1/features/QueueApiMockTest.java
@@ -16,13 +16,19 @@
  */
 package org.jclouds.openstack.marconi.v1.features;
 
+import com.google.common.collect.ImmutableMap;
 import com.squareup.okhttp.mockwebserver.MockResponse;
 import com.squareup.okhttp.mockwebserver.MockWebServer;
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
 import org.jclouds.openstack.marconi.v1.MarconiApi;
+import org.jclouds.openstack.marconi.v1.domain.QueueStats;
 import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
 import org.testng.annotations.Test;
 
+import java.util.Map;
+
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
 /**
@@ -51,4 +57,138 @@ public class QueueApiMockTest extends BaseOpenStackMockTest<MarconiApi> {
          server.shutdown();
       }
    }
+
+   public void deleteQueue() throws Exception {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(new MockResponse().setBody(accessRackspace));
+      server.enqueue(new MockResponse().setResponseCode(204));
+
+      try {
+         MarconiApi api = api(server.getUrl("/").toString(), "openstack-marconi");
+         QueueApi queueApi = api.getQueueApiForZone("DFW");
+         boolean success = queueApi.delete("jclouds-test");
+
+         assertTrue(success);
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         assertEquals(server.takeRequest().getRequestLine(), "DELETE /v1/123123/queues/jclouds-test HTTP/1.1");
+      }
+      finally {
+         server.shutdown();
+      }
+   }
+
+   public void existsQueue() throws Exception {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(new MockResponse().setBody(accessRackspace));
+      server.enqueue(new MockResponse().setResponseCode(204));
+
+      try {
+         MarconiApi api = api(server.getUrl("/").toString(), "openstack-marconi");
+         QueueApi queueApi = api.getQueueApiForZone("DFW");
+         boolean success = queueApi.exists("jclouds-test");
+
+         assertTrue(success);
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         assertEquals(server.takeRequest().getRequestLine(), "GET /v1/123123/queues/jclouds-test HTTP/1.1");
+      }
+      finally {
+         server.shutdown();
+      }
+   }
+
+   public void doesNotExistQueue() throws Exception {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(new MockResponse().setBody(accessRackspace));
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         MarconiApi api = api(server.getUrl("/").toString(), "openstack-marconi");
+         QueueApi queueApi = api.getQueueApiForZone("DFW");
+         boolean success = queueApi.exists("jclouds-blerg");
+
+         assertFalse(success);
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         assertEquals(server.takeRequest().getRequestLine(), "GET /v1/123123/queues/jclouds-blerg HTTP/1.1");
+      }
+      finally {
+         server.shutdown();
+      }
+   }
+
+   public void setMetadata() throws Exception {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(new MockResponse().setBody(accessRackspace));
+      server.enqueue(new MockResponse().setResponseCode(204));
+
+      try {
+         MarconiApi api = api(server.getUrl("/").toString(), "openstack-marconi");
+         QueueApi queueApi = api.getQueueApiForZone("DFW");
+         Map<String, String> metadata = ImmutableMap.of("key1", "value1");
+         boolean success = queueApi.setMetadata("jclouds-test", metadata);
+
+         assertTrue(success);
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         RecordedRequest request = server.takeRequest();
+         assertEquals(request.getRequestLine(), "PUT /v1/123123/queues/jclouds-test/metadata HTTP/1.1");
+         assertEquals(request.getUtf8Body(), "{\"key1\":\"value1\"}");
+      }
+      finally {
+         server.shutdown();
+      }
+   }
+
+   public void getMetadata() throws Exception {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(new MockResponse().setBody(accessRackspace));
+      server.enqueue(new MockResponse().setResponseCode(200).setBody("{\"key1\":\"value1\"}"));
+
+      try {
+         MarconiApi api = api(server.getUrl("/").toString(), "openstack-marconi");
+         QueueApi queueApi = api.getQueueApiForZone("DFW");
+         Map<String, String> metadata = queueApi.getMetadata("jclouds-test");
+
+         assertEquals(metadata.get("key1"), "value1");
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         assertEquals(server.takeRequest().getRequestLine(), "GET /v1/123123/queues/jclouds-test/metadata HTTP/1.1");
+      }
+      finally {
+         server.shutdown();
+      }
+   }
+
+   public void getQueueStatsWithoutTotal() throws Exception {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(new MockResponse().setBody(accessRackspace));
+      server.enqueue(new MockResponse().setResponseCode(200)
+            .setBody("{\"messages\":{\"claimed\":0,\"total\":0,\"free\":0}}"));
+
+      try {
+         MarconiApi api = api(server.getUrl("/").toString(), "openstack-marconi");
+         QueueApi queueApi = api.getQueueApiForZone("DFW");
+         QueueStats stats = queueApi.getStats("jclouds-test");
+
+         assertEquals(stats.getMessagesStats().getClaimed(), 0);
+         assertEquals(stats.getMessagesStats().getFree(), 0);
+         assertEquals(stats.getMessagesStats().getTotal(), 0);
+         assertFalse(stats.getMessagesStats().getOldest().isPresent());
+         assertFalse(stats.getMessagesStats().getNewest().isPresent());
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         assertEquals(server.takeRequest().getRequestLine(), "GET /v1/123123/queues/jclouds-test/stats HTTP/1.1");
+      }
+      finally {
+         server.shutdown();
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/60fd86d3/rackspace-cloudqueues-us/src/main/java/org/jclouds/rackspace/cloudqueues/us/CloudQueuesUSProviderMetadata.java
----------------------------------------------------------------------
diff --git a/rackspace-cloudqueues-us/src/main/java/org/jclouds/rackspace/cloudqueues/us/CloudQueuesUSProviderMetadata.java b/rackspace-cloudqueues-us/src/main/java/org/jclouds/rackspace/cloudqueues/us/CloudQueuesUSProviderMetadata.java
index 95d8c0c..0baf912 100644
--- a/rackspace-cloudqueues-us/src/main/java/org/jclouds/rackspace/cloudqueues/us/CloudQueuesUSProviderMetadata.java
+++ b/rackspace-cloudqueues-us/src/main/java/org/jclouds/rackspace/cloudqueues/us/CloudQueuesUSProviderMetadata.java
@@ -84,7 +84,7 @@ public class CloudQueuesUSProviderMetadata extends BaseProviderMetadata {
                   .identityName("${userName}")
                   .credentialName("${apiKey}")
                   .defaultEndpoint("https://identity.api.rackspacecloud.com/v2.0/")
-                  .endpointName("identity service url ending in /v2.0/")
+                  .endpointName("Rackspace Cloud Identity service URL ending in /v2.0/")
                   .documentation(URI.create("http://docs.rackspace.com/queues/api/v1.0/cq-devguide/content/overview.html"))
                   .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
                                               .add(CloudIdentityAuthenticationApiModule.class)