30
30
import static org .junit .jupiter .api .Assertions .assertNotNull ;
31
31
import static org .junit .jupiter .api .Assertions .assertThrows ;
32
32
33
+ import com .github .tomakehurst .wiremock .http .Fault ;
33
34
import com .github .tomakehurst .wiremock .junit5 .WireMockRuntimeInfo ;
34
35
import com .github .tomakehurst .wiremock .junit5 .WireMockTest ;
35
36
import com .github .tomakehurst .wiremock .stubbing .Scenario ;
36
37
import java .net .URI ;
38
+ import java .nio .charset .StandardCharsets ;
37
39
import java .time .Duration ;
38
40
import java .util .ArrayList ;
39
41
import java .util .List ;
@@ -92,10 +94,8 @@ public void setup(WireMockRuntimeInfo wm) {
92
94
.build ();
93
95
}
94
96
95
- // TODO - 1) update test names 2) add test for I/O error
96
-
97
97
@ Test
98
- public void stub_200_only () {
98
+ public void getObject_concurrentCallsReturn200_shouldSucceed () {
99
99
List <CompletableFuture <ResponseBytes <GetObjectResponse >>> futures = new ArrayList <>();
100
100
101
101
int numRuns = 1000 ;
@@ -108,7 +108,7 @@ public void stub_200_only() {
108
108
}
109
109
110
110
@ Test
111
- public void stub_200s_one503_more200s () {
111
+ public void getObject_single500WithinMany200s_shouldRetrySuccessfully () {
112
112
List <CompletableFuture <ResponseBytes <GetObjectResponse >>> futures = new ArrayList <>();
113
113
114
114
int numRuns = 1000 ;
@@ -130,7 +130,7 @@ public void stub_200s_one503_more200s() {
130
130
}
131
131
132
132
@ Test
133
- public void stub_503_then_200_multipleTimes () {
133
+ public void getObject_concurrent503s_shouldRetrySuccessfully () {
134
134
List <CompletableFuture <ResponseBytes <GetObjectResponse >>> futures = new ArrayList <>();
135
135
136
136
int numRuns = 1000 ;
@@ -143,7 +143,7 @@ public void stub_503_then_200_multipleTimes() {
143
143
}
144
144
145
145
@ Test
146
- public void stub_503_only ( WireMockRuntimeInfo wm ) {
146
+ public void getObject_503Response_shouldNotReuseInitialRequestId ( ) {
147
147
String firstRequestId = UUID .randomUUID ().toString ();
148
148
String secondRequestId = UUID .randomUUID ().toString ();
149
149
@@ -186,7 +186,7 @@ public void stub_503_only(WireMockRuntimeInfo wm) {
186
186
}
187
187
188
188
@ Test
189
- public void multipleParts_all_200 () {
189
+ public void multipartDownload_200Response_shouldSucceed () {
190
190
int totalParts = 3 ;
191
191
int partSize = 1024 ;
192
192
@@ -237,7 +237,7 @@ public void multipleParts_all_200() {
237
237
}
238
238
239
239
@ Test
240
- public void multipleParts_503OnFirstPart_then_200s () {
240
+ public void multipartDownload_503OnFirstPart_shouldRetrySuccessfully () {
241
241
int totalParts = 3 ;
242
242
int partSize = 1024 ;
243
243
@@ -306,6 +306,43 @@ public void multipleParts_503OnFirstPart_then_200s() {
306
306
verify (1 , getRequestedFor (urlEqualTo (String .format ("/%s/%s?partNumber=3" , BUCKET , KEY ))));
307
307
}
308
308
309
+ @ Test
310
+ public void getObject_iOError_shouldRetrySuccessfully () {
311
+ String requestId = UUID .randomUUID ().toString ();
312
+
313
+ stubFor (any (anyUrl ())
314
+ .inScenario ("io-error" )
315
+ .whenScenarioStateIs (Scenario .STARTED )
316
+ .willReturn (aResponse ()
317
+ .withFault (Fault .CONNECTION_RESET_BY_PEER ))
318
+ .willSetStateTo ("retry" ));
319
+
320
+ stubFor (any (anyUrl ())
321
+ .inScenario ("io-error" )
322
+ .whenScenarioStateIs ("retry" )
323
+ .willReturn (aResponse ()
324
+ .withStatus (200 )
325
+ .withHeader ("x-amz-request-id" , requestId )
326
+ .withBody ("Hello World" )));
327
+
328
+ ResponseBytes <GetObjectResponse > response = multipartClient .getObject (GetObjectRequest .builder ()
329
+ .bucket (BUCKET )
330
+ .key (KEY )
331
+ .build (),
332
+ AsyncResponseTransformer .toBytes ()).join ();
333
+
334
+ assertArrayEquals ("Hello World" .getBytes (StandardCharsets .UTF_8 ), response .asByteArray ());
335
+
336
+ verify (2 , getRequestedFor (urlEqualTo ("/" + BUCKET + "/" + KEY + "?partNumber=1" )));
337
+
338
+ List <SdkHttpResponse > responses = capturingInterceptor .getResponses ();
339
+ String finalRequestId = responses .get (responses .size () - 1 )
340
+ .firstMatchingHeader ("x-amz-request-id" )
341
+ .orElse (null );
342
+
343
+ assertEquals (requestId , finalRequestId );
344
+ }
345
+
309
346
private CompletableFuture <ResponseBytes <GetObjectResponse >> mock200Response (S3AsyncClient s3Client , int runNumber ) {
310
347
String runId = runNumber + " success" ;
311
348
@@ -331,7 +368,7 @@ private CompletableFuture<ResponseBytes<GetObjectResponse>> mockRetryableErrorTh
331
368
.whenScenarioStateIs (Scenario .STARTED )
332
369
.willReturn (aResponse ()
333
370
.withHeader ("x-amz-request-id" , String .valueOf (UUID .randomUUID ()))
334
- .withStatus (503 ).withBody (ERROR_BODY )
371
+ .withStatus (500 ).withBody (ERROR_BODY )
335
372
)
336
373
.willSetStateTo ("SecondAttempt" + runId ));
337
374
0 commit comments