com.hubrick.vertx.s3.client.AbstractS3ClientTest.java Source code

Java tutorial

Introduction

Here is the source code for com.hubrick.vertx.s3.client.AbstractS3ClientTest.java

Source

/**
 * Copyright (C) 2016 Etaia AS (oss@hubrick.com)
 *
 * 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
 *
 *         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 com.hubrick.vertx.s3.client;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Resources;
import com.hubrick.vertx.s3.AbstractFunctionalTest;
import com.hubrick.vertx.s3.S3TestCredentials;
import com.hubrick.vertx.s3.exception.HttpErrorException;
import com.hubrick.vertx.s3.model.AccessControlPolicy;
import com.hubrick.vertx.s3.model.CannedAcl;
import com.hubrick.vertx.s3.model.ErrorCode;
import com.hubrick.vertx.s3.model.Part;
import com.hubrick.vertx.s3.model.Response;
import com.hubrick.vertx.s3.model.header.CommonResponseHeaders;
import com.hubrick.vertx.s3.model.header.CompleteMultipartUploadResponseHeaders;
import com.hubrick.vertx.s3.model.header.ContinueMultipartUploadResponseHeaders;
import com.hubrick.vertx.s3.model.header.InitMultipartUploadResponseHeaders;
import com.hubrick.vertx.s3.model.request.AbortMultipartUploadRequest;
import com.hubrick.vertx.s3.model.request.AclHeadersRequest;
import com.hubrick.vertx.s3.model.request.CompleteMultipartUploadRequest;
import com.hubrick.vertx.s3.model.request.ContinueMultipartUploadRequest;
import com.hubrick.vertx.s3.model.request.CopyObjectRequest;
import com.hubrick.vertx.s3.model.request.DeleteObjectRequest;
import com.hubrick.vertx.s3.model.request.GetBucketRequest;
import com.hubrick.vertx.s3.model.request.GetObjectRequest;
import com.hubrick.vertx.s3.model.request.HeadObjectRequest;
import com.hubrick.vertx.s3.model.request.InitMultipartUploadRequest;
import com.hubrick.vertx.s3.model.request.PutObjectAclRequest;
import com.hubrick.vertx.s3.model.request.PutObjectRequest;
import com.hubrick.vertx.s3.model.response.CompleteMultipartUploadResponse;
import com.hubrick.vertx.s3.model.response.MultipartUploadWriteStream;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.unit.Async;
import io.vertx.ext.unit.TestContext;
import org.apache.commons.lang3.ArrayUtils;
import org.junit.Before;
import org.mockserver.model.BinaryBody;
import org.mockserver.model.Body;
import org.mockserver.model.Header;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.StringBody;
import org.mockserver.model.XmlBody;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static com.hubrick.vertx.s3.VertxMatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.nullValue;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;

/**
 * @author marcus
 * @since 1.0.0
 */
public abstract class AbstractS3ClientTest extends AbstractFunctionalTest {

    public static final String HOSTNAME = "localhost";

    private S3Client s3Client;

    @Before
    public void setUp() throws Exception {
        final S3ClientOptions clientOptions = new S3ClientOptions();
        clientOptions.setDefaultHost(HOSTNAME);
        clientOptions.setDefaultPort(MOCKSERVER_PORT);
        clientOptions.setMaxPoolSize(10);
        clientOptions.setAwsRegion(S3TestCredentials.REGION);
        clientOptions.setAwsServiceName(S3TestCredentials.SERVICE_NAME);
        clientOptions.setHostnameOverride(HOSTNAME);

        augmentClientOptions(clientOptions);

        s3Client = new S3Client(vertx, clientOptions,
                Clock.fixed(Instant.ofEpochSecond(1478782934), ZoneId.of("UTC")));

    }

    protected abstract void augmentClientOptions(final S3ClientOptions clientOptions);

    void addCredentials(final S3ClientOptions clientOptions) {
        clientOptions.setAwsAccessKey(S3TestCredentials.AWS_ACCESS_KEY);
        clientOptions.setAwsSecretKey(S3TestCredentials.AWS_SECRET_KEY);
    }

