You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ad...@apache.org on 2013/09/27 23:52:27 UTC

git commit: JCLOUDS-73: New Swift Account API, along with models, and mock/live tests

Updated Branches:
  refs/heads/master a2f5faf86 -> f46c86a97


JCLOUDS-73: New Swift Account API, along with models, and mock/live tests


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/f46c86a9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/tree/f46c86a9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/diff/f46c86a9

Branch: refs/heads/master
Commit: f46c86a979b3d8373ad67a5d2831dde152319ec3
Parents: a2f5faf
Author: Jeremy Daggett <je...@rackspace.com>
Authored: Wed Jul 17 13:51:29 2013 -0700
Committer: Adrian Cole <ad...@gmail.com>
Committed: Fri Sep 27 14:49:53 2013 -0700

----------------------------------------------------------------------
 openstack-swift/pom.xml                         |   7 +
 .../jclouds/openstack/swift/v1/SwiftApi.java    |  36 ++---
 .../binders/BindAccountMetadataToHeaders.java   |  92 +++++++++++
 .../swift/v1/config/SwiftHttpApiModule.java     |   4 +-
 .../swift/v1/config/SwiftProperties.java        |  26 ---
 .../openstack/swift/v1/domain/Account.java      | 157 ++++++++++++-------
 .../openstack/swift/v1/domain/Container.java    | 149 ++++++++----------
 .../openstack/swift/v1/features/AccountApi.java |  80 ++++++++--
 .../v1/functions/EntriesWithoutMetaPrefix.java  |  50 ++++++
 .../swift/v1/functions/MetadataFromHeaders.java |  31 ++++
 .../v1/functions/ParseAccountFromHeaders.java   |  34 ++++
 ...ParseAccountMetadataResponseFromHeaders.java |  40 -----
 .../swift/v1/handlers/SwiftErrorHandler.java    |   9 --
 .../swift/v1/AuthenticationMockTest.java        |  74 +++++++++
 .../v1/PasswordAuthenticationExpectTest.java    |  70 ---------
 .../swift/v1/SwiftApiMetadataTest.java          |   1 -
 .../swift/v1/SwiftErrorHandlerTest.java         |   1 -
 .../swift/v1/features/AccountApiExpectTest.java |  55 -------
 .../swift/v1/features/AccountApiLiveTest.java   |  64 ++++++--
 .../swift/v1/features/AccountApiMockTest.java   | 119 ++++++++++++++
 .../v1/features/ContainerApiExpectTest.java     |  74 ---------
 .../swift/v1/features/ContainerApiLiveTest.java |  11 +-
 .../swift/v1/features/ObjectApiExpectTest.java  |  28 ----
 .../v1/internal/BaseSwiftApiExpectTest.java     |  28 ----
 .../swift/v1/internal/BaseSwiftApiLiveTest.java |   6 +-
 .../swift/v1/internal/BaseSwiftExpectTest.java  |  50 ------
 .../swift/v1/internal/BaseSwiftMockTest.java    |  99 ++++++++++++
 .../v1/options/ListContainersOptionsTest.java   |   2 -
 .../swift/v1/parse/ParseContainerListTest.java  |   9 +-
 29 files changed, 821 insertions(+), 585 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/pom.xml
----------------------------------------------------------------------
diff --git a/openstack-swift/pom.xml b/openstack-swift/pom.xml
index ae84044..6159d6a 100644
--- a/openstack-swift/pom.xml
+++ b/openstack-swift/pom.xml
@@ -110,6 +110,13 @@
       <artifactId>logback-classic</artifactId>
       <scope>test</scope>
     </dependency>
+    <!-- TODO: change jclouds parent base pom to okhttp MWS, as google one is dead -->
+    <dependency>
+      <groupId>com.squareup.okhttp</groupId>
+      <artifactId>mockwebserver</artifactId>
+      <version>1.2.1</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <profiles>

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApi.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApi.java
index 826914c..562566b 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApi.java
@@ -18,6 +18,7 @@ package org.jclouds.openstack.swift.v1;
 
 import java.io.Closeable;
 import java.util.Set;
+
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.location.Region;
 import org.jclouds.location.functions.RegionToEndpoint;
