mirror of https://github.com/apache/jclouds.git
Issue 429: added SwiftClient and SwiftAsyncClient so that we can add features in swift, but that rackspace cloudfiles doesn't support
This commit is contained in:
parent
e00b465c78
commit
db3a533a92
|
@ -29,7 +29,7 @@ import org.jclouds.blobstore.ContainerNotFoundException;
|
||||||
import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
|
import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
|
||||||
import org.jclouds.cloudfiles.options.ListCdnContainerOptions;
|
import org.jclouds.cloudfiles.options.ListCdnContainerOptions;
|
||||||
import org.jclouds.http.HttpResponseException;
|
import org.jclouds.http.HttpResponseException;
|
||||||
import org.jclouds.openstack.swift.SwiftClientLiveTest;
|
import org.jclouds.openstack.swift.CommonSwiftClientLiveTest;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
@ -41,7 +41,7 @@ import com.google.common.collect.Iterables;
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = "live")
|
@Test(groups = "live")
|
||||||
public class CloudFilesClientLiveTest extends SwiftClientLiveTest {
|
public class CloudFilesClientLiveTest extends CommonSwiftClientLiveTest<CloudFilesClient> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CloudFilesClient getApi() {
|
public CloudFilesClient getApi() {
|
||||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.openstack.swift;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.DELETE;
|
||||||
|
@ -67,11 +66,7 @@ import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides asynchronous access to Cloud Files via their REST API.
|
* Common features between OpenStack Swift and CloudFiles
|
||||||
* <p/>
|
|
||||||
* All commands return a ListenableFuture of the result from Cloud Files. Any exceptions incurred
|
|
||||||
* during processing will be wrapped in an {@link ExecutionException} as documented in
|
|
||||||
* {@link ListenableFuture#get()}.
|
|
||||||
*
|
*
|
||||||
* @see CommonSwiftClient
|
* @see CommonSwiftClient
|
||||||
* @see <a href="http://www.rackspacecloud.com/cf-devguide-20090812.pdf" />
|
* @see <a href="http://www.rackspacecloud.com/cf-devguide-20090812.pdf" />
|
||||||
|
|
|
@ -21,8 +21,6 @@ package org.jclouds.openstack.swift;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||||
|
@ -37,11 +35,7 @@ import org.jclouds.openstack.swift.domain.SwiftObject;
|
||||||
import org.jclouds.openstack.swift.options.ListContainerOptions;
|
import org.jclouds.openstack.swift.options.ListContainerOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to Cloud Files via their REST API.
|
* Common features between OpenStack Swift and CloudFiles
|
||||||
* <p/>
|
|
||||||
* All commands return a Future of the result from Cloud Files. Any exceptions incurred
|
|
||||||
* during processing will be wrapped in an {@link ExecutionException} as documented in
|
|
||||||
* {@link Future#get()}.
|
|
||||||
*
|
*
|
||||||
* @see <a href="http://www.rackspacecloud.com/cf-devguide-20090812.pdf" />
|
* @see <a href="http://www.rackspacecloud.com/cf-devguide-20090812.pdf" />
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed 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;
|
||||||
|
|
||||||
|
import org.jclouds.openstack.filters.AuthenticateRequest;
|
||||||
|
import org.jclouds.rest.annotations.Endpoint;
|
||||||
|
import org.jclouds.rest.annotations.RequestFilters;
|
||||||
|
import org.jclouds.rest.annotations.SkipEncoding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functionality that's in Swift, and not in CloudFiles.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@SkipEncoding('/')
|
||||||
|
@RequestFilters(AuthenticateRequest.class)
|
||||||
|
@Endpoint(Storage.class)
|
||||||
|
public interface SwiftAsyncClient extends CommonSwiftAsyncClient {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed 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;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.jclouds.concurrent.Timeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functionality that's in Swift, and not in CloudFiles.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
|
||||||
|
public interface SwiftClient extends CommonSwiftClient {
|
||||||
|
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ import org.jclouds.blobstore.BlobStoreContextBuilder;
|
||||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||||
import org.jclouds.logging.jdk.config.JDKLoggingModule;
|
import org.jclouds.logging.jdk.config.JDKLoggingModule;
|
||||||
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
|
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
|
||||||
import org.jclouds.openstack.swift.config.BaseSwiftRestClientModule;
|
import org.jclouds.openstack.swift.config.SwiftRestClientModule;
|
||||||
|
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Module;
|
import com.google.inject.Module;
|
||||||
|
@ -44,10 +44,10 @@ import com.google.inject.Module;
|
||||||
* @author Adrian Cole, Andrew Newdigate
|
* @author Adrian Cole, Andrew Newdigate
|
||||||
* @see CloudFilesBlobStoreContext
|
* @see CloudFilesBlobStoreContext
|
||||||
*/
|
*/
|
||||||
public class SwiftContextBuilder extends BlobStoreContextBuilder<CommonSwiftClient, CommonSwiftAsyncClient> {
|
public class SwiftContextBuilder extends BlobStoreContextBuilder<SwiftClient, SwiftAsyncClient> {
|
||||||
|
|
||||||
public SwiftContextBuilder(Properties props) {
|
public SwiftContextBuilder(Properties props) {
|
||||||
super(CommonSwiftClient.class, CommonSwiftAsyncClient.class, props);
|
super(SwiftClient.class, SwiftAsyncClient.class, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,7 +57,6 @@ public class SwiftContextBuilder extends BlobStoreContextBuilder<CommonSwiftClie
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addClientModule(List<Module> modules) {
|
protected void addClientModule(List<Module> modules) {
|
||||||
modules.add(new BaseSwiftRestClientModule<CommonSwiftClient, CommonSwiftAsyncClient>(CommonSwiftClient.class,
|
modules.add(new SwiftRestClientModule());
|
||||||
CommonSwiftAsyncClient.class));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed 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.config;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.http.RequiresHttp;
|
||||||
|
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
|
||||||
|
import org.jclouds.openstack.swift.CommonSwiftClient;
|
||||||
|
import org.jclouds.openstack.swift.SwiftAsyncClient;
|
||||||
|
import org.jclouds.openstack.swift.SwiftClient;
|
||||||
|
import org.jclouds.rest.ConfiguresRestClient;
|
||||||
|
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@ConfiguresRestClient
|
||||||
|
@RequiresHttp
|
||||||
|
public class SwiftRestClientModule extends BaseSwiftRestClientModule<SwiftClient, SwiftAsyncClient> {
|
||||||
|
|
||||||
|
public SwiftRestClientModule() {
|
||||||
|
super(SwiftClient.class, SwiftAsyncClient.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
CommonSwiftClient provideCommonSwiftClient(SwiftClient in) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
CommonSwiftAsyncClient provideCommonSwiftClient(SwiftAsyncClient in) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,286 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed 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;
|
||||||
|
|
||||||
|
import static org.jclouds.openstack.swift.options.ListContainerOptions.Builder.underPath;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.domain.PageSet;
|
||||||
|
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
|
||||||
|
import org.jclouds.crypto.CryptoStreams;
|
||||||
|
import org.jclouds.http.HttpResponseException;
|
||||||
|
import org.jclouds.http.options.GetOptions;
|
||||||
|
import org.jclouds.io.Payloads;
|
||||||
|
import org.jclouds.openstack.swift.domain.AccountMetadata;
|
||||||
|
import org.jclouds.openstack.swift.domain.ContainerMetadata;
|
||||||
|
import org.jclouds.openstack.swift.domain.MutableObjectInfoWithMetadata;
|
||||||
|
import org.jclouds.openstack.swift.domain.ObjectInfo;
|
||||||
|
import org.jclouds.openstack.swift.domain.SwiftObject;
|
||||||
|
import org.jclouds.openstack.swift.options.ListContainerOptions;
|
||||||
|
import org.jclouds.util.Strings2;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of {@code JaxrsAnnotationProcessor}
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "live")
|
||||||
|
public abstract class CommonSwiftClientLiveTest<C extends CommonSwiftClient> extends BaseBlobStoreIntegrationTest {
|
||||||
|
|
||||||
|
public abstract C getApi();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this method overrides containerName to ensure it isn't found
|
||||||
|
*/
|
||||||
|
@Test(groups = { "integration", "live" })
|
||||||
|
public void deleteContainerIfEmptyNotFound() throws Exception {
|
||||||
|
assert getApi().deleteContainerIfEmpty("dbienf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListOwnedContainers() throws Exception {
|
||||||
|
String containerPrefix = getContainerName();
|
||||||
|
try {
|
||||||
|
Set<ContainerMetadata> response = getApi().listContainers();
|
||||||
|
assertNotNull(response);
|
||||||
|
long initialContainerCount = response.size();
|
||||||
|
assertTrue(initialContainerCount >= 0);
|
||||||
|
|
||||||
|
// Create test containers
|
||||||
|
String[] containerNames = new String[] { containerPrefix + ".testListOwnedContainers1",
|
||||||
|
containerPrefix + ".testListOwnedContainers2" };
|
||||||
|
assertTrue(getApi().createContainer(containerNames[0]));
|
||||||
|
assertTrue(getApi().createContainer(containerNames[1]));
|
||||||
|
|
||||||
|
// Test default listing
|
||||||
|
response = getApi().listContainers();
|
||||||
|
// assertEquals(response.size(), initialContainerCount + 2);// if the
|
||||||
|
// containers already
|
||||||
|
// exist, this will fail
|
||||||
|
|
||||||
|
// Test listing with options
|
||||||
|
response = getApi().listContainers(
|
||||||
|
ListContainerOptions.Builder.afterMarker(
|
||||||
|
containerNames[0].substring(0, containerNames[0].length() - 1)).maxResults(1));
|
||||||
|
assertEquals(response.size(), 1);
|
||||||
|
assertEquals(Iterables.get(response, 0).getName(), containerNames[0]);
|
||||||
|
|
||||||
|
response = getApi().listContainers(ListContainerOptions.Builder.afterMarker(containerNames[0]).maxResults(1));
|
||||||
|
assertEquals(response.size(), 1);
|
||||||
|
assertEquals(Iterables.get(response, 0).getName(), containerNames[1]);
|
||||||
|
|
||||||
|
// Cleanup and test containers have been removed
|
||||||
|
assertTrue(getApi().deleteContainerIfEmpty(containerNames[0]));
|
||||||
|
assertTrue(getApi().deleteContainerIfEmpty(containerNames[1]));
|
||||||
|
response = getApi().listContainers();
|
||||||
|
// assertEquals(response.size(), initialContainerCount + 2);// if the
|
||||||
|
// containers already
|
||||||
|
// exist, this will fail
|
||||||
|
} finally {
|
||||||
|
returnContainer(containerPrefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHeadAccountMetadata() throws Exception {
|
||||||
|
String containerPrefix = getContainerName();
|
||||||
|
String containerName = containerPrefix + ".testHeadAccountMetadata";
|
||||||
|
try {
|
||||||
|
AccountMetadata metadata = getApi().getAccountStatistics();
|
||||||
|
assertNotNull(metadata);
|
||||||
|
long initialContainerCount = metadata.getContainerCount();
|
||||||
|
|
||||||
|
assertTrue(getApi().createContainer(containerName));
|
||||||
|
|
||||||
|
metadata = getApi().getAccountStatistics();
|
||||||
|
assertNotNull(metadata);
|
||||||
|
assertTrue(metadata.getContainerCount() >= initialContainerCount);
|
||||||
|
|
||||||
|
assertTrue(getApi().deleteContainerIfEmpty(containerName));
|
||||||
|
} finally {
|
||||||
|
returnContainer(containerPrefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPutContainers() throws Exception {
|
||||||
|
String containerName = getContainerName();
|
||||||
|
try {
|
||||||
|
String containerName1 = containerName + ".hello";
|
||||||
|
assertTrue(getApi().createContainer(containerName1));
|
||||||
|
// List only the container just created, using a marker with the
|
||||||
|
// container name less 1 char
|
||||||
|
Set<ContainerMetadata> response = getApi().listContainers(
|
||||||
|
ListContainerOptions.Builder.afterMarker(containerName1.substring(0, containerName1.length() - 1))
|
||||||
|
.maxResults(1));
|
||||||
|
assertNotNull(response);
|
||||||
|
assertEquals(response.size(), 1);
|
||||||
|
assertEquals(Iterables.get(response, 0).getName(), containerName + ".hello");
|
||||||
|
|
||||||
|
String containerName2 = containerName + "?should-be-illegal-question-char";
|
||||||
|
assert getApi().createContainer(containerName2);
|
||||||
|
|
||||||
|
assert getApi().createContainer(containerName + "/illegal-slash-char");
|
||||||
|
|
||||||
|
assertTrue(getApi().deleteContainerIfEmpty(containerName1));
|
||||||
|
assertTrue(getApi().deleteContainerIfEmpty(containerName2));
|
||||||
|
} finally {
|
||||||
|
returnContainer(containerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListContainerPath() throws InterruptedException, ExecutionException, TimeoutException, IOException {
|
||||||
|
String containerName = getContainerName();
|
||||||
|
try {
|
||||||
|
|
||||||
|
String data = "foo";
|
||||||
|
|
||||||
|
getApi().putObject(containerName, newSwiftObject(data, "foo"));
|
||||||
|
getApi().putObject(containerName, newSwiftObject(data, "path/bar"));
|
||||||
|
|
||||||
|
PageSet<ObjectInfo> container = getApi().listObjects(containerName, underPath(""));
|
||||||
|
assert container.getNextMarker() == null;
|
||||||
|
assertEquals(container.size(), 1);
|
||||||
|
assertEquals(Iterables.get(container, 0).getName(), "foo");
|
||||||
|
container = getApi().listObjects(containerName, underPath("path"));
|
||||||
|
assert container.getNextMarker() == null;
|
||||||
|
assertEquals(container.size(), 1);
|
||||||
|
assertEquals(Iterables.get(container, 0).getName(), "path/bar");
|
||||||
|
} finally {
|
||||||
|
returnContainer(containerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObjectOperations() throws Exception {
|
||||||
|
String containerName = getContainerName();
|
||||||
|
try {
|
||||||
|
// Test PUT with string data, ETag hash, and a piece of metadata
|
||||||
|
String data = "Here is my data";
|
||||||
|
String key = "object";
|
||||||
|
SwiftObject object = newSwiftObject(data, key);
|
||||||
|
byte[] md5 = object.getPayload().getContentMetadata().getContentMD5();
|
||||||
|
String newEtag = getApi().putObject(containerName, object);
|
||||||
|
assert newEtag != null;
|
||||||
|
assertEquals(CryptoStreams.hex(md5), CryptoStreams.hex(object.getPayload().getContentMetadata()
|
||||||
|
.getContentMD5()));
|
||||||
|
|
||||||
|
// Test HEAD of missing object
|
||||||
|
assert getApi().getObjectInfo(containerName, "non-existent-object") == null;
|
||||||
|
|
||||||
|
// Test HEAD of object
|
||||||
|
MutableObjectInfoWithMetadata metadata = getApi().getObjectInfo(containerName, object.getInfo().getName());
|
||||||
|
assertEquals(metadata.getName(), object.getInfo().getName());
|
||||||
|
|
||||||
|
assertEquals(metadata.getBytes(), new Long(data.length()));
|
||||||
|
assertEquals(metadata.getContentType(), "text/plain; charset=UTF-8");
|
||||||
|
|
||||||
|
assertEquals(CryptoStreams.hex(md5), CryptoStreams.hex(metadata.getHash()));
|
||||||
|
assertEquals(metadata.getHash(), CryptoStreams.hex(newEtag));
|
||||||
|
assertEquals(metadata.getMetadata().entrySet().size(), 1);
|
||||||
|
assertEquals(metadata.getMetadata().get("metadata"), "metadata-value");
|
||||||
|
|
||||||
|
// // Test POST to update object's metadata
|
||||||
|
Map<String, String> userMetadata = Maps.newHashMap();
|
||||||
|
userMetadata.put("New-Metadata-1", "value-1");
|
||||||
|
userMetadata.put("New-Metadata-2", "value-2");
|
||||||
|
assertTrue(getApi().setObjectInfo(containerName, object.getInfo().getName(), userMetadata));
|
||||||
|
|
||||||
|
// Test GET of missing object
|
||||||
|
assert getApi().getObject(containerName, "non-existent-object") == null;
|
||||||
|
// Test GET of object (including updated metadata)
|
||||||
|
SwiftObject getBlob = getApi().getObject(containerName, object.getInfo().getName());
|
||||||
|
assertEquals(Strings2.toStringAndClose(getBlob.getPayload().getInput()), data);
|
||||||
|
// TODO assertEquals(getBlob.getName(),
|
||||||
|
// object.getMetadata().getName());
|
||||||
|
assertEquals(getBlob.getInfo().getBytes(), new Long(data.length()));
|
||||||
|
assertEquals(getBlob.getInfo().getContentType(), "text/plain; charset=UTF-8");
|
||||||
|
assertEquals(CryptoStreams.hex(md5), CryptoStreams.hex(getBlob.getInfo().getHash()));
|
||||||
|
assertEquals(CryptoStreams.hex(newEtag), getBlob.getInfo().getHash());
|
||||||
|
assertEquals(getBlob.getInfo().getMetadata().entrySet().size(), 2);
|
||||||
|
assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-1"), "value-1");
|
||||||
|
assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-2"), "value-2");
|
||||||
|
|
||||||
|
// Test PUT with invalid ETag (as if object's data was corrupted in
|
||||||
|
// transit)
|
||||||
|
String correctEtag = newEtag;
|
||||||
|
String incorrectEtag = "0" + correctEtag.substring(1);
|
||||||
|
object.getInfo().setHash(CryptoStreams.hex(incorrectEtag));
|
||||||
|
try {
|
||||||
|
getApi().putObject(containerName, object);
|
||||||
|
} catch (HttpResponseException e) {
|
||||||
|
assertEquals(e.getResponse().getStatusCode(), 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test PUT chunked/streamed upload with data of "unknown" length
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(data.getBytes("UTF-8"));
|
||||||
|
SwiftObject blob = getApi().newSwiftObject();
|
||||||
|
blob.getInfo().setName("chunked-object");
|
||||||
|
blob.setPayload(bais);
|
||||||
|
newEtag = getApi().putObject(containerName, blob);
|
||||||
|
assertEquals(CryptoStreams.hex(md5), CryptoStreams.hex(getBlob.getInfo().getHash()));
|
||||||
|
|
||||||
|
// Test GET with options
|
||||||
|
// Non-matching ETag
|
||||||
|
try {
|
||||||
|
getApi()
|
||||||
|
.getObject(containerName, object.getInfo().getName(),
|
||||||
|
GetOptions.Builder.ifETagDoesntMatch(newEtag));
|
||||||
|
} catch (HttpResponseException e) {
|
||||||
|
assertEquals(e.getResponse().getStatusCode(), 304);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matching ETag
|
||||||
|
getBlob = getApi().getObject(containerName, object.getInfo().getName(),
|
||||||
|
GetOptions.Builder.ifETagMatches(newEtag));
|
||||||
|
assertEquals(getBlob.getInfo().getHash(), CryptoStreams.hex(newEtag));
|
||||||
|
getBlob = getApi().getObject(containerName, object.getInfo().getName(), GetOptions.Builder.startAt(8));
|
||||||
|
assertEquals(Strings2.toStringAndClose(getBlob.getPayload().getInput()), data.substring(8));
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
returnContainer(containerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SwiftObject newSwiftObject(String data, String key) throws IOException {
|
||||||
|
SwiftObject object = getApi().newSwiftObject();
|
||||||
|
object.getInfo().setName(key);
|
||||||
|
object.setPayload(data);
|
||||||
|
Payloads.calculateMD5(object);
|
||||||
|
object.getInfo().setContentType("text/plain");
|
||||||
|
object.getInfo().getMetadata().put("Metadata", "metadata-value");
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ import com.google.inject.Module;
|
||||||
*/
|
*/
|
||||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||||
@Test(groups = "unit", testName = "SwiftClientTest")
|
@Test(groups = "unit", testName = "SwiftClientTest")
|
||||||
public abstract class SwiftClientTest<A extends CommonSwiftAsyncClient> extends RestClientTest<A> {
|
public abstract class CommonSwiftClientTest<A extends CommonSwiftAsyncClient> extends RestClientTest<A> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void checkFilters(HttpRequest request) {
|
protected void checkFilters(HttpRequest request) {
|
|
@ -19,271 +19,18 @@
|
||||||
|
|
||||||
package org.jclouds.openstack.swift;
|
package org.jclouds.openstack.swift;
|
||||||
|
|
||||||
import static org.jclouds.openstack.swift.options.ListContainerOptions.Builder.underPath;
|
|
||||||
import static org.testng.Assert.assertEquals;
|
|
||||||
import static org.testng.Assert.assertNotNull;
|
|
||||||
import static org.testng.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import org.jclouds.blobstore.domain.PageSet;
|
|
||||||
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
|
|
||||||
import org.jclouds.crypto.CryptoStreams;
|
|
||||||
import org.jclouds.http.HttpResponseException;
|
|
||||||
import org.jclouds.http.options.GetOptions;
|
|
||||||
import org.jclouds.io.Payloads;
|
|
||||||
import org.jclouds.openstack.swift.CommonSwiftClient;
|
|
||||||
import org.jclouds.openstack.swift.domain.AccountMetadata;
|
|
||||||
import org.jclouds.openstack.swift.domain.ContainerMetadata;
|
|
||||||
import org.jclouds.openstack.swift.domain.MutableObjectInfoWithMetadata;
|
|
||||||
import org.jclouds.openstack.swift.domain.ObjectInfo;
|
|
||||||
import org.jclouds.openstack.swift.domain.SwiftObject;
|
|
||||||
import org.jclouds.openstack.swift.options.ListContainerOptions;
|
|
||||||
import org.jclouds.util.Strings2;
|
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests behavior of {@code JaxrsAnnotationProcessor}
|
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = "live")
|
@Test(groups = "live")
|
||||||
public class SwiftClientLiveTest extends BaseBlobStoreIntegrationTest {
|
public class SwiftClientLiveTest extends CommonSwiftClientLiveTest<SwiftClient> {
|
||||||
|
|
||||||
public CommonSwiftClient getApi() {
|
@Override
|
||||||
return (CommonSwiftClient) context.getProviderSpecificContext().getApi();
|
public SwiftClient getApi() {
|
||||||
}
|
return (SwiftClient) context.getProviderSpecificContext().getApi();
|
||||||
|
|
||||||
/**
|
|
||||||
* this method overrides containerName to ensure it isn't found
|
|
||||||
*/
|
|
||||||
@Test(groups = { "integration", "live" })
|
|
||||||
public void deleteContainerIfEmptyNotFound() throws Exception {
|
|
||||||
assert getApi().deleteContainerIfEmpty("dbienf");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testListOwnedContainers() throws Exception {
|
|
||||||
String containerPrefix = getContainerName();
|
|
||||||
try {
|
|
||||||
Set<ContainerMetadata> response = getApi().listContainers();
|
|
||||||
assertNotNull(response);
|
|
||||||
long initialContainerCount = response.size();
|
|
||||||
assertTrue(initialContainerCount >= 0);
|
|
||||||
|
|
||||||
// Create test containers
|
|
||||||
String[] containerNames = new String[] { containerPrefix + ".testListOwnedContainers1",
|
|
||||||
containerPrefix + ".testListOwnedContainers2" };
|
|
||||||
assertTrue(getApi().createContainer(containerNames[0]));
|
|
||||||
assertTrue(getApi().createContainer(containerNames[1]));
|
|
||||||
|
|
||||||
// Test default listing
|
|
||||||
response = getApi().listContainers();
|
|
||||||
// assertEquals(response.size(), initialContainerCount + 2);// if the
|
|
||||||
// containers already
|
|
||||||
// exist, this will fail
|
|
||||||
|
|
||||||
// Test listing with options
|
|
||||||
response = getApi().listContainers(
|
|
||||||
ListContainerOptions.Builder.afterMarker(
|
|
||||||
containerNames[0].substring(0, containerNames[0].length() - 1)).maxResults(1));
|
|
||||||
assertEquals(response.size(), 1);
|
|
||||||
assertEquals(Iterables.get(response, 0).getName(), containerNames[0]);
|
|
||||||
|
|
||||||
response = getApi().listContainers(ListContainerOptions.Builder.afterMarker(containerNames[0]).maxResults(1));
|
|
||||||
assertEquals(response.size(), 1);
|
|
||||||
assertEquals(Iterables.get(response, 0).getName(), containerNames[1]);
|
|
||||||
|
|
||||||
// Cleanup and test containers have been removed
|
|
||||||
assertTrue(getApi().deleteContainerIfEmpty(containerNames[0]));
|
|
||||||
assertTrue(getApi().deleteContainerIfEmpty(containerNames[1]));
|
|
||||||
response = getApi().listContainers();
|
|
||||||
// assertEquals(response.size(), initialContainerCount + 2);// if the
|
|
||||||
// containers already
|
|
||||||
// exist, this will fail
|
|
||||||
} finally {
|
|
||||||
returnContainer(containerPrefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHeadAccountMetadata() throws Exception {
|
|
||||||
String containerPrefix = getContainerName();
|
|
||||||
String containerName = containerPrefix + ".testHeadAccountMetadata";
|
|
||||||
try {
|
|
||||||
AccountMetadata metadata = getApi().getAccountStatistics();
|
|
||||||
assertNotNull(metadata);
|
|
||||||
long initialContainerCount = metadata.getContainerCount();
|
|
||||||
|
|
||||||
assertTrue(getApi().createContainer(containerName));
|
|
||||||
|
|
||||||
metadata = getApi().getAccountStatistics();
|
|
||||||
assertNotNull(metadata);
|
|
||||||
assertTrue(metadata.getContainerCount() >= initialContainerCount);
|
|
||||||
|
|
||||||
assertTrue(getApi().deleteContainerIfEmpty(containerName));
|
|
||||||
} finally {
|
|
||||||
returnContainer(containerPrefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPutContainers() throws Exception {
|
|
||||||
String containerName = getContainerName();
|
|
||||||
try {
|
|
||||||
String containerName1 = containerName + ".hello";
|
|
||||||
assertTrue(getApi().createContainer(containerName1));
|
|
||||||
// List only the container just created, using a marker with the
|
|
||||||
// container name less 1 char
|
|
||||||
Set<ContainerMetadata> response = getApi().listContainers(
|
|
||||||
ListContainerOptions.Builder.afterMarker(containerName1.substring(0, containerName1.length() - 1))
|
|
||||||
.maxResults(1));
|
|
||||||
assertNotNull(response);
|
|
||||||
assertEquals(response.size(), 1);
|
|
||||||
assertEquals(Iterables.get(response, 0).getName(), containerName + ".hello");
|
|
||||||
|
|
||||||
String containerName2 = containerName + "?should-be-illegal-question-char";
|
|
||||||
assert getApi().createContainer(containerName2);
|
|
||||||
|
|
||||||
assert getApi().createContainer(containerName + "/illegal-slash-char");
|
|
||||||
|
|
||||||
assertTrue(getApi().deleteContainerIfEmpty(containerName1));
|
|
||||||
assertTrue(getApi().deleteContainerIfEmpty(containerName2));
|
|
||||||
} finally {
|
|
||||||
returnContainer(containerName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testListContainerPath() throws InterruptedException, ExecutionException, TimeoutException, IOException {
|
|
||||||
String containerName = getContainerName();
|
|
||||||
try {
|
|
||||||
|
|
||||||
String data = "foo";
|
|
||||||
|
|
||||||
getApi().putObject(containerName, newSwiftObject(data, "foo"));
|
|
||||||
getApi().putObject(containerName, newSwiftObject(data, "path/bar"));
|
|
||||||
|
|
||||||
PageSet<ObjectInfo> container = getApi().listObjects(containerName, underPath(""));
|
|
||||||
assert container.getNextMarker() == null;
|
|
||||||
assertEquals(container.size(), 1);
|
|
||||||
assertEquals(Iterables.get(container, 0).getName(), "foo");
|
|
||||||
container = getApi().listObjects(containerName, underPath("path"));
|
|
||||||
assert container.getNextMarker() == null;
|
|
||||||
assertEquals(container.size(), 1);
|
|
||||||
assertEquals(Iterables.get(container, 0).getName(), "path/bar");
|
|
||||||
} finally {
|
|
||||||
returnContainer(containerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testObjectOperations() throws Exception {
|
|
||||||
String containerName = getContainerName();
|
|
||||||
try {
|
|
||||||
// Test PUT with string data, ETag hash, and a piece of metadata
|
|
||||||
String data = "Here is my data";
|
|
||||||
String key = "object";
|
|
||||||
SwiftObject object = newSwiftObject(data, key);
|
|
||||||
byte[] md5 = object.getPayload().getContentMetadata().getContentMD5();
|
|
||||||
String newEtag = getApi().putObject(containerName, object);
|
|
||||||
assert newEtag != null;
|
|
||||||
assertEquals(CryptoStreams.hex(md5), CryptoStreams.hex(object.getPayload().getContentMetadata()
|
|
||||||
.getContentMD5()));
|
|
||||||
|
|
||||||
// Test HEAD of missing object
|
|
||||||
assert getApi().getObjectInfo(containerName, "non-existent-object") == null;
|
|
||||||
|
|
||||||
// Test HEAD of object
|
|
||||||
MutableObjectInfoWithMetadata metadata = getApi().getObjectInfo(containerName, object.getInfo().getName());
|
|
||||||
assertEquals(metadata.getName(), object.getInfo().getName());
|
|
||||||
|
|
||||||
assertEquals(metadata.getBytes(), new Long(data.length()));
|
|
||||||
assertEquals(metadata.getContentType(), "text/plain; charset=UTF-8");
|
|
||||||
|
|
||||||
assertEquals(CryptoStreams.hex(md5), CryptoStreams.hex(metadata.getHash()));
|
|
||||||
assertEquals(metadata.getHash(), CryptoStreams.hex(newEtag));
|
|
||||||
assertEquals(metadata.getMetadata().entrySet().size(), 1);
|
|
||||||
assertEquals(metadata.getMetadata().get("metadata"), "metadata-value");
|
|
||||||
|
|
||||||
// // Test POST to update object's metadata
|
|
||||||
Map<String, String> userMetadata = Maps.newHashMap();
|
|
||||||
userMetadata.put("New-Metadata-1", "value-1");
|
|
||||||
userMetadata.put("New-Metadata-2", "value-2");
|
|
||||||
assertTrue(getApi().setObjectInfo(containerName, object.getInfo().getName(), userMetadata));
|
|
||||||
|
|
||||||
// Test GET of missing object
|
|
||||||
assert getApi().getObject(containerName, "non-existent-object") == null;
|
|
||||||
// Test GET of object (including updated metadata)
|
|
||||||
SwiftObject getBlob = getApi().getObject(containerName, object.getInfo().getName());
|
|
||||||
assertEquals(Strings2.toStringAndClose(getBlob.getPayload().getInput()), data);
|
|
||||||
// TODO assertEquals(getBlob.getName(),
|
|
||||||
// object.getMetadata().getName());
|
|
||||||
assertEquals(getBlob.getInfo().getBytes(), new Long(data.length()));
|
|
||||||
assertEquals(getBlob.getInfo().getContentType(), "text/plain; charset=UTF-8");
|
|
||||||
assertEquals(CryptoStreams.hex(md5), CryptoStreams.hex(getBlob.getInfo().getHash()));
|
|
||||||
assertEquals(CryptoStreams.hex(newEtag), getBlob.getInfo().getHash());
|
|
||||||
assertEquals(getBlob.getInfo().getMetadata().entrySet().size(), 2);
|
|
||||||
assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-1"), "value-1");
|
|
||||||
assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-2"), "value-2");
|
|
||||||
|
|
||||||
// Test PUT with invalid ETag (as if object's data was corrupted in
|
|
||||||
// transit)
|
|
||||||
String correctEtag = newEtag;
|
|
||||||
String incorrectEtag = "0" + correctEtag.substring(1);
|
|
||||||
object.getInfo().setHash(CryptoStreams.hex(incorrectEtag));
|
|
||||||
try {
|
|
||||||
getApi().putObject(containerName, object);
|
|
||||||
} catch (HttpResponseException e) {
|
|
||||||
assertEquals(e.getResponse().getStatusCode(), 422);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test PUT chunked/streamed upload with data of "unknown" length
|
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(data.getBytes("UTF-8"));
|
|
||||||
SwiftObject blob = getApi().newSwiftObject();
|
|
||||||
blob.getInfo().setName("chunked-object");
|
|
||||||
blob.setPayload(bais);
|
|
||||||
newEtag = getApi().putObject(containerName, blob);
|
|
||||||
assertEquals(CryptoStreams.hex(md5), CryptoStreams.hex(getBlob.getInfo().getHash()));
|
|
||||||
|
|
||||||
// Test GET with options
|
|
||||||
// Non-matching ETag
|
|
||||||
try {
|
|
||||||
getApi()
|
|
||||||
.getObject(containerName, object.getInfo().getName(),
|
|
||||||
GetOptions.Builder.ifETagDoesntMatch(newEtag));
|
|
||||||
} catch (HttpResponseException e) {
|
|
||||||
assertEquals(e.getResponse().getStatusCode(), 304);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matching ETag
|
|
||||||
getBlob = getApi().getObject(containerName, object.getInfo().getName(),
|
|
||||||
GetOptions.Builder.ifETagMatches(newEtag));
|
|
||||||
assertEquals(getBlob.getInfo().getHash(), CryptoStreams.hex(newEtag));
|
|
||||||
getBlob = getApi().getObject(containerName, object.getInfo().getName(), GetOptions.Builder.startAt(8));
|
|
||||||
assertEquals(Strings2.toStringAndClose(getBlob.getPayload().getInput()), data.substring(8));
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
returnContainer(containerName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private SwiftObject newSwiftObject(String data, String key) throws IOException {
|
|
||||||
SwiftObject object = getApi().newSwiftObject();
|
|
||||||
object.getInfo().setName(key);
|
|
||||||
object.setPayload(data);
|
|
||||||
Payloads.calculateMD5(object);
|
|
||||||
object.getInfo().setContentType("text/plain");
|
|
||||||
object.getInfo().getMetadata().put("Metadata", "metadata-value");
|
|
||||||
return object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import org.jclouds.http.HttpRequest;
|
||||||
import org.jclouds.io.Payload;
|
import org.jclouds.io.Payload;
|
||||||
import org.jclouds.io.Payloads;
|
import org.jclouds.io.Payloads;
|
||||||
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
|
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
|
||||||
import org.jclouds.openstack.swift.SwiftClientTest;
|
import org.jclouds.openstack.swift.CommonSwiftClientTest;
|
||||||
import org.jclouds.openstack.swift.domain.SwiftObject;
|
import org.jclouds.openstack.swift.domain.SwiftObject;
|
||||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
@ -46,7 +46,7 @@ import com.google.inject.TypeLiteral;
|
||||||
*/
|
*/
|
||||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||||
@Test(groups = "unit", testName = "BindSwiftObjectMetadataToRequestTest")
|
@Test(groups = "unit", testName = "BindSwiftObjectMetadataToRequestTest")
|
||||||
public class BindSwiftObjectMetadataToRequestTest extends SwiftClientTest<CommonSwiftAsyncClient> {
|
public class BindSwiftObjectMetadataToRequestTest extends CommonSwiftClientTest<CommonSwiftAsyncClient> {
|
||||||
@Override
|
@Override
|
||||||
protected TypeLiteral<RestAnnotationProcessor<CommonSwiftAsyncClient>> createTypeLiteral() {
|
protected TypeLiteral<RestAnnotationProcessor<CommonSwiftAsyncClient>> createTypeLiteral() {
|
||||||
return new TypeLiteral<RestAnnotationProcessor<CommonSwiftAsyncClient>>() {
|
return new TypeLiteral<RestAnnotationProcessor<CommonSwiftAsyncClient>>() {
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.Blob.Factory;
|
import org.jclouds.blobstore.domain.Blob.Factory;
|
||||||
import org.jclouds.http.HttpRequest;
|
import org.jclouds.http.HttpRequest;
|
||||||
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
|
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
|
||||||
import org.jclouds.openstack.swift.SwiftClientTest;
|
import org.jclouds.openstack.swift.CommonSwiftClientTest;
|
||||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||||
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
@ -42,7 +42,7 @@ import com.google.inject.TypeLiteral;
|
||||||
*/
|
*/
|
||||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||||
@Test(groups = "unit", testName = "SwiftBlobRequestSignerTest")
|
@Test(groups = "unit", testName = "SwiftBlobRequestSignerTest")
|
||||||
public class SwiftBlobRequestSignerTest extends SwiftClientTest<CommonSwiftAsyncClient> {
|
public class SwiftBlobRequestSignerTest extends CommonSwiftClientTest<CommonSwiftAsyncClient> {
|
||||||
@Override
|
@Override
|
||||||
protected TypeLiteral<RestAnnotationProcessor<CommonSwiftAsyncClient>> createTypeLiteral() {
|
protected TypeLiteral<RestAnnotationProcessor<CommonSwiftAsyncClient>> createTypeLiteral() {
|
||||||
return new TypeLiteral<RestAnnotationProcessor<CommonSwiftAsyncClient>>() {
|
return new TypeLiteral<RestAnnotationProcessor<CommonSwiftAsyncClient>>() {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.HeaderParam;
|
import javax.ws.rs.HeaderParam;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
|
||||||
|
import org.jclouds.Constants;
|
||||||
import org.jclouds.openstack.functions.ParseAuthenticationResponseFromHeaders;
|
import org.jclouds.openstack.functions.ParseAuthenticationResponseFromHeaders;
|
||||||
import org.jclouds.openstack.reference.AuthHeaders;
|
import org.jclouds.openstack.reference.AuthHeaders;
|
||||||
import org.jclouds.rest.annotations.ResponseParser;
|
import org.jclouds.rest.annotations.ResponseParser;
|
||||||
|
@ -43,7 +44,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
||||||
* @see <a href="http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf" />
|
* @see <a href="http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf" />
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Path("/v" + OpenStackAuthAsyncClient.VERSION)
|
@Path("/v{" + Constants.PROPERTY_API_VERSION + "}")
|
||||||
public interface OpenStackAuthAsyncClient {
|
public interface OpenStackAuthAsyncClient {
|
||||||
public static final String VERSION = "1.0";
|
public static final String VERSION = "1.0";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue