diff --git a/labs/openstack-swift/pom.xml b/labs/openstack-swift/pom.xml
new file mode 100644
index 0000000000..d1480dd579
--- /dev/null
+++ b/labs/openstack-swift/pom.xml
@@ -0,0 +1,151 @@
+
+
+
+ 4.0.0
+
+ org.jclouds
+ jclouds-project
+ 1.5.0-SNAPSHOT
+ ../../project/pom.xml
+
+ org.jclouds.labs
+ openstack-swift
+ jcloud openstack-swift api
+ jclouds components to access an implementation of OpenStack Swift
+ bundle
+
+
+
+ http://localhost:5000
+
+ 1.0
+
+ FIXME_IDENTITY
+ FIXME_CREDENTIALS
+ passwordCredentials
+ FIXME_HTTPURL
+ FIXME_HTTPMD5
+
+
+
+
+ org.jclouds.common
+ openstack-common
+ ${project.version}
+
+
+ org.jclouds
+ jclouds-blobstore
+ ${project.version}
+
+
+ org.jclouds
+ jclouds-core
+ ${project.version}
+ test-jar
+ test
+
+
+ org.jclouds.common
+ openstack-common
+ ${project.version}
+ test-jar
+ test
+
+
+ org.jclouds
+ jclouds-blobstore
+ ${project.version}
+ test-jar
+ test
+
+
+ org.jclouds.driver
+ jclouds-slf4j
+ ${project.version}
+ test
+
+
+ ch.qos.logback
+ logback-classic
+ 1.0.0
+ test
+
+
+
+
+
+ live
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration
+ integration-test
+
+ test
+
+
+
+ ${test.openstack-swift.endpoint}
+ ${test.openstack-swift.api-version}
+ ${test.openstack-swift.build-version}
+ ${test.openstack-swift.identity}
+ ${test.openstack-swift.credential}
+ ${test.jclouds.keystone.credential-type}
+ ${jclouds.blobstore.httpstream.url}
+ ${jclouds.blobstore.httpstream.md5}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+
+
+ ${project.artifactId}
+ org.jclouds.openstack.swift.v1*;version="${project.version}"
+
+ org.jclouds.blobstore.internal;version="${project.version}",
+ org.jclouds.rest.internal;version="${project.version}",
+ org.jclouds*;version="${project.version}",
+ *
+
+
+
+
+
+
+
+
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApiMetadata.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApiMetadata.java
new file mode 100644
index 0000000000..60a20eea8b
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApiMetadata.java
@@ -0,0 +1,100 @@
+/**
+ * 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.swift.v1;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
+import org.jclouds.openstack.services.ServiceType;
+import org.jclouds.openstack.swift.v1.config.SwiftRestClientModule;
+import org.jclouds.rest.RestContext;
+import org.jclouds.rest.internal.BaseRestApiMetadata;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for Swift 1.0 API
+ *
+ * @author Adrian Cole
+ */
+public class SwiftApiMetadata extends BaseRestApiMetadata {
+
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 6725672099385580694L;
+
+ public static final TypeToken> CONTEXT_TOKEN = new TypeToken>() {
+ private static final long serialVersionUID = -5070937833892503232L;
+ };
+
+ @Override
+ public Builder toBuilder() {
+ return new Builder().fromApiMetadata(this);
+ }
+
+ public SwiftApiMetadata() {
+ this(new Builder());
+ }
+
+ protected SwiftApiMetadata(Builder builder) {
+ super(builder);
+ }
+
+ public static Properties defaultProperties() {
+ Properties properties = BaseRestApiMetadata.defaultProperties();
+ properties.setProperty(SERVICE_TYPE, ServiceType.OBJECT_STORE);
+ // TODO: this doesn't actually do anything yet.
+ properties.setProperty(KeystoneProperties.VERSION, "2.0");
+ return properties;
+ }
+
+ public static class Builder extends BaseRestApiMetadata.Builder {
+
+ protected Builder() {
+ super(SwiftClient.class, SwiftAsyncClient.class);
+ id("openstack-swift")
+ .name("OpenStack Swift Diablo+ API")
+ .identityName("tenantId:user")
+ .credentialName("password")
+ .documentation(URI.create("http://docs.openstack.org/api/openstack-object-storage/1.0/content/ch_object-storage-dev-overview.html"))
+ .version("1.0")
+ .defaultEndpoint("http://localhost:5000")
+ .defaultProperties(SwiftApiMetadata.defaultProperties())
+ .defaultModules(ImmutableSet.>of(SwiftRestClientModule.class));
+ }
+
+ @Override
+ public SwiftApiMetadata build() {
+ return new SwiftApiMetadata(this);
+ }
+
+ @Override
+ public Builder fromApiMetadata(ApiMetadata in) {
+ super.fromApiMetadata(in);
+ return this;
+ }
+
+ }
+
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftAsyncClient.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftAsyncClient.java
new file mode 100644
index 0000000000..5f1fc80d59
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftAsyncClient.java
@@ -0,0 +1,69 @@
+/**
+ * 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.swift.v1;
+
+import java.util.Set;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.Region;
+import org.jclouds.location.functions.RegionToEndpoint;
+import org.jclouds.openstack.swift.v1.features.AccountAsyncClient;
+import org.jclouds.openstack.swift.v1.features.ContainerAsyncClient;
+import org.jclouds.openstack.swift.v1.features.ObjectAsyncClient;
+import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.EndpointParam;
+
+import com.google.inject.Provides;
+
+/**
+ * Provides asynchronous access to Swift via their REST API.
+ *
+ *
+ * @see SwiftClient
+ * @see api doc
+ * @author Adrian Cole
+ */
+public interface SwiftAsyncClient {
+ /**
+ *
+ * @return the Region codes configured
+ */
+ @Provides
+ @Region
+ Set getConfiguredRegions();
+
+ /**
+ * Provides asynchronous access to Account features.
+ */
+ @Delegate
+ AccountAsyncClient getAccountClientForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+
+ /**
+ * Provides asynchronous access to Container features.
+ */
+ @Delegate
+ ContainerAsyncClient getContainerClientForRegion(
+ @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+
+ /**
+ * Provides asynchronous access to Object features.
+ */
+ @Delegate
+ ObjectAsyncClient getObjectClientForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftClient.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftClient.java
new file mode 100644
index 0000000000..4f1e30e70c
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftClient.java
@@ -0,0 +1,71 @@
+/**
+ * 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.swift.v1;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.Region;
+import org.jclouds.location.functions.RegionToEndpoint;
+import org.jclouds.openstack.swift.v1.features.AccountClient;
+import org.jclouds.openstack.swift.v1.features.ContainerClient;
+import org.jclouds.openstack.swift.v1.features.ObjectClient;
+import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.EndpointParam;
+
+import com.google.inject.Provides;
+
+/**
+ * Provides synchronous access to Swift.
+ *
+ *
+ * @see SwiftAsyncClient
+ * @see api doc
+ * @author Adrian Cole
+ */
+@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
+public interface SwiftClient {
+ /**
+ *
+ * @return the Region codes configured
+ */
+ @Provides
+ @Region
+ Set getConfiguredRegions();
+
+ /**
+ * Provides synchronous access to Account features.
+ */
+ @Delegate
+ AccountClient getAccountClientForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+
+ /**
+ * Provides synchronous access to Container features.
+ */
+ @Delegate
+ ContainerClient getContainerClientForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+
+ /**
+ * Provides synchronous access to Object features.
+ */
+ @Delegate
+ ObjectClient getObjectClientForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftProperties.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftProperties.java
new file mode 100644
index 0000000000..57216017cf
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftProperties.java
@@ -0,0 +1,28 @@
+/**
+ * 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.swift.v1.config;
+
+/**
+ * Configuration properties and constants used in openstack Swift connections.
+ *
+ * @author Adam Lowe
+ */
+public class SwiftProperties {
+
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftRestClientModule.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftRestClientModule.java
new file mode 100644
index 0000000000..54dfd01498
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftRestClientModule.java
@@ -0,0 +1,85 @@
+/**
+ * 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.swift.v1.config;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.json.config.GsonModule.DateAdapter;
+import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
+import org.jclouds.openstack.swift.v1.SwiftAsyncClient;
+import org.jclouds.openstack.swift.v1.SwiftClient;
+import org.jclouds.openstack.swift.v1.features.AccountAsyncClient;
+import org.jclouds.openstack.swift.v1.features.AccountClient;
+import org.jclouds.openstack.swift.v1.features.ContainerAsyncClient;
+import org.jclouds.openstack.swift.v1.features.ContainerClient;
+import org.jclouds.openstack.swift.v1.features.ObjectAsyncClient;
+import org.jclouds.openstack.swift.v1.features.ObjectClient;
+import org.jclouds.openstack.swift.v1.handlers.SwiftErrorHandler;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.config.RestClientModule;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Configures the Swift connection.
+ *
+ * @author Adrian Cole
+ */
+@ConfiguresRestClient
+public class SwiftRestClientModule extends RestClientModule {
+
+ public static final Map, Class>> DELEGATE_MAP = ImmutableMap., Class>> builder()
+ .put(AccountClient.class, AccountAsyncClient.class)
+ .put(ContainerClient.class, ContainerAsyncClient.class)
+ .put(ObjectClient.class, ObjectAsyncClient.class)
+ .build();
+
+ public SwiftRestClientModule() {
+ super(DELEGATE_MAP);
+ }
+
+ @Override
+ protected void configure() {
+ bind(DateAdapter.class).to(Iso8601DateAdapter.class);
+ super.configure();
+ }
+
+ @Override
+ protected void installLocations() {
+ // TODO: select this from KeystoneProperties.VERSION; note you select from
+ // a guice provided
+ // property, so it will have to come from somewhere else, maybe we move
+ // this to the the
+ // ContextBuilder
+ install(KeystoneAuthenticationModule.forRegions());
+ super.installLocations();
+ }
+
+ @Override
+ protected void bindErrorHandlers() {
+ bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(SwiftErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(SwiftErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(SwiftErrorHandler.class);
+ }
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/AccountMetadata.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/AccountMetadata.java
new file mode 100644
index 0000000000..61a53d5c4a
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/AccountMetadata.java
@@ -0,0 +1,101 @@
+package org.jclouds.openstack.swift.v1.domain;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * @author Adrian Cole
+ * @see api doc
+ */
+public class AccountMetadata {
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().fromAccountMetadata(this);
+ }
+
+ public static class Builder {
+ protected int containerCount;
+ protected long bytesUsed;
+
+ /**
+ * @see AccountMetadata#getContainerCount()
+ */
+ public Builder containerCount(int containerCount) {
+ this.containerCount = containerCount;
+ return this;
+ }
+
+ /**
+ * @see AccountMetadata#getBytesUsed()
+ */
+ public Builder bytesUsed(long bytesUsed) {
+ this.bytesUsed = bytesUsed;
+ return this;
+ }
+
+ public AccountMetadata build() {
+ return new AccountMetadata(containerCount, bytesUsed);
+ }
+
+ public Builder fromAccountMetadata(AccountMetadata from) {
+ return containerCount(from.getContainerCount()).bytesUsed(from.getBytesUsed());
+ }
+ }
+
+ protected final int containerCount;
+ protected final long bytesUsed;
+
+ public AccountMetadata(int containerCount, long bytesUsed) {
+ this.containerCount = containerCount;
+ this.bytesUsed = bytesUsed;
+ }
+
+ /**
+ *
+ * @return the number of containers in OpenStack Object Storage for the account
+ */
+ public int getContainerCount() {
+ return containerCount;
+ }
+
+ /**
+ * @return the total bytes stored in OpenStack Object Storage for the account
+ */
+ public long getBytesUsed() {
+ return bytesUsed;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object instanceof AccountMetadata) {
+ final AccountMetadata other = AccountMetadata.class.cast(object);
+ return equal(getContainerCount(), other.getContainerCount()) && equal(getBytesUsed(), other.getBytesUsed());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(getContainerCount(), getBytesUsed());
+ }
+
+ @Override
+ public String toString() {
+ return string().toString();
+ }
+
+ protected ToStringHelper string() {
+ return toStringHelper("").add("containerCount", getContainerCount()).add("bytesUsed", getBytesUsed());
+ }
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ContainerMetadata.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ContainerMetadata.java
new file mode 100644
index 0000000000..2852022535
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ContainerMetadata.java
@@ -0,0 +1,138 @@
+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 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 api
+ * doc
+ */
+public class ContainerMetadata implements Comparable {
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().fromAccountMetadata(this);
+ }
+
+ public static class Builder {
+ protected String name;
+ protected int count;
+ protected int bytes;
+
+ /**
+ * @see ContainerMetadata#getName()
+ */
+ public Builder name(String name) {
+ this.name = checkNotNull(name, "name");
+ return this;
+ }
+
+ /**
+ * @see ContainerMetadata#getCount()
+ */
+ public Builder count(int count) {
+ this.count = count;
+ return this;
+ }
+
+ /**
+ * @see ContainerMetadata#getBytes()
+ */
+ public Builder bytes(int bytes) {
+ this.bytes = bytes;
+ return this;
+ }
+
+ public ContainerMetadata build() {
+ return new ContainerMetadata(name, count, bytes);
+ }
+
+ public Builder fromAccountMetadata(ContainerMetadata from) {
+ return name(from.getName()).count(from.getCount()).bytes(from.getBytes());
+ }
+ }
+
+ protected final String name;
+ protected final int count;
+ protected final int bytes;
+
+ public ContainerMetadata(String name, int count, int bytes) {
+ this.name = checkNotNull(name, "name");
+ this.count = count;
+ this.bytes = bytes;
+ }
+
+ /**
+ *
+ * @return the name of the container
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ *
+ * @return the number of objects in the container
+ */
+ public int getCount() {
+ return count;
+ }
+
+ /**
+ * @return the total bytes stored in this container
+ */
+ public int getBytes() {
+ return bytes;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object instanceof ContainerMetadata) {
+ final ContainerMetadata other = ContainerMetadata.class.cast(object);
+ return equal(getName(), other.getName()) && equal(getCount(), other.getCount())
+ && equal(getBytes(), other.getBytes());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(getName(), getCount(), getBytes());
+ }
+
+ @Override
+ public String toString() {
+ return string().toString();
+ }
+
+ protected ToStringHelper string() {
+ return toStringHelper("").add("name", getName()).add("count", getCount()).add("bytes", getBytes());
+ }
+
+ @Override
+ public int compareTo(ContainerMetadata that) {
+ if (that == null)
+ return 1;
+ if (this == that)
+ return 0;
+ return this.getName().compareTo(that.getName());
+ }
+
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountAsyncClient.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountAsyncClient.java
new file mode 100644
index 0000000000..c159b221cd
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountAsyncClient.java
@@ -0,0 +1,83 @@
+/**
+ * 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.swift.v1.features;
+
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.openstack.filters.AuthenticateRequest;
+import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
+import org.jclouds.openstack.swift.v1.domain.ContainerMetadata;
+import org.jclouds.openstack.swift.v1.functions.ParseAccountMetadataResponseFromHeaders;
+import org.jclouds.openstack.swift.v1.options.ListContainersOptions;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SkipEncoding;
+import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Storage Account Services
+ *
+ * @see AccountClient
+ * @author Adrian Cole
+ * @see api doc
+ */
+@SkipEncoding( { '/', '=' })
+@RequestFilters(AuthenticateRequest.class)
+public interface AccountAsyncClient {
+
+ /**
+ * @see AccountClient#getAccountMetadata
+ */
+ @HEAD
+ @ResponseParser(ParseAccountMetadataResponseFromHeaders.class)
+ @Path("/")
+ ListenableFuture getAccountMetadata();
+
+ /**
+ * @see AccountClient#listContainers()
+ */
+ @GET
+ @Consumes(MediaType.APPLICATION_JSON)
+ @QueryParams(keys = "format", values = "json")
+ @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
+ @Path("/")
+ ListenableFuture> listContainers();
+
+ /**
+ * @see AccountClient#listContainers(ListContainersOptions)
+ */
+ @GET
+ @Consumes(MediaType.APPLICATION_JSON)
+ @QueryParams(keys = "format", values = "json")
+ @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
+ @Path("/")
+ ListenableFuture> listContainers(ListContainersOptions options);
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountClient.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountClient.java
new file mode 100644
index 0000000000..a00414c61a
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountClient.java
@@ -0,0 +1,62 @@
+/**
+ * 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.swift.v1.features;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
+import org.jclouds.openstack.swift.v1.domain.ContainerMetadata;
+import org.jclouds.openstack.swift.v1.options.ListContainersOptions;
+
+/**
+ * Storage Account Services
+ *
+ * @see AccountAsyncClient
+ * @author Adrian Cole
+ * @see api doc
+ */
+@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
+public interface AccountClient {
+ /**
+ * Retrieve Account Metadata
+ *
+ * @return account metadata including container count and bytes used
+ */
+ AccountMetadata getAccountMetadata();
+
+ /**
+ * @see #listContainers(ListContainersOptions)
+ */
+ Set listContainers();
+
+ /**
+ * 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.
+ *
+ * @param options
+ * @return a list of existing storage containers ordered by name.
+ */
+ Set listContainers(ListContainersOptions options);
+
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerAsyncClient.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerAsyncClient.java
new file mode 100644
index 0000000000..68fda93deb
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerAsyncClient.java
@@ -0,0 +1,38 @@
+/**
+ * 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.swift.v1.features;
+
+import org.jclouds.openstack.filters.AuthenticateRequest;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SkipEncoding;
+
+/**
+ * Storage Container Services
+ *
+ * @see ContainerClient
+ * @author Adrian Cole
+ * @see api doc
+ */
+@SkipEncoding({ '/', '=' })
+@RequestFilters(AuthenticateRequest.class)
+public interface ContainerAsyncClient {
+
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerClient.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerClient.java
new file mode 100644
index 0000000000..fc91e8e253
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerClient.java
@@ -0,0 +1,37 @@
+/**
+ * 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.swift.v1.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+
+/**
+ * Storage Container Services
+ *
+ * @see ContainerAsyncClient
+ * @author Adrian Cole
+ * @see api doc
+ */
+@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
+public interface ContainerClient {
+
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectAsyncClient.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectAsyncClient.java
new file mode 100644
index 0000000000..597a5e2e17
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectAsyncClient.java
@@ -0,0 +1,38 @@
+/**
+ * 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.swift.v1.features;
+
+import org.jclouds.openstack.filters.AuthenticateRequest;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SkipEncoding;
+
+/**
+ * Storage Object Services
+ *
+ * @see ObjectClient
+ * @author Adrian Cole
+ * @see api doc
+ */
+@SkipEncoding( { '/', '=' })
+@RequestFilters(AuthenticateRequest.class)
+public interface ObjectAsyncClient {
+
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectClient.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectClient.java
new file mode 100644
index 0000000000..18a8145401
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectClient.java
@@ -0,0 +1,43 @@
+/**
+ * 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.swift.v1.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+
+/**
+ * Storage Object Services An object represents the data and any metadata for the files stored in
+ * the system. Through the ReST interface, metadata for an object can be included by adding custom
+ * HTTP headers to the request and the data payload as the request body. Objects cannot exceed 5GB
+ * and must have names that do not exceed 1024 bytes after URL encoding. However, objects larger
+ * than 5GB can be segmented and then concatenated together so that you can upload 5 GB segments and
+ * download a single concatenated object. You can work with the segments and manifests directly with
+ * HTTP requests.
+ *
+ * @see ObjectAsyncClient
+ * @author Adrian Cole
+ * @see api doc
+ */
+@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
+public interface ObjectClient {
+
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java
new file mode 100644
index 0000000000..e01ccadfed
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java
@@ -0,0 +1,42 @@
+/**
+ * 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.swift.v1.functions;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
+
+import com.google.common.base.Function;
+
+/**
+ * This parses {@link AccountMetadata} from HTTP headers.
+ *
+ * @author James Murty
+ */
+public class ParseAccountMetadataResponseFromHeaders implements Function {
+
+ /**
+ * parses the http response headers to create a new {@link AccountMetadata} object.
+ */
+ public AccountMetadata apply(HttpResponse from) {
+ return AccountMetadata.builder()
+ .bytesUsed(Long.parseLong(from.getFirstHeaderOrNull("X-Account-Bytes-Used")))
+ .containerCount(Integer.parseInt(from.getFirstHeaderOrNull("X-Account-Container-Count")))
+ .build();
+ }
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
new file mode 100644
index 0000000000..0437dd48e3
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
@@ -0,0 +1,82 @@
+/**
+ * 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.swift.v1.handlers;
+
+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;
+import org.jclouds.http.HttpErrorHandler;
+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 + "([^/]+)$");
+ public static final Pattern CONTAINER_KEY_PATH = Pattern.compile(PREFIX + "([^/]+)/(.*)");
+
+ 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 = message != null ? new HttpResponseException(command, response, message)
+ : new HttpResponseException(command, response);
+ message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+ response.getStatusLine());
+ switch (response.getStatusCode()) {
+ case 401:
+ exception = new AuthorizationException(exception.getMessage(), exception);
+ break;
+ case 404:
+ if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
+ String path = command.getCurrentRequest().getEndpoint().getPath();
+ Matcher matcher = CONTAINER_PATH.matcher(path);
+ Exception oldException = exception;
+ if (matcher.find()) {
+ exception = new ContainerNotFoundException(matcher.group(1), message);
+ exception.initCause(oldException);
+ } else {
+ matcher = CONTAINER_KEY_PATH.matcher(path);
+ if (matcher.find()) {
+ exception = new KeyNotFoundException(matcher.group(1), matcher.group(2), message);
+ exception.initCause(oldException);
+ }
+ }
+ }
+ break;
+ }
+ command.setException(exception);
+ }
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainersOptions.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainersOptions.java
new file mode 100644
index 0000000000..e2afee6159
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainersOptions.java
@@ -0,0 +1,79 @@
+/**
+ * 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.swift.v1.options;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Contains options supported in the REST API for the GET container operation.
+ */
+public class ListContainersOptions extends BaseHttpRequestOptions {
+ public static final ListContainersOptions NONE = new ListContainersOptions();
+
+ /**
+ * Given a string value x, return object names greater in value than the specified marker.
+ */
+ public ListContainersOptions marker(String marker) {
+ queryParameters.put("marker", checkNotNull(marker, "marker"));
+ return this;
+ }
+
+ public String getMarker() {
+ return getFirstQueryOrNull("marker");
+ }
+
+ /**
+ * For an integer value n, limits the number of results to n values.
+ */
+ public ListContainersOptions limit(int limit) {
+ checkState(limit >= 0, "limit must be >= 0");
+ checkState(limit <= 10000, "limit must be <= 10000");
+ queryParameters.put("limit", Integer.toString(limit));
+ return this;
+ }
+
+ public int getLimit() {
+ String val = getFirstQueryOrNull("limit");
+ return val != null ? new Integer(val) : 10000;
+ }
+
+
+ public static class Builder {
+
+ /**
+ * @see ListContainersOptions#marker(String)
+ */
+ public static ListContainersOptions marker(String marker) {
+ ListContainersOptions options = new ListContainersOptions();
+ return options.marker(marker);
+ }
+
+ /**
+ * @see ListContainersOptions#limit(int)
+ */
+ public static ListContainersOptions limit(int limit) {
+ ListContainersOptions options = new ListContainersOptions();
+ return options.limit(limit);
+ }
+
+ }
+}
diff --git a/labs/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/labs/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
new file mode 100644
index 0000000000..84f1200b16
--- /dev/null
+++ b/labs/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
@@ -0,0 +1 @@
+org.jclouds.openstack.swift.v1.SwiftApiMetadata
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java
new file mode 100644
index 0000000000..8ec1e81980
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java
@@ -0,0 +1,75 @@
+/**
+ * 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.swift.v1;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+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.BaseSwiftClientExpectTest;
+import org.jclouds.openstack.swift.v1.parse.ParseContainerListTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ *
+ * @see KeystoneProperties#CREDENTIAL_TYPE
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "PasswordAuthenticationExpectTest")
+public class PasswordAuthenticationExpectTest extends BaseSwiftClientExpectTest {
+
+ /**
+ * 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 listContainers = HttpRequest
+ .builder()
+ .method("GET")
+ .endpoint(URI.create("https://objects.jclouds.org/v1.0/40806637803162/?format=json"))
+ .headers(
+ ImmutableMultimap. builder().put("Accept", "application/json")
+ .put("X-Auth-Token", authToken).build()).build();
+
+ HttpResponse listContainersResponse = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResource("/container_list.json")).build();
+
+ SwiftClient clientWhenContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+ responseWithKeystoneAccess, listContainers, listContainersResponse);
+
+ assertEquals(clientWhenContainersExist.getConfiguredRegions(), ImmutableSet.of("region-a.geo-1"));
+
+ assertEquals(clientWhenContainersExist.getAccountClientForRegion("region-a.geo-1").listContainers().toString(),
+ new ParseContainerListTest().expected().toString());
+ }
+
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java
new file mode 100644
index 0000000000..2cd22db3c8
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java
@@ -0,0 +1,38 @@
+/**
+ * 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.swift.v1;
+
+import org.jclouds.Wrapper;
+import org.jclouds.apis.internal.BaseApiMetadataTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "SwiftApiMetadataTest")
+// public class SwiftApiMetadataTest extends BaseBlobStoreApiMetadataTest {
+public class SwiftApiMetadataTest extends BaseApiMetadataTest {
+ public SwiftApiMetadataTest() {
+ super(new SwiftApiMetadata(), ImmutableSet.> of());
+ }
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java
new file mode 100644
index 0000000000..bc2a762f57
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java
@@ -0,0 +1,120 @@
+/**
+ * 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.swift.v1;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reportMatcher;
+import static org.easymock.EasyMock.verify;
+
+import java.net.URI;
+
+import org.easymock.IArgumentMatcher;
+import org.jclouds.blobstore.ContainerNotFoundException;
+import org.jclouds.blobstore.KeyNotFoundException;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.io.Payloads;
+import org.jclouds.openstack.swift.v1.handlers.SwiftErrorHandler;
+import org.jclouds.util.Strings2;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "SwiftErrorHandlerTest")
+public class SwiftErrorHandlerTest {
+
+ @Test
+ public void test404SetsKeyNotFoundExceptionMosso() {
+ assertCodeMakes("HEAD", URI
+ .create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"), 404,
+ "Not Found", "", KeyNotFoundException.class);
+ }
+
+ @Test
+ public void test404SetsKeyNotFoundExceptionSwift() {
+ assertCodeMakes("HEAD", URI
+ .create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"),
+ 404, "Not Found", "", KeyNotFoundException.class);
+ }
+
+ @Test
+ public void test404SetsContainerNotFoundExceptionMosso() {
+ assertCodeMakes("HEAD", URI
+ .create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"), 404,
+ "Not Found", "", ContainerNotFoundException.class);
+ }
+
+ @Test
+ public void test404SetsContainerNotFoundExceptionSwift() {
+ assertCodeMakes("HEAD", URI
+ .create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"),
+ 404, "Not Found", "", ContainerNotFoundException.class);
+ }
+
+ private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content,
+ Class extends Exception> expected) {
+ assertCodeMakes(method, uri, statusCode, message, "text/plain", content, expected);
+ }
+
+ private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType,
+ String content, Class extends Exception> expected) {
+
+ SwiftErrorHandler function = new SwiftErrorHandler();
+
+ HttpCommand command = createMock(HttpCommand.class);
+ HttpRequest request = new HttpRequest(method, uri);
+ HttpResponse response = new HttpResponse(statusCode, message, Payloads.newInputStreamPayload(Strings2
+ .toInputStream(content)));
+ response.getPayload().getContentMetadata().setContentType(contentType);
+
+ expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
+ command.setException(classEq(expected));
+
+ replay(command);
+
+ function.handleError(command, response);
+
+ verify(command);
+ }
+
+ public static Exception classEq(final Class extends Exception> in) {
+ reportMatcher(new IArgumentMatcher() {
+
+ @Override
+ public void appendTo(StringBuffer buffer) {
+ buffer.append("classEq(");
+ buffer.append(in);
+ buffer.append(")");
+ }
+
+ @Override
+ public boolean matches(Object arg) {
+ return arg.getClass() == in;
+ }
+
+ });
+ return null;
+ }
+
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountClientExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountClientExpectTest.java
new file mode 100644
index 0000000000..5038f6cae4
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountClientExpectTest.java
@@ -0,0 +1,104 @@
+/**
+ * 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
+ *
+ * Unles 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 expres or implied. See the License for the
+ * specific language governing permisions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.swift.v1.features;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.swift.v1.SwiftClient;
+import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftClientExpectTest;
+import org.jclouds.openstack.swift.v1.parse.ParseContainerListTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "AccountClientExpectTest")
+public class AccountClientExpectTest extends BaseSwiftClientExpectTest {
+
+ public void testGetAccountMetadataWhenResponseIs2xx() throws Exception {
+
+ HttpRequest getAccountMetadata = HttpRequest
+ .builder()
+ .method("HEAD")
+ .endpoint(URI.create("https://objects.jclouds.org/v1.0/40806637803162/"))
+ .headers(
+ ImmutableMultimap. builder()
+ .put("X-Auth-Token", authToken).build()).build();
+
+ HttpResponse listContainersResponse = HttpResponse.builder().statusCode(204)
+ .headers(ImmutableMultimap.of(
+ "X-Account-Container-Count", "3",
+ "X-Account-Bytes-Used", "323479")).build();
+
+ SwiftClient clientWhenContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+ responseWithKeystoneAccess, getAccountMetadata, listContainersResponse);
+
+ assertEquals(
+ clientWhenContainersExist.getAccountClientForRegion("region-a.geo-1").getAccountMetadata(),
+ AccountMetadata.builder().containerCount(3).bytesUsed(323479).build());
+ }
+
+ public void testListContainersWhenResponseIs2xx() throws Exception {
+
+ HttpRequest listContainers = HttpRequest
+ .builder()
+ .method("GET")
+ .endpoint(URI.create("https://objects.jclouds.org/v1.0/40806637803162/?format=json"))
+ .headers(
+ ImmutableMultimap. builder().put("Accept", "application/json")
+ .put("X-Auth-Token", authToken).build()).build();
+
+ HttpResponse listContainersResponse = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResource("/container_list.json")).build();
+
+ SwiftClient clientWhenContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+ responseWithKeystoneAccess, listContainers, listContainersResponse);
+
+ assertEquals(
+ clientWhenContainersExist.getAccountClientForRegion("region-a.geo-1").listContainers()
+ .toString(), new ParseContainerListTest().expected().toString());
+ }
+
+ public void testListContainersWhenResponseIs404() throws Exception {
+ HttpRequest listContainers = HttpRequest
+ .builder()
+ .method("GET")
+ .endpoint(URI.create("https://objects.jclouds.org/v1.0/40806637803162/?format=json"))
+ .headers(
+ ImmutableMultimap. builder().put("Accept", "application/json")
+ .put("X-Auth-Token", authToken).build()).build();
+
+ HttpResponse listContainersResponse = HttpResponse.builder().statusCode(404).build();
+
+ SwiftClient clientWhenNoContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+ responseWithKeystoneAccess, listContainers, listContainersResponse);
+
+ assertEquals(clientWhenNoContainersExist.getAccountClientForRegion("region-a.geo-1").listContainers(), ImmutableSet.of());
+
+ }
+
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountClientLiveTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountClientLiveTest.java
new file mode 100644
index 0000000000..1eb410a1db
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountClientLiveTest.java
@@ -0,0 +1,61 @@
+/**
+ * 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.swift.v1.features;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
+import org.jclouds.openstack.swift.v1.domain.ContainerMetadata;
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftClientLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "live", testName = "ContainerClientLiveTest")
+public class AccountClientLiveTest extends BaseSwiftClientLiveTest {
+
+ @Test
+ public void testGetAccountMetadata() throws Exception {
+ for (String regionId : swiftContext.getApi().getConfiguredRegions()) {
+ AccountClient client = swiftContext.getApi().getAccountClientForRegion(regionId);
+ AccountMetadata account = client.getAccountMetadata();
+ assertNotNull(account);
+ assertTrue(account.getContainerCount() >= 0);
+ assertTrue(account.getBytesUsed() >= 0);
+ }
+ }
+
+ @Test
+ public void testListContainers() throws Exception {
+ for (String regionId : swiftContext.getApi().getConfiguredRegions()) {
+ AccountClient client = swiftContext.getApi().getAccountClientForRegion(regionId);
+ Set response = client.listContainers();
+ assertNotNull(response);
+ for (ContainerMetadata container : response) {
+ assertNotNull(container.getName());
+ assertTrue(container.getCount() >= 0);
+ assertTrue(container.getBytes() >= 0);
+ }
+ }
+ }
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerClientExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerClientExpectTest.java
new file mode 100644
index 0000000000..ecec4c562c
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerClientExpectTest.java
@@ -0,0 +1,31 @@
+/**
+ * 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.swift.v1.features;
+
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftClientExpectTest;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "ContainerAsyncClientTest")
+public class ContainerClientExpectTest extends BaseSwiftClientExpectTest {
+
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerClientLiveTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerClientLiveTest.java
new file mode 100644
index 0000000000..dcbe482135
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerClientLiveTest.java
@@ -0,0 +1,31 @@
+/**
+ * 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.swift.v1.features;
+
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftClientLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "live", testName = "ContainerClientLiveTest")
+public class ContainerClientLiveTest extends BaseSwiftClientLiveTest {
+
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectClientExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectClientExpectTest.java
new file mode 100644
index 0000000000..f38bf988e1
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectClientExpectTest.java
@@ -0,0 +1,30 @@
+/**
+ * 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.swift.v1.features;
+
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftClientExpectTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "ObjectAsyncClientTest")
+public class ObjectClientExpectTest extends BaseSwiftClientExpectTest {
+
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectClientLiveTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectClientLiveTest.java
new file mode 100644
index 0000000000..f8d816c48e
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectClientLiveTest.java
@@ -0,0 +1,30 @@
+/**
+ * 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.swift.v1.features;
+
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftClientLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "live", testName = "ObjectClientLiveTest")
+public class ObjectClientLiveTest extends BaseSwiftClientLiveTest {
+
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftAsyncClientExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftAsyncClientExpectTest.java
new file mode 100644
index 0000000000..1668d4276b
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftAsyncClientExpectTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.swift.v1.internal;
+
+import java.util.Properties;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.swift.v1.SwiftAsyncClient;
+
+import com.google.common.base.Function;
+import com.google.inject.Module;
+
+/**
+ * Base class for writing KeyStone Rest Client Expect tests
+ *
+ * @author Adrian Cole
+ */
+public class BaseSwiftAsyncClientExpectTest extends BaseSwiftExpectTest {
+ public SwiftAsyncClient createClient(Function fn, Module module, Properties props) {
+ return createInjector(fn, module, props).getInstance(SwiftAsyncClient.class);
+ }
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftClientExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftClientExpectTest.java
new file mode 100644
index 0000000000..b3f4330057
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftClientExpectTest.java
@@ -0,0 +1,30 @@
+/**
+ * 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.swift.v1.internal;
+
+import org.jclouds.openstack.swift.v1.SwiftClient;
+
+/**
+ * Base class for writing KeyStone Rest Client Expect tests
+ *
+ * @author Adrian Cole
+ */
+public class BaseSwiftClientExpectTest extends BaseSwiftExpectTest {
+
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftClientLiveTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftClientLiveTest.java
new file mode 100644
index 0000000000..3eb8dfb0b4
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftClientLiveTest.java
@@ -0,0 +1,74 @@
+/**
+ * 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.swift.v1.internal;
+
+import java.util.Properties;
+
+import org.jclouds.apis.BaseContextLiveTest;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
+import org.jclouds.openstack.swift.v1.SwiftApiMetadata;
+import org.jclouds.openstack.swift.v1.SwiftAsyncClient;
+import org.jclouds.openstack.swift.v1.SwiftClient;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.AfterGroups;
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.Test;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Tests behavior of {@code SwiftClient}
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "live")
+public class BaseSwiftClientLiveTest extends BaseContextLiveTest> {
+
+ public BaseSwiftClientLiveTest() {
+ provider = "openstack-swift";
+ }
+
+ protected RestContext swiftContext;
+
+ @BeforeGroups(groups = { "integration", "live" })
+ @Override
+ public void setupContext() {
+ super.setupContext();
+ swiftContext = context;
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
+ return props;
+ }
+
+ @AfterGroups(groups = "live")
+ protected void tearDown() {
+ if (swiftContext != null)
+ swiftContext.close();
+ }
+
+ @Override
+ protected TypeToken> contextType() {
+ return SwiftApiMetadata.CONTEXT_TOKEN;
+ }
+
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftExpectTest.java
new file mode 100644
index 0000000000..67d55b8832
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftExpectTest.java
@@ -0,0 +1,52 @@
+/**
+ * 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.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.BaseRestClientExpectTest;
+
+/**
+ * Base class for writing Swift Expect tests
+ *
+ * @author Adrian Cole
+ */
+public class BaseSwiftExpectTest extends BaseRestClientExpectTest {
+ 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.initialAuthWithUsernameAndPassword(identity,
+ credential);
+ keystoneAuthWithAccessKeyAndSecretKey = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKey(identity,
+ credential);
+
+ authToken = KeystoneFixture.INSTANCE.getAuthToken();
+ responseWithKeystoneAccess = KeystoneFixture.INSTANCE.responseWithAccess();
+ // now, createContext arg will need tenant prefix
+ identity = KeystoneFixture.INSTANCE.getTenantName() + ":" + identity;
+ }
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/options/ListContainersOptionsTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/options/ListContainersOptionsTest.java
new file mode 100644
index 0000000000..64b207034b
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/options/ListContainersOptionsTest.java
@@ -0,0 +1,96 @@
+/**
+ * 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.swift.v1.options;
+
+import static org.jclouds.openstack.swift.v1.options.ListContainersOptions.Builder.limit;
+import static org.jclouds.openstack.swift.v1.options.ListContainersOptions.Builder.marker;
+import static org.testng.Assert.assertEquals;
+
+import java.util.Collections;
+
+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")
+public class ListContainersOptionsTest {
+
+ @Test
+ public void testAssignability() {
+ assert HttpRequestOptions.class.isAssignableFrom(ListContainersOptions.class);
+ assert !String.class.isAssignableFrom(ListContainersOptions.class);
+ }
+ @Test
+ public void testNoOptionsQueryString() {
+ HttpRequestOptions options = new ListContainersOptions();
+ assertEquals(options.buildQueryParameters().size(), 0);
+ }
+
+ @Test
+ public void testMarker() {
+ ListContainersOptions options = new ListContainersOptions();
+ options.marker("test");
+ assertEquals(options.buildQueryParameters().get("marker"), Collections.singletonList("test"));
+ }
+
+ @Test
+ public void testNullMarker() {
+ ListContainersOptions options = new ListContainersOptions();
+ assertEquals(options.buildQueryParameters().get("marker"), Collections.EMPTY_LIST);
+ }
+
+ @Test
+ public void testMarkerStatic() {
+ ListContainersOptions options = marker("test");
+ assertEquals(options.buildQueryParameters().get("marker"), Collections.singletonList("test"));
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testMarkerNPE() {
+ marker(null);
+ }
+
+ @Test
+ public void testLimit() {
+ ListContainersOptions options = new ListContainersOptions();
+ options.limit(1000);
+ assertEquals(options.buildQueryParameters().get("limit"), Collections.singletonList("1000"));
+ }
+
+ @Test
+ public void testNullLimit() {
+ ListContainersOptions options = new ListContainersOptions();
+ assertEquals(options.buildQueryParameters().get("limit"), Collections.EMPTY_LIST);
+ }
+
+ @Test
+ public void testLimitStatic() {
+ ListContainersOptions options = limit(1000);
+ assertEquals(options.buildQueryParameters().get("limit"), Collections.singletonList("1000"));
+ }
+
+ @Test(expectedExceptions = IllegalStateException.class)
+ public void testLimitNegative() {
+ limit(-1);
+ }
+}
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java
new file mode 100644
index 0000000000..3c583121c4
--- /dev/null
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java
@@ -0,0 +1,59 @@
+/**
+ * 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.swift.v1.parse;
+
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.json.BaseSetParserTest;
+import org.jclouds.openstack.swift.v1.domain.ContainerMetadata;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "ParseContainerListTest")
+public class ParseContainerListTest extends BaseSetParserTest {
+
+ @Override
+ public String resource() {
+ return "/container_list.json";
+ }
+
+ @Override
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Set expected() {
+ return ImmutableSet
+ .of(ContainerMetadata.builder()
+ .name("test_container_1")
+ .count(2)
+ .bytes(78)
+ .build(),
+ ContainerMetadata.builder()
+ .name("test_container_2")
+ .count(1)
+ .bytes(17)
+ .build());
+ }
+}
diff --git a/labs/openstack-swift/src/test/resources/container_list.json b/labs/openstack-swift/src/test/resources/container_list.json
new file mode 100644
index 0000000000..ef7e791530
--- /dev/null
+++ b/labs/openstack-swift/src/test/resources/container_list.json
@@ -0,0 +1,4 @@
+[
+ {"name":"test_container_1", "count":2, "bytes":78},
+ {"name":"test_container_2", "count":1, "bytes":17}
+]
\ No newline at end of file
diff --git a/labs/openstack-swift/src/test/resources/logback.xml b/labs/openstack-swift/src/test/resources/logback.xml
new file mode 100644
index 0000000000..bd89efb8c0
--- /dev/null
+++ b/labs/openstack-swift/src/test/resources/logback.xml
@@ -0,0 +1,51 @@
+
+
+
+ target/test-data/jclouds.log
+
+
+ %d %-5p [%c] [%thread] %m%n
+
+
+
+
+ target/test-data/jclouds-wire.log
+
+
+ %d %-5p [%c] [%thread] %m%n
+
+
+
+
+ target/test-data/jclouds-blobstore.log
+
+
+ %d %-5p [%c] [%thread] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/labs/pom.xml b/labs/pom.xml
index 60b5dee8da..b774ad00cb 100644
--- a/labs/pom.xml
+++ b/labs/pom.xml
@@ -41,5 +41,6 @@
savvis-symphonyvpdc
dmtf
carrenza-vcloud-director
+ openstack-swift