s3proxy/src/test/java/org/gaul/s3proxy/AwsSdkTest.java

1584 wiersze
66 KiB
Java

/*
* Copyright 2014-2020 Andrew Gaul <andrew@gaul.org>
*
* Licensed 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
*
* https://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.gaul.s3proxy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeTrue;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.HttpMethod;
import com.amazonaws.SDKGlobalConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.internal.SkipMd5CheckStrategy;
import com.amazonaws.services.s3.model.AbortMultipartUploadRequest;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.BucketLoggingConfiguration;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.CompleteMultipartUploadRequest;
import com.amazonaws.services.s3.model.CopyObjectRequest;
import com.amazonaws.services.s3.model.CopyPartRequest;
import com.amazonaws.services.s3.model.CopyPartResult;
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
import com.amazonaws.services.s3.model.DeleteObjectsResult;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.GroupGrantee;
import com.amazonaws.services.s3.model.HeadBucketRequest;
import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest;
import com.amazonaws.services.s3.model.InitiateMultipartUploadResult;
import com.amazonaws.services.s3.model.ListMultipartUploadsRequest;
import com.amazonaws.services.s3.model.ListObjectsRequest;
import com.amazonaws.services.s3.model.ListObjectsV2Request;
import com.amazonaws.services.s3.model.ListObjectsV2Result;
import com.amazonaws.services.s3.model.ListPartsRequest;
import com.amazonaws.services.s3.model.MultipartUploadListing;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.ObjectTagging;
import com.amazonaws.services.s3.model.PartETag;
import com.amazonaws.services.s3.model.PartListing;
import com.amazonaws.services.s3.model.Permission;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.ResponseHeaderOverrides;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.amazonaws.services.s3.model.SetBucketLoggingConfigurationRequest;
import com.amazonaws.services.s3.model.Tag;
import com.amazonaws.services.s3.model.UploadPartRequest;
import com.amazonaws.services.s3.model.UploadPartResult;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.io.ByteSource;
import com.google.common.io.ByteStreams;
import org.assertj.core.api.Fail;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.rest.HttpClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
public final class AwsSdkTest {
static {
System.setProperty(
SDKGlobalConfiguration.DISABLE_CERT_CHECKING_SYSTEM_PROPERTY,
"true");
disableSslVerification();
}
private static final ByteSource BYTE_SOURCE = ByteSource.wrap(new byte[1]);
private static final ClientConfiguration V2_SIGNER_CONFIG =
new ClientConfiguration().withSignerOverride("S3SignerType");
private URI s3Endpoint;
private EndpointConfiguration s3EndpointConfig;
private S3Proxy s3Proxy;
private BlobStoreContext context;
private String blobStoreType;
private String containerName;
private AWSCredentials awsCreds;
private AmazonS3 client;
private String servicePath;
@Before
public void setUp() throws Exception {
TestUtils.S3ProxyLaunchInfo info = TestUtils.startS3Proxy(
"s3proxy.conf");
awsCreds = new BasicAWSCredentials(info.getS3Identity(),
info.getS3Credential());
context = info.getBlobStore().getContext();
s3Proxy = info.getS3Proxy();
s3Endpoint = info.getSecureEndpoint();
servicePath = info.getServicePath();
s3EndpointConfig = new EndpointConfiguration(
s3Endpoint.toString() + servicePath, "us-east-1");
client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withEndpointConfiguration(s3EndpointConfig)
.build();
containerName = createRandomContainerName();
info.getBlobStore().createContainerInLocation(null, containerName);
blobStoreType = context.unwrap().getProviderMetadata().getId();
if (Quirks.OPAQUE_ETAG.contains(blobStoreType)) {
System.setProperty(
SkipMd5CheckStrategy
.DISABLE_GET_OBJECT_MD5_VALIDATION_PROPERTY,
"true");
System.setProperty(
SkipMd5CheckStrategy
.DISABLE_PUT_OBJECT_MD5_VALIDATION_PROPERTY,
"true");
}
}
@After
public void tearDown() throws Exception {
if (s3Proxy != null) {
s3Proxy.stop();
}
if (context != null) {
context.getBlobStore().deleteContainer(containerName);
context.close();
}
}
@Test
public void testAwsV2Signature() throws Exception {
client = AmazonS3ClientBuilder.standard()
.withClientConfiguration(V2_SIGNER_CONFIG)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withEndpointConfiguration(s3EndpointConfig)
.build();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, "foo", BYTE_SOURCE.openStream(),
metadata);
S3Object object = client.getObject(containerName, "foo");
assertThat(object.getObjectMetadata().getContentLength()).isEqualTo(
BYTE_SOURCE.size());
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testAwsV2SignatureWithOverrideParameters() throws Exception {
client = AmazonS3ClientBuilder.standard()
.withClientConfiguration(V2_SIGNER_CONFIG)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withEndpointConfiguration(s3EndpointConfig).build();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, "foo", BYTE_SOURCE.openStream(),
metadata);
String blobName = "foo";
ResponseHeaderOverrides headerOverride = new ResponseHeaderOverrides();
String expectedContentDisposition = "attachment; " + blobName;
headerOverride.setContentDisposition(expectedContentDisposition);
String expectedContentType = "text/plain";
headerOverride.setContentType(expectedContentType);
GetObjectRequest request = new GetObjectRequest(containerName,
blobName);
request.setResponseHeaders(headerOverride);
S3Object object = client.getObject(request);
assertThat(object.getObjectMetadata().getContentLength()).isEqualTo(
BYTE_SOURCE.size());
assertThat(object.getObjectMetadata().getContentDisposition())
.isEqualTo(expectedContentDisposition);
assertThat(object.getObjectMetadata().getContentType()).isEqualTo(
expectedContentType);
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testAwsV4Signature() throws Exception {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, "foo",
BYTE_SOURCE.openStream(), metadata);
S3Object object = client.getObject(containerName, "foo");
assertThat(object.getObjectMetadata().getContentLength()).isEqualTo(
BYTE_SOURCE.size());
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testAwsV4SignatureNonChunked() throws Exception {
client = AmazonS3ClientBuilder.standard()
.withChunkedEncodingDisabled(true)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withEndpointConfiguration(s3EndpointConfig)
.build();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, "foo",
BYTE_SOURCE.openStream(), metadata);
S3Object object = client.getObject(containerName, "foo");
assertThat(object.getObjectMetadata().getContentLength()).isEqualTo(
BYTE_SOURCE.size());
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testAwsV4SignaturePayloadUnsigned() throws Exception {
client = AmazonS3ClientBuilder.standard()
.withChunkedEncodingDisabled(true)
.withPayloadSigningEnabled(false)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withEndpointConfiguration(s3EndpointConfig)
.build();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, "foo",
BYTE_SOURCE.openStream(), metadata);
S3Object object = client.getObject(containerName, "foo");
assertThat(object.getObjectMetadata().getContentLength()).isEqualTo(
BYTE_SOURCE.size());
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testAwsV4SignatureBadIdentity() throws Exception {
client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(
new BasicAWSCredentials(
"bad-access-key", awsCreds.getAWSSecretKey())))
.withEndpointConfiguration(s3EndpointConfig)
.build();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
try {
client.putObject(containerName, "foo",
BYTE_SOURCE.openStream(), metadata);
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("InvalidAccessKeyId");
}
}
@Test
public void testAwsV4SignatureBadCredential() throws Exception {
client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(
new BasicAWSCredentials(
awsCreds.getAWSAccessKeyId(),
"bad-secret-key")))
.withEndpointConfiguration(s3EndpointConfig)
.build();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
try {
client.putObject(containerName, "foo",
BYTE_SOURCE.openStream(), metadata);
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("SignatureDoesNotMatch");
}
}
@Test
public void testAwsV2UrlSigning() throws Exception {
client = AmazonS3ClientBuilder.standard()
.withClientConfiguration(V2_SIGNER_CONFIG)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withEndpointConfiguration(s3EndpointConfig)
.build();
String blobName = "foo";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
Date expiration = new Date(System.currentTimeMillis() +
TimeUnit.HOURS.toMillis(1));
URL url = client.generatePresignedUrl(containerName, blobName,
expiration, HttpMethod.GET);
try (InputStream actual = url.openStream();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testAwsV2UrlSigningWithOverrideParameters() throws Exception {
client = AmazonS3ClientBuilder.standard()
.withClientConfiguration(V2_SIGNER_CONFIG)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withEndpointConfiguration(s3EndpointConfig).build();
String blobName = "foo";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(containerName, blobName);
generatePresignedUrlRequest.setMethod(HttpMethod.GET);
ResponseHeaderOverrides headerOverride = new ResponseHeaderOverrides();
headerOverride.setContentDisposition("attachment; " + blobName);
headerOverride.setContentType("text/plain");
generatePresignedUrlRequest.setResponseHeaders(headerOverride);
Date expiration = new Date(System.currentTimeMillis() +
TimeUnit.HOURS.toMillis(1));
generatePresignedUrlRequest.setExpiration(expiration);
URL url = client.generatePresignedUrl(generatePresignedUrlRequest);
URLConnection connection = url.openConnection();
try (InputStream actual = connection.getInputStream();
InputStream expected = BYTE_SOURCE.openStream()) {
String value = connection.getHeaderField("Content-Disposition");
assertThat(value).isEqualTo(headerOverride.getContentDisposition());
value = connection.getHeaderField("Content-Type");
assertThat(value).isEqualTo(headerOverride.getContentType());
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testAwsV4UrlSigning() throws Exception {
String blobName = "foo";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
Date expiration = new Date(System.currentTimeMillis() +
TimeUnit.HOURS.toMillis(1));
URL url = client.generatePresignedUrl(containerName, blobName,
expiration, HttpMethod.GET);
try (InputStream actual = url.openStream();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testMultipartCopy() throws Exception {
// B2 requires two parts to issue an MPU
assumeTrue(!blobStoreType.equals("b2"));
String sourceBlobName = "testMultipartCopy-source";
String targetBlobName = "testMultipartCopy-target";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, sourceBlobName,
BYTE_SOURCE.openStream(), metadata);
InitiateMultipartUploadRequest initiateRequest =
new InitiateMultipartUploadRequest(containerName,
targetBlobName);
InitiateMultipartUploadResult initResult =
client.initiateMultipartUpload(initiateRequest);
String uploadId = initResult.getUploadId();
CopyPartRequest copyRequest = new CopyPartRequest()
.withDestinationBucketName(containerName)
.withDestinationKey(targetBlobName)
.withSourceBucketName(containerName)
.withSourceKey(sourceBlobName)
.withUploadId(uploadId)
.withFirstByte(0L)
.withLastByte(BYTE_SOURCE.size() - 1)
.withPartNumber(1);
CopyPartResult copyPartResult = client.copyPart(copyRequest);
CompleteMultipartUploadRequest completeRequest =
new CompleteMultipartUploadRequest(
containerName, targetBlobName, uploadId,
ImmutableList.of(copyPartResult.getPartETag()));
client.completeMultipartUpload(completeRequest);
S3Object object = client.getObject(containerName, targetBlobName);
assertThat(object.getObjectMetadata().getContentLength()).isEqualTo(
BYTE_SOURCE.size());
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testBigMultipartUpload() throws Exception {
String key = "multipart-upload";
long partSize = context.getBlobStore().getMinimumMultipartPartSize();
long size = partSize + 1;
ByteSource byteSource = TestUtils.randomByteSource().slice(0, size);
InitiateMultipartUploadRequest initRequest =
new InitiateMultipartUploadRequest(containerName, key);
InitiateMultipartUploadResult initResponse =
client.initiateMultipartUpload(initRequest);
String uploadId = initResponse.getUploadId();
ByteSource byteSource1 = byteSource.slice(0, partSize);
UploadPartRequest uploadRequest1 = new UploadPartRequest()
.withBucketName(containerName)
.withKey(key)
.withUploadId(uploadId)
.withPartNumber(1)
.withInputStream(byteSource1.openStream())
.withPartSize(byteSource1.size());
uploadRequest1.getRequestClientOptions().setReadLimit(
(int) byteSource1.size());
UploadPartResult uploadPartResult1 = client.uploadPart(uploadRequest1);
ByteSource byteSource2 = byteSource.slice(partSize, size - partSize);
UploadPartRequest uploadRequest2 = new UploadPartRequest()
.withBucketName(containerName)
.withKey(key)
.withUploadId(uploadId)
.withPartNumber(2)
.withInputStream(byteSource2.openStream())
.withPartSize(byteSource2.size());
uploadRequest2.getRequestClientOptions().setReadLimit(
(int) byteSource2.size());
UploadPartResult uploadPartResult2 = client.uploadPart(uploadRequest2);
CompleteMultipartUploadRequest completeRequest =
new CompleteMultipartUploadRequest(
containerName, key, uploadId,
ImmutableList.of(
uploadPartResult1.getPartETag(),
uploadPartResult2.getPartETag()));
client.completeMultipartUpload(completeRequest);
S3Object object = client.getObject(containerName, key);
assertThat(object.getObjectMetadata().getContentLength()).isEqualTo(
size);
try (InputStream actual = object.getObjectContent();
InputStream expected = byteSource.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
// TODO: testMultipartUploadConditionalCopy
@Test
public void testUpdateBlobXmlAcls() throws Exception {
assumeTrue(!Quirks.NO_BLOB_ACCESS_CONTROL.contains(blobStoreType));
String blobName = "testUpdateBlobXmlAcls-blob";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
AccessControlList acl = client.getObjectAcl(containerName, blobName);
acl.grantPermission(GroupGrantee.AllUsers, Permission.Read);
client.setObjectAcl(containerName, blobName, acl);
assertThat(client.getObjectAcl(containerName, blobName)).isEqualTo(acl);
acl.revokeAllPermissions(GroupGrantee.AllUsers);
client.setObjectAcl(containerName, blobName, acl);
assertThat(client.getObjectAcl(containerName, blobName)).isEqualTo(acl);
acl.grantPermission(GroupGrantee.AllUsers, Permission.Write);
try {
client.setObjectAcl(containerName, blobName, acl);
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("NotImplemented");
}
}
@Test
public void testUnicodeObject() throws Exception {
String blobName = "ŪņЇЌœđЗ/☺ unicode € rocks ™";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
metadata = client.getObjectMetadata(containerName, blobName);
assertThat(metadata).isNotNull();
ObjectListing listing = client.listObjects(containerName);
List<S3ObjectSummary> summaries = listing.getObjectSummaries();
assertThat(summaries).hasSize(1);
S3ObjectSummary summary = summaries.iterator().next();
assertThat(summary.getKey()).isEqualTo(blobName);
}
@Test
public void testSpecialCharacters() throws Exception {
String prefix = "special !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
if (blobStoreType.equals("azureblob") || blobStoreType.equals("b2")) {
prefix = prefix.replace("\\", "");
}
if (blobStoreType.equals("azureblob")) {
// Avoid blob names that end with a dot (.), a forward slash (/), or
// a sequence or combination of the two.
prefix = prefix.replace("./", "/") + ".";
}
String blobName = prefix + "foo";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
ObjectListing listing = client.listObjects(new ListObjectsRequest()
.withBucketName(containerName)
.withPrefix(prefix));
List<S3ObjectSummary> summaries = listing.getObjectSummaries();
assertThat(summaries).hasSize(1);
S3ObjectSummary summary = summaries.iterator().next();
assertThat(summary.getKey()).isEqualTo(blobName);
}
@Test
public void testAtomicMpuAbort() throws Exception {
String key = "testAtomicMpuAbort";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, key, BYTE_SOURCE.openStream(),
metadata);
InitiateMultipartUploadRequest initRequest =
new InitiateMultipartUploadRequest(containerName, key);
InitiateMultipartUploadResult initResponse =
client.initiateMultipartUpload(initRequest);
String uploadId = initResponse.getUploadId();
client.abortMultipartUpload(new AbortMultipartUploadRequest(
containerName, key, uploadId));
S3Object object = client.getObject(containerName, key);
assertThat(object.getObjectMetadata().getContentLength()).isEqualTo(
BYTE_SOURCE.size());
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testOverrideResponseHeader() throws Exception {
String blobName = "foo";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
String cacheControl = "no-cache";
String contentDisposition = "attachment; filename=foo.html";
String contentEncoding = "gzip";
String contentLanguage = "en";
String contentType = "text/html; charset=UTF-8";
String expires = "Wed, 13 Jul 2016 21:23:51 GMT";
long expiresTime = 1468445031000L;
GetObjectRequest getObjectRequest = new GetObjectRequest(containerName,
blobName);
getObjectRequest.setResponseHeaders(
new ResponseHeaderOverrides()
.withCacheControl(cacheControl)
.withContentDisposition(contentDisposition)
.withContentEncoding(contentEncoding)
.withContentLanguage(contentLanguage)
.withContentType(contentType)
.withExpires(expires));
S3Object object = client.getObject(getObjectRequest);
try (InputStream is = object.getObjectContent()) {
assertThat(is).isNotNull();
ByteStreams.copy(is, ByteStreams.nullOutputStream());
}
ObjectMetadata reponseMetadata = object.getObjectMetadata();
assertThat(reponseMetadata.getCacheControl()).isEqualTo(
cacheControl);
assertThat(reponseMetadata.getContentDisposition()).isEqualTo(
contentDisposition);
assertThat(reponseMetadata.getContentEncoding()).isEqualTo(
contentEncoding);
assertThat(reponseMetadata.getContentLanguage()).isEqualTo(
contentLanguage);
assertThat(reponseMetadata.getContentType()).isEqualTo(
contentType);
assertThat(reponseMetadata.getHttpExpiresDate().getTime())
.isEqualTo(expiresTime);
}
@Test
public void testDeleteMultipleObjectsEmpty() throws Exception {
DeleteObjectsRequest request = new DeleteObjectsRequest(containerName)
.withKeys();
try {
client.deleteObjects(request);
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("MalformedXML");
}
}
@Test
public void testDeleteMultipleObjects() throws Exception {
String blobName = "foo";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
DeleteObjectsRequest request = new DeleteObjectsRequest(containerName)
.withKeys(blobName);
// without quiet
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
DeleteObjectsResult result = client.deleteObjects(request);
assertThat(result.getDeletedObjects()).hasSize(1);
assertThat(result.getDeletedObjects().iterator().next().getKey())
.isEqualTo(blobName);
// with quiet
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
result = client.deleteObjects(request.withQuiet(true));
assertThat(result.getDeletedObjects()).isEmpty();
}
@Test
public void testPartNumberMarker() throws Exception {
String blobName = "foo";
InitiateMultipartUploadResult result = client.initiateMultipartUpload(
new InitiateMultipartUploadRequest(containerName, blobName));
ListPartsRequest request = new ListPartsRequest(containerName,
blobName, result.getUploadId());
client.listParts(request.withPartNumberMarker(0));
try {
client.listParts(request.withPartNumberMarker(1));
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("NotImplemented");
}
}
@Test
public void testHttpClient() throws Exception {
String blobName = "blob-name";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
if (Quirks.NO_BLOB_ACCESS_CONTROL.contains(blobStoreType)) {
client.setBucketAcl(containerName,
CannedAccessControlList.PublicRead);
} else {
client.setObjectAcl(containerName, blobName,
CannedAccessControlList.PublicRead);
}
HttpClient httpClient = context.utils().http();
URI uri = new URI(s3Endpoint.getScheme(), s3Endpoint.getUserInfo(),
s3Endpoint.getHost(), s3Proxy.getSecurePort(),
servicePath + "/" + containerName + "/" + blobName,
/*query=*/ null, /*fragment=*/ null);
try (InputStream actual = httpClient.get(uri);
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testListBuckets() throws Exception {
ImmutableList.Builder<String> builder = ImmutableList.builder();
for (Bucket bucket : client.listBuckets()) {
builder.add(bucket.getName());
}
assertThat(builder.build()).contains(containerName);
}
@Test
public void testContainerExists() throws Exception {
client.headBucket(new HeadBucketRequest(containerName));
try {
client.headBucket(new HeadBucketRequest(
createRandomContainerName()));
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("404 Not Found");
}
}
@Test
public void testContainerCreateDelete() throws Exception {
String containerName2 = createRandomContainerName();
client.createBucket(containerName2);
try {
client.createBucket(containerName2);
client.deleteBucket(containerName2);
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("BucketAlreadyOwnedByYou");
}
}
@Test
public void testContainerDelete() throws Exception {
client.headBucket(new HeadBucketRequest(containerName));
client.deleteBucket(containerName);
try {
client.headBucket(new HeadBucketRequest(containerName));
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("404 Not Found");
}
}
private void putBlobAndCheckIt(String blobName) throws Exception {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
S3Object object = client.getObject(containerName, blobName);
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testBlobPutGet() throws Exception {
putBlobAndCheckIt("blob");
putBlobAndCheckIt("blob%");
putBlobAndCheckIt("blob%%");
}
@Test
public void testBlobEscape() throws Exception {
ObjectListing listing = client.listObjects(containerName);
assertThat(listing.getObjectSummaries()).isEmpty();
putBlobAndCheckIt("blob%");
listing = client.listObjects(containerName);
assertThat(listing.getObjectSummaries()).hasSize(1);
assertThat(listing.getObjectSummaries().iterator().next().getKey())
.isEqualTo("blob%");
}
@Test
public void testBlobList() throws Exception {
ObjectListing listing = client.listObjects(containerName);
assertThat(listing.getObjectSummaries()).isEmpty();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
ImmutableList.Builder<String> builder = ImmutableList.builder();
client.putObject(containerName, "blob1", BYTE_SOURCE.openStream(),
metadata);
listing = client.listObjects(containerName);
for (S3ObjectSummary summary : listing.getObjectSummaries()) {
builder.add(summary.getKey());
}
assertThat(builder.build()).containsOnly("blob1");
builder = ImmutableList.builder();
client.putObject(containerName, "blob2", BYTE_SOURCE.openStream(),
metadata);
listing = client.listObjects(containerName);
for (S3ObjectSummary summary : listing.getObjectSummaries()) {
builder.add(summary.getKey());
}
assertThat(builder.build()).containsOnly("blob1", "blob2");
}
@Test
public void testBlobListRecursive() throws Exception {
ObjectListing listing = client.listObjects(containerName);
assertThat(listing.getObjectSummaries()).isEmpty();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, "prefix/blob1",
BYTE_SOURCE.openStream(), metadata);
client.putObject(containerName, "prefix/blob2",
BYTE_SOURCE.openStream(), metadata);
ImmutableList.Builder<String> builder = ImmutableList.builder();
listing = client.listObjects(new ListObjectsRequest()
.withBucketName(containerName)
.withDelimiter("/"));
assertThat(listing.getObjectSummaries()).isEmpty();
for (String prefix : listing.getCommonPrefixes()) {
builder.add(prefix);
}
assertThat(builder.build()).containsOnly("prefix/");
builder = ImmutableList.builder();
listing = client.listObjects(containerName);
for (S3ObjectSummary summary : listing.getObjectSummaries()) {
builder.add(summary.getKey());
}
assertThat(builder.build()).containsOnly("prefix/blob1",
"prefix/blob2");
assertThat(listing.getCommonPrefixes()).isEmpty();
}
@Test
public void testBlobListRecursiveImplicitMarker() throws Exception {
ObjectListing listing = client.listObjects(containerName);
assertThat(listing.getObjectSummaries()).isEmpty();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, "blob1", BYTE_SOURCE.openStream(),
metadata);
client.putObject(containerName, "blob2", BYTE_SOURCE.openStream(),
metadata);
listing = client.listObjects(new ListObjectsRequest()
.withBucketName(containerName)
.withMaxKeys(1));
assertThat(listing.getObjectSummaries()).hasSize(1);
assertThat(listing.getObjectSummaries().iterator().next().getKey())
.isEqualTo("blob1");
listing = client.listObjects(new ListObjectsRequest()
.withBucketName(containerName)
.withMaxKeys(1)
.withMarker("blob1"));
assertThat(listing.getObjectSummaries()).hasSize(1);
assertThat(listing.getObjectSummaries().iterator().next().getKey())
.isEqualTo("blob2");
}
@Test
public void testBlobListV2() throws Exception {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
for (int i = 1; i < 5; ++i) {
client.putObject(containerName, String.valueOf(i),
BYTE_SOURCE.openStream(), metadata);
}
ListObjectsV2Result result = client.listObjectsV2(
new ListObjectsV2Request()
.withBucketName(containerName)
.withMaxKeys(1)
.withStartAfter("1"));
assertThat(result.getContinuationToken()).isEmpty();
assertThat(result.getStartAfter()).isEqualTo("1");
assertThat(result.getNextContinuationToken()).isEqualTo("2");
assertThat(result.isTruncated()).isTrue();
assertThat(result.getObjectSummaries()).hasSize(1);
assertThat(result.getObjectSummaries().get(0).getKey()).isEqualTo("2");
result = client.listObjectsV2(
new ListObjectsV2Request()
.withBucketName(containerName)
.withMaxKeys(1)
.withContinuationToken(result.getNextContinuationToken()));
assertThat(result.getContinuationToken()).isEqualTo("2");
assertThat(result.getStartAfter()).isEmpty();
assertThat(result.getNextContinuationToken()).isEqualTo("3");
assertThat(result.isTruncated()).isTrue();
assertThat(result.getObjectSummaries()).hasSize(1);
assertThat(result.getObjectSummaries().get(0).getKey()).isEqualTo("3");
result = client.listObjectsV2(
new ListObjectsV2Request()
.withBucketName(containerName)
.withMaxKeys(1)
.withContinuationToken(result.getNextContinuationToken()));
assertThat(result.getContinuationToken()).isEqualTo("3");
assertThat(result.getStartAfter()).isEmpty();
assertThat(result.getNextContinuationToken()).isNull();
assertThat(result.isTruncated()).isFalse();
assertThat(result.getObjectSummaries()).hasSize(1);
assertThat(result.getObjectSummaries().get(0).getKey()).isEqualTo("4");
}
@Test
public void testBlobMetadata() throws Exception {
String blobName = "blob";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
ObjectMetadata newMetadata = client.getObjectMetadata(containerName,
blobName);
assertThat(newMetadata.getContentLength())
.isEqualTo(BYTE_SOURCE.size());
}
@Test
public void testBlobRemove() throws Exception {
String blobName = "blob";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
assertThat(client.getObjectMetadata(containerName, blobName))
.isNotNull();
client.deleteObject(containerName, blobName);
try {
client.getObjectMetadata(containerName, blobName);
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("404 Not Found");
}
client.deleteObject(containerName, blobName);
}
@Test
public void testSinglepartUpload() throws Exception {
String blobName = "singlepart-upload";
String cacheControl = "max-age=3600";
String contentDisposition = "attachment; filename=new.jpg";
String contentEncoding = "gzip";
String contentLanguage = "fr";
String contentType = "audio/mp4";
Map<String, String> userMetadata = ImmutableMap.of(
"key1", "value1",
"key2", "value2");
ObjectMetadata metadata = new ObjectMetadata();
if (!Quirks.NO_CACHE_CONTROL_SUPPORT.contains(blobStoreType)) {
metadata.setCacheControl(cacheControl);
}
if (!Quirks.NO_CONTENT_DISPOSITION.contains(blobStoreType)) {
metadata.setContentDisposition(contentDisposition);
}
if (!Quirks.NO_CONTENT_ENCODING.contains(blobStoreType)) {
metadata.setContentEncoding(contentEncoding);
}
if (!Quirks.NO_CONTENT_LANGUAGE.contains(blobStoreType)) {
metadata.setContentLanguage(contentLanguage);
}
metadata.setContentLength(BYTE_SOURCE.size());
metadata.setContentType(contentType);
// TODO: expires
metadata.setUserMetadata(userMetadata);
client.putObject(containerName, blobName, BYTE_SOURCE.openStream(),
metadata);
S3Object object = client.getObject(containerName, blobName);
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
ObjectMetadata newContentMetadata = object.getObjectMetadata();
if (!Quirks.NO_CACHE_CONTROL_SUPPORT.contains(blobStoreType)) {
assertThat(newContentMetadata.getCacheControl()).isEqualTo(
cacheControl);
}
if (!Quirks.NO_CONTENT_DISPOSITION.contains(blobStoreType)) {
assertThat(newContentMetadata.getContentDisposition()).isEqualTo(
contentDisposition);
}
if (!Quirks.NO_CONTENT_ENCODING.contains(blobStoreType)) {
assertThat(newContentMetadata.getContentEncoding()).isEqualTo(
contentEncoding);
}
if (!Quirks.NO_CONTENT_LANGUAGE.contains(blobStoreType)) {
assertThat(newContentMetadata.getContentLanguage()).isEqualTo(
contentLanguage);
}
assertThat(newContentMetadata.getContentType()).isEqualTo(
contentType);
// TODO: expires
assertThat(newContentMetadata.getUserMetadata()).isEqualTo(
userMetadata);
}
// TODO: fails for GCS (jclouds not implemented)
@Test
public void testMultipartUpload() throws Exception {
String blobName = "multipart-upload";
String cacheControl = "max-age=3600";
String contentDisposition = "attachment; filename=new.jpg";
String contentEncoding = "gzip";
String contentLanguage = "fr";
String contentType = "audio/mp4";
Map<String, String> userMetadata = ImmutableMap.of(
"key1", "value1",
"key2", "value2");
ObjectMetadata metadata = new ObjectMetadata();
if (!Quirks.NO_CACHE_CONTROL_SUPPORT.contains(blobStoreType)) {
metadata.setCacheControl(cacheControl);
}
if (!Quirks.NO_CONTENT_DISPOSITION.contains(blobStoreType)) {
metadata.setContentDisposition(contentDisposition);
}
if (!Quirks.NO_CONTENT_ENCODING.contains(blobStoreType)) {
metadata.setContentEncoding(contentEncoding);
}
if (!Quirks.NO_CONTENT_LANGUAGE.contains(blobStoreType)) {
metadata.setContentLanguage(contentLanguage);
}
metadata.setContentType(contentType);
// TODO: expires
metadata.setUserMetadata(userMetadata);
InitiateMultipartUploadResult result = client.initiateMultipartUpload(
new InitiateMultipartUploadRequest(containerName, blobName,
metadata));
ByteSource byteSource = TestUtils.randomByteSource().slice(
0, context.getBlobStore().getMinimumMultipartPartSize() + 1);
ByteSource byteSource1 = byteSource.slice(
0, context.getBlobStore().getMinimumMultipartPartSize());
ByteSource byteSource2 = byteSource.slice(
context.getBlobStore().getMinimumMultipartPartSize(), 1);
UploadPartResult part1 = client.uploadPart(new UploadPartRequest()
.withBucketName(containerName)
.withKey(blobName)
.withUploadId(result.getUploadId())
.withPartNumber(1)
.withPartSize(byteSource1.size())
.withInputStream(byteSource1.openStream()));
UploadPartResult part2 = client.uploadPart(new UploadPartRequest()
.withBucketName(containerName)
.withKey(blobName)
.withUploadId(result.getUploadId())
.withPartNumber(2)
.withPartSize(byteSource2.size())
.withInputStream(byteSource2.openStream()));
client.completeMultipartUpload(new CompleteMultipartUploadRequest(
containerName, blobName, result.getUploadId(),
ImmutableList.of(part1.getPartETag(), part2.getPartETag())));
ObjectListing listing = client.listObjects(containerName);
assertThat(listing.getObjectSummaries()).hasSize(1);
S3Object object = client.getObject(containerName, blobName);
try (InputStream actual = object.getObjectContent();
InputStream expected = byteSource.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
ObjectMetadata newContentMetadata = object.getObjectMetadata();
if (!Quirks.NO_CACHE_CONTROL_SUPPORT.contains(blobStoreType)) {
assertThat(newContentMetadata.getCacheControl()).isEqualTo(
cacheControl);
}
if (!Quirks.NO_CONTENT_DISPOSITION.contains(blobStoreType)) {
assertThat(newContentMetadata.getContentDisposition()).isEqualTo(
contentDisposition);
}
if (!Quirks.NO_CONTENT_ENCODING.contains(blobStoreType)) {
assertThat(newContentMetadata.getContentEncoding()).isEqualTo(
contentEncoding);
}
if (!Quirks.NO_CONTENT_LANGUAGE.contains(blobStoreType)) {
assertThat(newContentMetadata.getContentLanguage()).isEqualTo(
contentLanguage);
}
assertThat(newContentMetadata.getContentType()).isEqualTo(
contentType);
// TODO: expires
assertThat(newContentMetadata.getUserMetadata()).isEqualTo(
userMetadata);
}
// this test runs for several minutes
@Ignore
@Test
public void testMaximumMultipartUpload() throws Exception {
// skip with remote blobstores to avoid excessive run-times
assumeTrue(blobStoreType.equals("filesystem") ||
blobStoreType.equals("transient"));
String blobName = "multipart-upload";
int numParts = 10_000;
ByteSource byteSource = TestUtils.randomByteSource().slice(0, numParts);
InitiateMultipartUploadResult result = client.initiateMultipartUpload(
new InitiateMultipartUploadRequest(containerName, blobName));
ImmutableList.Builder<PartETag> parts = ImmutableList.builder();
for (int i = 0; i < numParts; ++i) {
ByteSource partByteSource = byteSource.slice(i, 1);
UploadPartResult partResult = client.uploadPart(
new UploadPartRequest()
.withBucketName(containerName)
.withKey(blobName)
.withUploadId(result.getUploadId())
.withPartNumber(i + 1)
.withPartSize(partByteSource.size())
.withInputStream(partByteSource.openStream()));
parts.add(partResult.getPartETag());
}
client.completeMultipartUpload(new CompleteMultipartUploadRequest(
containerName, blobName, result.getUploadId(), parts.build()));
ObjectListing listing = client.listObjects(containerName);
assertThat(listing.getObjectSummaries()).hasSize(1);
S3Object object = client.getObject(containerName, blobName);
try (InputStream actual = object.getObjectContent();
InputStream expected = byteSource.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
@Test
public void testMultipartUploadAbort() throws Exception {
String blobName = "multipart-upload-abort";
ByteSource byteSource = TestUtils.randomByteSource().slice(
0, context.getBlobStore().getMinimumMultipartPartSize());
InitiateMultipartUploadResult result = client.initiateMultipartUpload(
new InitiateMultipartUploadRequest(containerName, blobName));
// TODO: google-cloud-storage and openstack-swift cannot list multipart
// uploads
MultipartUploadListing multipartListing = client.listMultipartUploads(
new ListMultipartUploadsRequest(containerName));
if (blobStoreType.equals("azureblob")) {
// Azure does not create a manifest during initiate multi-part
// upload. Instead the first part creates this.
assertThat(multipartListing.getMultipartUploads()).isEmpty();
} else {
assertThat(multipartListing.getMultipartUploads()).hasSize(1);
}
PartListing partListing = client.listParts(new ListPartsRequest(
containerName, blobName, result.getUploadId()));
assertThat(partListing.getParts()).isEmpty();
client.uploadPart(new UploadPartRequest()
.withBucketName(containerName)
.withKey(blobName)
.withUploadId(result.getUploadId())
.withPartNumber(1)
.withPartSize(byteSource.size())
.withInputStream(byteSource.openStream()));
multipartListing = client.listMultipartUploads(
new ListMultipartUploadsRequest(containerName));
assertThat(multipartListing.getMultipartUploads()).hasSize(1);
partListing = client.listParts(new ListPartsRequest(
containerName, blobName, result.getUploadId()));
assertThat(partListing.getParts()).hasSize(1);
client.abortMultipartUpload(new AbortMultipartUploadRequest(
containerName, blobName, result.getUploadId()));
multipartListing = client.listMultipartUploads(
new ListMultipartUploadsRequest(containerName));
if (blobStoreType.equals("azureblob")) {
// Azure does not support explicit abort. It automatically
// removes incomplete multi-part uploads after 7 days.
assertThat(multipartListing.getMultipartUploads()).hasSize(1);
} else {
assertThat(multipartListing.getMultipartUploads()).isEmpty();
}
ObjectListing listing = client.listObjects(containerName);
assertThat(listing.getObjectSummaries()).isEmpty();
}
// TODO: Fails since B2 returns the Cache-Control header on reads but does
// not accept it on writes.
@Test
public void testCopyObjectPreserveMetadata() throws Exception {
String fromName = "from-name";
String toName = "to-name";
String cacheControl = "max-age=3600";
String contentDisposition = "attachment; filename=old.jpg";
String contentEncoding = "gzip";
String contentLanguage = "en";
String contentType = "audio/ogg";
Map<String, String> userMetadata = ImmutableMap.of(
"key1", "value1",
"key2", "value2");
ObjectMetadata metadata = new ObjectMetadata();
if (!Quirks.NO_CACHE_CONTROL_SUPPORT.contains(blobStoreType)) {
metadata.setCacheControl(cacheControl);
}
metadata.setContentLength(BYTE_SOURCE.size());
if (!Quirks.NO_CONTENT_DISPOSITION.contains(blobStoreType)) {
metadata.setContentDisposition(contentDisposition);
}
if (!Quirks.NO_CONTENT_ENCODING.contains(blobStoreType)) {
metadata.setContentEncoding(contentEncoding);
}
if (!Quirks.NO_CONTENT_LANGUAGE.contains(blobStoreType)) {
metadata.setContentLanguage(contentLanguage);
}
metadata.setContentType(contentType);
// TODO: expires
metadata.setUserMetadata(userMetadata);
client.putObject(containerName, fromName, BYTE_SOURCE.openStream(),
metadata);
client.copyObject(containerName, fromName, containerName, toName);
S3Object object = client.getObject(containerName, toName);
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
ObjectMetadata contentMetadata = object.getObjectMetadata();
assertThat(contentMetadata.getContentLength()).isEqualTo(
BYTE_SOURCE.size());
if (!Quirks.NO_CACHE_CONTROL_SUPPORT.contains(blobStoreType)) {
assertThat(contentMetadata.getCacheControl()).isEqualTo(
cacheControl);
}
if (!Quirks.NO_CONTENT_DISPOSITION.contains(blobStoreType)) {
assertThat(contentMetadata.getContentDisposition()).isEqualTo(
contentDisposition);
}
if (!Quirks.NO_CONTENT_ENCODING.contains(blobStoreType)) {
assertThat(contentMetadata.getContentEncoding()).isEqualTo(
contentEncoding);
}
if (!Quirks.NO_CONTENT_LANGUAGE.contains(blobStoreType)) {
assertThat(contentMetadata.getContentLanguage()).isEqualTo(
contentLanguage);
}
assertThat(contentMetadata.getContentType()).isEqualTo(
contentType);
// TODO: expires
assertThat(contentMetadata.getUserMetadata()).isEqualTo(
userMetadata);
}
@Test
public void testCopyObjectReplaceMetadata() throws Exception {
String fromName = "from-name";
String toName = "to-name";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
if (!Quirks.NO_CACHE_CONTROL_SUPPORT.contains(blobStoreType)) {
metadata.setCacheControl("max-age=3600");
}
if (!Quirks.NO_CONTENT_DISPOSITION.contains(blobStoreType)) {
metadata.setContentDisposition("attachment; filename=old.jpg");
}
if (!Quirks.NO_CONTENT_ENCODING.contains(blobStoreType)) {
metadata.setContentEncoding("compress");
}
if (!Quirks.NO_CONTENT_LANGUAGE.contains(blobStoreType)) {
metadata.setContentLanguage("en");
}
metadata.setContentType("audio/ogg");
// TODO: expires
metadata.setUserMetadata(ImmutableMap.of(
"key1", "value1",
"key2", "value2"));
client.putObject(containerName, fromName, BYTE_SOURCE.openStream(),
metadata);
String cacheControl = "max-age=1800";
String contentDisposition = "attachment; filename=new.jpg";
String contentEncoding = "gzip";
String contentLanguage = "fr";
String contentType = "audio/mp4";
ObjectMetadata contentMetadata = new ObjectMetadata();
if (!Quirks.NO_CACHE_CONTROL_SUPPORT.contains(blobStoreType)) {
contentMetadata.setCacheControl(cacheControl);
}
if (!Quirks.NO_CONTENT_DISPOSITION.contains(blobStoreType)) {
contentMetadata.setContentDisposition(contentDisposition);
}
if (!Quirks.NO_CONTENT_ENCODING.contains(blobStoreType)) {
contentMetadata.setContentEncoding(contentEncoding);
}
if (!Quirks.NO_CONTENT_LANGUAGE.contains(blobStoreType)) {
contentMetadata.setContentLanguage(contentLanguage);
}
contentMetadata.setContentType(contentType);
// TODO: expires
Map<String, String> userMetadata = ImmutableMap.of(
"key3", "value3",
"key4", "value4");
contentMetadata.setUserMetadata(userMetadata);
client.copyObject(new CopyObjectRequest(
containerName, fromName, containerName, toName)
.withNewObjectMetadata(contentMetadata));
S3Object object = client.getObject(containerName, toName);
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
ObjectMetadata toContentMetadata = object.getObjectMetadata();
if (!Quirks.NO_CACHE_CONTROL_SUPPORT.contains(blobStoreType)) {
assertThat(contentMetadata.getCacheControl()).isEqualTo(
cacheControl);
}
if (!Quirks.NO_CONTENT_DISPOSITION.contains(blobStoreType)) {
assertThat(toContentMetadata.getContentDisposition()).isEqualTo(
contentDisposition);
}
if (!Quirks.NO_CONTENT_ENCODING.contains(blobStoreType)) {
assertThat(toContentMetadata.getContentEncoding()).isEqualTo(
contentEncoding);
}
if (!Quirks.NO_CONTENT_LANGUAGE.contains(blobStoreType)) {
assertThat(toContentMetadata.getContentLanguage()).isEqualTo(
contentLanguage);
}
assertThat(toContentMetadata.getContentType()).isEqualTo(
contentType);
// TODO: expires
assertThat(toContentMetadata.getUserMetadata()).isEqualTo(
userMetadata);
}
@Test
public void testConditionalGet() throws Exception {
assumeTrue(!blobStoreType.equals("b2"));
String blobName = "blob-name";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
PutObjectResult result = client.putObject(containerName, blobName,
BYTE_SOURCE.openStream(), metadata);
S3Object object = client.getObject(
new GetObjectRequest(containerName, blobName)
.withMatchingETagConstraint(result.getETag()));
try (InputStream is = object.getObjectContent()) {
assertThat(is).isNotNull();
ByteStreams.copy(is, ByteStreams.nullOutputStream());
}
object = client.getObject(
new GetObjectRequest(containerName, blobName)
.withNonmatchingETagConstraint(result.getETag()));
assertThat(object).isNull();
}
@Test
public void testStorageClass() throws Exception {
String blobName = "test-storage-class";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
PutObjectRequest request = new PutObjectRequest(
containerName, blobName, BYTE_SOURCE.openStream(), metadata)
.withStorageClass("STANDARD_IA");
client.putObject(request);
metadata = client.getObjectMetadata(containerName, blobName);
assertThat(metadata.getStorageClass()).isEqualTo("STANDARD_IA");
}
@Test
public void testUnknownHeader() throws Exception {
String blobName = "test-unknown-header";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
PutObjectRequest request = new PutObjectRequest(
containerName, blobName, BYTE_SOURCE.openStream(), metadata)
.withTagging(new ObjectTagging(ImmutableList.<Tag>of()));
try {
client.putObject(request);
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("NotImplemented");
}
}
@Test
public void testGetBucketPolicy() throws Exception {
try {
client.getBucketPolicy(containerName);
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("NoSuchPolicy");
}
}
@Test
public void testUnknownParameter() throws Exception {
try {
client.setBucketLoggingConfiguration(
new SetBucketLoggingConfigurationRequest(
containerName, new BucketLoggingConfiguration()));
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("NotImplemented");
}
}
@Test
public void testBlobStoreLocator() throws Exception {
final BlobStore blobStore1 = context.getBlobStore();
final BlobStore blobStore2 = ContextBuilder
.newBuilder(blobStoreType)
.credentials("other-identity", "credential")
.build(BlobStoreContext.class)
.getBlobStore();
s3Proxy.setBlobStoreLocator(new BlobStoreLocator() {
@Nullable
@Override
public Map.Entry<String, BlobStore> locateBlobStore(
String identity, String container, String blob) {
if (identity.equals(awsCreds.getAWSAccessKeyId())) {
return Maps.immutableEntry(awsCreds.getAWSSecretKey(),
blobStore1);
} else if (identity.equals("other-identity")) {
return Maps.immutableEntry("credential", blobStore2);
} else {
return null;
}
}
});
// check first access key
List<Bucket> buckets = client.listBuckets();
assertThat(buckets).hasSize(1);
assertThat(buckets.get(0).getName()).isEqualTo(containerName);
// check second access key
client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(
new BasicAWSCredentials("other-identity",
"credential")))
.withEndpointConfiguration(s3EndpointConfig)
.build();
buckets = client.listBuckets();
assertThat(buckets).isEmpty();
// check invalid access key
client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(
new BasicAWSCredentials("bad-identity", "credential")))
.withEndpointConfiguration(s3EndpointConfig)
.build();
try {
client.listBuckets();
Fail.failBecauseExceptionWasNotThrown(AmazonS3Exception.class);
} catch (AmazonS3Exception e) {
assertThat(e.getErrorCode()).isEqualTo("InvalidAccessKeyId");
}
}
private static final class NullX509TrustManager
implements X509TrustManager {
@Override
@Nullable
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
}
static void disableSslVerification() {
try {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new NullX509TrustManager() };
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(
sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (KeyManagementException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static String createRandomContainerName() {
return "s3proxy-" + new Random().nextInt(Integer.MAX_VALUE);
}
}