Skip to content

Commit 61375dd

Browse files
committed
Add parameterized test for AsyncResponseTransformer types
1 parent 357e486 commit 61375dd

File tree

2 files changed

+59
-32
lines changed

2 files changed

+59
-32
lines changed

core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/async/SplittingTransformer.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,11 +281,8 @@ public CompletableFuture<ResponseT> prepare() {
281281
return;
282282
}
283283

284-
// This isn't necessary, might be good for debugging? Or can just log error
285-
/*e.addSuppressed(NonRetryableException.create(
286-
"Error occurred during multipart download. Request will not be retried."));*/
287-
288-
individualFuture.completeExceptionally(e);
284+
individualFuture.completeExceptionally(NonRetryableException.create(
285+
"Error occurred during multipart download. Request will not be retried.", e));
289286
});
290287
individualFuture.whenComplete((r, e) -> {
291288
if (isCancelled.get()) {

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/multipart/S3MultipartClientGetObjectWiremockTest.java

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,25 @@
3030
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
3131
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
3232
import com.github.tomakehurst.wiremock.stubbing.Scenario;
33+
import java.io.IOException;
34+
import java.io.UncheckedIOException;
3335
import java.net.URI;
36+
import java.nio.file.Files;
37+
import java.nio.file.Path;
3438
import java.time.Duration;
3539
import java.util.ArrayList;
3640
import java.util.List;
3741
import java.util.UUID;
3842
import java.util.concurrent.CompletableFuture;
3943
import java.util.concurrent.CompletionException;
4044
import java.util.concurrent.TimeUnit;
45+
import java.util.stream.Stream;
4146
import org.junit.jupiter.api.BeforeEach;
42-
import org.junit.jupiter.api.Test;
4347
import org.junit.jupiter.api.Timeout;
48+
import org.junit.jupiter.params.ParameterizedTest;
49+
import org.junit.jupiter.params.provider.MethodSource;
4450
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
4551
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
46-
import software.amazon.awssdk.core.ResponseBytes;
4752
import software.amazon.awssdk.core.async.AsyncResponseTransformer;
4853
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
4954
import software.amazon.awssdk.regions.Region;
@@ -54,9 +59,9 @@
5459
@WireMockTest
5560
@Timeout(value = 30, unit = TimeUnit.SECONDS)
5661
public class S3MultipartClientGetObjectWiremockTest {
57-
public static final String BUCKET = "Example-Bucket";
58-
public static final String KEY = "Key";
59-
private static final int MAX_ATTEMPTS = 7;
62+
private static final String BUCKET = "Example-Bucket";
63+
private static final String KEY = "Key";
64+
private static int fileCounter = 0;
6065
private S3AsyncClient multipartClient;
6166

6267
@BeforeEach
@@ -72,13 +77,38 @@ public void setup(WireMockRuntimeInfo wm) {
7277
.build();
7378
}
7479

75-
@Test
76-
public void getObject_single500WithinMany200s_shouldNotRetryError() {
77-
List<CompletableFuture<ResponseBytes<GetObjectResponse>>> futures = new ArrayList<>();
80+
private static Stream<TransformerFactory> responseTransformerFactories() {
81+
return Stream.of(
82+
AsyncResponseTransformer::toBytes,
83+
AsyncResponseTransformer::toBlockingInputStream,
84+
// TODO - hanging
85+
//AsyncResponseTransformer::toPublisher,
86+
() -> {
87+
try {
88+
Path tempDir = Files.createTempDirectory("s3-test");
89+
Path tempFile = tempDir.resolve("testFile" + fileCounter + ".txt");
90+
fileCounter++;
91+
tempFile.toFile().deleteOnExit();
92+
return AsyncResponseTransformer.toFile(tempFile);
93+
} catch (IOException e) {
94+
throw new UncheckedIOException(e);
95+
}
96+
}
97+
);
98+
}
99+
100+
interface TransformerFactory {
101+
AsyncResponseTransformer<GetObjectResponse, ?> create();
102+
}
103+
104+
@ParameterizedTest
105+
@MethodSource("responseTransformerFactories")
106+
public void getObject_single500WithinMany200s_shouldNotRetryError(TransformerFactory transformerFactory) {
107+
List<CompletableFuture<?>> futures = new ArrayList<>();
78108

79109
int numRuns = 1000;
80110
for (int i = 0; i < numRuns; i++) {
81-
CompletableFuture<ResponseBytes<GetObjectResponse>> resp = mock200Response(multipartClient, i);
111+
CompletableFuture<?> resp = mock200Response(multipartClient, i, transformerFactory);
82112
futures.add(resp);
83113
}
84114

@@ -100,12 +130,12 @@ public void getObject_single500WithinMany200s_shouldNotRetryError() {
100130
.withHeader("x-amz-request-id", String.valueOf(UUID.randomUUID()))
101131
.withBody("Hello World")));
102132

103-
CompletableFuture<ResponseBytes<GetObjectResponse>> requestWithRetryableError =
104-
multipartClient.getObject(r -> r.bucket(BUCKET).key(errorKey), AsyncResponseTransformer.toBytes());
133+
CompletableFuture<?> requestWithRetryableError =
134+
multipartClient.getObject(r -> r.bucket(BUCKET).key(errorKey), transformerFactory.create());
105135
futures.add(requestWithRetryableError);
106136

107137
for (int i = 0; i < numRuns; i++) {
108-
CompletableFuture<ResponseBytes<GetObjectResponse>> resp = mock200Response(multipartClient, i + 1000);
138+
CompletableFuture<?> resp = mock200Response(multipartClient, i + 1000, transformerFactory);
109139
futures.add(resp);
110140
}
111141

@@ -119,19 +149,7 @@ public void getObject_single500WithinMany200s_shouldNotRetryError() {
119149
verify(1, getRequestedFor(urlEqualTo(String.format("/%s/%s?partNumber=1", BUCKET, errorKey))));
120150
}
121151

122-
private String errorBody(String errorCode, String errorMessage) {
123-
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
124-
+ "<Error>\n"
125-
+ " <Code>" + errorCode + "</Code>\n"
126-
+ " <Message>" + errorMessage + "</Message>\n"
127-
+ "</Error>";
128-
}
129-
130-
private String internalErrorBody() {
131-
return errorBody("InternalError", "We encountered an internal error. Please try again.");
132-
}
133-
134-
private CompletableFuture<ResponseBytes<GetObjectResponse>> mock200Response(S3AsyncClient s3Client, int runNumber) {
152+
private CompletableFuture<?> mock200Response(S3AsyncClient s3Client, int runNumber, TransformerFactory transformerFactory) {
135153
String runId = runNumber + " success";
136154

137155
stubFor(any(anyUrl())
@@ -142,8 +160,20 @@ private CompletableFuture<ResponseBytes<GetObjectResponse>> mock200Response(S3As
142160
.withHeader("x-amz-request-id", String.valueOf(UUID.randomUUID()))
143161
.withBody("Hello World")));
144162

145-
return s3Client.getObject(r -> r.bucket(BUCKET).key("key")
163+
return s3Client.getObject(r -> r.bucket(BUCKET).key(KEY)
146164
.overrideConfiguration(c -> c.putHeader("RunNum", runId)),
147-
AsyncResponseTransformer.toBytes());
165+
transformerFactory.create());
166+
}
167+
168+
private String errorBody(String errorCode, String errorMessage) {
169+
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
170+
+ "<Error>\n"
171+
+ " <Code>" + errorCode + "</Code>\n"
172+
+ " <Message>" + errorMessage + "</Message>\n"
173+
+ "</Error>";
174+
}
175+
176+
private String internalErrorBody() {
177+
return errorBody("InternalError", "We encountered an internal error. Please try again.");
148178
}
149179
}

0 commit comments

Comments
 (0)