    void mockGetObject(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "GET", "/bucket/key", 200, "response".getBytes(), expectedHeaders);
    }

    void mockGetObjectErrorResponse(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "GET", "/bucket/key", 403,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml")),
                expectedHeaders);
    }

    void verifyGetObject(TestContext testContext) {
        final Async async = testContext.async();
        s3Client.getObject("bucket", "key", new GetObjectRequest(), (getObjectResponse) -> {
            assertThat(testContext, getObjectResponse.getHeader(), notNullValue());
            assertThat(testContext, getObjectResponse.getData(), notNullValue());

            getObjectResponse.getData().handler(buffer -> {
                assertThat(testContext, new String(buffer.getBytes(), StandardCharsets.UTF_8), is("response"));
                async.complete();

            });
        }, testContext::fail);
    }

    void verifyGetObjectErrorResponse(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.getObject("bucket", "key", new GetObjectRequest(), (result) -> {
            testContext.fail("Exceptions should be thrown");
        }, error -> {
            assertThat(testContext, error, instanceOf(HttpErrorException.class));

            final HttpErrorException httpErrorException = (HttpErrorException) error;
            assertThat(testContext, httpErrorException.getStatus(), is(403));
            assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                    is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
            async.complete();
        });
    }

    void mockGetObjectAcl(AccessControlPolicy accessControlPolicy, Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("acl", ImmutableList.of("")), "GET", "/bucket/key", 200, null,
                new StringBody("<AccessControlPolicy><Owner><ID>" + accessControlPolicy.getOwner().getId()
                        + "</ID><DisplayName>" + accessControlPolicy.getOwner().getDisplayName()
                        + "</DisplayName></Owner>" + "<AccessControlList><Grant><Grantee><ID>"
                        + accessControlPolicy.getGrants().get(0).getGrantee().getId() + "</ID><DisplayName>"
                        + accessControlPolicy.getGrants().get(0).getGrantee().getDisplayName()
                        + "</DisplayName></Grantee><Permission>"
                        + accessControlPolicy.getGrants().get(0).getPermission()
                        + "</Permission></Grant></AccessControlList></AccessControlPolicy>"),
                Collections.emptyList(), expectedHeaders);
    }

    void mockGetObjectAclErrorResponse(Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("acl", ImmutableList.of("")), "GET", "/bucket/key", 403, null,
                new BinaryBody(Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml"))),
                Collections.emptyList(), expectedHeaders);
    }

    void verifyGetObjectAcl(TestContext testContext, AccessControlPolicy accessControlPolicy) {
        final Async async = testContext.async();
        s3Client.getObjectAcl("bucket", "key", (getObjectResponse) -> {
            assertThat(testContext, getObjectResponse.getHeader(), notNullValue());
            assertThat(testContext, getObjectResponse.getData(), notNullValue());
            assertThat(testContext, getObjectResponse.getData(), is(accessControlPolicy));

            async.complete();
        }, testContext::fail);
    }

    void verifyGetObjectAclErrorResponse(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.getObjectAcl("bucket", "key", (result) -> {
            testContext.fail("Exceptions should be thrown");
        }, error -> {
            assertThat(testContext, error, instanceOf(HttpErrorException.class));

            final HttpErrorException httpErrorException = (HttpErrorException) error;
            assertThat(testContext, httpErrorException.getStatus(), is(403));
            assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                    is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
            async.complete();
        });
    }

    void mockHeadObject(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "HEAD", "/bucket/key", 200, "0".getBytes(), expectedHeaders);
    }

    void mockHeadObjectErrorResponse(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "HEAD", "/bucket/key", 403, "0".getBytes(), expectedHeaders);
    }

    void verifyHeadObject(TestContext testContext) {
        final Async async = testContext.async();
        s3Client.headObject("bucket", "key", new HeadObjectRequest(), (response) -> {
            assertThat(testContext, response, notNullValue());
            async.complete();
        }, testContext::fail);
    }

    void verifyHeadObjectErrorResponse(final TestContext testContext) {
        final Async async = testContext.async();
        s3Client.headObject("bucket", "key", new HeadObjectRequest(), (result) -> {
            testContext.fail("Exceptions should be thrown");
        }, error -> {
            assertThat(testContext, error, instanceOf(HttpErrorException.class));

            final HttpErrorException httpErrorException = (HttpErrorException) error;
            assertThat(testContext, httpErrorException.getStatus(), is(403));
            assertThat(testContext, httpErrorException.getErrorResponse(), nullValue());
            async.complete();
        });
    }

    void mockPutObject(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "PUT", "/bucket/key", 200, new StringBody("test"), new StringBody("<>"),
                Collections.emptyList(), expectedHeaders);
    }

    void mockPutObjectErrorResponse(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "PUT", "/bucket/key", 403, new StringBody("test"),
                new BinaryBody(Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml"))),
                Collections.emptyList(), expectedHeaders);
    }

    void verifyPutObject(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.putObject("bucket", "key", new PutObjectRequest(Buffer.buffer("test")), (putResponseHeaders) -> {
            assertThat(testContext, putResponseHeaders, notNullValue());
            async.complete();
        }, testContext::fail);
    }

    void verifyPutObjectErrorResponse(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.putObject("bucket", "key", new PutObjectRequest(Buffer.buffer("test")), (result) -> {
            testContext.fail("Exceptions should be thrown");
        }, error -> {
            assertThat(testContext, error, instanceOf(HttpErrorException.class));

            final HttpErrorException httpErrorException = (HttpErrorException) error;
            assertThat(testContext, httpErrorException.getStatus(), is(403));
            assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                    is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
            async.complete();
        });
    }

    void mockPutObjectAclWithHeaders(Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("acl", ImmutableList.of("")), "PUT", "/bucket/key", 200, "test".getBytes(),
                Collections.emptyList(), expectedHeaders);
    }

    void verifyPutObjectAclWithHeaders(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.putObjectAcl("bucket", "key",
                new PutObjectAclRequest(new AclHeadersRequest().withAmzAcl(CannedAcl.PRIVATE)),
                (putResponseHeaders) -> {
                    assertThat(testContext, putResponseHeaders, notNullValue());
                    async.complete();
                }, testContext::fail);
    }

    void mockPutObjectAclWithHeadersErrorResponse(Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("acl", ImmutableList.of("")), "PUT", "/bucket/key", 403,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml")),
                Collections.emptyList(), expectedHeaders);
    }

    void verifyPutObjectAclWithHeadersErrorResponse(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.putObjectAcl("bucket", "key",
                new PutObjectAclRequest(new AclHeadersRequest().withAmzAcl(CannedAcl.PRIVATE)), (result) -> {
                    testContext.fail("Exceptions should be thrown");
                }, error -> {
                    assertThat(testContext, error, instanceOf(HttpErrorException.class));

                    final HttpErrorException httpErrorException = (HttpErrorException) error;
                    assertThat(testContext, httpErrorException.getStatus(), is(403));
                    assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                            is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
                    async.complete();
                });
    }

    void mockPutObjectAclWithBody(AccessControlPolicy accessControlPolicy, Header... expectedHeaders)
            throws IOException {
        mock(ImmutableMap.of("acl", ImmutableList.of("")), "PUT", "/bucket/key", 200,
                new XmlBody("<AccessControlPolicy><Owner><ID>" + accessControlPolicy.getOwner().getId()
                        + "</ID><DisplayName>" + accessControlPolicy.getOwner().getDisplayName()
                        + "</DisplayName></Owner>" + "<AccessControlList><Grant><Grantee><ID>"
                        + accessControlPolicy.getGrants().get(0).getGrantee().getId() + "</ID><DisplayName>"
                        + accessControlPolicy.getGrants().get(0).getGrantee().getDisplayName()
                        + "</DisplayName></Grantee><Permission>"
                        + accessControlPolicy.getGrants().get(0).getPermission()
                        + "</Permission></Grant></AccessControlList></AccessControlPolicy>"),
                new StringBody("<>"), Collections.emptyList(), expectedHeaders);
    }

    void verifyPutObjectAclWithBody(AccessControlPolicy accessControlPolicy, final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.putObjectAcl("bucket", "key", new PutObjectAclRequest(accessControlPolicy),
                (putResponseHeaders) -> {
                    assertThat(testContext, putResponseHeaders, notNullValue());
                    async.complete();
                }, testContext::fail);
    }

    void mockPutObjectAclWithBodyErrorResponse(AccessControlPolicy accessControlPolicy, Header... expectedHeaders)
            throws IOException {
        mock(ImmutableMap.of("acl", ImmutableList.of("")), "PUT", "/bucket/key", 403,
                new XmlBody("<AccessControlPolicy><Owner><ID>" + accessControlPolicy.getOwner().getId()
                        + "</ID><DisplayName>" + accessControlPolicy.getOwner().getDisplayName()
                        + "</DisplayName></Owner>" + "<AccessControlList><Grant><Grantee><ID>"
                        + accessControlPolicy.getGrants().get(0).getGrantee().getId() + "</ID><DisplayName>"
                        + accessControlPolicy.getGrants().get(0).getGrantee().getDisplayName()
                        + "</DisplayName></Grantee><Permission>"
                        + accessControlPolicy.getGrants().get(0).getPermission()
                        + "</Permission></Grant></AccessControlList></AccessControlPolicy>"),
                new BinaryBody(Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml"))),
                Collections.emptyList(), expectedHeaders);
    }

    void verifyPutObjectAclWithBodyErrorResponse(AccessControlPolicy accessControlPolicy,
            final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.putObjectAcl("bucket", "key", new PutObjectAclRequest(accessControlPolicy), (result) -> {
            testContext.fail("Exceptions should be thrown");
        }, error -> {
            assertThat(testContext, error, instanceOf(HttpErrorException.class));

            final HttpErrorException httpErrorException = (HttpErrorException) error;
            assertThat(testContext, httpErrorException.getStatus(), is(403));
            assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                    is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
            async.complete();
        });
    }

    void mockInitMultipartUpload(String uploadId, Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("uploads", ImmutableList.of("")), "POST", "/bucket/key", 200,
                ("<InitiateMultipartUploadResult><Bucket>bucket</Bucket><Key>key</Key><UploadId>" + uploadId
                        + "</UploadId></InitiateMultipartUploadResult>").getBytes(),
                expectedHeaders);
    }

    void mockInitMultipartUploadErrorResponse(Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("uploads", ImmutableList.of("")), "POST", "/bucket/key", 403,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml")),
                expectedHeaders);
    }

    void verifyInitMultipartUpload(final TestContext testContext) {

        final Async async = testContext.async();
        callInitMultipartUpload(testContext, event -> {
            assertThat(testContext, event.getData(), notNullValue());
            assertThat(testContext, event.getHeader(), notNullValue());

            async.complete();
        });
    }

    void verifyInitMultipartUploadErrorResponse(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.initMultipartUpload("bucket", "key", new InitMultipartUploadRequest(), (result) -> {
            testContext.fail("Exceptions should be thrown");
        }, error -> {
            assertThat(testContext, error, instanceOf(HttpErrorException.class));

            final HttpErrorException httpErrorException = (HttpErrorException) error;
            assertThat(testContext, httpErrorException.getStatus(), is(403));
            assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                    is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
            async.complete();
        });
    }

    void callInitMultipartUpload(final TestContext testContext,
            Handler<Response<InitMultipartUploadResponseHeaders, MultipartUploadWriteStream>> handler) {

        s3Client.initMultipartUpload("bucket", "key", new InitMultipartUploadRequest(), handler, testContext::fail);
    }

    void mockContinueMultipartUpload(Integer partNumber, String uploadId, Header... expectedHeaders)
            throws IOException {
        mock(ImmutableMap.of("partNumber", ImmutableList.of(partNumber.toString()), "uploadId",
                ImmutableList.of(uploadId)), "PUT", "/bucket/key", 200, "<>".getBytes(),
                ImmutableList.of(new Header("ETag", "someetag")), expectedHeaders);
    }

    void mockContinueMultipartUploadErrorResponse(Integer partNumber, String uploadId, Header... expectedHeaders)
            throws IOException {
        mock(ImmutableMap
                .of("partNumber", ImmutableList.of(partNumber.toString()), "uploadId", ImmutableList.of(uploadId)),
                "PUT", "/bucket/key", 403,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml")),
                expectedHeaders);
    }

    void verifyContinueMultipartUpload(final TestContext testContext, Integer partNumber, String uploadId) {

        final Async async = testContext.async();
        callContinueMultipartUpload(testContext, partNumber, uploadId, event -> {
            assertThat(testContext, event.getData(), nullValue());
            assertThat(testContext, event.getHeader(), notNullValue());

            async.complete();
        });
    }

    void verifyContinueMultipartUploadErrorResponse(final TestContext testContext, Integer partNumber,
            String uploadId) {

        final Async async = testContext.async();
        s3Client.continueMultipartUpload("bucket", "key",
                new ContinueMultipartUploadRequest(Buffer.buffer("whatever".getBytes()), partNumber, uploadId),
                (result) -> {
                    testContext.fail("Exceptions should be thrown");
                }, error -> {
                    assertThat(testContext, error, instanceOf(HttpErrorException.class));

                    final HttpErrorException httpErrorException = (HttpErrorException) error;
                    assertThat(testContext, httpErrorException.getStatus(), is(403));
                    assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                            is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
                    async.complete();
                });
    }

    void callContinueMultipartUpload(final TestContext testContext, Integer partNumber, String uploadId,
            Handler<Response<ContinueMultipartUploadResponseHeaders, Void>> handler) {

        s3Client.continueMultipartUpload("bucket", "key",
                new ContinueMultipartUploadRequest(Buffer.buffer("some data".getBytes()), partNumber, uploadId),
                handler, testContext::fail);
    }

    void mockCompleteMultipartUpload(String uploadId, Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("uploadId", ImmutableList.of(uploadId)), "POST", "/bucket/key", 200,
                "<CompleteMultipartUploadResult><Location>whatever</Location><Bucket>bucket</Bucket><Key>key</Key><ETag>whatever</ETag></CompleteMultipartUploadResult>"
                        .getBytes(),
                expectedHeaders);
    }

    void mockCompleteMultipartUploadErrorResponse(String uploadId, Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("uploadId", ImmutableList.of(uploadId)), "POST", "/bucket/key", 403,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml")),
                expectedHeaders);
    }

    void verifyCompleteMultipartUpload(final TestContext testContext, String uploadId) {

        final Async async = testContext.async();
        callCompleteMultipartUpload(testContext, Collections.emptyList(), uploadId, event -> {
            assertThat(testContext, event.getData(), notNullValue());
            assertThat(testContext, event.getHeader(), notNullValue());

            async.complete();
        });
    }

    void verifyCompleteMultipartUploadErrorResponse(final TestContext testContext, String uploadId) {

        final Async async = testContext.async();
        s3Client.completeMultipartUpload("bucket", "key",
                new CompleteMultipartUploadRequest(uploadId, Collections.emptyList()), (result) -> {
                    testContext.fail("Exceptions should be thrown");
                }, error -> {
                    assertThat(testContext, error, instanceOf(HttpErrorException.class));

                    final HttpErrorException httpErrorException = (HttpErrorException) error;
                    assertThat(testContext, httpErrorException.getStatus(), is(403));
                    assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                            is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
                    async.complete();
                });
    }

    void callCompleteMultipartUpload(final TestContext testContext, List<Part> parts, String uploadId,
            Handler<Response<CompleteMultipartUploadResponseHeaders, CompleteMultipartUploadResponse>> handler) {

        s3Client.completeMultipartUpload("bucket", "key", new CompleteMultipartUploadRequest(uploadId, parts),
                handler, testContext::fail);
    }

    void mockAbortMultipartUpload(String uploadId, Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("uploadId", ImmutableList.of(uploadId)), "DELETE", "/bucket/key", 200, "<>".getBytes(),
                expectedHeaders);
    }

    void mockAbortMultipartUploadErrorResponse(String uploadId, Header... expectedHeaders) throws IOException {
        mock(ImmutableMap.of("uploadId", ImmutableList.of(uploadId)), "DELETE", "/bucket/key", 403,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml")),
                expectedHeaders);
    }

    void verifyAbortMultipartUpload(final TestContext testContext, String uploadId) {
        final Async async = testContext.async();
        callAbortMultipartUpload(testContext, uploadId, event -> {
            assertThat(testContext, event.getData(), nullValue());
            assertThat(testContext, event.getHeader(), notNullValue());

            async.complete();
        });
    }

    void verifyAbortMultipartUploadErrorResponse(final TestContext testContext, String uploadId) {

        final Async async = testContext.async();
        s3Client.abortMultipartUpload("bucket", "key", new AbortMultipartUploadRequest(uploadId), (result) -> {
            testContext.fail("Exceptions should be thrown");
        }, error -> {
            assertThat(testContext, error, instanceOf(HttpErrorException.class));

            final HttpErrorException httpErrorException = (HttpErrorException) error;
            assertThat(testContext, httpErrorException.getStatus(), is(403));
            assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                    is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
            async.complete();
        });
    }

    void callAbortMultipartUpload(final TestContext testContext, String uploadId,
            Handler<Response<CommonResponseHeaders, Void>> handler) {

        s3Client.abortMultipartUpload("bucket", "key", new AbortMultipartUploadRequest(uploadId), handler,
                testContext::fail);
    }

    void mockDeleteObject(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "DELETE", "/bucket/key", 200, "<>".getBytes(), expectedHeaders);
    }

    void mockDeleteObjectErrorResponse(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "DELETE", "/bucket/key", 403,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml")),
                expectedHeaders);
    }

    void verifyDeleteObject(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.deleteObject("bucket", "key", new DeleteObjectRequest(), (commonResponseHeaders) -> {
            assertThat(testContext, commonResponseHeaders, notNullValue());
            async.complete();
        }, testContext::fail);
    }

    void verifyDeleteObjectErrorResponse(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.deleteObject("bucket", "key", new DeleteObjectRequest(), (result) -> {
            testContext.fail("Exceptions should be thrown");
        }, error -> {
            assertThat(testContext, error, instanceOf(HttpErrorException.class));

            final HttpErrorException httpErrorException = (HttpErrorException) error;
            assertThat(testContext, httpErrorException.getStatus(), is(403));
            assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                    is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
            async.complete();
        });
    }

    void mockCopyObject(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "PUT", "/destinationBucket/destinationKey", 200,
                "<CopyObjectResult></CopyObjectResult>".getBytes(),
                ArrayUtils.add(expectedHeaders, Header.header("X-Amz-Copy-Source", "/sourceBucket/sourceKey")));
    }

    void mockCopyObjectErrorResponse(Header... expectedHeaders) throws IOException {
        mock(Collections.emptyMap(), "PUT", "/destinationBucket/destinationKey", 403,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml")),
                ArrayUtils.add(expectedHeaders, Header.header("X-Amz-Copy-Source", "/sourceBucket/sourceKey")));
    }

    void verifyCopyObject(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.copyObject("sourceBucket", "sourceKey", "destinationBucket", "destinationKey",
                new CopyObjectRequest(), (copyObjectResponse) -> {
                    assertThat(testContext, copyObjectResponse.getHeader(), notNullValue());
                    assertThat(testContext, copyObjectResponse.getData(), notNullValue());
                    async.complete();
                }, testContext::fail);
    }

    void verifyCopyObjectErrorResponse(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.copyObject("sourceBucket", "sourceKey", "destinationBucket", "destinationKey",
                new CopyObjectRequest(), (result) -> {
                    testContext.fail("Exceptions should be thrown");
                }, error -> {
                    assertThat(testContext, error, instanceOf(HttpErrorException.class));

                    final HttpErrorException httpErrorException = (HttpErrorException) error;
                    assertThat(testContext, httpErrorException.getStatus(), is(403));
                    assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                            is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
                    async.complete();
                });
    }

    void mockGetBucket(Map<String, List<String>> expectedQueryParams, Header... expectedHeaders)
            throws IOException {
        mock(expectedQueryParams, "GET", "/sourceBucket", 200,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/listBucketResult.xml")),
                expectedHeaders);
    }

    void mockGetBucketErrorResponse(Map<String, List<String>> expectedQueryParams, Header... expectedHeaders)
            throws IOException {
        mock(expectedQueryParams, "GET", "/sourceBucket", 403,
                Resources.toByteArray(
                        Resources.getResource(AbstractS3ClientTest.class, "/response/errorResponse.xml")),
                expectedHeaders);
    }

    void verifyGetBucket(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.getBucket("sourceBucket", new GetBucketRequest().withContinuationToken(
                "14HF6Dfbr92F1EYlZIrMwxPYKQl5lD/mbwiw5+Nlrn1lYIZX3YGzo16Dgz+dxbxFeNGmLsnzwnbbuQM0CMl0krVwh8TBj8nCmNtq/iQCK6gzln8z3U4C71Mh2HyEMHcMgrZGR/akosVql7/AIctj6rA=="),
                (getBucketRespone) -> {
                    assertThat(testContext, getBucketRespone, notNullValue());
                    assertThat(testContext, getBucketRespone.getHeader().getContentType(),
                            is("application/xml;charset=UTF-8"));
                    assertThat(testContext, getBucketRespone.getData().getContentsList(), hasSize(5));
                    assertThat(testContext, getBucketRespone.getData().getName(), is("bucket"));

                    async.complete();
                }, testContext::fail);
    }

    void verifyGetBucketErrorResponse(final TestContext testContext) {

        final Async async = testContext.async();
        s3Client.getBucket("sourceBucket", new GetBucketRequest().withContinuationToken(
                "14HF6Dfbr92F1EYlZIrMwxPYKQl5lD/mbwiw5+Nlrn1lYIZX3YGzo16Dgz+dxbxFeNGmLsnzwnbbuQM0CMl0krVwh8TBj8nCmNtq/iQCK6gzln8z3U4C71Mh2HyEMHcMgrZGR/akosVql7/AIctj6rA=="),
                (result) -> {
                    testContext.fail("Exceptions should be thrown");
                }, error -> {
                    assertThat(testContext, error, instanceOf(HttpErrorException.class));

                    final HttpErrorException httpErrorException = (HttpErrorException) error;
                    assertThat(testContext, httpErrorException.getStatus(), is(403));
                    assertThat(testContext, httpErrorException.getErrorResponse().getCode(),
                            is(ErrorCode.SIGNATURE_DOES_NOT_MATCH));
                    async.complete();
                });
    }

    void mock(Map<String, List<String>> expectedQueryParams, String method, String path, Integer statusCode,
            byte[] responseBody, Header... expectedHeaders) throws IOException {
        mock(expectedQueryParams, method, path, statusCode, null, new BinaryBody(responseBody),
                Collections.emptyList(), expectedHeaders);
    }

    void mock(Map<String, List<String>> expectedQueryParams, String method, String path, Integer statusCode,
            byte[] responseBody, List<Header> responseHeaders, Header... expectedHeaders) throws IOException {
        mock(expectedQueryParams, method, path, statusCode, null, new BinaryBody(responseBody), responseHeaders,
                expectedHeaders);
    }

    void mock(Map<String, List<String>> expectedQueryParams, String method, String path, Integer statusCode,
            Body requestBody, Body responseBody, List<Header> responseHeaders, Header... expectedHeaders)
            throws IOException {
        final HttpRequest httpRequest = request().withMethod(method).withPath(path).withHeaders(expectedHeaders)
                .withQueryStringParameters(expectedQueryParams);

        if (requestBody != null) {
            httpRequest.withBody(requestBody);
        }

        getMockServerClient().when(httpRequest)
                .respond(response().withStatusCode(statusCode).withHeaders(responseHeaders)
                        .withHeader(Header.header("Content-Type", "application/xml;charset=UTF-8"))
                        .withBody(responseBody));
    }
}