From a6b80c7beb473b30a5bfeff3dc1595ede794d231 Mon Sep 17 00:00:00 2001 From: "adrian.f.cole" Date: Sun, 10 May 2009 00:13:21 +0000 Subject: [PATCH] finished copyobject tests git-svn-id: http://jclouds.googlecode.com/svn/trunk@573 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../java/org/jclouds/http/HttpMessage.java | 6 + .../commands/options/CopyObjectOptions.java | 5 +- .../s3/filters/RequestAuthorizeSignature.java | 7 +- .../commands/CopyObjectIntegrationTest.java | 158 +++++++++++++++++- .../aws/s3/config/S3ContextModuleTest.java | 124 ++++++++++++++ 5 files changed, 287 insertions(+), 13 deletions(-) create mode 100644 s3/src/test/java/org/jclouds/aws/s3/config/S3ContextModuleTest.java diff --git a/core/src/main/java/org/jclouds/http/HttpMessage.java b/core/src/main/java/org/jclouds/http/HttpMessage.java index 4c83c4ac71..96c58a3b3e 100644 --- a/core/src/main/java/org/jclouds/http/HttpMessage.java +++ b/core/src/main/java/org/jclouds/http/HttpMessage.java @@ -28,6 +28,12 @@ import java.util.Collection; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +/** + * Provides base functionality of HTTP requests and responses. + * + * @author Adrian Cole + * + */ public class HttpMessage { protected Multimap headers = HashMultimap.create(); diff --git a/s3/src/main/java/org/jclouds/aws/s3/commands/options/CopyObjectOptions.java b/s3/src/main/java/org/jclouds/aws/s3/commands/options/CopyObjectOptions.java index bb2044660c..1ed06347e3 100644 --- a/s3/src/main/java/org/jclouds/aws/s3/commands/options/CopyObjectOptions.java +++ b/s3/src/main/java/org/jclouds/aws/s3/commands/options/CopyObjectOptions.java @@ -235,8 +235,10 @@ public class CopyObjectOptions extends BaseHttpRequestOptions { public Multimap buildRequestHeaders() { Multimap returnVal = HashMultimap.create(); returnVal.putAll(headers); - if (metadata != null) + if (metadata != null) { returnVal.putAll(metadata); + returnVal.put("x-amz-metadata-directive", "REPLACE"); + } return returnVal; } @@ -250,7 +252,6 @@ public class CopyObjectOptions extends BaseHttpRequestOptions { checkArgument(header.startsWith("x-amz-meta-"), "Metadata keys must start with x-amz-meta-"); } - metadata.put("x-amz-copy-source-if-unmodified-since", "REPLACE"); this.metadata = metadata; return this; } diff --git a/s3/src/main/java/org/jclouds/aws/s3/filters/RequestAuthorizeSignature.java b/s3/src/main/java/org/jclouds/aws/s3/filters/RequestAuthorizeSignature.java index 1111053034..53bc51f52a 100644 --- a/s3/src/main/java/org/jclouds/aws/s3/filters/RequestAuthorizeSignature.java +++ b/s3/src/main/java/org/jclouds/aws/s3/filters/RequestAuthorizeSignature.java @@ -24,6 +24,8 @@ package org.jclouds.aws.s3.filters; import java.util.Collection; +import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; @@ -130,11 +132,12 @@ public class RequestAuthorizeSignature implements HttpRequestFilter { } private void appendAmzHeaders(HttpRequest request, StringBuilder toSign) { - for (String header : request.getHeaders().keySet()) { + Set headers = new TreeSet(request.getHeaders().keySet()); + for (String header : headers) { if (header.startsWith("x-amz-")) { toSign.append(header).append(":"); for (String value : request.getHeaders().get(header)) - toSign.append(value.replaceAll("\r?\n", " ")).append(","); + toSign.append(value.replaceAll("\r?\n", "")).append(","); toSign.deleteCharAt(toSign.lastIndexOf(",")); toSign.append("\n"); } diff --git a/s3/src/test/java/org/jclouds/aws/s3/commands/CopyObjectIntegrationTest.java b/s3/src/test/java/org/jclouds/aws/s3/commands/CopyObjectIntegrationTest.java index aff8348745..e328d0bcd9 100644 --- a/s3/src/test/java/org/jclouds/aws/s3/commands/CopyObjectIntegrationTest.java +++ b/s3/src/test/java/org/jclouds/aws/s3/commands/CopyObjectIntegrationTest.java @@ -23,14 +23,29 @@ */ package org.jclouds.aws.s3.commands; +import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceMd5DoesntMatch; +import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceMd5Matches; +import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceModifiedSince; +import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceUnmodifiedSince; +import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.overrideMetadataWith; +import static org.testng.Assert.assertEquals; + import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.jclouds.aws.s3.S3Headers; import org.jclouds.aws.s3.S3IntegrationTest; +import org.jclouds.aws.s3.S3ResponseException; +import org.jclouds.aws.s3.S3Utils; +import org.jclouds.aws.s3.domain.S3Object; +import org.joda.time.DateTime; import org.testng.annotations.Test; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + /** * Tests integrated functionality of all copyObject commands. *

