/**
* 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.services;
import static org.jclouds.s3.options.ListBucketOptions.Builder.afterMarker;
import static org.jclouds.s3.options.ListBucketOptions.Builder.delimiter;
import static org.jclouds.s3.options.ListBucketOptions.Builder.maxResults;
import static org.jclouds.s3.options.ListBucketOptions.Builder.withPrefix;
import static org.jclouds.s3.options.PutBucketOptions.Builder.withBucketAcl;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
import org.jclouds.s3.S3ApiMetadata;
import org.jclouds.s3.S3Client;
import org.jclouds.s3.domain.AccessControlList;
import org.jclouds.s3.domain.AccessControlList.CanonicalUserGrantee;
import org.jclouds.s3.domain.AccessControlList.EmailAddressGrantee;
import org.jclouds.s3.domain.AccessControlList.Grant;
import org.jclouds.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.s3.domain.AccessControlList.Permission;
import org.jclouds.s3.domain.BucketLogging;
import org.jclouds.s3.domain.BucketMetadata;
import org.jclouds.s3.domain.CannedAccessPolicy;
import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.Payer;
import org.jclouds.s3.domain.S3Object;
import org.jclouds.s3.internal.StubS3AsyncClient;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
*
* @author James Murty
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" })
public class BucketsLiveTest extends BaseBlobStoreIntegrationTest {
public BucketsLiveTest() {
this.provider = "s3";
BaseBlobStoreIntegrationTest.SANITY_CHECK_RETURNED_BUCKET_NAME = true;
}
public S3Client getApi() {
return view.unwrap(S3ApiMetadata.CONTEXT_TOKEN).getApi();
}
/**
* this method overrides bucketName to ensure it isn't found
*/
@Test(groups = { "integration", "live" })
public void deleteBucketIfEmptyNotFound() throws Exception {
assert getApi().deleteBucketIfEmpty("dbienf");
}
@Test(groups = { "integration", "live" })
public void deleteBucketIfEmptyButHasContents() throws Exception {
String bucketName = getContainerName();
try {
addBlobToContainer(bucketName, "test");
assert !getApi().deleteBucketIfEmpty(bucketName);
} finally {
returnContainer(bucketName);
}
}
public void testPrivateAclIsDefaultForBucket() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String bucketName = getContainerName();
try {
AccessControlList acl = getApi().getBucketACL(bucketName);
assertEquals(acl.getGrants().size(), 1);
assertNotNull(acl.getOwner());
String ownerId = acl.getOwner().getId();
assertTrue(acl.hasPermission(ownerId, Permission.FULL_CONTROL));
} finally {
returnContainer(bucketName);
}
}
public void testUpdateBucketACL() throws InterruptedException, ExecutionException, TimeoutException, IOException,
Exception {
String bucketName = getContainerName();
try {
// Confirm the bucket is private
AccessControlList acl = getApi().getBucketACL(bucketName);
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().putBucketACL(bucketName, acl));
// Confirm that the updated ACL has stuck.
acl = getApi().getBucketACL(bucketName);
checkGrants(acl);
} finally {
destroyContainer(bucketName);
}
}
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(StubS3AsyncClient.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(StubS3AsyncClient.TEST_ACL_EMAIL), Permission.READ_ACP);
acl.addPermission(new CanonicalUserGrantee(ownerId), Permission.WRITE_ACP);
}
public void testPublicReadAccessPolicy() throws Exception {
String bucketName = getScratchContainerName();
try {
getApi().putBucketInRegion(null, bucketName, withBucketAcl(CannedAccessPolicy.PUBLIC_READ));
AccessControlList acl = getApi().getBucketACL(bucketName);
assertTrue(acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ), acl.toString());
// TODO: I believe that the following should work based on the above acl assertion passing.
// However, it fails on 403
// URL url = new URL(String.format("http://%s.s3.amazonaws.com", bucketName));
// Utils.toStringAndClose(url.openStream());
} finally {
destroyContainer(bucketName);
}
}
@Test(expectedExceptions = IOException.class)
public void testDefaultAccessPolicy() throws Exception {
String bucketName = getContainerName();
try {
URL url = new URL(String.format("https://%s.s3.amazonaws.com", bucketName));
Strings2.toStringAndClose(url.openStream());
} finally {
returnContainer(bucketName);
}
}
public void testBucketPayer() throws Exception {
final String bucketName = getContainerName();
try {
assertEquals(Payer.BUCKET_OWNER, getApi().getBucketPayer(bucketName));
getApi().setBucketPayer(bucketName, Payer.REQUESTER);
assertConsistencyAware(new Runnable() {
public void run() {
try {
assertEquals(Payer.REQUESTER, getApi().getBucketPayer(bucketName));
} catch (Exception e) {
Throwables.propagateIfPossible(e);
}
}
});
getApi().setBucketPayer(bucketName, Payer.BUCKET_OWNER);
assertConsistencyAware(new Runnable() {
public void run() {
try {
assertEquals(Payer.BUCKET_OWNER, getApi().getBucketPayer(bucketName));
} catch (Exception e) {
Throwables.propagateIfPossible(e);
}
}
});
} finally {
destroyContainer(bucketName);
}
}
public void testBucketLogging() throws Exception {
final String bucketName = getContainerName();
final String targetBucket = getContainerName();
try {
assertNull(getApi().getBucketLogging(bucketName));
setupAclForBucketLoggingTarget(targetBucket);
final BucketLogging logging = new BucketLogging(targetBucket, "access_log-",
ImmutableSet.<Grant> of(new Grant(new EmailAddressGrantee(StubS3AsyncClient.TEST_ACL_EMAIL),
Permission.FULL_CONTROL)));
getApi().enableBucketLogging(bucketName, logging);
assertConsistencyAware(new Runnable() {
public void run() {
try {
BucketLogging newLogging = getApi().getBucketLogging(bucketName);
assert newLogging !=null;
AccessControlList acl = new AccessControlList();
for (Grant grant : newLogging.getTargetGrants()) { // TODO: add permission
// checking features to
// bucketlogging
acl.addPermission(grant.getGrantee(), grant.getPermission());
}
// EmailAddressGrantee is replaced by a CanonicalUserGrantee, so we cannot test by
// email addr
assertTrue(acl.hasPermission(StubS3AsyncClient.TEST_ACL_ID, Permission.FULL_CONTROL), acl.toString());
assertEquals(logging.getTargetBucket(), newLogging.getTargetBucket());
assertEquals(logging.getTargetPrefix(), newLogging.getTargetPrefix());
} catch (Exception e) {
Throwables.propagateIfPossible(e);
}
}
});
getApi().disableBucketLogging(bucketName);
assertConsistencyAware(new Runnable() {
public void run() {
try {
assertNull(getApi().getBucketLogging(bucketName));
} catch (Exception e) {
Throwables.propagateIfPossible(e);
}
}
});
} finally {
destroyContainer(bucketName);
destroyContainer(targetBucket);
}
}
private void setupAclForBucketLoggingTarget(final String targetBucket) {
// http://docs.amazonwebservices.com/AmazonS3/latest/LoggingHowTo.html
AccessControlList acl = getApi().getBucketACL(targetBucket);
acl.addPermission(GroupGranteeURI.LOG_DELIVERY, Permission.WRITE);
acl.addPermission(GroupGranteeURI.LOG_DELIVERY, Permission.READ_ACP);
assertTrue(getApi().putBucketACL(targetBucket, acl));
}
void bucketExists() throws Exception {
String bucketName = getContainerName();
try {
Set<BucketMetadata> list = getApi().listOwnedBuckets();
BucketMetadata firstBucket = Iterables.get(list, 0);
BucketMetadata toMatch = new BucketMetadata(bucketName, new Date(), firstBucket.getOwner());
assert list.contains(toMatch);
} finally {
returnContainer(bucketName);
}
}
protected void addAlphabetUnderRoot(String bucketName) {
for (char letter = 'a'; letter <= 'z'; letter++) {
S3Object blob = getApi().newS3Object();
blob.getMetadata().setKey(letter + "");
blob.setPayload(letter + "content");
getApi().putObject(bucketName, blob);
}
}
public void testListBucketMarker() throws InterruptedException, ExecutionException, TimeoutException {
String bucketName = getContainerName();
try {
addAlphabetUnderRoot(bucketName);
ListBucketResponse bucket = getApi().listBucket(bucketName, afterMarker("y"));
assertEquals(bucket.getMarker(), "y");
assert !bucket.isTruncated();
assertEquals(bucket.size(), 1);
} finally {
returnContainer(bucketName);
}
}
public void testListBucketDelimiter() throws InterruptedException, ExecutionException, TimeoutException {
String bucketName = getContainerName();
try {
String prefix = "apps";
addTenObjectsUnderPrefix(bucketName, prefix);
add15UnderRoot(bucketName);
ListBucketResponse bucket = getApi().listBucket(bucketName, delimiter("/"));
assertEquals(bucket.getDelimiter(), "/");
assert !bucket.isTruncated();
assertEquals(bucket.size(), 15);
assertEquals(bucket.getCommonPrefixes().size(), 1);
} finally {
returnContainer(bucketName);
}
}
public void testListBucketPrefix() throws InterruptedException, ExecutionException, TimeoutException {
String bucketName = getContainerName();
try {
String prefix = "apps";
addTenObjectsUnderPrefix(bucketName, prefix);
add15UnderRoot(bucketName);
ListBucketResponse bucket = getApi().listBucket(bucketName, withPrefix("apps/"));
assert !bucket.isTruncated();
assertEquals(bucket.size(), 10);
assertEquals(bucket.getPrefix(), "apps/");
} finally {
returnContainer(bucketName);
}
}
public void testListBucketMaxResults() throws InterruptedException, ExecutionException, TimeoutException {
String bucketName = getContainerName();
try {
addAlphabetUnderRoot(bucketName);
ListBucketResponse bucket = getApi().listBucket(bucketName, maxResults(5));
assertEquals(bucket.getMaxKeys(), 5);
assert bucket.isTruncated();
assertEquals(bucket.size(), 5);
} finally {
returnContainer(bucketName);
}
}
protected void add15UnderRoot(String bucketName) {
for (int i = 0; i < 15; i++) {
S3Object blob = getApi().newS3Object();
blob.getMetadata().setKey(i + "");
blob.setPayload(i + "content");
getApi().putObject(bucketName, blob);
}
}
protected void addTenObjectsUnderPrefix(String bucketName, String prefix) {
for (int i = 0; i < 10; i++) {
S3Object blob = getApi().newS3Object();
blob.getMetadata().setKey(prefix + "/" + i);
blob.setPayload(i + "content");
getApi().putObject(bucketName, blob);
}
}
}