|
@@ -34,10 +34,14 @@ import com.amazonaws.services.s3.model.PutObjectResult;
|
|
|
import com.amazonaws.services.s3.model.StorageClass;
|
|
|
import com.amazonaws.services.s3.model.UploadPartRequest;
|
|
|
import com.amazonaws.services.s3.model.UploadPartResult;
|
|
|
+import org.elasticsearch.cluster.metadata.RepositoryMetaData;
|
|
|
import org.elasticsearch.common.blobstore.BlobPath;
|
|
|
import org.elasticsearch.common.blobstore.BlobStore;
|
|
|
+import org.elasticsearch.common.blobstore.BlobStoreException;
|
|
|
import org.elasticsearch.common.collect.Tuple;
|
|
|
+import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.common.unit.ByteSizeUnit;
|
|
|
+import org.elasticsearch.common.unit.ByteSizeValue;
|
|
|
import org.elasticsearch.repositories.ESBlobStoreContainerTestCase;
|
|
|
import org.mockito.ArgumentCaptor;
|
|
|
|
|
@@ -46,10 +50,12 @@ import java.io.IOException;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
import java.util.stream.Collectors;
|
|
|
import java.util.stream.IntStream;
|
|
|
|
|
|
-import static org.elasticsearch.repositories.s3.S3BlobStoreTests.randomMockS3BlobStore;
|
|
|
+import static org.hamcrest.Matchers.equalTo;
|
|
|
import static org.hamcrest.Matchers.instanceOf;
|
|
|
import static org.mockito.Matchers.any;
|
|
|
import static org.mockito.Mockito.doNothing;
|
|
@@ -397,10 +403,99 @@ public class S3BlobStoreContainerTests extends ESBlobStoreContainerTestCase {
|
|
|
assertNumberOfMultiparts(factor + 1, remaining, (size * factor) + remaining, size);
|
|
|
}
|
|
|
|
|
|
+ public void testInitCannedACL() {
|
|
|
+ String[] aclList = new String[]{
|
|
|
+ "private", "public-read", "public-read-write", "authenticated-read",
|
|
|
+ "log-delivery-write", "bucket-owner-read", "bucket-owner-full-control"};
|
|
|
+
|
|
|
+ //empty acl
|
|
|
+ assertThat(S3BlobStore.initCannedACL(null), equalTo(CannedAccessControlList.Private));
|
|
|
+ assertThat(S3BlobStore.initCannedACL(""), equalTo(CannedAccessControlList.Private));
|
|
|
+
|
|
|
+ // it should init cannedACL correctly
|
|
|
+ for (String aclString : aclList) {
|
|
|
+ CannedAccessControlList acl = S3BlobStore.initCannedACL(aclString);
|
|
|
+ assertThat(acl.toString(), equalTo(aclString));
|
|
|
+ }
|
|
|
+
|
|
|
+ // it should accept all aws cannedACLs
|
|
|
+ for (CannedAccessControlList awsList : CannedAccessControlList.values()) {
|
|
|
+ CannedAccessControlList acl = S3BlobStore.initCannedACL(awsList.toString());
|
|
|
+ assertThat(acl, equalTo(awsList));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testInvalidCannedACL() {
|
|
|
+ BlobStoreException ex = expectThrows(BlobStoreException.class, () -> S3BlobStore.initCannedACL("test_invalid"));
|
|
|
+ assertThat(ex.getMessage(), equalTo("cannedACL is not valid: [test_invalid]"));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testInitStorageClass() {
|
|
|
+ // it should default to `standard`
|
|
|
+ assertThat(S3BlobStore.initStorageClass(null), equalTo(StorageClass.Standard));
|
|
|
+ assertThat(S3BlobStore.initStorageClass(""), equalTo(StorageClass.Standard));
|
|
|
+
|
|
|
+ // it should accept [standard, standard_ia, onezone_ia, reduced_redundancy, intelligent_tiering]
|
|
|
+ assertThat(S3BlobStore.initStorageClass("standard"), equalTo(StorageClass.Standard));
|
|
|
+ assertThat(S3BlobStore.initStorageClass("standard_ia"), equalTo(StorageClass.StandardInfrequentAccess));
|
|
|
+ assertThat(S3BlobStore.initStorageClass("onezone_ia"), equalTo(StorageClass.OneZoneInfrequentAccess));
|
|
|
+ assertThat(S3BlobStore.initStorageClass("reduced_redundancy"), equalTo(StorageClass.ReducedRedundancy));
|
|
|
+ assertThat(S3BlobStore.initStorageClass("intelligent_tiering"), equalTo(StorageClass.IntelligentTiering));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testCaseInsensitiveStorageClass() {
|
|
|
+ assertThat(S3BlobStore.initStorageClass("sTandaRd"), equalTo(StorageClass.Standard));
|
|
|
+ assertThat(S3BlobStore.initStorageClass("sTandaRd_Ia"), equalTo(StorageClass.StandardInfrequentAccess));
|
|
|
+ assertThat(S3BlobStore.initStorageClass("oNeZoNe_iA"), equalTo(StorageClass.OneZoneInfrequentAccess));
|
|
|
+ assertThat(S3BlobStore.initStorageClass("reduCED_redundancy"), equalTo(StorageClass.ReducedRedundancy));
|
|
|
+ assertThat(S3BlobStore.initStorageClass("intelLigeNt_tieriNG"), equalTo(StorageClass.IntelligentTiering));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testInvalidStorageClass() {
|
|
|
+ BlobStoreException ex = expectThrows(BlobStoreException.class, () -> S3BlobStore.initStorageClass("whatever"));
|
|
|
+ assertThat(ex.getMessage(), equalTo("`whatever` is not a valid S3 Storage Class."));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testRejectGlacierStorageClass() {
|
|
|
+ BlobStoreException ex = expectThrows(BlobStoreException.class, () -> S3BlobStore.initStorageClass("glacier"));
|
|
|
+ assertThat(ex.getMessage(), equalTo("Glacier storage class is not supported"));
|
|
|
+ }
|
|
|
+
|
|
|
private static void assertNumberOfMultiparts(final int expectedParts, final long expectedRemaining, long totalSize, long partSize) {
|
|
|
final Tuple<Long, Long> result = S3BlobContainer.numberOfMultiparts(totalSize, partSize);
|
|
|
|
|
|
assertEquals("Expected number of parts [" + expectedParts + "] but got [" + result.v1() + "]", expectedParts, (long) result.v1());
|
|
|
assertEquals("Expected remaining [" + expectedRemaining + "] but got [" + result.v2() + "]", expectedRemaining, (long) result.v2());
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates a new {@link S3BlobStore} with random settings.
|
|
|
+ * <p>
|
|
|
+ * The blobstore uses a {@link MockAmazonS3} client.
|
|
|
+ */
|
|
|
+ public static S3BlobStore randomMockS3BlobStore() {
|
|
|
+ String bucket = randomAlphaOfLength(randomIntBetween(1, 10)).toLowerCase(Locale.ROOT);
|
|
|
+ ByteSizeValue bufferSize = new ByteSizeValue(randomIntBetween(5, 100), ByteSizeUnit.MB);
|
|
|
+ boolean serverSideEncryption = randomBoolean();
|
|
|
+
|
|
|
+ String cannedACL = null;
|
|
|
+ if (randomBoolean()) {
|
|
|
+ cannedACL = randomFrom(CannedAccessControlList.values()).toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ String storageClass = null;
|
|
|
+ if (randomBoolean()) {
|
|
|
+ storageClass = randomValueOtherThan(StorageClass.Glacier, () -> randomFrom(StorageClass.values())).toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ final AmazonS3 client = new MockAmazonS3(new ConcurrentHashMap<>(), bucket, serverSideEncryption, cannedACL, storageClass);
|
|
|
+ final S3Service service = new S3Service() {
|
|
|
+ @Override
|
|
|
+ public synchronized AmazonS3Reference client(RepositoryMetaData repositoryMetaData) {
|
|
|
+ return new AmazonS3Reference(client);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return new S3BlobStore(service, bucket, serverSideEncryption, bufferSize, cannedACL, storageClass,
|
|
|
+ new RepositoryMetaData(bucket, "s3", Settings.EMPTY));
|
|
|
+ }
|
|
|
}
|