From 137862e2f3f95e6343e51a5634a2543f0888be58 Mon Sep 17 00:00:00 2001 From: John Viegas Date: Fri, 8 Sep 2023 14:46:59 -0700 Subject: [PATCH] Test cases to check on Failure --- services-custom/s3-transfer-manager/pom.xml | 5 + ...3TransferManagerUploadIntegrationTest.java | 18 -- .../S3CrtTransferProgressListenerTest.java | 195 ++++++++++++++++++ .../crt/S3CrtResponseHandlerAdapter.java | 1 - 4 files changed, 200 insertions(+), 19 deletions(-) create mode 100644 services-custom/s3-transfer-manager/src/test/java/software/amazon/awssdk/transfer/s3/internal/S3CrtTransferProgressListenerTest.java diff --git a/services-custom/s3-transfer-manager/pom.xml b/services-custom/s3-transfer-manager/pom.xml index 42ba838e9ed8..9968535f9df9 100644 --- a/services-custom/s3-transfer-manager/pom.xml +++ b/services-custom/s3-transfer-manager/pom.xml @@ -212,6 +212,11 @@ ${commons-codec.verion} test + + wiremock-jre8 + com.github.tomakehurst + test + diff --git a/services-custom/s3-transfer-manager/src/it/java/software/amazon/awssdk/transfer/s3/S3TransferManagerUploadIntegrationTest.java b/services-custom/s3-transfer-manager/src/it/java/software/amazon/awssdk/transfer/s3/S3TransferManagerUploadIntegrationTest.java index f87059596732..026652ecef62 100644 --- a/services-custom/s3-transfer-manager/src/it/java/software/amazon/awssdk/transfer/s3/S3TransferManagerUploadIntegrationTest.java +++ b/services-custom/s3-transfer-manager/src/it/java/software/amazon/awssdk/transfer/s3/S3TransferManagerUploadIntegrationTest.java @@ -26,7 +26,6 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletionException; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -35,7 +34,6 @@ import software.amazon.awssdk.core.sync.ResponseTransformer; import software.amazon.awssdk.services.s3.model.ChecksumAlgorithm; import software.amazon.awssdk.services.s3.model.GetObjectResponse; -import software.amazon.awssdk.services.s3.model.NoSuchBucketException; import software.amazon.awssdk.testutils.RandomTempFile; import software.amazon.awssdk.transfer.s3.model.CompletedFileUpload; import software.amazon.awssdk.transfer.s3.model.CompletedUpload; @@ -148,20 +146,4 @@ void upload_file_Interupted_CancelsTheListener() throws IOException, Interrupted assertThat(transferListener.getRatioTransferredList().get(transferListener.getRatioTransferredList().size() - 1)) .isNotEqualTo(100.0); } - - @Test - void upload_file_errorPropagatedToListener() throws IOException, InterruptedException { - Map metadata = new HashMap<>(); - CaptureTransferListener transferListener = new CaptureTransferListener(); - metadata.put("x-amz-meta-foobar", "FOO BAR"); - FileUpload fileUpload = - tm.uploadFile(u -> u.putObjectRequest(p -> p.bucket(TEST_BUCKET+TEST_BUCKET).key(TEST_KEY).metadata(metadata).checksumAlgorithm(ChecksumAlgorithm.CRC32)) - .source(testFile.toPath()) - .addTransferListener(LoggingTransferListener.create()) - .addTransferListener(transferListener) - .build()); - assertThatExceptionOfType(CompletionException.class).isThrownBy( - () -> fileUpload.completionFuture().join()); - assertThat(transferListener.getExceptionCaught()).isInstanceOf(NoSuchBucketException.class); - } } diff --git a/services-custom/s3-transfer-manager/src/test/java/software/amazon/awssdk/transfer/s3/internal/S3CrtTransferProgressListenerTest.java b/services-custom/s3-transfer-manager/src/test/java/software/amazon/awssdk/transfer/s3/internal/S3CrtTransferProgressListenerTest.java new file mode 100644 index 000000000000..99d59c4472da --- /dev/null +++ b/services-custom/s3-transfer-manager/src/test/java/software/amazon/awssdk/transfer/s3/internal/S3CrtTransferProgressListenerTest.java @@ -0,0 +1,195 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.transfer.s3.internal; + + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.any; +import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; + +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletionException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.S3CrtAsyncClientBuilder; +import software.amazon.awssdk.services.s3.model.NoSuchBucketException; +import software.amazon.awssdk.services.s3.model.S3Exception; +import software.amazon.awssdk.testutils.RandomTempFile; +import software.amazon.awssdk.transfer.s3.CaptureTransferListener; +import software.amazon.awssdk.transfer.s3.S3TransferManager; +import software.amazon.awssdk.transfer.s3.model.FileUpload; +import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener; +import software.amazon.awssdk.transfer.s3.progress.TransferListener; + +@WireMockTest +public class S3CrtTransferProgressListenerTest { + public static final String ERROR_CODE = "NoSuchBucket"; + public static final String ERROR_MESSAGE = "We encountered an internal error. Please try again."; + public static final String ERROR_BODY = "\n" + + "\n" + + " " + ERROR_CODE + "\n" + + " " + ERROR_MESSAGE + "\n" + + ""; + private static final String EXAMPLE_BUCKET = "Example-Bucket"; + private static final String TEST_KEY = "16mib_file.dat"; + private static final int OBJ_SIZE = 16 * 1024; + private RandomTempFile testFile; + + + @BeforeEach + public void setUp() throws IOException { + testFile = new RandomTempFile(TEST_KEY, OBJ_SIZE); + } + + private static void assertMockOnFailure(TransferListener transferListenerMock) { + Mockito.verify(transferListenerMock, times(1)).bytesTransferred(ArgumentMatchers.any()); + Mockito.verify(transferListenerMock, times(1)).transferFailed(ArgumentMatchers.any()); + Mockito.verify(transferListenerMock, times(1)).transferInitiated(ArgumentMatchers.any()); + Mockito.verify(transferListenerMock, times(0)).transferComplete(ArgumentMatchers.any()); + } + + private S3CrtAsyncClientBuilder getAsyncClientBuilder(WireMockRuntimeInfo wm) { + return S3AsyncClient.crtBuilder() + .region(Region.US_EAST_1) + .endpointOverride(URI.create(wm.getHttpBaseUrl())) + .credentialsProvider( + StaticCredentialsProvider.create(AwsBasicCredentials.create("key", "secret"))); + + } + + @Test + void listeners_reports_ErrorsWithValidPayload(WireMockRuntimeInfo wm) { + TransferListener transferListenerMock = mock(TransferListener.class); + stubFor(any(anyUrl()).willReturn(aResponse().withStatus(404).withBody(ERROR_BODY))); + S3TransferManager tm = new GenericS3TransferManager(getAsyncClientBuilder(wm).build(), mock(UploadDirectoryHelper.class), + mock(TransferManagerConfiguration.class), + mock(DownloadDirectoryHelper.class)); + CaptureTransferListener transferListener = new CaptureTransferListener(); + FileUpload fileUpload = + tm.uploadFile(u -> u.putObjectRequest(p -> p.bucket(EXAMPLE_BUCKET).key("KEY")) + .source(testFile) + .addTransferListener(LoggingTransferListener.create()) + .addTransferListener(transferListener) + .addTransferListener(transferListenerMock) + .build()); + + assertThatExceptionOfType(CompletionException.class).isThrownBy(() -> fileUpload.completionFuture().join()); + assertThat(transferListener.getExceptionCaught()).isInstanceOf(NoSuchBucketException.class); + assertThat(transferListener.isTransferComplete()).isFalse(); + assertThat(transferListener.isTransferInitiated()).isTrue(); + + assertMockOnFailure(transferListenerMock); + } + + @Test + void listeners_reports_ErrorsWithValidInValidPayload(WireMockRuntimeInfo wm) throws InterruptedException { + TransferListener transferListenerMock = mock(TransferListener.class); + + stubFor(any(anyUrl()).willReturn(aResponse().withStatus(404).withBody("?"))); + S3TransferManager tm = new GenericS3TransferManager(getAsyncClientBuilder(wm).build(), mock(UploadDirectoryHelper.class), + mock(TransferManagerConfiguration.class), + mock(DownloadDirectoryHelper.class)); + CaptureTransferListener transferListener = new CaptureTransferListener(); + FileUpload fileUpload = + tm.uploadFile(u -> u.putObjectRequest(p -> p.bucket(EXAMPLE_BUCKET).key("KEY")) + .source(testFile) + .addTransferListener(LoggingTransferListener.create()) + .addTransferListener(transferListener) + .addTransferListener(transferListenerMock) + .build()); + + Thread.sleep(10); + + assertThatExceptionOfType(CompletionException.class).isThrownBy(() -> fileUpload.completionFuture().join()); + + assertThat(transferListener.getExceptionCaught()).isInstanceOf(S3Exception.class); + assertThat(transferListener.isTransferComplete()).isFalse(); + assertThat(transferListener.isTransferInitiated()).isTrue(); + assertMockOnFailure(transferListenerMock); + + } + + + @Test + void listeners_reports_ErrorsWhenCancelled(WireMockRuntimeInfo wm) { + TransferListener transferListenerMock = mock(TransferListener.class); + + stubFor(any(anyUrl()).willReturn(aResponse().withStatus(200).withBody("{}"))); + S3TransferManager tm = new GenericS3TransferManager(getAsyncClientBuilder(wm).build(), mock(UploadDirectoryHelper.class), + mock(TransferManagerConfiguration.class), + mock(DownloadDirectoryHelper.class)); + CaptureTransferListener transferListener = new CaptureTransferListener(); + + tm.uploadFile(u -> u.putObjectRequest(p -> p.bucket(EXAMPLE_BUCKET).key("KEY")) + .source(testFile) + .addTransferListener(LoggingTransferListener.create()) + .addTransferListener(transferListener) + .addTransferListener(transferListenerMock) + .build()).completionFuture().cancel(true); + + assertThat(transferListener.getExceptionCaught()).isInstanceOf(CancellationException.class); + assertThat(transferListener.isTransferComplete()).isFalse(); + assertThat(transferListener.isTransferInitiated()).isTrue(); + assertMockOnFailure(transferListenerMock); + + } + + @Test + void listeners_reports_ProgressWhenSuccess(WireMockRuntimeInfo wm) throws InterruptedException { + TransferListener transferListenerMock = mock(TransferListener.class); + + stubFor(any(anyUrl()).willReturn(aResponse().withStatus(200).withBody("{}"))); + S3TransferManager tm = new GenericS3TransferManager(getAsyncClientBuilder(wm).build(), mock(UploadDirectoryHelper.class), + mock(TransferManagerConfiguration.class), + mock(DownloadDirectoryHelper.class)); + + CaptureTransferListener transferListener = new CaptureTransferListener(); + + tm.uploadFile(u -> u.putObjectRequest(p -> p.bucket(EXAMPLE_BUCKET).key("KEY")) + .source(testFile) + .addTransferListener(LoggingTransferListener.create()) + .addTransferListener(transferListener) + .addTransferListener(transferListenerMock) + .build()).completionFuture().join(); + + Thread.sleep(20); + + assertThat(transferListener.getExceptionCaught()).isNull(); + assertThat(transferListener.isTransferComplete()).isTrue(); + assertThat(transferListener.isTransferInitiated()).isTrue(); + Mockito.verify(transferListenerMock, times(1)).bytesTransferred(ArgumentMatchers.any()); + Mockito.verify(transferListenerMock, times(0)).transferFailed(ArgumentMatchers.any()); + Mockito.verify(transferListenerMock, times(1)).transferInitiated(ArgumentMatchers.any()); + Mockito.verify(transferListenerMock, times(1)).transferComplete(ArgumentMatchers.any()); + } + + +} diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3CrtResponseHandlerAdapter.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3CrtResponseHandlerAdapter.java index ec81d624351e..cff1a6b6193a 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3CrtResponseHandlerAdapter.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3CrtResponseHandlerAdapter.java @@ -152,7 +152,6 @@ private void onErrorResponseComplete(byte[] errorPayload) { } private void failResponseHandlerAndFuture(Throwable exception) { - this.progressListener.subscriberOnError(exception); resultFuture.completeExceptionally(exception); runAndLogError(log.logger(), "Exception thrown in SdkAsyncHttpResponseHandler#onError, ignoring", () -> responseHandler.onError(exception));