http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java new file mode 100644 index 0000000..cc934e4 --- /dev/null +++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.functions; + +import static com.google.common.io.BaseEncoding.base16; +import static com.google.common.net.HttpHeaders.ETAG; +import static com.google.common.net.HttpHeaders.LAST_MODIFIED; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_DELETE_AT; + +import java.net.URI; +import java.util.Date; + +import javax.inject.Inject; + +import org.jclouds.date.DateService; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.io.MutableContentMetadata; +import org.jclouds.io.Payload; +import org.jclouds.openstack.swift.v1.domain.SwiftObject; +import org.jclouds.rest.InvocationContext; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.common.base.Function; +import com.google.common.hash.HashCode; + +public class ParseObjectFromResponse implements Function<HttpResponse, SwiftObject>, + InvocationContext<ParseObjectFromResponse> { + private final DateService dates; + + @Inject + ParseObjectFromResponse(DateService dates) { + this.dates = dates; + } + + private String uri; + private String name; + + @Override + public SwiftObject apply(HttpResponse from) { + + Payload payload = from.getPayload(); + MutableContentMetadata contentMeta = payload.getContentMetadata(); + + String deleteAt = from.getFirstHeaderOrNull(OBJECT_DELETE_AT); + if (deleteAt != null) { + long fromEpoch = Long.parseLong(from.getFirstHeaderOrNull(OBJECT_DELETE_AT)) * 1000; + contentMeta.setExpires(new Date(fromEpoch)); + payload.setContentMetadata(contentMeta); + } + + String etag = from.getFirstHeaderOrNull(ETAG); + if (etag != null) { + payload.getContentMetadata().setContentMD5(HashCode.fromBytes(base16().lowerCase().decode(etag))); + } + + return SwiftObject.builder() + .uri(URI.create(uri)) + .name(name) + .etag(etag) + .payload(payload) + .lastModified(dates.rfc822DateParse(from.getFirstHeaderOrNull(LAST_MODIFIED))) + .headers(from.getHeaders()) + .metadata(EntriesWithoutMetaPrefix.INSTANCE.apply(from.getHeaders())).build(); + } + + @Override + public ParseObjectFromResponse setContext(HttpRequest request) { + this.uri = request.getEndpoint().toString(); + this.name = GeneratedHttpRequest.class.cast(request).getInvocation().getArgs().get(0).toString(); + return this; + } +}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java new file mode 100644 index 0000000..ff12e0f --- /dev/null +++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.functions; + +import static com.google.common.io.BaseEncoding.base16; +import static org.jclouds.http.Uris.uriBuilder; + +import java.util.Date; +import java.util.List; + +import javax.inject.Inject; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.io.Payload; +import org.jclouds.io.Payloads; +import org.jclouds.openstack.swift.v1.domain.Container; +import org.jclouds.openstack.swift.v1.domain.ObjectList; +import org.jclouds.openstack.swift.v1.domain.SwiftObject; +import org.jclouds.rest.InvocationContext; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import com.google.common.hash.HashCode; +import com.google.common.io.ByteSource; + +public class ParseObjectListFromResponse implements Function<HttpResponse, ObjectList>, + InvocationContext<ParseObjectListFromResponse> { + + private static final class InternalObject { + String name; + String hash; + long bytes; + String content_type; + Date last_modified; + Date expires; + } + + private final ParseJson<List<InternalObject>> json; + private final ParseContainerFromHeaders parseContainer; + + @Inject + ParseObjectListFromResponse(ParseJson<List<InternalObject>> json, ParseContainerFromHeaders parseContainer) { + this.json = json; + this.parseContainer = parseContainer; + } + + private ToSwiftObject toSwiftObject; + + @Override + public ObjectList apply(HttpResponse from) { + List<SwiftObject> objects = Lists.transform(json.apply(from), toSwiftObject); + Container container = parseContainer.apply(from); + return ObjectList.create(objects, container); + } + + static class ToSwiftObject implements Function<InternalObject, SwiftObject> { + private final String containerUri; + + ToSwiftObject(String containerUri) { + this.containerUri = containerUri; + } + + @Override + public SwiftObject apply(InternalObject input) { + return SwiftObject.builder() + .uri(uriBuilder(containerUri).clearQuery().appendPath(input.name).build()) + .name(input.name) + .etag(input.hash) + .payload(payload(input.bytes, input.hash, input.content_type, input.expires)) + .lastModified(input.last_modified).build(); + } + } + + @Override + public ParseObjectListFromResponse setContext(HttpRequest request) { + parseContainer.name = GeneratedHttpRequest.class.cast(request).getCaller().get().getArgs().get(1).toString(); + String containerUri = request.getEndpoint().toString(); + int queryIndex = containerUri.indexOf('?'); + if (queryIndex != -1) { + containerUri = containerUri.substring(0, queryIndex); + } + toSwiftObject = new ToSwiftObject(containerUri); + return this; + } + + private static Payload payload(long bytes, String hash, String contentType, Date expires) { + Payload payload = Payloads.newByteSourcePayload(ByteSource.empty()); + payload.getContentMetadata().setContentLength(bytes); + payload.getContentMetadata().setContentType(contentType); + payload.getContentMetadata().setExpires(expires); + if (hash != null) { + payload.getContentMetadata().setContentMD5(HashCode.fromBytes(base16().lowerCase().decode(hash))); + } + return payload; + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java new file mode 100644 index 0000000..2bde41c --- /dev/null +++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.handlers; + +import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.jclouds.blobstore.ContainerNotFoundException; +import org.jclouds.blobstore.KeyNotFoundException; +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.openstack.swift.v1.CopyObjectException; +import org.jclouds.openstack.swift.v1.reference.SwiftHeaders; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.InsufficientResourcesException; + +// TODO: is there error spec someplace? let's type errors, etc. +public class SwiftErrorHandler implements HttpErrorHandler { + public static final String PREFIX = "^/v[0-9][^/]*/[a-zA-Z]+_[^/]+/"; + public static final Pattern CONTAINER_PATH = Pattern.compile(PREFIX + "([^/]+)$"); + public static final Pattern CONTAINER_KEY_PATH = Pattern.compile(PREFIX + "([^/]+)/(.*)"); + + public void handleError(HttpCommand command, HttpResponse response) { + // it is important to always read fully and close streams + byte[] data = closeClientButKeepContentStream(response); + String message = data != null ? new String(data) : null; + + Exception exception = message != null ? new HttpResponseException(command, response, message) + : new HttpResponseException(command, response); + message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(), + response.getStatusLine()); + switch (response.getStatusCode()) { + case 401: + exception = new AuthorizationException(exception.getMessage(), exception); + break; + case 404: + Exception oldException = exception; + String sourcePath = command.getCurrentRequest().getFirstHeaderOrNull(SwiftHeaders.OBJECT_COPY_FROM); + if (sourcePath != null) { + // the path returned here is in the form "/v1/tenant-id/destContainer/destObject" + String path = command.getCurrentRequest().getEndpoint().getPath(); + int startOfDestinationPath = path.lastIndexOf("/", path.lastIndexOf("/") - 1); + // get the "/destContainer/destObject" portion of the path + 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); + + if (matcher.find()) { + exception = new ContainerNotFoundException(matcher.group(1), message); + exception.initCause(oldException); + } else { + matcher = CONTAINER_KEY_PATH.matcher(path); + if (matcher.find()) { + exception = new KeyNotFoundException(matcher.group(1), matcher.group(2), message); + exception.initCause(oldException); + } + } + } + break; + case 409: + exception = new IllegalStateException(exception.getMessage(), exception); + break; + case 413: + exception = new InsufficientResourcesException(exception.getMessage(), exception); + break; + } + command.setException(exception); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java new file mode 100644 index 0000000..2014f61 --- /dev/null +++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.options; + +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_ACL_ANYBODY_READ; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_METADATA_PREFIX; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_READ; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.VERSIONS_LOCATION; + +import java.util.Map; + +import org.jclouds.http.options.BaseHttpRequestOptions; +import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders; + +import com.google.common.collect.Multimap; + +/** + * Options for creating a {@link Container} + * + * @see ContainerApi#create(String, CreateContainerOptions) + */ +public class CreateContainerOptions extends BaseHttpRequestOptions { + + public static final CreateContainerOptions NONE = new CreateContainerOptions(); + + /** + * Sets the headers on a container at creation. + */ + public CreateContainerOptions headers(Multimap<String, String> headers) { + this.headers.putAll(headers); + return this; + } + + /** + * Sets the metadata on a container at creation. + */ + public CreateContainerOptions metadata(Map<String, String> metadata) { + this.headers.putAll(bindMetadataToHeaders.toHeaders(metadata)); + return this; + } + + /** + * Sets the public ACL on the container so that anybody can read it. + */ + public CreateContainerOptions anybodyRead() { + this.headers.put(CONTAINER_READ, CONTAINER_ACL_ANYBODY_READ); + return this; + } + + /** + * Sets the container that will contain object versions. + */ + public CreateContainerOptions versionsLocation(String containerName) { + this.headers.put(VERSIONS_LOCATION, containerName); + return this; + } + + public static class Builder { + + /** + * @see CreateContainerOptions#anybodyRead + */ + public static CreateContainerOptions anybodyRead() { + CreateContainerOptions options = new CreateContainerOptions(); + return options.anybodyRead(); + } + + /** + * @see CreateContainerOptions#headers + */ + public static CreateContainerOptions headers(Multimap<String, String> headers) { + CreateContainerOptions options = new CreateContainerOptions(); + return options.headers(headers); + } + + /** + * @see CreateContainerOptions#metadata + */ + public static CreateContainerOptions metadata(Map<String, String> metadata) { + CreateContainerOptions options = new CreateContainerOptions(); + return options.metadata(metadata); + } + + /** + * @see CreateContainerOptions#versionsLocation + */ + public static CreateContainerOptions versionsLocation(String containerName) { + CreateContainerOptions options = new CreateContainerOptions(); + return options.versionsLocation(containerName); + } + } + + private static final BindMetadataToHeaders bindMetadataToHeaders = new BindMetadataToHeaders(CONTAINER_METADATA_PREFIX); +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java new file mode 100644 index 0000000..8b01aae --- /dev/null +++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.options; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import org.jclouds.http.options.BaseHttpRequestOptions; + +/** + * Options for listing containers. + * + * @see ContainerApi#list(ListContainerOptions) + */ +public class ListContainerOptions extends BaseHttpRequestOptions { + public static final ListContainerOptions NONE = new ListContainerOptions(); + + /** + * list operation returns no more than this amount. + */ + public ListContainerOptions limit(int limit) { + checkState(limit >= 0, "limit must be >= 0"); + checkState(limit <= 10000, "limit must be <= 10000"); + queryParameters.put("limit", Integer.toString(limit)); + return this; + } + + /** + * object names greater in value than the specified marker are returned. + */ + public ListContainerOptions marker(String marker) { + queryParameters.put("marker", checkNotNull(marker, "marker")); + return this; + } + + /** + * object names less in value than the specified marker are returned. + */ + public ListContainerOptions endMarker(String endMarker) { + queryParameters.put("end_marker", checkNotNull(endMarker, "endMarker")); + return this; + } + + /** + * object names beginning with this substring are returned. + */ + public ListContainerOptions prefix(String prefix) { + queryParameters.put("prefix", checkNotNull(prefix, "prefix")); + return this; + } + + /** + * object names nested in the container are returned. + */ + public ListContainerOptions delimiter(char delimiter) { + queryParameters.put("delimiter", Character.toString(delimiter)); + return this; + } + + /** + * object names nested in the pseudo path are returned. + */ + public ListContainerOptions path(String path) { + queryParameters.put("path", checkNotNull(path, "path")); + return this; + } + + public static class Builder { + + /** + * @see ListContainerOptions#limit + */ + public static ListContainerOptions limit(int limit) { + ListContainerOptions options = new ListContainerOptions(); + return options.limit(limit); + } + + /** + * @see ListContainerOptions#marker + */ + public static ListContainerOptions marker(String marker) { + ListContainerOptions options = new ListContainerOptions(); + return options.marker(marker); + } + + /** + * @see ListContainerOptions#endMarker + */ + public static ListContainerOptions endMarker(String endMarker) { + ListContainerOptions options = new ListContainerOptions(); + return options.endMarker(endMarker); + } + + /** + * @see ListContainerOptions#prefix + */ + public static ListContainerOptions prefix(String prefix) { + ListContainerOptions options = new ListContainerOptions(); + return options.prefix(prefix); + } + + /** + * @see ListContainerOptions#delimiter + */ + public static ListContainerOptions delimiter(char delimiter) { + ListContainerOptions options = new ListContainerOptions(); + return options.delimiter(delimiter); + } + + /** + * @see ListContainerOptions#path + */ + public static ListContainerOptions path(String path) { + ListContainerOptions options = new ListContainerOptions(); + return options.path(path); + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/PutOptions.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/PutOptions.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/PutOptions.java new file mode 100644 index 0000000..d4a1ed3 --- /dev/null +++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/PutOptions.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.options; + +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_METADATA_PREFIX; + +import java.util.Map; + +import org.jclouds.http.options.BaseHttpRequestOptions; +import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders; + +import com.google.common.collect.Multimap; + +/** + * Options for creating an Object. + */ +public class PutOptions extends BaseHttpRequestOptions { + + public static final PutOptions NONE = new PutOptions(); + + /** + * Sets the metadata on a container at creation. + */ + public PutOptions metadata(Map<String, String> metadata) { + this.headers.putAll(bindMetadataToHeaders.toHeaders(metadata)); + return this; + } + + /** + * Sets the headers on a container at creation. + */ + public PutOptions headers(Multimap<String, String> headers) { + this.headers.putAll(headers); + return this; + } + + public static class Builder { + + /** + * @see PutOptions#headers + */ + public static PutOptions headers(Multimap<String, String> headers) { + PutOptions options = new PutOptions(); + return options.headers(headers); + } + + /** + * @see PutOptions#metadata + */ + public static PutOptions metadata(Map<String, String> metadata) { + PutOptions options = new PutOptions(); + return options.metadata(metadata); + } + } + + private static final BindMetadataToHeaders bindMetadataToHeaders = new BindMetadataToHeaders(OBJECT_METADATA_PREFIX); +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/UpdateContainerOptions.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/UpdateContainerOptions.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/UpdateContainerOptions.java new file mode 100644 index 0000000..f74b7fe --- /dev/null +++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/UpdateContainerOptions.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.options; + +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_ACL_ANYBODY_READ; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_METADATA_PREFIX; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_READ; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.VERSIONS_LOCATION; + +import java.util.Map; + +import org.jclouds.http.options.BaseHttpRequestOptions; +import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders; + +import com.google.common.collect.Multimap; + +/** + * Options for updating a {@link Container}. + * + * @see org.jclouds.openstack.swift.v1.features.ContainerApi#update(String, UpdateContainerOptions) + */ +public class UpdateContainerOptions extends BaseHttpRequestOptions { + public static final UpdateContainerOptions NONE = new UpdateContainerOptions(); + + /** + * Sets the headers on a container at creation. + */ + public UpdateContainerOptions headers(Multimap<String, String> headers) { + this.headers.putAll(headers); + return this; + } + + /** + * Sets the metadata on a container at creation. + */ + public UpdateContainerOptions metadata(Map<String, String> metadata) { + this.headers.putAll(bindMetadataToHeaders.toHeaders(metadata)); + return this; + } + + /** + * Sets the public ACL on the container so that anybody can read it. + */ + public UpdateContainerOptions anybodyRead() { + this.headers.put(CONTAINER_READ, CONTAINER_ACL_ANYBODY_READ); + return this; + } + + /** + * Sets the container that will contain object versions. + */ + public UpdateContainerOptions versionsLocation(String containerName) { + this.headers.put(VERSIONS_LOCATION, containerName); + return this; + } + + public static class Builder { + + /** + * @see UpdateContainerOptions#anybodyRead + */ + public static UpdateContainerOptions anybodyRead() { + UpdateContainerOptions options = new UpdateContainerOptions(); + return options.anybodyRead(); + } + + /** + * @see UpdateContainerOptions#headers + */ + public static UpdateContainerOptions headers(Multimap<String, String> headers) { + UpdateContainerOptions options = new UpdateContainerOptions(); + return options.headers(headers); + } + + /** + * @see UpdateContainerOptions#metadata + */ + public static UpdateContainerOptions metadata(Map<String, String> metadata) { + UpdateContainerOptions options = new UpdateContainerOptions(); + return options.metadata(metadata); + } + + /** + * @see UpdateContainerOptions#versionsLocation + */ + public static UpdateContainerOptions versionsLocation(String containerName) { + UpdateContainerOptions options = new UpdateContainerOptions(); + return options.versionsLocation(containerName); + } + } + + private static final BindMetadataToHeaders bindMetadataToHeaders = new BindMetadataToHeaders(CONTAINER_METADATA_PREFIX); +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java new file mode 100644 index 0000000..caab5e7 --- /dev/null +++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.reference; + +/** + * Common headers in Swift. + */ +public final class SwiftHeaders { + + // Common Metadata Prefixes + public static final String ACCOUNT_METADATA_PREFIX = "X-Account-Meta-"; + public static final String CONTAINER_METADATA_PREFIX = "X-Container-Meta-"; + public static final String OBJECT_METADATA_PREFIX = "X-Object-Meta-"; + public static final String USER_METADATA_PREFIX = OBJECT_METADATA_PREFIX; + + // Metadata Removal Prefixes + public static final String ACCOUNT_REMOVE_METADATA_PREFIX = "X-Remove-Account-Meta-"; + public static final String CONTAINER_REMOVE_METADATA_PREFIX = "X-Remove-Container-Meta-"; + public static final String OBJECT_REMOVE_METADATA_PREFIX = "X-Remove-Object-Meta-"; + + // TempURL + public static final String ACCOUNT_TEMPORARY_URL_KEY = ACCOUNT_METADATA_PREFIX + "Temp-Url-Key"; + public static final String ACCOUNT_TEMPORARY_URL_KEY_2 = ACCOUNT_TEMPORARY_URL_KEY + "-2"; + + // Account Headers + public static final String ACCOUNT_BYTES_USED = "X-Account-Bytes-Used"; + public static final String ACCOUNT_CONTAINER_COUNT = "X-Account-Container-Count"; + public static final String ACCOUNT_OBJECT_COUNT = "X-Account-Object-Count"; + + // Container Headers + public static final String CONTAINER_BYTES_USED = "X-Container-Bytes-Used"; + public static final String CONTAINER_OBJECT_COUNT = "X-Container-Object-Count"; + + // Public access - not supported in all Swift Impls + public static final String CONTAINER_READ = "X-Container-Read"; + public static final String CONTAINER_WRITE = "X-Container-Write"; + public static final String CONTAINER_ACL_ANYBODY_READ = ".r:*,.rlistings"; + + // CORS + public static final String CONTAINER_ACCESS_CONTROL_ALLOW_ORIGIN = CONTAINER_METADATA_PREFIX + "Access-Control-Allow-Origin"; + public static final String CONTAINER_ACCESS_CONTROL_MAX_AGE = CONTAINER_METADATA_PREFIX + "Access-Control-Max-Age"; + public static final String CONTAINER_ACCESS_CONTROL_EXPOSE_HEADERS = CONTAINER_METADATA_PREFIX + "Access-Control-Expose-Headers"; + + // Container Quota + public static final String CONTAINER_QUOTA_BYTES = CONTAINER_METADATA_PREFIX + "Quota-Bytes"; + public static final String CONTAINER_QUOTA_COUNT = CONTAINER_METADATA_PREFIX + "Quota-Count"; + + // Container Sync + public static final String CONTAINER_SYNC_KEY = "X-Container-Sync-Key"; + public static final String CONTAINER_SYNC_TO = "X-Container-Sync-To"; + + // Versioning + public static final String VERSIONS_LOCATION = "X-Versions-Location"; + + // Misc functionality + public static final String CONTAINER_WEB_MODE = "X-Web-Mode"; + + public static final String OBJECT_COPY_FROM = "X-Copy-From"; + public static final String OBJECT_DELETE_AFTER = "X-Delete-After"; + public static final String OBJECT_DELETE_AT = "X-Delete-At"; + public static final String OBJECT_MANIFEST = "X-Object-Manifest"; + /** Get the newest version of the object for GET and HEAD requests */ + public static final String OBJECT_NEWEST = "X-Newest"; + + // Static Large Object + public static final String STATIC_LARGE_OBJECT = "X-Static-Large-Object"; + + // Static Web + public static final String STATIC_WEB_INDEX = CONTAINER_METADATA_PREFIX + "Web-Index"; + public static final String STATIC_WEB_DIRECTORY_TYPE = CONTAINER_METADATA_PREFIX + "Web-Directory-Type"; + public static final String STATIC_WEB_ERROR = CONTAINER_METADATA_PREFIX + "Web-Error"; + public static final String STATIC_WEB_LISTINGS = CONTAINER_METADATA_PREFIX + "Web-Listings"; + public static final String STATIC_WEB_LISTINGS_CSS = CONTAINER_METADATA_PREFIX + "Web-Listings-CSS"; + + private SwiftHeaders() { + throw new AssertionError("intentionally unimplemented"); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/apis/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata new file mode 100644 index 0000000..c5b8017 --- /dev/null +++ b/apis/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.jclouds.openstack.swift.v1.SwiftApiMetadata http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java new file mode 100644 index 0000000..8b5e895 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1; + +import static com.google.common.base.Charsets.UTF_8; +import static org.jclouds.openstack.swift.v1.features.AccountApiMockTest.accountResponse; +import static org.testng.Assert.assertEquals; + +import java.util.Properties; + +import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; + +/** + * @see KeystoneProperties#CREDENTIAL_TYPE + */ +@Test +public class AuthenticationMockTest extends BaseOpenStackMockTest<SwiftApi> { + + @DataProvider(name = "jclouds.keystone.credential-type") + Object[][] credentialTypeToPostBody() { + Object[][] credentialTypeToPostBody = new Object[2][2]; + credentialTypeToPostBody[0][0] = "apiAccessKeyCredentials"; + credentialTypeToPostBody[0][1] = "{\"auth\":{\"apiAccessKeyCredentials\":{\"accessKey\":\"joe\",\"secretKey\":\"letmein\"},\"tenantName\":\"jclouds\"}}"; + credentialTypeToPostBody[1][0] = "passwordCredentials"; + credentialTypeToPostBody[1][1] = "{\"auth\":{\"passwordCredentials\":{\"username\":\"joe\",\"password\":\"letmein\"},\"tenantName\":\"jclouds\"}}"; + return credentialTypeToPostBody; + } + + @Test(dataProvider = "jclouds.keystone.credential-type") + public void authenticateCredentialType(String credentialType, String expectedPost) throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(accountResponse())); + + try { + Properties overrides = new Properties(); + overrides.setProperty("jclouds.keystone.credential-type", credentialType); + + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift", overrides); + + api.getAccountApi("DFW").get(); + + assertEquals(server.getRequestCount(), 2); + RecordedRequest authRequest = server.takeRequest(); + assertEquals(authRequest.getRequestLine(), "POST /tokens HTTP/1.1"); + assertEquals(new String(authRequest.getBody(), UTF_8), expectedPost); + } finally { + server.shutdown(); + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java new file mode 100644 index 0000000..6fbe4d9 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1; + +import org.jclouds.View; +import org.jclouds.apis.internal.BaseApiMetadataTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; + +@Test(groups = "unit", testName = "SwiftApiMetadataTest") +// public class SwiftApiMetadataTest extends BaseBlobStoreApiMetadataTest { +public class SwiftApiMetadataTest extends BaseApiMetadataTest { + public SwiftApiMetadataTest() { + super(new SwiftApiMetadata(), ImmutableSet.<TypeToken<? extends View>> of()); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java new file mode 100644 index 0000000..703da9b --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reportMatcher; +import static org.easymock.EasyMock.verify; +import static org.jclouds.io.Payloads.newByteSourcePayload; + +import java.net.URI; + +import org.easymock.IArgumentMatcher; +import org.jclouds.blobstore.ContainerNotFoundException; +import org.jclouds.blobstore.KeyNotFoundException; +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.openstack.swift.v1.handlers.SwiftErrorHandler; +import org.testng.annotations.Test; + +import com.google.common.io.ByteSource; + +/** + * Tests the {@link SwiftErrorHandler} + */ +@Test(groups = "unit", testName = "SwiftErrorHandlerTest") +public class SwiftErrorHandlerTest { + + @Test + public void test404SetsKeyNotFoundExceptionMosso() { + assertCodeMakes("HEAD", URI + .create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"), 404, + "Not Found", "", KeyNotFoundException.class); + } + + @Test + public void test404SetsKeyNotFoundExceptionSwift() { + assertCodeMakes("HEAD", URI + .create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"), + 404, "Not Found", "", KeyNotFoundException.class); + } + + @Test + public void test404SetsContainerNotFoundExceptionMosso() { + assertCodeMakes("HEAD", URI + .create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"), 404, + "Not Found", "", ContainerNotFoundException.class); + } + + @Test + public void test404SetsContainerNotFoundExceptionSwift() { + assertCodeMakes("HEAD", URI + .create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"), + 404, "Not Found", "", ContainerNotFoundException.class); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content, + Class<? extends Exception> expected) { + assertCodeMakes(method, uri, statusCode, message, "text/plain", content, expected); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType, + String content, Class<? extends Exception> expected) { + + SwiftErrorHandler function = new SwiftErrorHandler(); + + HttpCommand command = createMock(HttpCommand.class); + HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build(); + HttpResponse response = HttpResponse.builder().statusCode(statusCode).message(message) + .payload(newByteSourcePayload(ByteSource.wrap(content.getBytes()))).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() { + + @Override + public void appendTo(StringBuffer buffer) { + buffer.append("classEq("); + buffer.append(in); + buffer.append(")"); + } + + @Override + public boolean matches(Object arg) { + return arg.getClass() == in; + } + + }); + return null; + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java new file mode 100644 index 0000000..dd65210 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1; + +import static java.lang.String.format; +import static org.jclouds.io.Payloads.newByteSourcePayload; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.UUID; + +import org.jclouds.openstack.swift.v1.domain.SwiftObject; +import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest; +import org.jclouds.util.Strings2; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.io.ByteSource; + +@Test(groups = "live", testName = "TemporaryUrlSignerLiveTest") +public class TemporaryUrlSignerLiveTest extends BaseSwiftApiLiveTest<SwiftApi> { + + private String name = getClass().getSimpleName(); + private String containerName = getClass().getSimpleName() + "Container"; + + public void signForPublicAccess() throws Exception { + for (String regionId : api.getConfiguredRegions()) { + SwiftObject object = api.getObjectApi(regionId, containerName).get(name); + + long expires = System.currentTimeMillis() / 1000 + 5; + String signature = TemporaryUrlSigner.checkApiEvery(api.getAccountApi(regionId), 5) + .sign("GET", object.getUri().getPath(), expires); + + URI signed = URI.create(format("%s?temp_url_sig=%s&temp_url_expires=%s", object.getUri(), signature, expires)); + + InputStream publicStream = signed.toURL().openStream(); + assertEquals(Strings2.toStringAndClose(publicStream), "swifty"); + + // let it expire + Thread.sleep(5000); + try { + signed.toURL().openStream(); + fail("should have expired!"); + } catch (IOException e) { + } + } + } + + @Override + @BeforeClass(groups = "live") + public void setup() { + super.setup(); + String key = UUID.randomUUID().toString(); + for (String regionId : api.getConfiguredRegions()) { + api.getAccountApi(regionId).updateTemporaryUrlKey(key); + api.getContainerApi(regionId).create(containerName); + api.getObjectApi(regionId, containerName) + .put(name, newByteSourcePayload(ByteSource.wrap("swifty".getBytes()))); + } + } + + @AfterMethod + @AfterClass(groups = "live") + public void tearDown() { + for (String regionId : api.getConfiguredRegions()) { + api.getObjectApi(regionId, containerName).delete(name); + api.getContainerApi(regionId).deleteIfEmpty(containerName); + } + super.tearDown(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java new file mode 100644 index 0000000..8f42cf3 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1; + +import static org.jclouds.openstack.swift.v1.features.AccountApiMockTest.accountResponse; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY; +import static org.testng.Assert.assertEquals; + +import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest; +import org.testng.annotations.Test; + +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; + +@Test(groups = "unit", testName = "TemporaryUrlSignerMockTest") +public class TemporaryUrlSignerMockTest extends BaseOpenStackMockTest<SwiftApi> { + + @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "accountApi") + public void whenAccountApiIsNull() { + TemporaryUrlSigner.checkApiEvery(null, 10000); + } + + public void whenAccountApiHasKey() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(accountResponse().addHeader(ACCOUNT_TEMPORARY_URL_KEY, "mykey"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + String signature = TemporaryUrlSigner.checkApiEvery(api.getAccountApi("DFW"), 10000) + .sign("GET", "/v1/AUTH_account/container/object", 1323479485l); + + assertEquals(signature, "d9fc2067e52b06598421664cf6610bfc8fc431f6"); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + assertEquals(server.takeRequest().getRequestLine(), + "HEAD /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9 HTTP/1.1"); + } finally { + server.shutdown(); + } + } + + @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = ".*returned a null temporaryUrlKey!") + public void whenAccountApiDoesntHaveKey() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(accountResponse())); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + TemporaryUrlSigner.checkApiEvery(api.getAccountApi("DFW"), 10000) + .sign("GET", "/v1/AUTH_account/container/object", 1323479485l); + } finally { + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + assertEquals(server.takeRequest().getRequestLine(), + "HEAD /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9 HTTP/1.1"); + server.shutdown(); + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedBlobStoreContextLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedBlobStoreContextLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedBlobStoreContextLiveTest.java new file mode 100644 index 0000000..97f5448 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedBlobStoreContextLiveTest.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.blobstore; + +import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; + +import java.io.IOException; +import java.util.Properties; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import org.jclouds.blobstore.BlobRequestSigner; +import org.jclouds.blobstore.BlobStore; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.blobstore.domain.PageSet; +import org.jclouds.blobstore.domain.StorageMetadata; +import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest; +import org.jclouds.domain.Location; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.io.ByteStreams2; +import org.jclouds.io.MutableContentMetadata; +import org.jclouds.io.Payload; +import org.jclouds.io.Payloads; +import org.jclouds.rest.HttpClient; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.common.io.ByteSource; +import com.google.common.hash.Hashing; +import com.google.common.net.MediaType; +import com.google.common.net.HttpHeaders; + +@Test(groups = "live") +public class RegionScopedBlobStoreContextLiveTest extends BaseBlobStoreIntegrationTest { + + public RegionScopedBlobStoreContextLiveTest() { + provider = "openstack-swift"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE); + return props; + } + + @Test + public void testRegionsAreNotEmpty() { + assertFalse(RegionScopedBlobStoreContext.class.cast(view).getConfiguredRegions().isEmpty()); + } + + @Test + public void testLocationsMatch() { + RegionScopedBlobStoreContext ctx = RegionScopedBlobStoreContext.class.cast(view); + for (String regionId : ctx.getConfiguredRegions()) { + Set<? extends Location> locations = ctx.getBlobStore(regionId).listAssignableLocations(); + assertEquals(locations.size(), 1, "expected one region " + regionId + " " + locations); + Location location = locations.iterator().next(); + assertEquals(location.getId(), regionId, "region id " + regionId + " didn't match getId(): " + location); + } + } + + @Test + public void testListBlobs() throws InterruptedException, ExecutionException { + RegionScopedBlobStoreContext ctx = RegionScopedBlobStoreContext.class.cast(view); + for (String regionId : ctx.getConfiguredRegions()) { + ctx.getBlobStore(regionId).list(); + } + } + + @Test + public void testSign() throws InterruptedException, ExecutionException, + IOException { + RegionScopedBlobStoreContext ctx = RegionScopedBlobStoreContext.class.cast(view); + for (String regionId : ctx.getConfiguredRegions()) { + BlobStore region = ctx.getBlobStore(regionId); + PageSet<? extends StorageMetadata> containers = region.list(); + if (containers.isEmpty()) { + continue; + } + String containerName = Iterables.getLast(containers).getName(); + + final ByteSource input = ByteSource.wrap("str".getBytes()); + final HttpClient client = ctx.utils().http(); + + // test signed put + String blobName = "test-" + UUID.randomUUID(); + Blob blob2 = region.blobBuilder(blobName).forSigning() + .contentLength(input.size()) + .contentMD5(input.hash(Hashing.md5()).asBytes()) + .contentType(MediaType.OCTET_STREAM.toString()).build(); + BlobRequestSigner signer = ctx.getSigner(regionId); + HttpResponse response; + try { + HttpRequest putRequest; + putRequest = signer.signPutBlob(containerName, blob2, 600); + MutableContentMetadata metadata = blob2.getMetadata() + .getContentMetadata(); + HttpRequest.Builder<?> putRequestBuilder = putRequest.toBuilder() + .addHeader(HttpHeaders.CONTENT_TYPE, + metadata.getContentType()); + putRequestBuilder.addHeader(HttpHeaders.CONTENT_LENGTH, + String.valueOf(input.size())); + putRequestBuilder.payload(input); + putRequest = putRequestBuilder.build(); + Payload payload = Payloads.newPayload(input.read()); + putRequest.setPayload(payload); + assertNotNull(putRequest, "regionId=" + regionId + ", container=" + + containerName + ", blob=" + blobName); + response = client.invoke(putRequest); + if (response.getStatusCode() != 200 + && response.getStatusCode() != 201) { + fail("Signed PUT expected to return 200 or 201 but returned " + + response.getStatusCode()); + } + } catch (Exception e) { + fail("Failed signed put test: " + e); + } + + // test signed get + try { + HttpRequest getRequest = signer.signGetBlob(containerName, + blobName); + assertNotNull(getRequest, "regionId=" + regionId + ", container=" + + containerName + ", blob=" + blobName); + response = client.invoke(getRequest); + if (response.getStatusCode() != 200) { + fail("Signed GET expected to return 200 but returned " + + response.getStatusCode()); + } + Payload payload = response.getPayload(); + assertEquals(ByteStreams2.toByteArrayAndClose(payload.openStream()), input.read(), + "Data with signed GET not identical to what was put"); + } catch (Exception e) { + fail("Failed signed GET test: " + e); + } + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java new file mode 100644 index 0000000..6d26100 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.blobstore.integration; + +import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE; + +import java.util.Properties; + +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest; +import org.testng.SkipException; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "SwiftBlobIntegrationLiveTest") +public class SwiftBlobIntegrationLiveTest extends BaseBlobIntegrationTest { + + public SwiftBlobIntegrationLiveTest() { + provider = "openstack-swift"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE); + return props; + } + + // Object/Container name contains forbidden chars from "<> + @Override + @DataProvider(name = "delete") + public Object[][] createData() { + return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unicâªde" }, { "path/foo" }, { "colon:" }, + { "asteri*k" }, { "p|pe" } }; + } + + @Override + public void testGetTwoRanges() { + throw new SkipException("unsupported in swift"); + } + + @Override + public void testCreateBlobWithExpiry() throws InterruptedException { + throw new SkipException("unsupported in swift"); + } + + @Test(groups = { "integration", "live" }) + public void testGetIfUnmodifiedSince() throws InterruptedException { + throw new SkipException("unsupported in swift"); + } + + @Override + protected int getIncorrectContentMD5StatusCode() { + return 422; + } + + @Override + protected void checkContentLanguage(Blob blob, String contentLanguage) { + assert blob.getPayload().getContentMetadata().getContentLanguage() == null; + assert blob.getMetadata().getContentMetadata().getContentLanguage() == null; + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java new file mode 100644 index 0000000..d9996bf --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.blobstore.integration; + +import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE; + +import java.util.Properties; + +import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "SwiftBlobLiveTest") +public class SwiftBlobLiveTest extends BaseBlobLiveTest { + + public SwiftBlobLiveTest() { + provider = "openstack-swift"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE); + return props; + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java new file mode 100644 index 0000000..9dd603f --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.blobstore.integration; + +import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE; + +import java.util.Properties; + +import org.jclouds.blobstore.integration.internal.BaseBlobSignerLiveTest; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "SwiftBlobSignerLiveTest") +public class SwiftBlobSignerLiveTest extends BaseBlobSignerLiveTest { + + public SwiftBlobSignerLiveTest() { + provider = "openstack-swift"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE); + return props; + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java new file mode 100644 index 0000000..d954867 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.blobstore.integration; + +import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE; +import static org.testng.Assert.assertTrue; + +import java.util.Properties; + +import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "SwiftContainerIntegrationLiveTest") +public class SwiftContainerIntegrationLiveTest extends BaseContainerIntegrationTest { + + public SwiftContainerIntegrationLiveTest() { + provider = "openstack-swift"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE); + return props; + } + + @Override + public void testListRootUsesDelimiter() throws InterruptedException { + try { + super.testListRootUsesDelimiter(); + } catch (AssertionError e) { + // swift doesn't have the "common prefixes" in the response that s3 + // does. If we wanted this to pass, we'd need to create + // pseudo-directories implicitly, which is costly and troublesome. It + // is better to fail this assertion. + assertTrue(e.getMessage().matches(".*16.* but .*15.*"), e.getMessage()); + // ^^ squishy regex to deal with various formats of testng messages. + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java new file mode 100644 index 0000000..9bd85d6 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.blobstore.integration; + +import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE; + +import java.util.Properties; + +import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "SwiftContainerLiveTest") +public class SwiftContainerLiveTest extends BaseContainerLiveTest { + + public SwiftContainerLiveTest() { + provider = "openstack-swift"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE); + return props; + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java new file mode 100644 index 0000000..1da1a68 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.blobstore.integration; + +import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE; + +import java.util.Properties; + +import org.jclouds.blobstore.integration.internal.BaseServiceIntegrationTest; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "SwiftServiceIntegrationLiveTest") +public class SwiftServiceIntegrationLiveTest extends BaseServiceIntegrationTest { + + public SwiftServiceIntegrationLiveTest() { + provider = "openstack-swift"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE); + return props; + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java new file mode 100644 index 0000000..e4225fc --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.config; + +import static org.testng.Assert.assertEquals; + +import org.jclouds.openstack.swift.v1.config.SwiftTypeAdapters.BulkDeleteResponseAdapter; +import org.jclouds.openstack.swift.v1.config.SwiftTypeAdapters.ExtractArchiveResponseAdapter; +import org.jclouds.openstack.swift.v1.domain.BulkDeleteResponse; +import org.jclouds.openstack.swift.v1.domain.ExtractArchiveResponse; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +@Test +public class SwiftTypeAdaptersTest { + Gson gson = new GsonBuilder() + .registerTypeAdapter(ExtractArchiveResponse.class, new ExtractArchiveResponseAdapter()) + .registerTypeAdapter(BulkDeleteResponse.class, new BulkDeleteResponseAdapter()) + .create(); + + public void extractArchiveWithoutErrors() { + assertEquals(gson.fromJson("" + + "{\n" + + " \"Response Status\": \"201 Created\",\n" + + " \"Response Body\": \"\",\n" + + " \"Errors\": [],\n" + + " \"Number Files Created\": 10\n" + + "}", ExtractArchiveResponse.class), ExtractArchiveResponse.create(10, ImmutableMap.<String, String> of())); + } + + public void extractArchiveWithErrorsAndDecodesPaths() { + assertEquals( + gson.fromJson("" + + "{\n" + + " \"Response Status\": \"201 Created\",\n" + + " \"Response Body\": \"\",\n" + + " \"Errors\": [\n" + + " [\"/v1/12345678912345/mycontainer/home/xx%3Cyy\", \"400 Bad Request\"],\n" + + " [\"/v1/12345678912345/mycontainer/../image.gif\", \"400 Bad Request\"]\n" + + " ],\n" + + " \"Number Files Created\": 8\n" + + "}", ExtractArchiveResponse.class), + ExtractArchiveResponse.create( + 8, + ImmutableMap.<String, String> builder() + .put("/v1/12345678912345/mycontainer/home/xx<yy", "400 Bad Request") + .put("/v1/12345678912345/mycontainer/../image.gif", "400 Bad Request").build())); + } + + public void bulkDeleteWithoutErrors() { + assertEquals(gson.fromJson("" + + "{\n" + + " \"Response Status\": \"200 OK\",\n" + + " \"Response Body\": \"\",\n" + + " \"Errors\": [],\n" + + " \"Number Not Found\": 1,\n" + + " \"Number Deleted\": 9\n" + + "}", BulkDeleteResponse.class), BulkDeleteResponse.create(9, 1, ImmutableMap.<String, String> of())); + } + + public void bulkDeleteWithErrorsAndDecodesPaths() { + assertEquals(gson.fromJson("" + + "{\n" + + " \"Response Status\": \"400 Bad Request\",\n" + + " \"Response Body\": \"\",\n" + + " \"Errors\": [\n" + + " [\"/v1/12345678912345/Not%20Empty\", \"409 Conflict\"]" + + " ],\n" + + " \"Number Deleted\": 0\n" + + "}", BulkDeleteResponse.class), + BulkDeleteResponse.create(0, 0, ImmutableMap.of("/v1/12345678912345/Not Empty", "409 Conflict"))); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java new file mode 100644 index 0000000..3841b33 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.Map; +import java.util.Map.Entry; + +import org.jclouds.openstack.swift.v1.SwiftApi; +import org.jclouds.openstack.swift.v1.domain.Account; +import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +@Test(groups = "live", testName = "AccountApiLiveTest") +public class AccountApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> { + + public void testGet() throws Exception { + for (String regionId : regions) { + AccountApi accountApi = api.getAccountApi(regionId); + Account account = accountApi.get(); + + assertNotNull(account); + assertTrue(account.getContainerCount() >= 0); + assertTrue(account.getObjectCount() >= 0); + assertTrue(account.getBytesUsed() >= 0); + } + } + + public void testUpdateMetadata() throws Exception { + for (String regionId : regions) { + AccountApi accountApi = api.getAccountApi(regionId); + + Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar"); + + assertTrue(accountApi.updateMetadata(meta)); + + accountHasMetadata(accountApi, meta); + } + } + + public void testDeleteMetadata() throws Exception { + for (String regionId : regions) { + AccountApi accountApi = api.getAccountApi(regionId); + + Map<String, String> meta = ImmutableMap.of("MyDelete1", "foo", "MyDelete2", "bar"); + + assertTrue(accountApi.updateMetadata(meta)); + accountHasMetadata(accountApi, meta); + + assertTrue(accountApi.deleteMetadata(meta)); + Account account = accountApi.get(); + for (Entry<String, String> entry : meta.entrySet()) { + // note keys are returned in lower-case! + assertFalse(account.getMetadata().containsKey(entry.getKey().toLowerCase())); + } + } + } + + static void accountHasMetadata(AccountApi accountApi, Map<String, String> meta) { + Account account = accountApi.get(); + for (Entry<String, String> entry : meta.entrySet()) { + // note keys are returned in lower-case! + assertEquals(account.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue(), + account + " didn't have metadata: " + entry); + } + } +}
