mirror of https://github.com/apache/jclouds.git
Merge pull request #827 from everett-toews/swift-copy-object-squashed-4
Squashed commits of my previous swift-copy-object pull request
This commit is contained in:
commit
b0a12bf303
|
@ -96,6 +96,7 @@ public class CloudFilesClientLiveTest extends CommonSwiftClientLiveTest<CloudFil
|
|||
Set<ContainerCDNMetadata> cdnMetadataList = getApi().listCDNContainers();
|
||||
assertTrue(cdnMetadataList.size() >= 1);
|
||||
|
||||
cdnMetadata = getApi().getCDNMetadata(containerNameWithCDN);
|
||||
final long initialTTL = cdnMetadata.getTTL();
|
||||
assertTrue(cdnMetadataList.contains(new ContainerCDNMetadata(containerNameWithCDN, true, initialTTL, cdnUri)));
|
||||
|
||||
|
|
|
@ -35,10 +35,13 @@ import org.jclouds.blobstore.binders.BindMapToHeadersWithPrefix;
|
|||
import org.jclouds.blobstore.domain.PageSet;
|
||||
import org.jclouds.blobstore.functions.ReturnFalseOnContainerNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnFalseOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnContainerNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound;
|
||||
import org.jclouds.http.functions.ParseETagHeader;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.openstack.filters.AuthenticateRequest;
|
||||
import org.jclouds.openstack.swift.binders.BindIterableToHeadersWithContainerDeleteMetadataPrefix;
|
||||
import org.jclouds.openstack.swift.binders.BindMapToHeadersWithContainerMetadataPrefix;
|
||||
import org.jclouds.openstack.swift.binders.BindSwiftObjectMetadataToRequest;
|
||||
import org.jclouds.openstack.swift.domain.AccountMetadata;
|
||||
import org.jclouds.openstack.swift.domain.ContainerMetadata;
|
||||
|
@ -47,14 +50,26 @@ import org.jclouds.openstack.swift.domain.ObjectInfo;
|
|||
import org.jclouds.openstack.swift.domain.SwiftObject;
|
||||
import org.jclouds.openstack.swift.functions.ObjectName;
|
||||
import org.jclouds.openstack.swift.functions.ParseAccountMetadataResponseFromHeaders;
|
||||
import org.jclouds.openstack.swift.functions.ParseContainerMetadataFromHeaders;
|
||||
import org.jclouds.openstack.swift.functions.ParseObjectFromHeadersAndHttpContent;
|
||||
import org.jclouds.openstack.swift.functions.ParseObjectInfoFromHeaders;
|
||||
import org.jclouds.openstack.swift.functions.ParseObjectInfoListFromJsonResponse;
|
||||
import org.jclouds.openstack.swift.functions.ReturnTrueOn404FalseOn409;
|
||||
import org.jclouds.openstack.swift.options.CreateContainerOptions;
|
||||
import org.jclouds.openstack.swift.options.ListContainerOptions;
|
||||
import org.jclouds.rest.annotations.*;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
import org.jclouds.rest.annotations.BinderParam;
|
||||
import org.jclouds.rest.annotations.Endpoint;
|
||||
import org.jclouds.rest.annotations.ExceptionParser;
|
||||
import org.jclouds.rest.annotations.Headers;
|
||||
import org.jclouds.rest.annotations.ParamParser;
|
||||
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.ReturnVoidOnNotFoundOr404;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
|
@ -89,13 +104,50 @@ public interface CommonSwiftAsyncClient {
|
|||
@Path("/")
|
||||
ListenableFuture<? extends Set<ContainerMetadata>> listContainers(ListContainerOptions... options);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#getContainerMetadata
|
||||
*/
|
||||
@Beta
|
||||
@HEAD
|
||||
@ResponseParser(ParseContainerMetadataFromHeaders.class)
|
||||
@ExceptionParser(ReturnNullOnContainerNotFound.class)
|
||||
@Path("/{container}")
|
||||
ListenableFuture<ContainerMetadata> getContainerMetadata(@PathParam("container") String container);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#setContainerMetadata
|
||||
*/
|
||||
@POST
|
||||
@Path("/{container}")
|
||||
@ExceptionParser(ReturnFalseOnContainerNotFound.class)
|
||||
ListenableFuture<Boolean> setContainerMetadata(@PathParam("container") String container,
|
||||
@BinderParam(BindMapToHeadersWithContainerMetadataPrefix.class) Map<String, String> containerMetadata);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#deleteContainerMetadata
|
||||
*/
|
||||
@POST
|
||||
@Path("/{container}")
|
||||
@ExceptionParser(ReturnFalseOnContainerNotFound.class)
|
||||
ListenableFuture<Boolean> deleteContainerMetadata(@PathParam("container") String container,
|
||||
@BinderParam(BindIterableToHeadersWithContainerDeleteMetadataPrefix.class) Iterable<String> metadataKeys);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#createContainer
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{container}")
|
||||
ListenableFuture<Boolean> createContainer(@PathParam("container") String container,
|
||||
CreateContainerOptions... options);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#setObjectInfo
|
||||
*/
|
||||
@POST
|
||||
@Path("/{container}/{name}")
|
||||
ListenableFuture<Boolean> setObjectInfo(@PathParam("container") String container, @PathParam("name") String name,
|
||||
@BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> userMetadata);
|
||||
ListenableFuture<Boolean> setObjectInfo(@PathParam("container") String container,
|
||||
@PathParam("name") String name,
|
||||
@BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> userMetadata);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#createContainer
|
||||
|
@ -120,7 +172,7 @@ public interface CommonSwiftAsyncClient {
|
|||
@ResponseParser(ParseObjectInfoListFromJsonResponse.class)
|
||||
@Path("/{container}")
|
||||
ListenableFuture<PageSet<ObjectInfo>> listObjects(@PathParam("container") String container,
|
||||
ListContainerOptions... options);
|
||||
ListContainerOptions... options);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#containerExists
|
||||
|
@ -136,9 +188,20 @@ public interface CommonSwiftAsyncClient {
|
|||
@PUT
|
||||
@Path("/{container}/{name}")
|
||||
@ResponseParser(ParseETagHeader.class)
|
||||
ListenableFuture<String> putObject(
|
||||
@PathParam("container") String container,
|
||||
@PathParam("name") @ParamParser(ObjectName.class) @BinderParam(BindSwiftObjectMetadataToRequest.class) SwiftObject object);
|
||||
ListenableFuture<String> putObject(@PathParam("container") String container,
|
||||
@PathParam("name") @ParamParser(ObjectName.class) @BinderParam(BindSwiftObjectMetadataToRequest.class) SwiftObject object);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#copyObject
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{destinationContainer}/{destinationObject}")
|
||||
@Headers(keys = SwiftHeaders.OBJECT_COPY_FROM, values = "/{sourceContainer}/{sourceObject}")
|
||||
@ExceptionParser(ReturnFalseOnContainerNotFound.class)
|
||||
ListenableFuture<Boolean> copyObject(@PathParam("sourceContainer") String sourceContainer,
|
||||
@PathParam("sourceObject") String sourceObject,
|
||||
@PathParam("destinationContainer") String destinationContainer,
|
||||
@PathParam("destinationObject") String destinationObject);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#getObject
|
||||
|
@ -147,8 +210,9 @@ public interface CommonSwiftAsyncClient {
|
|||
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
|
||||
@ExceptionParser(ReturnNullOnKeyNotFound.class)
|
||||
@Path("/{container}/{name}")
|
||||
ListenableFuture<SwiftObject> getObject(@PathParam("container") String container, @PathParam("name") String name,
|
||||
GetOptions... options);
|
||||
ListenableFuture<SwiftObject> getObject(@PathParam("container") String container,
|
||||
@PathParam("name") String name,
|
||||
GetOptions... options);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#getObjectInfo
|
||||
|
@ -158,7 +222,7 @@ public interface CommonSwiftAsyncClient {
|
|||
@ExceptionParser(ReturnNullOnKeyNotFound.class)
|
||||
@Path("/{container}/{name}")
|
||||
ListenableFuture<MutableObjectInfoWithMetadata> getObjectInfo(@PathParam("container") String container,
|
||||
@PathParam("name") String name);
|
||||
@PathParam("name") String name);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#objectExists
|
||||
|
@ -166,7 +230,8 @@ public interface CommonSwiftAsyncClient {
|
|||
@HEAD
|
||||
@ExceptionParser(ReturnFalseOnKeyNotFound.class)
|
||||
@Path("/{container}/{name}")
|
||||
ListenableFuture<Boolean> objectExists(@PathParam("container") String container, @PathParam("name") String name);
|
||||
ListenableFuture<Boolean> objectExists(@PathParam("container") String container,
|
||||
@PathParam("name") String name);
|
||||
|
||||
/**
|
||||
* @see CommonSwiftClient#removeObject
|
||||
|
@ -174,13 +239,14 @@ public interface CommonSwiftAsyncClient {
|
|||
@DELETE
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
@Path("/{container}/{name}")
|
||||
ListenableFuture<Void> removeObject(@PathParam("container") String container, @PathParam("name") String name);
|
||||
ListenableFuture<Void> removeObject(@PathParam("container") String container,
|
||||
@PathParam("name") String name);
|
||||
|
||||
@PUT
|
||||
@Path("/{container}/{name}")
|
||||
@ResponseParser(ParseETagHeader.class)
|
||||
@Headers(keys = "X-Object-Manifest", values="{container}/{name}")
|
||||
ListenableFuture<String> putObjectManifest(@PathParam("container") String container,
|
||||
@PathParam("name") String name);
|
||||
@PathParam("name") String name);
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ 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.CreateContainerOptions;
|
||||
import org.jclouds.openstack.swift.options.ListContainerOptions;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
|
@ -87,24 +88,38 @@ public interface CommonSwiftClient {
|
|||
*/
|
||||
Set<ContainerMetadata> listContainers(ListContainerOptions... options);
|
||||
|
||||
boolean setObjectInfo(String container, String name, Map<String, String> userMetadata);
|
||||
ContainerMetadata getContainerMetadata(String container);
|
||||
|
||||
boolean setContainerMetadata(String container, Map<String, String> containerMetadata);
|
||||
|
||||
boolean deleteContainerMetadata(String container, Iterable<String> metadataKeys);
|
||||
|
||||
boolean createContainer(String container);
|
||||
|
||||
boolean createContainer(String container, CreateContainerOptions... options);
|
||||
|
||||
boolean deleteContainerIfEmpty(String container);
|
||||
|
||||
PageSet<ObjectInfo> listObjects(String container, ListContainerOptions... options);
|
||||
|
||||
boolean containerExists(String container);
|
||||
|
||||
@Timeout(duration = 5 * 1024 * 1024 / 128, timeUnit = TimeUnit.SECONDS)
|
||||
String putObject(String container, SwiftObject object);
|
||||
PageSet<ObjectInfo> listObjects(String container, ListContainerOptions... options);
|
||||
|
||||
@Timeout(duration = 5 * 1024 * 1024 / 512, timeUnit = TimeUnit.SECONDS)
|
||||
SwiftObject getObject(String container, String name, GetOptions... options);
|
||||
|
||||
boolean setObjectInfo(String container, String name, Map<String, String> userMetadata);
|
||||
|
||||
MutableObjectInfoWithMetadata getObjectInfo(String container, String name);
|
||||
|
||||
@Timeout(duration = 5 * 1024 * 1024 / 128, timeUnit = TimeUnit.SECONDS)
|
||||
String putObject(String container, SwiftObject object);
|
||||
|
||||
/**
|
||||
* @return True If the object was copied
|
||||
* @throws CopyObjectException If the object was not copied
|
||||
*/
|
||||
boolean copyObject(String sourceContainer, String sourceObject, String destinationContainer, String destinationObject);
|
||||
|
||||
void removeObject(String container, String name);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* Thrown when an object cannot be copied.
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class CopyObjectException extends ResourceNotFoundException {
|
||||
|
||||
private String sourcePath;
|
||||
private String destinationPath;
|
||||
|
||||
public CopyObjectException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CopyObjectException(String sourcePath, String destinationPath, String message) {
|
||||
super(String.format("Either the source path %s or the destination path %s was not found. " +
|
||||
"(message: %s)", sourcePath, destinationPath, message));
|
||||
this.sourcePath = sourcePath;
|
||||
this.destinationPath = destinationPath;
|
||||
}
|
||||
|
||||
public CopyObjectException(Exception from) {
|
||||
super(from);
|
||||
}
|
||||
|
||||
public String getSourcePath() {
|
||||
return sourcePath;
|
||||
}
|
||||
|
||||
public String getDestinationPath() {
|
||||
return destinationPath;
|
||||
}
|
||||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -2272965726680721281L;
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* 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.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Singleton
|
||||
public class BindIterableToHeadersWithContainerDeleteMetadataPrefix implements Binder {
|
||||
private final Function<String, String> FN;
|
||||
|
||||
public BindIterableToHeadersWithContainerDeleteMetadataPrefix() {
|
||||
FN = new Function<String, String>() {
|
||||
|
||||
@Override
|
||||
public String apply(String element) {
|
||||
String inLowercase = element.toLowerCase();
|
||||
return (inLowercase.startsWith(SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX)) ? inLowercase : SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX + inLowercase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "prefix: " + SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
|
||||
checkArgument(checkNotNull(input, "input") instanceof Iterable<?>, "this binder is only valid for Iterable!");
|
||||
checkNotNull(request, "request");
|
||||
|
||||
Iterable<String> metadataKeys = Iterables.transform((Iterable<String>) input, FN);
|
||||
HashMultimap<String, String> headers = HashMultimap.create();
|
||||
|
||||
for (String metadataKey: metadataKeys) {
|
||||
headers.put(metadataKey, "");
|
||||
}
|
||||
|
||||
return (R) request.toBuilder().replaceHeaders(headers).build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package org.jclouds.openstack.swift.binders;
|
||||
|
||||
import org.jclouds.blobstore.binders.BindMapToHeadersWithPrefix;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
|
||||
public class BindMapToHeadersWithContainerMetadataPrefix extends BindMapToHeadersWithPrefix {
|
||||
|
||||
public BindMapToHeadersWithContainerMetadataPrefix() {
|
||||
super(SwiftHeaders.CONTAINER_METADATA_PREFIX);
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.hpcloud.objectstorage.functions;
|
||||
package org.jclouds.openstack.swift.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
|
@ -32,6 +32,8 @@ import org.jclouds.http.HttpErrorHandler;
|
|||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.openstack.swift.CopyObjectException;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
|
||||
/**
|
||||
|
@ -61,10 +63,21 @@ public class ParseSwiftErrorFromHttpResponse implements HttpErrorHandler {
|
|||
exception = new AuthorizationException(exception.getMessage(), exception);
|
||||
break;
|
||||
case 404:
|
||||
if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
|
||||
String sourcePath = command.getCurrentRequest().getFirstHeaderOrNull(SwiftHeaders.OBJECT_COPY_FROM);
|
||||
Exception oldException = exception;
|
||||
|
||||
if (sourcePath != null) {
|
||||
String path = command.getCurrentRequest().getEndpoint().getPath();
|
||||
int startOfDestinationPath = path.lastIndexOf("/", path.lastIndexOf("/")-1);
|
||||
String destinationPath = path.substring(startOfDestinationPath);
|
||||
|
||||
exception = new CopyObjectException(sourcePath, destinationPath, message);
|
||||
exception.initCause(oldException);
|
||||
}
|
||||
else 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);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.hpcloud.objectstorage.options;
|
||||
package org.jclouds.openstack.swift.options;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
@ -61,17 +61,11 @@ public class CreateContainerOptions extends BaseHttpRequestOptions {
|
|||
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* @see org.jclouds.hpcloud.objectstorage.options.CreateContainerOptions#withPublicAccess
|
||||
*/
|
||||
public static CreateContainerOptions withPublicAccess() {
|
||||
CreateContainerOptions options = new CreateContainerOptions();
|
||||
return options.withPublicAccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.hpcloud.objectstorage.options.CreateContainerOptions#withMetadata(Multimap<String, String>)
|
||||
*/
|
||||
public static CreateContainerOptions withMetadata(Map<String, String> metadata) {
|
||||
CreateContainerOptions options = new CreateContainerOptions();
|
||||
return (CreateContainerOptions) options.withMetadata(metadata);
|
|
@ -29,7 +29,9 @@ public interface SwiftHeaders {
|
|||
public static final String CONTAINER_BYTES_USED = "X-Container-Bytes-Used";
|
||||
public static final String CONTAINER_OBJECT_COUNT = "X-Container-Object-Count";
|
||||
public static final String CONTAINER_METADATA_PREFIX = "X-Container-Meta-";
|
||||
public static final String CONTAINER_DELETE_METADATA_PREFIX = "X-Remove-Container-Meta-";
|
||||
public static final String USER_METADATA_PREFIX = "X-Object-Meta-";
|
||||
public static final String OBJECT_COPY_FROM = "X-Copy-From";
|
||||
|
||||
public static final String CONTAINER_READ = "X-Container-Read";
|
||||
public static final String CONTAINER_WRITE = "X-Container-Write";
|
||||
|
|
|
@ -20,8 +20,10 @@ 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.assertFalse;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -274,6 +276,64 @@ public abstract class CommonSwiftClientLiveTest<C extends CommonSwiftClient> ext
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyObjectOperations() throws Exception {
|
||||
String sourceContainer = getContainerName();
|
||||
String sourceObject = "original.txt";
|
||||
String sourcePath = "/" + sourceContainer + "/" + sourceObject;
|
||||
String badSource = "badsource";
|
||||
String destinationContainer = getContainerName();
|
||||
String destinationObject = "copy.txt";
|
||||
String destinationPath = "/" + destinationContainer + "/" + destinationObject;
|
||||
String badDestination = "baddestination";
|
||||
String data = "Hello World";
|
||||
SwiftObject sourceSwiftObject = newSwiftObject(data, sourceObject);
|
||||
|
||||
getApi().putObject(sourceContainer, sourceSwiftObject);
|
||||
|
||||
// test that not giving a destination name *doesn't* copy source name to the destination container with
|
||||
// the source name but copy still returns success :(
|
||||
assertTrue(getApi().copyObject(sourceContainer, sourceObject, destinationContainer, ""));
|
||||
assertTrue(!getApi().objectExists(destinationContainer, sourceObject));
|
||||
|
||||
// test copy works
|
||||
assertTrue(getApi().copyObject(sourceContainer, sourceObject, destinationContainer, destinationObject));
|
||||
assertTrue(getApi().objectExists(destinationContainer, destinationObject));
|
||||
|
||||
SwiftObject destinationSwiftObject = getApi().getObject(destinationContainer, destinationObject);
|
||||
assertEquals(Strings2.toString(destinationSwiftObject.getPayload()), data);
|
||||
|
||||
// test exception thrown on bad destination container
|
||||
try {
|
||||
assertFalse(getApi().copyObject(sourceContainer, sourceObject, badDestination, destinationObject));
|
||||
fail("Expected CopyObjectException");
|
||||
}
|
||||
catch (CopyObjectException e) {
|
||||
assertEquals(e.getSourcePath(), sourcePath);
|
||||
assertEquals(e.getDestinationPath(), "/" + badDestination + "/" + destinationObject);
|
||||
}
|
||||
|
||||
// test exception thrown on bad source container
|
||||
try {
|
||||
assertFalse(getApi().copyObject(badSource, sourceObject, destinationContainer, destinationObject));
|
||||
fail("Expected CopyObjectException");
|
||||
}
|
||||
catch (CopyObjectException e) {
|
||||
assertEquals(e.getSourcePath(), "/" + badSource + "/" + sourceObject);
|
||||
assertEquals(e.getDestinationPath(), destinationPath);
|
||||
}
|
||||
|
||||
// test exception thrown on bad source name
|
||||
try {
|
||||
assertFalse(getApi().copyObject(sourceContainer, badSource, destinationContainer, destinationObject));
|
||||
fail("Expected CopyObjectException");
|
||||
}
|
||||
catch (CopyObjectException e) {
|
||||
assertEquals(e.getSourcePath(), "/" + sourceContainer + "/" + badSource);
|
||||
assertEquals(e.getDestinationPath(), destinationPath);
|
||||
}
|
||||
}
|
||||
|
||||
protected void testGetObjectContentType(SwiftObject getBlob) {
|
||||
String contentType = getBlob.getPayload().getContentMetadata().getContentType();
|
||||
assert contentType.startsWith("text/plain") || "application/x-www-form-urlencoded".equals(contentType): contentType;
|
||||
|
|
|
@ -23,9 +23,14 @@ import static org.testng.Assert.assertTrue;
|
|||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.openstack.swift.internal.BaseSwiftExpectTest;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
|
@ -33,7 +38,8 @@ import org.testng.annotations.Test;
|
|||
@Test(testName = "SwiftClientExpectTest")
|
||||
public class SwiftClientExpectTest extends BaseSwiftExpectTest<SwiftClient> {
|
||||
|
||||
public void testContainerExistsWhenResponseIs2xxReturnsTrue() throws Exception {
|
||||
@Test
|
||||
public void testContainerExistsWhenResponseIs2xxReturnsTrue() {
|
||||
HttpRequest headContainer = HttpRequest.builder()
|
||||
.method("HEAD")
|
||||
.endpoint(swiftEndpointWithHostReplaced + "/foo")
|
||||
|
@ -47,7 +53,8 @@ public class SwiftClientExpectTest extends BaseSwiftExpectTest<SwiftClient> {
|
|||
assertTrue(clientWhenContainerExists.containerExists("foo"));
|
||||
}
|
||||
|
||||
public void testContainerExistsWhenResponseIs404ReturnsFalse() throws Exception {
|
||||
@Test
|
||||
public void testContainerExistsWhenResponseIs404ReturnsFalse() {
|
||||
HttpRequest headContainer = HttpRequest.builder()
|
||||
.method("HEAD")
|
||||
.endpoint(swiftEndpointWithHostReplaced + "/foo")
|
||||
|
@ -59,7 +66,150 @@ public class SwiftClientExpectTest extends BaseSwiftExpectTest<SwiftClient> {
|
|||
authResponse, headContainer, headContainerResponse);
|
||||
|
||||
assertFalse(clientWhenContainerDoesntExist.containerExists("foo"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetContainerMetadataWhenResponseIs2xxReturnsTrue() {
|
||||
HttpRequest setContainerMetadataRequest = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint(swiftEndpointWithHostReplaced + "/foo")
|
||||
.addHeader(SwiftHeaders.CONTAINER_METADATA_PREFIX + "key", "value")
|
||||
.addHeader("X-Auth-Token", authToken).build();
|
||||
|
||||
HttpResponse setContainerMetadataResponse = HttpResponse.builder().statusCode(204).build();
|
||||
|
||||
SwiftClient clientSetContainerMetadata = requestsSendResponses(authRequest,
|
||||
authResponse, setContainerMetadataRequest, setContainerMetadataResponse);
|
||||
|
||||
assertTrue(clientSetContainerMetadata.setContainerMetadata("foo", ImmutableMap.<String, String> of("key", "value")));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = HttpResponseException.class)
|
||||
public void testSetContainerMetadataWhenResponseIs400ThrowsException() {
|
||||
HttpRequest setContainerMetadataRequest = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint(swiftEndpointWithHostReplaced + "/foo")
|
||||
.addHeader(SwiftHeaders.CONTAINER_METADATA_PREFIX, "value")
|
||||
.addHeader("X-Auth-Token", authToken).build();
|
||||
|
||||
HttpResponse setContainerMetadataResponse = HttpResponse.builder()
|
||||
.statusCode(400)
|
||||
.message("Metadata name cannot be empty").build();
|
||||
|
||||
SwiftClient clientSetContainerMetadata = requestsSendResponses(authRequest,
|
||||
authResponse, setContainerMetadataRequest, setContainerMetadataResponse);
|
||||
|
||||
clientSetContainerMetadata.setContainerMetadata("foo", ImmutableMap.<String, String> of("", "value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetContainerMetadataWhenResponseIs404ReturnsFalse() {
|
||||
HttpRequest setContainerMetadataRequest = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint(swiftEndpointWithHostReplaced + "/foo")
|
||||
.addHeader(SwiftHeaders.CONTAINER_METADATA_PREFIX + "key", "value")
|
||||
.addHeader("X-Auth-Token", authToken).build();
|
||||
|
||||
HttpResponse setContainerMetadataResponse = HttpResponse.builder()
|
||||
.statusCode(404).build();
|
||||
|
||||
SwiftClient clientSetContainerMetadata = requestsSendResponses(authRequest,
|
||||
authResponse, setContainerMetadataRequest, setContainerMetadataResponse);
|
||||
|
||||
assertFalse(clientSetContainerMetadata.setContainerMetadata("foo", ImmutableMap.<String, String> of("key", "value")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteContainerMetadataWhenResponseIs2xxReturnsTrue() {
|
||||
HttpRequest deleteContainerMetadataRequest = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint(swiftEndpointWithHostReplaced + "/foo")
|
||||
.addHeader(SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX + "bar", "")
|
||||
.addHeader("X-Auth-Token", authToken).build();
|
||||
|
||||
HttpResponse deleteContainerMetadataResponse = HttpResponse.builder().statusCode(204).build();
|
||||
|
||||
SwiftClient clientDeleteContainerMetadata = requestsSendResponses(authRequest,
|
||||
authResponse, deleteContainerMetadataRequest, deleteContainerMetadataResponse);
|
||||
|
||||
assertTrue(clientDeleteContainerMetadata.deleteContainerMetadata("foo", ImmutableList.<String> of("bar")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteContainerMetadataEmptyWhenResponseIs2xxReturnsTrue() {
|
||||
HttpRequest deleteContainerMetadataRequest = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint(swiftEndpointWithHostReplaced + "/foo")
|
||||
.addHeader(SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX, "")
|
||||
.addHeader("X-Auth-Token", authToken).build();
|
||||
|
||||
HttpResponse deleteContainerMetadataResponse = HttpResponse.builder().statusCode(204).build();
|
||||
|
||||
SwiftClient clientDeleteContainerMetadata = requestsSendResponses(authRequest,
|
||||
authResponse, deleteContainerMetadataRequest, deleteContainerMetadataResponse);
|
||||
|
||||
assertTrue(clientDeleteContainerMetadata.deleteContainerMetadata("foo", ImmutableList.<String> of("")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteContainerMetadataWhenResponseIs404ReturnsFalse() {
|
||||
HttpRequest deleteContainerMetadataRequest = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint(swiftEndpointWithHostReplaced + "/foo")
|
||||
.addHeader(SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX + "bar", "")
|
||||
.addHeader("X-Auth-Token", authToken).build();
|
||||
|
||||
HttpResponse deleteContainerMetadataResponse = HttpResponse.builder().statusCode(404).build();
|
||||
|
||||
SwiftClient clientDeleteContainerMetadata = requestsSendResponses(authRequest,
|
||||
authResponse, deleteContainerMetadataRequest, deleteContainerMetadataResponse);
|
||||
|
||||
assertFalse(clientDeleteContainerMetadata.deleteContainerMetadata("foo", ImmutableList.<String> of("bar")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyObjectWhenResponseIs2xxReturnsTrue() {
|
||||
String sourceContainer = "bar";
|
||||
String sourceObject = "foo.txt";
|
||||
String sourcePath = "/" + sourceContainer + "/" + sourceObject;
|
||||
String destinationContainer = "foo";
|
||||
String destinationObject = "bar.txt";
|
||||
String destinationPath = "/" + destinationContainer + "/" + destinationObject;
|
||||
|
||||
HttpRequest copyObjectRequest = HttpRequest.builder()
|
||||
.method("PUT")
|
||||
.endpoint(swiftEndpointWithHostReplaced + destinationPath)
|
||||
.addHeader(SwiftHeaders.OBJECT_COPY_FROM, sourcePath)
|
||||
.addHeader("X-Auth-Token", authToken).build();
|
||||
|
||||
HttpResponse copyObjectResponse = HttpResponse.builder().statusCode(201).build();
|
||||
|
||||
SwiftClient clientCopyObject = requestsSendResponses(authRequest,
|
||||
authResponse, copyObjectRequest, copyObjectResponse);
|
||||
|
||||
assertTrue(clientCopyObject.copyObject(sourceContainer, sourceObject, destinationContainer, destinationObject));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = CopyObjectException.class)
|
||||
public void testCopyObjectWhenResponseIs404ThrowsException() {
|
||||
String sourceContainer = "bar";
|
||||
String sourceObject = "foo.txt";
|
||||
String sourcePath = "/" + sourceContainer + "/" + sourceObject;
|
||||
String destinationContainer = "foo";
|
||||
String destinationObject = "bar.txt";
|
||||
String destinationPath = "/" + destinationContainer + "/" + destinationObject;
|
||||
|
||||
HttpRequest copyObjectRequest = HttpRequest.builder()
|
||||
.method("PUT")
|
||||
.endpoint(swiftEndpointWithHostReplaced + destinationPath)
|
||||
.addHeader(SwiftHeaders.OBJECT_COPY_FROM, sourcePath)
|
||||
.addHeader("X-Auth-Token", authToken).build();
|
||||
|
||||
HttpResponse copyObjectResponse = HttpResponse.builder().statusCode(404).build();
|
||||
|
||||
SwiftClient clientCopyObject = requestsSendResponses(authRequest,
|
||||
authResponse, copyObjectRequest, copyObjectResponse);
|
||||
|
||||
assertTrue(clientCopyObject.copyObject(sourceContainer, sourceObject, destinationContainer, destinationObject));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* 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.binders;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.openstack.swift.CommonSwiftClientTest;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code BindIterableToHeadersWithContainerDeleteMetadataPrefix}
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||
@Test(groups = "unit", testName = "BindIterableToHeadersWithContainerDeleteMetadataPrefixTest")
|
||||
public class BindIterableToHeadersWithContainerDeleteMetadataPrefixTest extends CommonSwiftClientTest {
|
||||
|
||||
@Test
|
||||
public void testMetadataKeysBind() {
|
||||
List<String> metadataKeys = ImmutableList.of("foo", "bar");
|
||||
|
||||
HttpRequest request = HttpRequest.builder().method("PUT").endpoint("http://localhost").build();
|
||||
BindIterableToHeadersWithContainerDeleteMetadataPrefix binder =
|
||||
injector.getInstance(BindIterableToHeadersWithContainerDeleteMetadataPrefix.class);
|
||||
|
||||
HttpRequest actualRequest = binder.bindToRequest(request, metadataKeys);
|
||||
HttpRequest expectedRequest = HttpRequest.builder()
|
||||
.method("PUT")
|
||||
.endpoint("http://localhost")
|
||||
.addHeader(SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX + "foo", "")
|
||||
.addHeader(SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX + "bar", "")
|
||||
.build();
|
||||
|
||||
assertEquals(actualRequest, expectedRequest);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullListIsBad() {
|
||||
HttpRequest request = HttpRequest.builder().method("PUT").endpoint("http://localhost").build();
|
||||
BindIterableToHeadersWithContainerDeleteMetadataPrefix binder =
|
||||
injector.getInstance(BindIterableToHeadersWithContainerDeleteMetadataPrefix.class);
|
||||
|
||||
binder.bindToRequest(request, null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullRequestIsBad() {
|
||||
List<String> metadataKeys = ImmutableList.of("foo", "bar");
|
||||
BindIterableToHeadersWithContainerDeleteMetadataPrefix binder =
|
||||
injector.getInstance(BindIterableToHeadersWithContainerDeleteMetadataPrefix.class);
|
||||
|
||||
binder.bindToRequest(null, metadataKeys);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* 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.binders;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.openstack.swift.CommonSwiftClientTest;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code BindListToHeadersWithContainerDeleteMetadataPrefix}
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||
@Test(groups = "unit", testName = "BindListToHeadersWithContainerDeleteMetadataPrefixTest")
|
||||
public class BindMapToHeadersWithContainerMetadataPrefixTest extends CommonSwiftClientTest {
|
||||
|
||||
@Test
|
||||
public void testMetadataKeysBind() {
|
||||
List<String> metadataKeys = ImmutableList.of("foo", "bar");
|
||||
|
||||
HttpRequest request = HttpRequest.builder().method("PUT").endpoint("http://localhost").build();
|
||||
BindIterableToHeadersWithContainerDeleteMetadataPrefix binder =
|
||||
injector.getInstance(BindIterableToHeadersWithContainerDeleteMetadataPrefix.class);
|
||||
|
||||
HttpRequest actualRequest = binder.bindToRequest(request, metadataKeys);
|
||||
HttpRequest expectedRequest = HttpRequest.builder()
|
||||
.method("PUT")
|
||||
.endpoint("http://localhost")
|
||||
.addHeader(SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX + "foo", "")
|
||||
.addHeader(SwiftHeaders.CONTAINER_DELETE_METADATA_PREFIX + "bar", "")
|
||||
.build();
|
||||
|
||||
assertEquals(actualRequest, expectedRequest);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullListIsBad() {
|
||||
HttpRequest request = HttpRequest.builder().method("PUT").endpoint("http://localhost").build();
|
||||
BindIterableToHeadersWithContainerDeleteMetadataPrefix binder =
|
||||
injector.getInstance(BindIterableToHeadersWithContainerDeleteMetadataPrefix.class);
|
||||
|
||||
binder.bindToRequest(request, null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullRequestIsBad() {
|
||||
List<String> metadataKeys = ImmutableList.of("foo", "bar");
|
||||
BindIterableToHeadersWithContainerDeleteMetadataPrefix binder =
|
||||
injector.getInstance(BindIterableToHeadersWithContainerDeleteMetadataPrefix.class);
|
||||
|
||||
binder.bindToRequest(null, metadataKeys);
|
||||
}
|
||||
}
|
|
@ -18,15 +18,28 @@
|
|||
*/
|
||||
package org.jclouds.openstack.swift.blobstore.integration;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
|
||||
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
|
||||
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
|
||||
import org.jclouds.openstack.swift.CommonSwiftClient;
|
||||
import org.jclouds.openstack.swift.domain.ContainerMetadata;
|
||||
import org.jclouds.openstack.swift.options.CreateContainerOptions;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* @author James Murty
|
||||
* @author Adrian Cole
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Test(groups = "live")
|
||||
public class SwiftContainerIntegrationLiveTest extends BaseContainerIntegrationTest {
|
||||
|
@ -40,4 +53,53 @@ public class SwiftContainerIntegrationLiveTest extends BaseContainerIntegrationT
|
|||
public SwiftContainerIntegrationLiveTest() {
|
||||
provider = System.getProperty("test.swift.provider", "swift");
|
||||
}
|
||||
|
||||
@Test(groups = "live")
|
||||
public void testSetGetContainerMetadata() throws InterruptedException {
|
||||
BlobStore blobStore = view.getBlobStore();
|
||||
RestContext<CommonSwiftClient, CommonSwiftAsyncClient> swift = blobStore.getContext().unwrap();
|
||||
String containerName = getContainerName();
|
||||
|
||||
assertTrue(swift.getApi().createContainer(containerName));
|
||||
|
||||
ImmutableMap<String, String> metadata = ImmutableMap.<String, String> of(
|
||||
"key1", "value1",
|
||||
"key2", "value2");
|
||||
|
||||
assertTrue(swift.getApi().setContainerMetadata(containerName, metadata));
|
||||
|
||||
ContainerMetadata containerMetadata = swift.getApi().getContainerMetadata(containerName);
|
||||
|
||||
assertEquals(containerMetadata.getMetadata().get("key1"), "value1");
|
||||
assertEquals(containerMetadata.getMetadata().get("key2"), "value2");
|
||||
}
|
||||
|
||||
@Test(groups = "live")
|
||||
public void testCreateDeleteContainerMetadata() throws InterruptedException {
|
||||
BlobStore blobStore = view.getBlobStore();
|
||||
RestContext<CommonSwiftClient, CommonSwiftAsyncClient> swift = blobStore.getContext().unwrap();
|
||||
String containerName = getContainerName();
|
||||
CreateContainerOptions options = CreateContainerOptions.Builder
|
||||
.withPublicAccess()
|
||||
.withMetadata(ImmutableMap.<String, String> of(
|
||||
"key1", "value1",
|
||||
"key2", "value2",
|
||||
"key3", "value3"));
|
||||
|
||||
assertTrue(swift.getApi().createContainer(containerName, options));
|
||||
|
||||
ContainerMetadata containerMetadata = swift.getApi().getContainerMetadata(containerName);
|
||||
|
||||
assertEquals(containerMetadata.getMetadata().size(), 3);
|
||||
assertEquals(containerMetadata.getMetadata().get("key1"), "value1");
|
||||
assertEquals(containerMetadata.getMetadata().get("key2"), "value2");
|
||||
assertEquals(containerMetadata.getMetadata().get("key3"), "value3");
|
||||
|
||||
assertTrue(swift.getApi().deleteContainerMetadata(containerName, ImmutableList.<String> of("key2","key3")));
|
||||
|
||||
containerMetadata = swift.getApi().getContainerMetadata(containerName);
|
||||
|
||||
assertEquals(containerMetadata.getMetadata().size(), 1);
|
||||
assertEquals(containerMetadata.getMetadata().get("key1"), "value1");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,5 +46,4 @@ public class SwiftContainerLiveTest extends BaseContainerLiveTest {
|
|||
public void testPublicAccess() throws MalformedURLException, InterruptedException, IOException {
|
||||
super.testPublicAccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* 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.functions;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.openstack.swift.domain.ContainerMetadata;
|
||||
import org.jclouds.openstack.swift.functions.ParseContainerMetadataFromHeaders;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code ParseContainerMetadataFromHeaders}
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
@Test(groups = "unit")
|
||||
public class ParseContainerMetadataFromHeadersTest {
|
||||
|
||||
Injector i = Guice.createInjector(new AbstractModule() {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
}
|
||||
});
|
||||
|
||||
public void testParseContainerMetadataHeaders() {
|
||||
ParseContainerMetadataFromHeaders parser = i.getInstance(ParseContainerMetadataFromHeaders.class);
|
||||
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
|
||||
expect(request.getArgs()).andReturn(ImmutableList.<Object> of("container", "key")).atLeastOnce();
|
||||
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/test")).atLeastOnce();
|
||||
replay(request);
|
||||
parser.setContext(request);
|
||||
|
||||
HttpResponse response = HttpResponse.builder().statusCode(204).message("No Content").payload("")
|
||||
.addHeader(SwiftHeaders.CONTAINER_BYTES_USED, "42")
|
||||
.addHeader(SwiftHeaders.CONTAINER_OBJECT_COUNT, "1")
|
||||
.addHeader(SwiftHeaders.CONTAINER_METADATA_PREFIX + "label1", "test1")
|
||||
.addHeader(SwiftHeaders.CONTAINER_METADATA_PREFIX + "label2", "test2").build();
|
||||
|
||||
response.getPayload().getContentMetadata().setContentType("text/plain");
|
||||
ContainerMetadata containerMetadata = parser.apply(response);
|
||||
|
||||
assertEquals(containerMetadata.getBytes(), 42);
|
||||
assertEquals(containerMetadata.getCount(), 1);
|
||||
assertEquals(containerMetadata.getMetadata().get("label1"), "test1");
|
||||
assertEquals(containerMetadata.getMetadata().get("label2"), "test2");
|
||||
}
|
||||
}
|
|
@ -31,9 +31,14 @@ import org.jclouds.blobstore.ContainerNotFoundException;
|
|||
import org.jclouds.blobstore.KeyNotFoundException;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpRequest.Builder;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.openstack.swift.CopyObjectException;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
|
@ -41,6 +46,13 @@ import org.testng.annotations.Test;
|
|||
@Test(groups = { "unit" })
|
||||
public class ParseSwiftErrorFromHttpResponseTest {
|
||||
|
||||
@Test
|
||||
public void test404SetsCopyObjectException() {
|
||||
assertCodeMakes("HEAD",
|
||||
URI.create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"), 404,
|
||||
"Not Found", "text/plain", "", "/bad/source/path", CopyObjectException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404SetsKeyNotFoundExceptionMosso() {
|
||||
assertCodeMakes("HEAD",
|
||||
|
@ -76,24 +88,34 @@ public class ParseSwiftErrorFromHttpResponseTest {
|
|||
|
||||
private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType,
|
||||
String content, Class<? extends Exception> expected) {
|
||||
|
||||
ParseSwiftErrorFromHttpResponse function = new ParseSwiftErrorFromHttpResponse();
|
||||
|
||||
HttpCommand command = createMock(HttpCommand.class);
|
||||
HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build();
|
||||
HttpResponse response = HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build();
|
||||
response.getPayload().getContentMetadata().setContentType(contentType);
|
||||
|
||||
expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
|
||||
command.setException(classEq(expected));
|
||||
|
||||
replay(command);
|
||||
|
||||
function.handleError(command, response);
|
||||
|
||||
verify(command);
|
||||
assertCodeMakes(method, uri, statusCode, message, contentType, content, "", expected);
|
||||
}
|
||||
|
||||
private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType,
|
||||
String content, String copyObjectSourcePath, Class<? extends Exception> expected) {
|
||||
ParseSwiftErrorFromHttpResponse function = new ParseSwiftErrorFromHttpResponse();
|
||||
|
||||
HttpCommand command = createMock(HttpCommand.class);
|
||||
Builder<?> requestBuilder = HttpRequest.builder().method(method).endpoint(uri);
|
||||
|
||||
if (!Strings.isNullOrEmpty(copyObjectSourcePath)) {
|
||||
requestBuilder.addHeader(SwiftHeaders.OBJECT_COPY_FROM, copyObjectSourcePath);
|
||||
}
|
||||
|
||||
HttpRequest request = requestBuilder.build();
|
||||
HttpResponse response = HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build();
|
||||
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() {
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ 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.CreateContainerOptions;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
|
@ -160,12 +161,33 @@ public class StubSwiftAsyncClient implements CommonSwiftAsyncClient {
|
|||
})));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<ContainerMetadata> getContainerMetadata(String container) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ListenableFuture<Boolean> setContainerMetadata(String container, Map<String, String> containerMetadata) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ListenableFuture<Boolean> deleteContainerMetadata(String container, Iterable<String> metadataKeys) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ListenableFuture<Boolean> createContainer(String container, CreateContainerOptions... options) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ListenableFuture<PageSet<ObjectInfo>> listObjects(String container,
|
||||
org.jclouds.openstack.swift.options.ListContainerOptions... optionsList) {
|
||||
ListContainerOptions options = container2ContainerListOptions.apply(optionsList);
|
||||
return Futures.compose(blobStore.list(container, options), resource2ObjectList, service);
|
||||
}
|
||||
|
||||
public ListenableFuture<Boolean> copyObject(String sourceContainer, String sourceObject, String destinationContainer, String destinationObject) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ListenableFuture<String> putObject(String container, SwiftObject object) {
|
||||
return blobStore.putBlob(container, object2Blob.apply(object));
|
||||
}
|
||||
|
@ -195,5 +217,4 @@ public class StubSwiftAsyncClient implements CommonSwiftAsyncClient {
|
|||
public ListenableFuture<Boolean> objectExists(String bucketName, String key) {
|
||||
return blobStore.blobExists(bucketName, key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,10 +16,11 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.hpcloud.objectstorage.options;
|
||||
package org.jclouds.openstack.swift.options;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.jclouds.openstack.swift.options.CreateContainerOptions;
|
||||
import org.jclouds.openstack.swift.reference.SwiftHeaders;
|
||||
import org.testng.annotations.Test;
|
||||
|
|
@ -23,16 +23,11 @@ import java.util.Set;
|
|||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HEAD;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnContainerNotFound;
|
||||
import org.jclouds.hpcloud.objectstorage.extensions.HPCloudCDNAsyncClient;
|
||||
import org.jclouds.hpcloud.objectstorage.functions.ParseContainerMetadataFromHeaders;
|
||||
import org.jclouds.hpcloud.objectstorage.options.CreateContainerOptions;
|
||||
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
|
||||
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
|
||||
import org.jclouds.openstack.swift.Storage;
|
||||
|
@ -44,10 +39,8 @@ import org.jclouds.rest.annotations.Endpoint;
|
|||
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 com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
|
@ -69,24 +62,6 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||
@Endpoint(Storage.class)
|
||||
public interface HPCloudObjectStorageAsyncClient extends CommonSwiftAsyncClient {
|
||||
|
||||
/**
|
||||
* @see HPCloudObjectStorageClient#getCDNMetadata(String)
|
||||
*/
|
||||
@Beta
|
||||
@HEAD
|
||||
@ResponseParser(ParseContainerMetadataFromHeaders.class)
|
||||
@ExceptionParser(ReturnNullOnContainerNotFound.class)
|
||||
@Path("/{container}")
|
||||
ListenableFuture<ContainerMetadata> getContainerMetadata(@PathParam("container") String container);
|
||||
|
||||
/**
|
||||
* @see HPCloudObjectStorageClient#createContainer
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{container}")
|
||||
ListenableFuture<Boolean> createContainer(@PathParam("container") String container,
|
||||
CreateContainerOptions... options);
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.swift.CommonSwiftClient#listContainers
|
||||
*/
|
||||
|
|
|
@ -22,9 +22,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.hpcloud.objectstorage.extensions.HPCloudCDNClient;
|
||||
import org.jclouds.hpcloud.objectstorage.options.CreateContainerOptions;
|
||||
import org.jclouds.openstack.swift.CommonSwiftClient;
|
||||
import org.jclouds.openstack.swift.domain.ContainerMetadata;
|
||||
import org.jclouds.rest.annotations.Delegate;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
@ -46,10 +44,6 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
|
||||
public interface HPCloudObjectStorageClient extends CommonSwiftClient {
|
||||
|
||||
boolean createContainer(String container, CreateContainerOptions... options);
|
||||
|
||||
ContainerMetadata getContainerMetadata(String container);
|
||||
|
||||
/**
|
||||
* Provides synchronous access to CDN features.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue