blob: b06413eac76b94279dfd1e10be59634ea01d733b [file] [log] [blame]
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.s3;
import static org.jclouds.s3.internal.StubS3AsyncClient.TEST_ACL_EMAIL;
import static org.jclouds.s3.internal.StubS3AsyncClient.TEST_ACL_ID;
import static org.jclouds.s3.options.CopyObjectOptions.Builder.ifSourceETagDoesntMatch;
import static org.jclouds.s3.options.CopyObjectOptions.Builder.ifSourceETagMatches;
import static org.jclouds.s3.options.CopyObjectOptions.Builder.ifSourceModifiedSince;
import static org.jclouds.s3.options.CopyObjectOptions.Builder.ifSourceUnmodifiedSince;
import static org.jclouds.s3.options.CopyObjectOptions.Builder.overrideAcl;
import static org.jclouds.s3.options.CopyObjectOptions.Builder.overrideMetadataWith;
import static org.jclouds.s3.options.PutObjectOptions.Builder.withAcl;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
import org.jclouds.http.HttpResponseException;
import org.jclouds.s3.domain.AccessControlList;
import org.jclouds.s3.domain.CannedAccessPolicy;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.S3Object;
import org.jclouds.s3.domain.AccessControlList.CanonicalUserGrantee;
import org.jclouds.s3.domain.AccessControlList.EmailAddressGrantee;
import org.jclouds.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.s3.domain.AccessControlList.Permission;
import org.jclouds.s3.options.PutObjectOptions;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
/**
*
* @author James Murty
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" })
public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
public S3ClientLiveTest() {
this.provider = "s3";
}
public S3Client getApi() {
return view.unwrap(S3ApiMetadata.CONTEXT_TOKEN).getApi();
}
/**
* this method overrides containerName to ensure it isn't found
*/
@Test(groups = { "integration", "live" })
public void deleteContainerIfEmptyNotFound() throws Exception {
assert getApi().deleteBucketIfEmpty("dbienf");
}
@Test(groups = { "integration", "live" })
public void deleteContainerIfEmptyButHasContents() throws Exception {
String containerName = getContainerName();
try {
addBlobToContainer(containerName, "test");
assert !getApi().deleteBucketIfEmpty(containerName);
} finally {
returnContainer(containerName);
}
}
protected URL getObjectURL(String containerName, String key) throws Exception {
URL url = new URL(String.format("http://%s.%s/%s", containerName, URI.create(endpoint).getHost(), key));
return url;
}
public void testPutCannedAccessPolicyPublic() throws Exception {
String containerName = getContainerName();
try {
String key = "hello";
S3Object object = getApi().newS3Object();
object.getMetadata().setKey(key);
object.setPayload(TEST_STRING);
getApi().putObject(containerName, object,
withAcl(CannedAccessPolicy.PUBLIC_READ));
URL url = this.getObjectURL(containerName, key);
Strings2.toStringAndClose(url.openStream());
} finally {
returnContainer(containerName);
}
}
public void testCopyCannedAccessPolicyPublic() throws Exception {
String containerName = getContainerName();
String destinationContainer = getContainerName();
try {
addBlobToContainer(containerName, sourceKey);
validateContent(containerName, sourceKey);
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
overrideAcl(CannedAccessPolicy.PUBLIC_READ));
validateContent(destinationContainer, destinationKey);
URL url = getObjectURL(destinationContainer, destinationKey);
Strings2.toStringAndClose(url.openStream());
} finally {
returnContainer(containerName);
returnContainer(destinationContainer);
}
}
String sourceKey = "apples";
String destinationKey = "pears";
public void testPublicWriteOnObject() throws InterruptedException, ExecutionException, TimeoutException, IOException {
final String publicReadWriteObjectKey = "public-read-write-acl";
final String containerName = getContainerName();
try {
S3Object object = getApi().newS3Object();
object.getMetadata().setKey(publicReadWriteObjectKey);
object.setPayload("");
// Public Read-Write object
getApi()
.putObject(containerName, object,
new PutObjectOptions().withAcl(CannedAccessPolicy.PUBLIC_READ_WRITE));
assertConsistencyAware(new Runnable() {
public void run() {
try {
AccessControlList acl = getApi().getObjectACL(containerName, publicReadWriteObjectKey);
assertEquals(acl.getGrants().size(), 3);
assertEquals(acl.getPermissions(GroupGranteeURI.ALL_USERS).size(), 2);
assertTrue(acl.getOwner() != null);
String ownerId = acl.getOwner().getId();
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.WRITE));
assertFalse(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ_ACP));
assertFalse(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.WRITE_ACP));
assertFalse(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.FULL_CONTROL));
} catch (Exception e) {
Throwables.propagateIfPossible(e);
}
}
});
} finally {
returnContainer(containerName);
}
}
public void testUpdateObjectACL() throws InterruptedException, ExecutionException, TimeoutException, IOException {
String containerName = getContainerName();
try {
String objectKey = "private-acl";
// Private object
addBlobToContainer(containerName, objectKey);
AccessControlList acl = getApi().getObjectACL(containerName, objectKey);
String ownerId = acl.getOwner().getId();
assertEquals(acl.getGrants().size(), 1);
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
addGrantsToACL(acl);
assertEquals(acl.getGrants().size(), 4);
assertTrue(getApi().putObjectACL(containerName, objectKey, acl));
// Confirm that the updated ACL has stuck.
acl = getApi().getObjectACL(containerName, objectKey);
checkGrants(acl);
/*
* Revoke all of owner's permissions!
*/
acl.revokeAllPermissions(new CanonicalUserGrantee(ownerId));
if (!ownerId.equals(TEST_ACL_ID))
acl.revokeAllPermissions(new CanonicalUserGrantee(TEST_ACL_ID));
assertEquals(acl.getGrants().size(), 1);
// Only public read permission should remain...
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
// Update the object's ACL settings
assertTrue(getApi().putObjectACL(containerName, objectKey, acl));
// Confirm that the updated ACL has stuck
acl = getApi().getObjectACL(containerName, objectKey);
assertEquals(acl.getGrants().size(), 1);
assertEquals(acl.getPermissions(ownerId).size(), 0);
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
} finally {
returnContainer(containerName);
}
}
public void testPrivateAclIsDefaultForObject() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String privateObjectKey = "private-acl";
String containerName = getContainerName();
try {
// Private object
addBlobToContainer(containerName, privateObjectKey);
AccessControlList acl = getApi().getObjectACL(containerName, privateObjectKey);
assertEquals(acl.getGrants().size(), 1);
assertTrue(acl.getOwner() != null);
String ownerId = acl.getOwner().getId();
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
} finally {
returnContainer(containerName);
}
}
public void testPublicReadOnObject() throws InterruptedException, ExecutionException, TimeoutException, IOException {
final String publicReadObjectKey = "public-read-acl";
final String containerName = getContainerName();
try {
S3Object object = getApi().newS3Object();
object.getMetadata().setKey(publicReadObjectKey);
object.setPayload("");
getApi().putObject(containerName, object, new PutObjectOptions().withAcl(CannedAccessPolicy.PUBLIC_READ));
assertConsistencyAware(new Runnable() {
public void run() {
try {
AccessControlList acl = getApi().getObjectACL(containerName, publicReadObjectKey);
assertEquals(acl.getGrants().size(), 2);
assertEquals(acl.getPermissions(GroupGranteeURI.ALL_USERS).size(), 1);
assertTrue(acl.getOwner() != null);
String ownerId = acl.getOwner().getId();
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ));
} catch (Exception e) {
Throwables.propagateIfPossible(e);
}
}
});
} finally {
returnContainer(containerName);
}
}
protected String addBlobToContainer(String sourceContainer, String key) {
S3Object sourceObject = getApi().newS3Object();
sourceObject.getMetadata().setKey(key);
sourceObject.getMetadata().getContentMetadata().setContentType("text/xml");
sourceObject.setPayload(TEST_STRING);
return getApi().putObject(sourceContainer, sourceObject);
}
protected S3Object validateObject(String sourceContainer, String key) throws InterruptedException,
ExecutionException, TimeoutException, IOException {
assertConsistencyAwareContainerSize(sourceContainer, 1);
S3Object newObject = getApi().getObject(sourceContainer, key);
assert newObject != null;
assertEquals(Strings2.toString(newObject.getPayload()), TEST_STRING);
return newObject;
}
public void testMetadataWithCacheControlAndContentDisposition() throws Exception {
String key = "hello";
S3Object object = getApi().newS3Object();
object.getMetadata().setKey(key);
object.setPayload(TEST_STRING);
object.getMetadata().setCacheControl("no-cache");
object.getMetadata().getContentMetadata().setContentDisposition("attachment; filename=hello.txt");
String containerName = getContainerName();
try {
getApi().putObject(containerName, object);
S3Object newObject = validateObject(containerName, key);
assertCacheControl(newObject, "no-cache");
assertEquals(newObject.getMetadata().getContentMetadata().getContentDisposition(),
"attachment; filename=hello.txt");
} finally {
returnContainer(containerName);
}
}
protected void assertCacheControl(S3Object newObject, String string) {
assert (newObject.getMetadata().getCacheControl().indexOf(string) != -1) : newObject.getMetadata()
.getCacheControl();
}
protected void assertContentEncoding(S3Object newObject, String string) {
assert (newObject.getPayload().getContentMetadata().getContentEncoding().indexOf(string) != -1) : newObject
.getPayload().getContentMetadata().getContentEncoding();
assert (newObject.getMetadata().getContentMetadata().getContentEncoding().indexOf(string) != -1) : newObject
.getMetadata().getContentMetadata().getContentEncoding();
}
@Test(groups = { "integration", "live" })
public void testMetadataContentEncoding() throws Exception {
String key = "hello";
S3Object object = getApi().newS3Object();
object.getMetadata().setKey(key);
object.setPayload(TEST_STRING);
object.getMetadata().getContentMetadata().setContentEncoding("x-compress");
String containerName = getContainerName();
try {
getApi().putObject(containerName, object);
S3Object newObject = validateObject(containerName, key);
assertContentEncoding(newObject, "x-compress");
} finally {
returnContainer(containerName);
}
}
public void testCopyObject() throws Exception {
String containerName = getContainerName();
String destinationContainer = getContainerName();
try {
addToContainerAndValidate(containerName, sourceKey);
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey);
validateContent(destinationContainer, destinationKey);
} finally {
returnContainer(containerName);
returnContainer(destinationContainer);
}
}
protected String addToContainerAndValidate(String containerName, String sourceKey) throws InterruptedException,
ExecutionException, TimeoutException, IOException {
String etag = addBlobToContainer(containerName, sourceKey);
validateContent(containerName, sourceKey);
return etag;
}
// TODO: fails on linux and windows
public void testCopyIfModifiedSince() throws InterruptedException, ExecutionException, TimeoutException, IOException {
String containerName = getContainerName();
String destinationContainer = getContainerName();
try {
Date before = new Date();
addToContainerAndValidate(containerName, sourceKey + "mod");
Date after = new Date(System.currentTimeMillis() + 1000);
getApi().copyObject(containerName, sourceKey + "mod", destinationContainer, destinationKey,
ifSourceModifiedSince(before));
validateContent(destinationContainer, destinationKey);
try {
getApi().copyObject(containerName, sourceKey + "mod", destinationContainer, destinationKey,
ifSourceModifiedSince(after));
} catch (HttpResponseException ex) {
assertEquals(ex.getResponse().getStatusCode(), 412);
}
} finally {
returnContainer(containerName);
returnContainer(destinationContainer);
}
}
// TODO: fails on linux and windows
public void testCopyIfUnmodifiedSince() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String containerName = getContainerName();
String destinationContainer = getContainerName();
try {
Date before = new Date();
addToContainerAndValidate(containerName, sourceKey + "un");
Date after = new Date(System.currentTimeMillis() + 1000);
getApi().copyObject(containerName, sourceKey + "un", destinationContainer, destinationKey,
ifSourceUnmodifiedSince(after));
validateContent(destinationContainer, destinationKey);
try {
getApi().copyObject(containerName, sourceKey + "un", destinationContainer, destinationKey,
ifSourceModifiedSince(before));
} catch (HttpResponseException ex) {
assertEquals(ex.getResponse().getStatusCode(), 412);
}
} finally {
returnContainer(containerName);
returnContainer(destinationContainer);
}
}
public void testCopyIfMatch() throws InterruptedException, ExecutionException, TimeoutException, IOException {
String containerName = getContainerName();
String destinationContainer = getContainerName();
try {
String goodETag = addToContainerAndValidate(containerName, sourceKey);
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
ifSourceETagMatches(goodETag));
validateContent(destinationContainer, destinationKey);
try {
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
ifSourceETagMatches("setsds"));
} catch (HttpResponseException ex) {
assertEquals(ex.getResponse().getStatusCode(), 412);
}
} finally {
returnContainer(containerName);
returnContainer(destinationContainer);
}
}
public void testCopyIfNoneMatch() throws IOException, InterruptedException, ExecutionException, TimeoutException {
String containerName = getContainerName();
String destinationContainer = getContainerName();
try {
String goodETag = addToContainerAndValidate(containerName, sourceKey);
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
ifSourceETagDoesntMatch("asfasdf"));
validateContent(destinationContainer, destinationKey);
try {
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
ifSourceETagDoesntMatch(goodETag));
} catch (HttpResponseException ex) {
assertEquals(ex.getResponse().getStatusCode(), 412);
}
} finally {
returnContainer(containerName);
returnContainer(destinationContainer);
}
}
public void testCopyWithMetadata() throws InterruptedException, ExecutionException, TimeoutException, IOException {
String containerName = getContainerName();
String destinationContainer = getContainerName();
try {
addToContainerAndValidate(containerName, sourceKey);
Map<String, String> metadata = Maps.newHashMap();
metadata.put("adrian", "cole");
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
overrideMetadataWith(metadata));
validateContent(destinationContainer, destinationKey);
ObjectMetadata objectMeta = getApi().headObject(destinationContainer, destinationKey);
assertEquals(objectMeta.getUserMetadata(), metadata);
} finally {
returnContainer(containerName);
returnContainer(destinationContainer);
}
}
private void checkGrants(AccessControlList acl) {
String ownerId = acl.getOwner().getId();
assertEquals(acl.getGrants().size(), 4, acl.toString());
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL), acl.toString());
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
assertTrue(acl.hasPermission(ownerId, Permission.WRITE_ACP), acl.toString());
// EmailAddressGrantee is replaced by a CanonicalUserGrantee, so we cannot test by email addr
assertTrue(acl.hasPermission(TEST_ACL_ID, Permission.READ_ACP), acl.toString());
}
private void addGrantsToACL(AccessControlList acl) {
String ownerId = acl.getOwner().getId();
acl.addPermission(GroupGranteeURI.ALL_USERS, Permission.READ);
acl.addPermission(new EmailAddressGrantee(TEST_ACL_EMAIL), Permission.READ_ACP);
acl.addPermission(new CanonicalUserGrantee(ownerId), Permission.WRITE_ACP);
}
}