@@ -31,44 +32,27 @@ import org.jclouds.rest.annotations.EndpointParam;
 import com.google.inject.Provides;
 
 /**
- * Provides access to Swift.
- * <p/>
- *
- * @see <a href="http://docs.openstack.org/api/openstack-object-storage/1.0/content">api doc</a>
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content">api
+ *      doc</a>
  * @author Adrian Cole
  * @author Zack Shoylev
  */
 public interface SwiftApi extends Closeable {
-   /**
-    * 
-    * @return the Region codes configured
-    */
+
    @Provides
    @Region
-   Set<String> getConfiguredRegions();
+   Set<String> configuredRegions();
 
-   /**
-    * Provides access to Extension features.
-    */
    @Delegate
-   ExtensionApi getExtensionApiForRegion(
-         @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   ExtensionApi extensionApiInRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
 
-   /**
-    * Provides access to Account features.
-    */
    @Delegate
-   AccountApi getAccountApiForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   AccountApi accountApiInRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
 
-   /**
-    * Provides access to Container features.
-    */
    @Delegate
-   ContainerApi getContainerApiForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   ContainerApi containerApiInRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
 
-   /**
-    * Provides access to Object features.
-    */
    @Delegate
-   ObjectApi getObjectApiForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   ObjectApi objectApiInRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/binders/BindAccountMetadataToHeaders.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/binders/BindAccountMetadataToHeaders.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/binders/BindAccountMetadataToHeaders.java
new file mode 100644
index 0000000..96e58bc
--- /dev/null
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/binders/BindAccountMetadataToHeaders.java
@@ -0,0 +1,92 @@
+/*
+ * 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.jclouds.openstack.swift.v1.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableMultimap.Builder;
+
+/**
+ * Will lower-case header keys due to a swift implementation to return headers
+ * in a different case than sent. ex.
+ * 
+ * <pre>
+ * >> X-Account-Meta-MyDelete1: foo
+ * >> X-Account-Meta-MyDelete2: bar
+ * </pre>
+ * 
+ * results in:
+ * 
+ * <pre>
+ * << X-Account-Meta-Mydelete1: foo
+ * << X-Account-Meta-Mydelete2: bar
+ * </pre>
+ * 
+ * <h4>Note</h4> <br/>
+ * HTTP response headers keys are known to be case-insensitive, but this
+ * practice of mixing up case will prevent metadata keys such as those in
+ * Turkish from working.
+ * 
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/create-update-account-metadata.html">documentation</a>
+ */
+public class BindAccountMetadataToHeaders implements Binder {
+
+   private static final String ACCOUNT_METADATA_PREFIX = "x-account-meta-";
+
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      checkNotNull(request, "request");
+      checkArgument(input instanceof Map<?, ?>, "input must be a non-null java.util.Map!");
+      Map<String, String> metadata = Map.class.cast(input);
+      Builder<String, String> headers = ImmutableMultimap.<String, String> builder();
+      for (Entry<String, String> keyVal : metadata.entrySet()) {
+         String keyInLowercase = keyVal.getKey().toLowerCase();
+         if (keyVal.getKey().startsWith(ACCOUNT_METADATA_PREFIX)) {
+            putAccountMetadata(headers, keyInLowercase, keyVal.getValue());
+         } else {
+            putAccountMetadata(headers, String.format("%s%s", ACCOUNT_METADATA_PREFIX, keyInLowercase),
+                  keyVal.getValue());
+         }
+      }
+      return (R) request.toBuilder().replaceHeaders(headers.build()).build();
+   }
+
+   protected void putAccountMetadata(Builder<String, String> headers, String key, String value) {
+      headers.put(key, value);
+   }
+
+   /**
+    * @see <a
+    *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/delete-account-metadata.html">documentation</a>
+    */
+   public static class InRemoval extends BindAccountMetadataToHeaders {
+      @Override
+      protected void putAccountMetadata(Builder<String, String> headers, String key, String value) {
+         headers.put(String.format("x-remove%s", key.substring(1)), "ignored");
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftHttpApiModule.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftHttpApiModule.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftHttpApiModule.java
index 9d35e2f..1822ebb 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftHttpApiModule.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftHttpApiModule.java
@@ -41,8 +41,6 @@ import com.google.common.collect.Multimap;
 import com.google.inject.Provides;
 
 /**
- * Configures the Swift connection.
- * 
  * @author Adrian Cole
  * @author Zack Shoylev
  */
@@ -73,7 +71,7 @@ public class SwiftHttpApiModule extends HttpApiModule<SwiftApi> {
             .build(new CacheLoader<String, Set<? extends Extension>>() {
                @Override
                public Set<? extends Extension> load(String key) throws Exception {
-                  return swiftApi.get().getExtensionApiForRegion(key).list();
+                  return swiftApi.get().extensionApiInRegion(key).list();
                }
             });
    }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftProperties.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftProperties.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftProperties.java
deleted file mode 100644
index 70983bd..0000000
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftProperties.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.swift.v1.config;
-
-/**
- * Configuration properties and constants used in openstack Swift connections.
- *
- * @author Adam Lowe
- */
-public class SwiftProperties {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java
index aaa07ec..02f13aa 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java
@@ -18,77 +18,53 @@ package org.jclouds.openstack.swift.v1.domain;
 
 import static com.google.common.base.Objects.equal;
 import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.beans.ConstructorProperties;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableMap;
 
 /**
- * @author Adrian Cole
- * @see <a href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-account-metadata.html">api doc</a>
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-account-metadata.html">api
+ *      doc</a>
  */
 public class Account {
 
-   public static Builder builder() {
-      return new Builder();
-   }
+   private final long containerCount;
+   private final long objectCount;
+   private final long bytesUsed;
+   private final Map<String, String> metadata;
 
-   public Builder toBuilder() {
-      return builder().fromAccountMetadata(this);
+   // parsed from headers, so ConstructorProperties here would be misleading
+   protected Account(long containerCount, long objectCount, long bytesUsed, Map<String, String> metadata) {
+      this.containerCount = containerCount;
+      this.objectCount = objectCount;
+      this.bytesUsed = bytesUsed;
+      this.metadata = checkNotNull(metadata, "metadata");
    }
 
-   public static class Builder {
-      protected int containerCount;
-      protected long bytesUsed;
-
-      /**
-       * @see Account#getContainerCount()
-       */
-      public Builder containerCount(int containerCount) {
-         this.containerCount = containerCount;
-         return this;
-      }
-
-      /**
-       * @see Account#getBytesUsed()
-       */
-      public Builder bytesUsed(long bytesUsed) {
-         this.bytesUsed = bytesUsed;
-         return this;
-      }
-
-      public Account build() {
-         return new Account(containerCount, bytesUsed);
-      }
-
-      public Builder fromAccountMetadata(Account from) {
-         return containerCount(from.getContainerCount()).bytesUsed(from.getBytesUsed());
-      }
+   public long containerCount() {
+      return containerCount;
    }
-  
-   protected int containerCount;
-   protected long bytesUsed;
 
-   @ConstructorProperties({"containerCount", "bytesUsed"})
-   protected Account(int containerCount, long bytesUsed) {
-      this.containerCount = containerCount;
-      this.bytesUsed = bytesUsed;
+   public long objectCount() {
+      return objectCount;
    }
 
-   /**
-    * 
-    * @return the number of containers in OpenStack Object Storage for the account
-    */
-   public int getContainerCount() {
-      return containerCount;
+   public long bytesUsed() {
+      return bytesUsed;
    }
 
    /**
-    * @return the total bytes stored in OpenStack Object Storage for the account
+    * In current swift implementations, headers keys are lower-cased. This means
+    * characters such as turkish will probably not work out well.
     */
-   public long getBytesUsed() {
-      return bytesUsed;
+   public Map<String, String> metadata() {
+      return metadata;
    }
 
    @Override
@@ -97,8 +73,11 @@ public class Account {
          return true;
       }
       if (object instanceof Account) {
-         final Account other = Account.class.cast(object);
-         return equal(getContainerCount(), other.getContainerCount()) && equal(getBytesUsed(), other.getBytesUsed());
+         Account that = Account.class.cast(object);
+         return equal(containerCount(), that.containerCount()) //
+               && equal(objectCount(), that.objectCount()) //
+               && equal(bytesUsed(), that.bytesUsed()) //
+               && equal(metadata(), that.metadata());
       } else {
          return false;
       }
@@ -106,7 +85,7 @@ public class Account {
 
    @Override
    public int hashCode() {
-      return Objects.hashCode(getContainerCount(), getBytesUsed());
+      return Objects.hashCode(containerCount(), objectCount(), bytesUsed());
    }
 
    @Override
@@ -115,6 +94,74 @@ public class Account {
    }
 
    protected ToStringHelper string() {
-      return toStringHelper("").add("containerCount", getContainerCount()).add("bytesUsed", getBytesUsed());
+      return toStringHelper("") //
+            .add("containerCount", containerCount()) //
+            .add("objectCount", objectCount()) //
+            .add("bytesUsed", bytesUsed()) //
+            .add("metadata", metadata());
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromContainer(this);
+   }
+
+   public static class Builder {
+      protected long containerCount;
+      protected long objectCount;
+      protected long bytesUsed;
+      protected Map<String, String> metadata = ImmutableMap.of();
+
+      /**
+       * @see Account#containerCount()
+       */
+      public Builder containerCount(long containerCount) {
+         this.containerCount = containerCount;
+         return this;
+      }
+
+      /**
+       * @see Account#objectCount()
+       */
+      public Builder objectCount(long objectCount) {
+         this.objectCount = objectCount;
+         return this;
+      }
+
+      /**
+       * @see Account#bytesUsed()
+       */
+      public Builder bytesUsed(long bytesUsed) {
+         this.bytesUsed = bytesUsed;
+         return this;
+      }
+
+      /**
+       * Will lower-case all metadata keys due to a swift implementation
+       * decision.
+       * 
+       * @see Account#metadata()
+       */
+      public Builder metadata(Map<String, String> metadata) {
+         ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String> builder();
+         for (Entry<String, String> entry : checkNotNull(metadata, "metadata").entrySet()) {
+            builder.put(entry.getKey().toLowerCase(), entry.getValue());
+         }
+         this.metadata = builder.build();
+         return this;
+      }
+
+      public Account build() {
+         return new Account(containerCount, objectCount, bytesUsed, metadata);
+      }
+
+      public Builder fromContainer(Account from) {
+         return containerCount(from.containerCount())//
+               .objectCount(from.objectCount())//
+               .bytesUsed(from.bytesUsed());
+      }
    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java
index 4a62906..612aa80 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java
@@ -26,95 +26,33 @@ import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
 
 /**
- * retrieve a list of existing storage containers ordered by name. The sort order for the name is
- * based on a binary comparison, a single built-in collating sequence that compares string data
- * using SQLite's memcmp() function, regardless of text encoding.
- * 
- * @author Adrian Cole
  * @see <a
  *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/s_listcontainers.html">api
  *      doc</a>
  */
 public class Container implements Comparable<Container> {
 
-   public static Builder builder() {
-      return new Builder();
-   }
-
-   public Builder toBuilder() {
-      return builder().fromContainer(this);
-   }
-
-   public static class Builder {
-      protected String name;
-      protected int count;
-      protected int bytes;
-
-      /**
-       * @see Container#getName()
-       */
-      public Builder name(String name) {
-         this.name = checkNotNull(name, "name");
-         return this;
-      }
-
-      /**
-       * @see Container#getCount()
-       */
-      public Builder count(int count) {
-         this.count = count;
-         return this;
-      }
-
-      /**
-       * @see Container#getBytes()
-       */
-      public Builder bytes(int bytes) {
-         this.bytes = bytes;
-         return this;
-      }
-
-      public Container build() {
-         return new Container(name, count, bytes);
-      }
-
-      public Builder fromContainer(Container from) {
-         return name(from.getName()).count(from.getCount()).bytes(from.getBytes());
-      }
-   }
-  
-   protected String name;
-   protected int count;
-   protected int bytes;
+   private final String name;
+   private final long objectCount;
+   private final long bytesUsed;
 
-   @ConstructorProperties({"name", "count", "bytes"})
-   protected Container(String name, int count, int bytes) {
+   @ConstructorProperties({ "name", "count", "bytes" })
+   protected Container(String name, long objectCount, long bytesUsed) {
       this.name = checkNotNull(name, "name");
-      this.count = count;
-      this.bytes = bytes;
+      this.objectCount = objectCount;
+      this.bytesUsed = bytesUsed;
    }
 
-   /**
-    * 
-    * @return the name of the container
-    */
-   public String getName() {
+   public String name() {
       return name;
    }
 
-   /**
-    * 
-    * @return the number of objects in the container
-    */
-   public int getCount() {
-      return count;
+   public long objectCount() {
+      return objectCount;
    }
 
-   /**
-    * @return the total bytes stored in this container
-    */
-   public int getBytes() {
-      return bytes;
+   public long bytesUsed() {
+      return bytesUsed;
    }
 
    @Override
@@ -123,9 +61,10 @@ public class Container implements Comparable<Container> {
          return true;
       }
       if (object instanceof Container) {
-         final Container other = Container.class.cast(object);
-         return equal(getName(), other.getName()) && equal(getCount(), other.getCount())
-                  && equal(getBytes(), other.getBytes());
+         final Container that = Container.class.cast(object);
+         return equal(name(), that.name()) //
+               && equal(objectCount(), that.objectCount()) //
+               && equal(bytesUsed(), that.bytesUsed());
       } else {
          return false;
       }
@@ -133,7 +72,7 @@ public class Container implements Comparable<Container> {
 
    @Override
    public int hashCode() {
-      return Objects.hashCode(getName(), getCount(), getBytes());
+      return Objects.hashCode(name(), objectCount(), bytesUsed());
    }
 
    @Override
@@ -142,7 +81,10 @@ public class Container implements Comparable<Container> {
    }
 
    protected ToStringHelper string() {
-      return toStringHelper("").add("name", getName()).add("count", getCount()).add("bytes", getBytes());
+      return toStringHelper("") //
+            .add("name", name()) //
+            .add("objectCount", objectCount()) //
+            .add("bytesUsed", bytesUsed());
    }
 
    @Override
@@ -151,7 +93,54 @@ public class Container implements Comparable<Container> {
          return 1;
       if (this == that)
          return 0;
-      return this.getName().compareTo(that.getName());
+      return this.name().compareTo(that.name());
    }
 
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromContainer(this);
+   }
+
+   public static class Builder {
+      protected String name;
+      protected long objectCount;
+      protected long bytesUsed;
+
+      /**
+       * @see Container#name()
+       */
+      public Builder name(String name) {
+         this.name = checkNotNull(name, "name");
+         return this;
+      }
+
+      /**
+       * @see Container#objectCount()
+       */
+      public Builder objectCount(long objectCount) {
+         this.objectCount = objectCount;
+         return this;
+      }
+
+      /**
+       * @see Container#bytesUsed()
+       */
+      public Builder bytesUsed(long bytesUsed) {
+         this.bytesUsed = bytesUsed;
+         return this;
+      }
+
+      public Container build() {
+         return new Container(name, objectCount, bytesUsed);
+      }
+
+      public Builder fromContainer(Container from) {
+         return name(from.name()) //
+               .objectCount(from.objectCount()) //
+               .bytesUsed(from.bytesUsed());
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
index 4c7f0e8..fe49b4e 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
@@ -16,34 +16,94 @@
  */
 package org.jclouds.openstack.swift.v1.features;
 
+import java.util.Map;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
 import javax.ws.rs.HEAD;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.swift.v1.binders.BindAccountMetadataToHeaders;
 import org.jclouds.openstack.swift.v1.domain.Account;
-import org.jclouds.openstack.swift.v1.functions.ParseAccountMetadataResponseFromHeaders;
+import org.jclouds.openstack.swift.v1.functions.ParseAccountFromHeaders;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.ResponseParser;
 
 /**
- * Storage Account Services
+ * Provides access to the Swift Account API.
+ * 
+ * <p/>
+ * Account metadata prefixed with {@code X-Account-Meta-} will be converted
+ * appropriately using a binder/parser.
  * 
- * @author Adrian Cole
- * @author Zack Shoylev
+ * @see {@link Account}
+ * @see metadata
  * @see <a
- *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/storage-account-services.html"
- *      >api doc</a>
+ *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/storage-account-services.html">
+ *      Storage Account Services API</a>
  */
 @RequestFilters(AuthenticateRequest.class)
 public interface AccountApi {
-   
+
    /**
-    * Retrieve Account Metadata
+    * Gets the {@link Account}.
+    * 
+    * @return the Account.
     * 
-    * @return account metadata including container count and bytes used
+    * @see <a
+    *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-account-metadata.html">
+    *      Get Account Metadata API</a>
     */
+   @Named("account:get")
+   @Consumes(MediaType.APPLICATION_JSON)
    @HEAD
-   @ResponseParser(ParseAccountMetadataResponseFromHeaders.class)
+   @ResponseParser(ParseAccountFromHeaders.class)
    @Path("/")
    Account get();
 
+   /**
+    * Creates or updates the Account metadata.
+    * 
+    * @param metadata
+    *           the Account metadata to create or update.
+    * 
+    * @see <a
+    *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/create-update-account-metadata.html">
+    *      Create or Update Account Metadata API</a>
+    * 
+    * @return <code>true</code> if the Account Metadata was successfully created
+    *         or updated, false if not.
+    */
+   @Named("account:createOrUpdateMetadata")
+   @Consumes
+   @POST
+   @Fallback(FalseOnNotFoundOr404.class)
+   @Path("/")
+   boolean createOrUpdateMetadata(@BinderParam(BindAccountMetadataToHeaders.class) Map<String, String> metadata);
+
+   /**
+    * Deletes Account metadata.
+    * 
+    * @param metadata
+    *           the Account metadata to delete.
+    * 
+    * @return <code>true</code> if the Account Metadata was successfully
+    *         deleted, false if not.
+    * 
+    * @see <a
+    *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/delete-account-metadata.html">
+    *      Delete Account Metadata API</a>
+    */
+   @Named("account:deleteMetadata")
+   @Consumes
+   @POST
+   @Fallback(FalseOnNotFoundOr404.class)
+   @Path("/")
+   boolean deleteMetadata(@BinderParam(BindAccountMetadataToHeaders.InRemoval.class) Map<String, String> metadata);
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/EntriesWithoutMetaPrefix.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/EntriesWithoutMetaPrefix.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/EntriesWithoutMetaPrefix.java
new file mode 100644
index 0000000..06f0eaf
--- /dev/null
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/EntriesWithoutMetaPrefix.java
@@ -0,0 +1,50 @@
+/*
+ * 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.jclouds.openstack.swift.v1.functions;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multimap;
+
+/**
+ * Extracts entries whose keys start with {@code .*-Meta-}.
+ * 
+ * @param from
+ *           a {@link Multimap} containing the prefixed headers.
+ * 
+ * @return the extracted {@code Metadata} without the prefixed keys.
+ * 
+ * @see {@link SwiftResource#metadata()}
+ */
+enum EntriesWithoutMetaPrefix implements Function<Multimap<String, String>, Map<String, String>> {
+   INSTANCE;
+
+   @Override
+   public Map<String, String> apply(Multimap<String, String> arg0) {
+      ImmutableMap.Builder<String, String> metadata = ImmutableMap.builder();
+      for (Entry<String, String> header : arg0.entries()) {
+         int index = header.getKey().indexOf("-Meta-");
+         if (index != -1) {
+            metadata.put(header.getKey().substring(index + 6), header.getValue());
+         }
+      }
+      return metadata.build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/MetadataFromHeaders.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/MetadataFromHeaders.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/MetadataFromHeaders.java
new file mode 100644
index 0000000..cdd49f1
--- /dev/null
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/MetadataFromHeaders.java
@@ -0,0 +1,31 @@
+/*
+ * 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.jclouds.openstack.swift.v1.functions;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpResponse;
+
+import com.google.common.base.Function;
+
+/** Extracts metadata entries from http response headers. */
+public class MetadataFromHeaders implements Function<HttpResponse, Map<String, String>> {
+   @Override
+   public Map<String, String> apply(HttpResponse from) {
+      return EntriesWithoutMetaPrefix.INSTANCE.apply(from.getHeaders());
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountFromHeaders.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountFromHeaders.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountFromHeaders.java
new file mode 100644
index 0000000..b03c8ec
--- /dev/null
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountFromHeaders.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.swift.v1.functions;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.swift.v1.domain.Account;
+
+import com.google.common.base.Function;
+
+public class ParseAccountFromHeaders implements Function<HttpResponse, Account> {
+
+   @Override
+   public Account apply(HttpResponse from) {
+      return Account.builder() //
+            .bytesUsed(Long.parseLong(from.getFirstHeaderOrNull("X-Account-Bytes-Used"))) //
+            .containerCount(Integer.parseInt(from.getFirstHeaderOrNull("X-Account-Container-Count"))) //
+            .objectCount(Integer.parseInt(from.getFirstHeaderOrNull("X-Account-Object-Count"))) //
+            .metadata(EntriesWithoutMetaPrefix.INSTANCE.apply(from.getHeaders())).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java
deleted file mode 100644
index 6fb20fe..0000000
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.swift.v1.functions;
-
-import org.jclouds.http.HttpResponse;
-import org.jclouds.openstack.swift.v1.domain.Account;
-
-import com.google.common.base.Function;
-
-/**
- * This parses {@link Account} from HTTP headers.
- * 
- * @author James Murty
- */
-public class ParseAccountMetadataResponseFromHeaders implements Function<HttpResponse, Account> {
-
-   /**
-    * parses the http response headers to create a new {@link Account} object.
-    */
-   public Account apply(HttpResponse from) {
-      return Account.builder()
-               .bytesUsed(Long.parseLong(from.getFirstHeaderOrNull("X-Account-Bytes-Used")))
-               .containerCount(Integer.parseInt(from.getFirstHeaderOrNull("X-Account-Container-Count")))
-               .build();
-   }
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
index 2cd5343..e71daa6 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
@@ -21,8 +21,6 @@ import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.inject.Singleton;
-
 import org.jclouds.blobstore.ContainerNotFoundException;
 import org.jclouds.blobstore.KeyNotFoundException;
 import org.jclouds.http.HttpCommand;
@@ -31,14 +29,7 @@ import org.jclouds.http.HttpResponse;
 import org.jclouds.http.HttpResponseException;
 import org.jclouds.rest.AuthorizationException;
 
-/**
- * This will parse and set an appropriate exception on the command object.
- * 
- * @author Adrian Cole
- * 
- */
 // TODO: is there error spec someplace? let's type errors, etc.
-@Singleton
 public class SwiftErrorHandler implements HttpErrorHandler {
    public static final String PREFIX = "^/v[0-9][^/]*/[a-zA-Z]+_[^/]+/";
    public static final Pattern CONTAINER_PATH = Pattern.compile(PREFIX + "([^/]+)$");

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java
new file mode 100644
index 0000000..db6ca3b
--- /dev/null
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.jclouds.openstack.swift.v1;
+
+import static com.google.common.base.Charsets.UTF_8;
+import static org.jclouds.openstack.swift.v1.features.AccountApiMockTest.accountResponse;
+import static org.testng.Assert.assertEquals;
+
+import java.util.Properties;
+
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftMockTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
+
+/**
+ * @see KeystoneProperties#CREDENTIAL_TYPE
+ * 
+ * @author Adrian Cole
+ */
+@Test
+public class AuthenticationMockTest extends BaseSwiftMockTest {
+
+   @DataProvider(name = "jclouds.keystone.credential-type")
+   Object[][] credentialTypeToPostBody() {
+      Object[][] credentialTypeToPostBody = new Object[2][2];
+      credentialTypeToPostBody[0][0] = "apiAccessKeyCredentials";
+      credentialTypeToPostBody[0][1] = "{\"auth\":{\"apiAccessKeyCredentials\":{\"accessKey\":\"joe\",\"secretKey\":\"letmein\"},\"tenantName\":\"jclouds\"}}";
+      credentialTypeToPostBody[1][0] = "passwordCredentials";
+      credentialTypeToPostBody[1][1] = "{\"auth\":{\"passwordCredentials\":{\"username\":\"joe\",\"password\":\"letmein\"},\"tenantName\":\"jclouds\"}}";
+      return credentialTypeToPostBody;
+   }
+
+   @Test(dataProvider = "jclouds.keystone.credential-type")
+   public void authenticateCredentialType(String credentialType, String expectedPost) throws Exception {
+      MockWebServer server = mockSwiftServer();
+      server.enqueue(new MockResponse().setBody(access));
+      server.enqueue(accountResponse());
+
+      try {
+         Properties overrides = new Properties();
+         overrides.setProperty("jclouds.keystone.credential-type", credentialType);
+
+         SwiftApi api = swiftApi(server.getUrl("/").toString(), overrides);
+
+         api.accountApiInRegion("DFW").get();
+
+         assertEquals(server.getRequestCount(), 2);
+         RecordedRequest authRequest = server.takeRequest();
+         assertEquals(authRequest.getRequestLine(), "POST /tokens HTTP/1.1");
+         assertEquals(new String(authRequest.getBody(), UTF_8), expectedPost);
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java
deleted file mode 100644
index 7e0a746..0000000
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.swift.v1;
-
-import static org.testng.Assert.assertEquals;
-
-import java.util.Properties;
-
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
-import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiExpectTest;
-import org.jclouds.openstack.swift.v1.parse.ParseContainerListTest;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableSet;
-
-/**
- * 
- * @see KeystoneProperties#CREDENTIAL_TYPE
- * @author Adrian Cole
- */
-@Test(groups = "unit", testName = "PasswordAuthenticationExpectTest")
-public class PasswordAuthenticationExpectTest extends BaseSwiftApiExpectTest {
-
-   /**
-    * this reflects the properties that a user would pass to createContext
-    */
-   @Override
-   protected Properties setupProperties() {
-      Properties contextProperties = super.setupProperties();
-      contextProperties.setProperty("jclouds.keystone.credential-type", "passwordCredentials");
-      return contextProperties;
-   }
-
-   public void testListContainersWhenResponseIs2xx() throws Exception {
-      HttpRequest list = HttpRequest
-            .builder()
-            .method("GET")
-            .endpoint("https://objects.jclouds.org/v1.0/40806637803162/?format=json")
-            .addHeader("Accept", "application/json")
-            .addHeader("X-Auth-Token", authToken).build();
-
-      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
-            .payload(payloadFromResource("/container_list.json")).build();
-
-      SwiftApi apiWhenContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, list, listResponse);
-
-      assertEquals(apiWhenContainersExist.getConfiguredRegions(), ImmutableSet.of("region-a.geo-1"));
-
-      assertEquals(apiWhenContainersExist.getContainerApiForRegion("region-a.geo-1").list().toString(),
-            new ParseContainerListTest().expected().toString());
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java
index 7b83ef1..99c8cd6 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java
@@ -24,7 +24,6 @@ import com.google.common.collect.ImmutableSet;
 import com.google.common.reflect.TypeToken;
 
 /**
- * 
  * @author Adrian Cole
  */
 @Test(groups = "unit", testName = "SwiftApiMetadataTest")

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java
index ddd38dd..5483175 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java
@@ -34,7 +34,6 @@ import org.jclouds.openstack.swift.v1.handlers.SwiftErrorHandler;
 import org.testng.annotations.Test;
 
 /**
- * 
  * @author Adrian Cole
  */
 @Test(groups = "unit", testName = "SwiftErrorHandlerTest")

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiExpectTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiExpectTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiExpectTest.java
deleted file mode 100644
index 3eb9bd6..0000000
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiExpectTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.swift.v1.features;
-
-import static org.testng.Assert.assertEquals;
-
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.openstack.swift.v1.SwiftApi;
-import org.jclouds.openstack.swift.v1.domain.Account;
-import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiExpectTest;
-import org.testng.annotations.Test;
-
-/**
- * @author Adrian Cole
- */
-@Test(groups = "unit", testName = "AccountApiExpectTest")
-public class AccountApiExpectTest extends BaseSwiftApiExpectTest {
-   
-   public void testGetAccountMetadataWhenResponseIs2xx() throws Exception {
-
-      HttpRequest get = HttpRequest
-            .builder()
-            .method("HEAD")
-            .endpoint("https://objects.jclouds.org/v1.0/40806637803162/")
-            .addHeader("X-Auth-Token", authToken).build();
-
-      HttpResponse listResponse = HttpResponse.builder().statusCode(204)
-            .addHeader("X-Account-Container-Count", "3")
-            .addHeader("X-Account-Bytes-Used", "323479").build();
-
-      SwiftApi apiWhenExists = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, listResponse);
-
-      assertEquals(
-            apiWhenExists.getAccountApiForRegion("region-a.geo-1").get(),
-            Account.builder().containerCount(3).bytesUsed(323479).build());
-   }
-   
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
index d112e1c..af9f879 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
@@ -16,29 +16,71 @@
  */
 package org.jclouds.openstack.swift.v1.features;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 
+import java.util.Map;
+import java.util.Map.Entry;
+
 import org.jclouds.openstack.swift.v1.domain.Account;
 import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
 import org.testng.annotations.Test;
 
-/**
- * @author Adrian Cole
- * @author Zack Shoylev
- */
-@Test(groups = "live", testName = "ContainerApiLiveTest")
+import com.google.common.collect.ImmutableMap;
+
+@Test(groups = "live", testName = "AccountApiLiveTest")
 public class AccountApiLiveTest extends BaseSwiftApiLiveTest {
 
-   @Test
-   public void testGetAccountMetadata() throws Exception {
-      for (String regionId : api.getConfiguredRegions()) {
-         AccountApi accountApi = api.getAccountApiForRegion(regionId);
+   public void get() throws Exception {
+      for (String regionId : api.configuredRegions()) {
+         AccountApi accountApi = api.accountApiInRegion(regionId);
          Account account = accountApi.get();
+
          assertNotNull(account);
-         assertTrue(account.getContainerCount() >= 0);
-         assertTrue(account.getBytesUsed() >= 0);
+         assertTrue(account.containerCount() >= 0);
+         assertTrue(account.objectCount() >= 0);
+         assertTrue(account.bytesUsed() >= 0);
+      }
+   }
+
+   public void createOrUpdateMetadata() throws Exception {
+      for (String regionId : api.configuredRegions()) {
+         AccountApi accountApi = api.accountApiInRegion(regionId);
+
+         Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar");
+
+         assertTrue(accountApi.createOrUpdateMetadata(meta));
+
+         accountHasMetadata(accountApi, meta);
       }
    }
 
+   public void deleteMetadata() throws Exception {
+      for (String regionId : api.configuredRegions()) {
+         AccountApi accountApi = api.accountApiInRegion(regionId);
+
+         Map<String, String> meta = ImmutableMap.of("MyDelete1", "foo", "MyDelete2", "bar");
+
+         assertTrue(accountApi.createOrUpdateMetadata(meta));
+         accountHasMetadata(accountApi, meta);
+
+         assertTrue(accountApi.deleteMetadata(meta));
+         Account account = accountApi.get();
+         for (Entry<String, String> entry : meta.entrySet()) {
+            // note keys are returned in lower-case!
+            assertFalse(account.metadata().containsKey(entry.getKey().toLowerCase()));
+         }
+      }
+   }
+
+   static void accountHasMetadata(AccountApi accountApi, Map<String, String> meta) {
+      Account account = accountApi.get();
+      for (Entry<String, String> entry : meta.entrySet()) {
+         // note keys are returned in lower-case!
+         assertEquals(account.metadata().get(entry.getKey().toLowerCase()), entry.getValue(), //
+               account + " didn't have metadata: " + entry);
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java
new file mode 100644
index 0000000..b561ca2
--- /dev/null
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.jclouds.openstack.swift.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.jclouds.openstack.swift.v1.SwiftApi;
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftMockTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
+
+/**
+ * @author Jeremy Daggett
+ */
+@Test
+public class AccountApiMockTest extends BaseSwiftMockTest {
+
+   /** upper-cases first char, and lower-cases rest!! **/
+   public void getKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception {
+      MockWebServer server = mockSwiftServer();
+      server.enqueue(new MockResponse().setBody(access));
+      server.enqueue(accountResponse() //
+            // note silly casing
+            .addHeader("X-Account-Meta-Apiname", "swift") //
+            .addHeader("X-Account-Meta-Apiversion", "v1.1"));
+
+      try {
+         SwiftApi api = swiftApi(server.getUrl("/").toString());
+         Map<String, String> metadata = api.accountApiInRegion("DFW").get().metadata();
+         for (Entry<String, String> entry : metadata.entrySet()) {
+            assertEquals(metadata.get(entry.getKey().toLowerCase()), entry.getValue());
+         }
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         assertEquals(server.takeRequest().getRequestLine(),
+               "HEAD /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/ HTTP/1.1");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void createOrUpdateMetadata() throws Exception {
+      MockWebServer server = mockSwiftServer();
+      server.enqueue(new MockResponse().setBody(access));
+      server.enqueue(accountResponse() //
+            .addHeader("X-Account-Meta-ApiName", "swift") //
+            .addHeader("X-Account-Meta-ApiVersion", "v1.1"));
+
+      try {
+         SwiftApi api = swiftApi(server.getUrl("/").toString());
+         assertTrue(api.accountApiInRegion("DFW").createOrUpdateMetadata(metadata));
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         RecordedRequest replaceRequest = server.takeRequest();
+         assertEquals(replaceRequest.getRequestLine(),
+               "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/ HTTP/1.1");
+         for (Entry<String, String> entry : metadata.entrySet()) {
+            assertEquals(replaceRequest.getHeader("x-account-meta-" + entry.getKey().toLowerCase()), entry.getValue());
+         }
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void deleteMetadata() throws Exception {
+      MockWebServer server = mockSwiftServer();
+      server.enqueue(new MockResponse().setBody(access));
+      server.enqueue(accountResponse());
+
+      try {
+         SwiftApi api = swiftApi(server.getUrl("/").toString());
+         assertTrue(api.accountApiInRegion("DFW").deleteMetadata(metadata));
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         RecordedRequest deleteRequest = server.takeRequest();
+         assertEquals(deleteRequest.getRequestLine(),
+               "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/ HTTP/1.1");
+         for (String key : metadata.keySet()) {
+            assertEquals(deleteRequest.getHeader("x-remove-account-meta-" + key.toLowerCase()), "ignored");
+         }
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   private final static Map<String, String> metadata = ImmutableMap.of("ApiName", "swift", "ApiVersion", "v1.1");
+
+   public static MockResponse accountResponse() {
+      return new MockResponse() //
+            .addHeader("X-Account-Container-Count", "3") //
+            .addHeader("X-Account-Object-Count", "42") //
+            .addHeader("X-Account-Bytes-Used", "323479");
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiExpectTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiExpectTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiExpectTest.java
deleted file mode 100644
index 7dd68d0..0000000
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiExpectTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.swift.v1.features;
-
-import static org.testng.Assert.assertEquals;
-
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.openstack.swift.v1.SwiftApi;
-import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiExpectTest;
-import org.jclouds.openstack.swift.v1.parse.ParseContainerListTest;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableSet;
-
-/**
- * 
- * @author Adrian Cole
- */
-@Test(groups = "unit", testName = "ContainerAsyncApiTest")
-public class ContainerApiExpectTest extends BaseSwiftApiExpectTest {
-   public void testListContainersWhenResponseIs2xx() throws Exception {
-
-      HttpRequest list = HttpRequest
-            .builder()
-            .method("GET")
-            .endpoint("https://objects.jclouds.org/v1.0/40806637803162/?format=json")
-            .addHeader("Accept", "application/json")
-            .addHeader("X-Auth-Token", authToken).build();
-
-      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
-            .payload(payloadFromResource("/container_list.json")).build();
-
-      SwiftApi apiWhenContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, list, listResponse);
-
-      assertEquals(
-            apiWhenContainersExist.getContainerApiForRegion("region-a.geo-1").list()
-                  .toString(), new ParseContainerListTest().expected().toString());
-   }
-
-   public void testListContainersWhenResponseIs404() throws Exception {
-      HttpRequest list = HttpRequest
-            .builder()
-            .method("GET")
-            .endpoint("https://objects.jclouds.org/v1.0/40806637803162/?format=json")
-            .addHeader("Accept", "application/json")
-            .addHeader("X-Auth-Token", authToken).build();
-
-      HttpResponse listResponse = HttpResponse.builder().statusCode(404).build();
-
-      SwiftApi apiWhenNoContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, list, listResponse);
-
-      assertEquals(apiWhenNoContainersExist.getContainerApiForRegion("region-a.geo-1").list().toSet(),
-               ImmutableSet.of());
-
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
index d547a45..93b248e 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
@@ -26,7 +26,6 @@ import org.testng.annotations.Test;
 import com.google.common.collect.FluentIterable;
 
 /**
- * 
  * @author Adrian Cole
  */
 @Test(groups = "live", testName = "ContainerApiLiveTest")
@@ -34,14 +33,14 @@ public class ContainerApiLiveTest extends BaseSwiftApiLiveTest {
 
    @Test
    public void testListContainers() throws Exception {
-      for (String regionId : api.getConfiguredRegions()) {
-         ContainerApi containerApi = api.getContainerApiForRegion(regionId);
+      for (String regionId : api.configuredRegions()) {
+         ContainerApi containerApi = api.containerApiInRegion(regionId);
          FluentIterable<? extends Container> response = containerApi.list();
          assertNotNull(response);
          for (Container container : response) {
-            assertNotNull(container.getName());
-            assertTrue(container.getCount() >= 0);
-            assertTrue(container.getBytes() >= 0);
+            assertNotNull(container.name());
+            assertTrue(container.objectCount() >= 0);
+            assertTrue(container.bytesUsed() >= 0);
          }
       }
    }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiExpectTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiExpectTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiExpectTest.java
deleted file mode 100644
index db521d2..0000000
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiExpectTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.swift.v1.features;
-
-import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiExpectTest;
-import org.testng.annotations.Test;
-
-/**
- * @author Adrian Cole
- */
-@Test(groups = "unit", testName = "ObjectAsyncApiTest")
-public class ObjectApiExpectTest extends BaseSwiftApiExpectTest {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiExpectTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiExpectTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiExpectTest.java
deleted file mode 100644
index 2b18142..0000000
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiExpectTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.swift.v1.internal;
-
-import org.jclouds.openstack.swift.v1.SwiftApi;
-
-/**
- * Base class for writing KeyStone Rest Api Expect tests
- * 
- * @author Adrian Cole
- */
-public class BaseSwiftApiExpectTest extends BaseSwiftExpectTest<SwiftApi> {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiLiveTest.java
index 5f09d97..fc01490 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiLiveTest.java
@@ -17,15 +17,11 @@
 package org.jclouds.openstack.swift.v1.internal;
 
 import java.util.Properties;
+
 import org.jclouds.apis.BaseApiLiveTest;
 import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
 import org.jclouds.openstack.swift.v1.SwiftApi;
 
-/**
- * Tests behavior of {@code SwiftApi}
- * 
- * @author Adrian Cole
- */
 public class BaseSwiftApiLiveTest extends BaseApiLiveTest<SwiftApi> {
 
    public BaseSwiftApiLiveTest() {

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftExpectTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftExpectTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftExpectTest.java
deleted file mode 100644
index 1d0c59a..0000000
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftExpectTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.openstack.swift.v1.internal;
-
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture;
-import org.jclouds.rest.internal.BaseRestApiExpectTest;
-
-/**
- * Base class for writing Swift Expect tests
- * 
- * @author Adrian Cole
- */
-public class BaseSwiftExpectTest<T> extends BaseRestApiExpectTest<T> {
-   protected HttpRequest keystoneAuthWithUsernameAndPassword;
-   protected HttpRequest keystoneAuthWithAccessKeyAndSecretKey;
-   protected String authToken;
-   protected HttpResponse responseWithKeystoneAccess;
-   protected HttpRequest extensionsOfSwiftRequest;
-   protected HttpResponse extensionsOfSwiftResponse;
-   protected HttpResponse unmatchedExtensionsOfSwiftResponse;
-
-   public BaseSwiftExpectTest() {
-      provider = "openstack-swift";
-      keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPasswordAndTenantName(identity,
-            credential);
-      keystoneAuthWithAccessKeyAndSecretKey = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKeyAndTenantName(identity,
-            credential);
-      
-      authToken = KeystoneFixture.INSTANCE.getAuthToken();
-      responseWithKeystoneAccess = KeystoneFixture.INSTANCE.responseWithAccess();
-      // now, createContext arg will need tenant prefix
-      identity = KeystoneFixture.INSTANCE.getTenantName() + ":" + identity;
-   }
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftMockTest.java
new file mode 100644
index 0000000..300b097
--- /dev/null
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftMockTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.jclouds.openstack.swift.v1.internal;
+
+import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
+import static org.jclouds.Constants.PROPERTY_MAX_RETRIES;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.jclouds.ContextBuilder;
+import org.jclouds.concurrent.config.ExecutorServiceModule;
+import org.jclouds.openstack.swift.v1.SwiftApi;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import com.squareup.okhttp.mockwebserver.QueueDispatcher;
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
+
+/**
+ * @author Jeremy Daggett
+ */
+public class BaseSwiftMockTest {
+
+   public static String access = "{\"access\":{\"token\":{\"id\":\"b84f4a37-5126-4603-9521-ccd0665fbde1\",\"expires\":\"2013-04-13T16:49:57.000-05:00\",\"tenant\":{\"id\":\"123123\",\"name\":\"123123\"}},\"serviceCatalog\":[{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudMonitoring\",\"type\":\"rax:monitor\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"},{\"region\":\"ORD\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"}],\"name\":\"cloudFilesCDN\",\"type\":\"rax:object-cdn\"},{\"endpoints\":[{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"},{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudLoadBalancers\",\"type\":\"rax:load-balancer\"},{\"
 endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudDatabases\",\"type\":\"rax:database\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"internalURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"},{\"region\":\"ORD\",\"tenantId\":\"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"publicURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\",\"internalURL\":\"URL/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9\"}],\"name\":\"cloudFiles\",\"type\":\"object-store\"},{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\",\"versionInfo\":\"URL/v1.0\",\"versionList\":\"URL/\",\"versionId\":\"1.0\"}],\"name\":\"cloudServers\",\"type\":\"compute\"},{\"endpoints\":[{\"re
 gion\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v2/123123\",\"versionInfo\":\"URL/v2\",\"versionList\":\"URL/\",\"versionId\":\"2\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v2/123123\",\"versionInfo\":\"URL/v2\",\"versionList\":\"URL/\",\"versionId\":\"2\"}],\"name\":\"cloudServersOpenStack\",\"type\":\"compute\"},{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudDNS\",\"type\":\"rax:dns\"},{\"endpoints\":[{\"tenantId\":\"123123\",\"publicURL\":\"URL/v1.0/123123\"}],\"name\":\"cloudBackup\",\"type\":\"rax:backup\"},{\"endpoints\":[{\"region\":\"DFW\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\"},{\"region\":\"ORD\",\"tenantId\":\"123123\",\"publicURL\":\"URL/v1/123123\"}],\"name\":\"cloudBlockStorage\",\"type\":\"volume\"}],\"user\":{\"id\":\"1234\",\"roles\":[{\"id\":\"3\",\"description\":\"User Admin Role.\",\"name\":\"identity:user-admin\"}],\"name\":\"jclouds-joe\",\"RAX-AUTH:defaultRegion\"
 :\"DFW\"}}}";
+
+   public static SwiftApi swiftApi(String uri, Properties overrides) {
+      overrides.setProperty(PROPERTY_MAX_RETRIES, "1");
+
+      return ContextBuilder.newBuilder("openstack-swift") //
+            .credentials("jclouds:joe", "letmein") //
+            .endpoint(uri) //
+            .overrides(overrides) //
+            .modules(modules) //
+            .buildApi(SwiftApi.class);
+   }
+
+   public static SwiftApi swiftApi(String uri) {
+      return swiftApi(uri, new Properties());
+   }
+
+   private static final Set<Module> modules = ImmutableSet.<Module> of(new ExecutorServiceModule(sameThreadExecutor(),
+         sameThreadExecutor()));
+
+   public static MockWebServer mockSwiftServer() throws IOException {
+      MockWebServer server = new MockWebServer();
+      server.play();
+      URL url = server.getUrl("");
+      server.setDispatcher(getURLReplacingQueueDispatcher(url));
+      return server;
+   }
+
+   /**
+    * there's no built-in way to defer evaluation of a response header, hence
+    * this method, which allows us to send back links to the mock server.
+    */
+   public static QueueDispatcher getURLReplacingQueueDispatcher(final URL url) {
+      final QueueDispatcher dispatcher = new QueueDispatcher() {
+         protected final BlockingQueue<MockResponse> responseQueue = new LinkedBlockingQueue<MockResponse>();
+
+         @Override
+         public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
+            MockResponse response = responseQueue.take();
+            if (response.getBody() != null) {
+               String newBody = new String(response.getBody()).replace(":\"URL", ":\"" + url.toString());
+               response = response.setBody(newBody);
+            }
+            return response;
+         }
+
+         @Override
+         public void enqueueResponse(MockResponse response) {
+            responseQueue.add(response);
+         }
+      };
+
+      return dispatcher;
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/options/ListContainersOptionsTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/options/ListContainersOptionsTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/options/ListContainersOptionsTest.java
index 4f4b74e..df9d4d6 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/options/ListContainersOptionsTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/options/ListContainersOptionsTest.java
@@ -26,8 +26,6 @@ import org.jclouds.http.options.HttpRequestOptions;
 import org.testng.annotations.Test;
 
 /**
- * Tests possible uses of ListContainerOptions and ListContainerOptions.Builder.*
- * 
  * @author Adrian Cole
  */
 @Test(testName = "ListContainersOptionsTest")

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/f46c86a9/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java
index fac9c5d..4101fb2 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java
@@ -28,7 +28,6 @@ import org.testng.annotations.Test;
 import com.google.common.collect.ImmutableSet;
 
 /**
- * 
  * @author Adrian Cole
  */
 @Test(groups = "unit", testName = "ParseContainerListTest")
@@ -45,13 +44,13 @@ public class ParseContainerListTest extends BaseSetParserTest<Container> {
       return ImmutableSet
             .of(Container.builder()
                   .name("test_container_1")
-                  .count(2)
-                  .bytes(78)
+                  .objectCount(2)
+                  .bytesUsed(78)
                   .build(),
                 Container.builder()
                   .name("test_container_2")
-                  .count(1)
-                  .bytes(17)
+                  .objectCount(1)
+                  .bytesUsed(17)
                   .build());
    }
 }