@@ -64,33 +79,158 @@ public class CopyObjectIntegrationTest extends S3IntegrationTest { throws InterruptedException, ExecutionException, TimeoutException, IOException { createBucketAndEnsureEmpty(sourceBucket); + addToBucketAndValidate(sourceBucket, sourceKey); + } + + private void addToBucketAndValidate(String sourceBucket, String sourceKey) + throws InterruptedException, ExecutionException, TimeoutException, + IOException { addObjectToBucket(sourceBucket, sourceKey); validateContent(sourceBucket, sourceKey); } @Test - void testCopyIfModifiedSince() { - // TODO + void testCopyIfModifiedSince() throws InterruptedException, + ExecutionException, TimeoutException, IOException { + String sourceBucket = bucketPrefix + "testCopyIfModifiedSince"; + String sourceKey = "apples"; + String destinationBucket = bucketPrefix + + "testCopyIfModifiedSinceDestination"; + String destinationKey = "pears"; + + DateTime before = new DateTime(); + setupSourceBucket(sourceBucket, sourceKey); + DateTime after = new DateTime().plusSeconds(1); + + createBucketAndEnsureEmpty(destinationBucket); + client.copyObject(sourceBucket, sourceKey, destinationBucket, + destinationKey, ifSourceModifiedSince(before)).get(10, + TimeUnit.SECONDS); + validateContent(destinationBucket, destinationKey); + + try { + client.copyObject(sourceBucket, sourceKey, destinationBucket, + destinationKey, ifSourceModifiedSince(after)).get(10, + TimeUnit.SECONDS); + } catch (ExecutionException e) { + S3ResponseException ex = (S3ResponseException) e.getCause(); + assertEquals(ex.getResponse().getStatusCode(), 412); + } } @Test - void testCopyIfUnmodifiedSince() { - // TODO + void testCopyIfUnmodifiedSince() throws InterruptedException, + ExecutionException, TimeoutException, IOException { + String sourceBucket = bucketPrefix + "testCopyIfUnmodifiedSince"; + String sourceKey = "apples"; + String destinationBucket = bucketPrefix + + "testCopyIfUnmodifiedSinceDestination"; + String destinationKey = "pears"; + + DateTime before = new DateTime(); + setupSourceBucket(sourceBucket, sourceKey); + DateTime after = new DateTime().plusSeconds(1); + + createBucketAndEnsureEmpty(destinationBucket); + client.copyObject(sourceBucket, sourceKey, destinationBucket, + destinationKey, ifSourceUnmodifiedSince(after)).get(10, + TimeUnit.SECONDS); + validateContent(destinationBucket, destinationKey); + + try { + client.copyObject(sourceBucket, sourceKey, destinationBucket, + destinationKey, ifSourceModifiedSince(before)).get(10, + TimeUnit.SECONDS); + } catch (ExecutionException e) { + S3ResponseException ex = (S3ResponseException) e.getCause(); + assertEquals(ex.getResponse().getStatusCode(), 412); + } } @Test - void testCopyIfMatch() { - // TODO + void testCopyIfMatch() throws InterruptedException, ExecutionException, + TimeoutException, IOException { + String sourceBucket = bucketPrefix + "testCopyIfMatch"; + String sourceKey = "apples"; + byte[] realMd5 = S3Utils.md5(TEST_STRING); + byte[] badMd5 = S3Utils.md5("alf"); + + String destinationBucket = bucketPrefix + "testCopyIfMatchDestination"; + String destinationKey = "pears"; + + setupSourceBucket(sourceBucket, sourceKey); + + createBucketAndEnsureEmpty(destinationBucket); + client.copyObject(sourceBucket, sourceKey, destinationBucket, + destinationKey, ifSourceMd5Matches(realMd5)).get(10, + TimeUnit.SECONDS); + validateContent(destinationBucket, destinationKey); + + try { + client.copyObject(sourceBucket, sourceKey, destinationBucket, + destinationKey, ifSourceMd5Matches(badMd5)).get(10, + TimeUnit.SECONDS); + } catch (ExecutionException e) { + S3ResponseException ex = (S3ResponseException) e.getCause(); + assertEquals(ex.getResponse().getStatusCode(), 412); + } } @Test - void testCopyIfNoneMatch() { - // TODO + void testCopyIfNoneMatch() throws IOException, InterruptedException, + ExecutionException, TimeoutException { + String sourceBucket = bucketPrefix + "testCopyIfNoneMatch"; + String sourceKey = "apples"; + byte[] realMd5 = S3Utils.md5(TEST_STRING); + byte[] badMd5 = S3Utils.md5("alf"); + + String destinationBucket = bucketPrefix + + "testCopyIfNoneMatchDestination"; + String destinationKey = "pears"; + + setupSourceBucket(sourceBucket, sourceKey); + + createBucketAndEnsureEmpty(destinationBucket); + client.copyObject(sourceBucket, sourceKey, destinationBucket, + destinationKey, ifSourceMd5DoesntMatch(badMd5)).get(10, + TimeUnit.SECONDS); + validateContent(destinationBucket, destinationKey); + + try { + client.copyObject(sourceBucket, sourceKey, destinationBucket, + destinationKey, ifSourceMd5DoesntMatch(realMd5)).get(10, + TimeUnit.SECONDS); + } catch (ExecutionException e) { + S3ResponseException ex = (S3ResponseException) e.getCause(); + assertEquals(ex.getResponse().getStatusCode(), 412); + } } @Test - void testCopyWithMetadata() { + void testCopyWithMetadata() throws InterruptedException, + ExecutionException, TimeoutException, IOException { + String sourceBucket = bucketPrefix + "testCopyWithMetadata"; + String sourceKey = "apples"; + String destinationBucket = bucketPrefix + + "testCopyWithMetadataDestination"; + String destinationKey = "pears"; + setupSourceBucket(sourceBucket, sourceKey); + + Multimap metadata = HashMultimap.create(); + metadata.put(S3Headers.USER_METADATA_PREFIX + "adrian", "cole"); + + createBucketAndEnsureEmpty(destinationBucket); + client.copyObject(sourceBucket, sourceKey, destinationBucket, + destinationKey, overrideMetadataWith(metadata)).get(10, + TimeUnit.SECONDS); + + validateContent(destinationBucket, destinationKey); + + S3Object.Metadata objectMeta = client.headObject(destinationBucket, + destinationKey).get(10, TimeUnit.SECONDS); + + assertEquals(objectMeta.getUserMetadata(), metadata); } } \ No newline at end of file diff --git a/s3/src/test/java/org/jclouds/aws/s3/config/S3ContextModuleTest.java b/s3/src/test/java/org/jclouds/aws/s3/config/S3ContextModuleTest.java new file mode 100644 index 0000000000..de723ee5af --- /dev/null +++ b/s3/src/test/java/org/jclouds/aws/s3/config/S3ContextModuleTest.java @@ -0,0 +1,124 @@ +/** + * + * Copyright (C) 2009 Adrian Cole + * + * ==================================================================== + * 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.aws.s3.config; + +import static org.testng.Assert.assertEquals; + +import org.jclouds.aws.s3.S3Constants; +import org.jclouds.aws.s3.filters.ParseS3ErrorFromXmlContent; +import org.jclouds.http.HttpResponseHandler; +import org.jclouds.http.annotation.ClientErrorHandler; +import org.jclouds.http.annotation.RedirectHandler; +import org.jclouds.http.annotation.ServerErrorHandler; +import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.name.Names; + +/** + * + * @author Adrian Cole + */ +@Test +public class S3ContextModuleTest { + + Injector injector = null; + + @BeforeMethod + void setUpInjector() { + injector = Guice.createInjector(new S3ContextModule() { + @Override + protected void configure() { + bindConstant().annotatedWith( + Names.named(S3Constants.PROPERTY_AWS_ACCESSKEYID)).to( + "localhost"); + bindConstant().annotatedWith( + Names.named(S3Constants.PROPERTY_AWS_SECRETACCESSKEY)) + .to("localhost"); + bindConstant().annotatedWith( + Names.named(S3Constants.PROPERTY_HTTP_ADDRESS)).to( + "localhost"); + bindConstant().annotatedWith( + Names.named(S3Constants.PROPERTY_HTTP_PORT)).to("1000"); + bindConstant().annotatedWith( + Names.named(S3Constants.PROPERTY_HTTP_SECURE)).to( + "false"); + super.configure(); + } + }, new JavaUrlHttpFutureCommandClientModule()); + } + + @AfterMethod + void tearDownInjector() { + injector = null; + } + + private static class ClientErrorHandlerTest { + @Inject + @ClientErrorHandler + HttpResponseHandler errorHandler; + } + + @Test + void testClientErrorHandler() { + ClientErrorHandlerTest error = injector + .getInstance(ClientErrorHandlerTest.class); + assertEquals(error.errorHandler.getClass(), + ParseS3ErrorFromXmlContent.class); + } + + private static class ServerErrorHandlerTest { + @Inject + @ServerErrorHandler + HttpResponseHandler errorHandler; + } + + @Test + void testServerErrorHandler() { + ServerErrorHandlerTest error = injector + .getInstance(ServerErrorHandlerTest.class); + assertEquals(error.errorHandler.getClass(), + ParseS3ErrorFromXmlContent.class); + } + + private static class RedirectHandlerTest { + @Inject + @RedirectHandler + HttpResponseHandler errorHandler; + } + + @Test + void testRedirectHandler() { + RedirectHandlerTest error = injector + .getInstance(RedirectHandlerTest.class); + assertEquals(error.errorHandler.getClass(), + ParseS3ErrorFromXmlContent.class); + } + +} \ No newline at end of file