30
30
import com .github .tomakehurst .wiremock .junit5 .WireMockRuntimeInfo ;
31
31
import com .github .tomakehurst .wiremock .junit5 .WireMockTest ;
32
32
import com .github .tomakehurst .wiremock .stubbing .Scenario ;
33
+ import java .io .IOException ;
34
+ import java .io .UncheckedIOException ;
33
35
import java .net .URI ;
36
+ import java .nio .file .Files ;
37
+ import java .nio .file .Path ;
34
38
import java .time .Duration ;
35
39
import java .util .ArrayList ;
36
40
import java .util .List ;
37
41
import java .util .UUID ;
38
42
import java .util .concurrent .CompletableFuture ;
39
43
import java .util .concurrent .CompletionException ;
40
44
import java .util .concurrent .TimeUnit ;
45
+ import java .util .stream .Stream ;
41
46
import org .junit .jupiter .api .BeforeEach ;
42
- import org .junit .jupiter .api .Test ;
43
47
import org .junit .jupiter .api .Timeout ;
48
+ import org .junit .jupiter .params .ParameterizedTest ;
49
+ import org .junit .jupiter .params .provider .MethodSource ;
44
50
import software .amazon .awssdk .auth .credentials .AwsBasicCredentials ;
45
51
import software .amazon .awssdk .auth .credentials .StaticCredentialsProvider ;
46
- import software .amazon .awssdk .core .ResponseBytes ;
47
52
import software .amazon .awssdk .core .async .AsyncResponseTransformer ;
48
53
import software .amazon .awssdk .http .nio .netty .NettyNioAsyncHttpClient ;
49
54
import software .amazon .awssdk .regions .Region ;
54
59
@ WireMockTest
55
60
@ Timeout (value = 30 , unit = TimeUnit .SECONDS )
56
61
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 ;
60
65
private S3AsyncClient multipartClient ;
61
66
62
67
@ BeforeEach
@@ -72,13 +77,38 @@ public void setup(WireMockRuntimeInfo wm) {
72
77
.build ();
73
78
}
74
79
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 <>();
78
108
79
109
int numRuns = 1000 ;
80
110
for (int i = 0 ; i < numRuns ; i ++) {
81
- CompletableFuture <ResponseBytes < GetObjectResponse >> resp = mock200Response (multipartClient , i );
111
+ CompletableFuture <?> resp = mock200Response (multipartClient , i , transformerFactory );
82
112
futures .add (resp );
83
113
}
84
114
@@ -100,12 +130,12 @@ public void getObject_single500WithinMany200s_shouldNotRetryError() {
100
130
.withHeader ("x-amz-request-id" , String .valueOf (UUID .randomUUID ()))
101
131
.withBody ("Hello World" )));
102
132
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 ());
105
135
futures .add (requestWithRetryableError );
106
136
107
137
for (int i = 0 ; i < numRuns ; i ++) {
108
- CompletableFuture <ResponseBytes < GetObjectResponse >> resp = mock200Response (multipartClient , i + 1000 );
138
+ CompletableFuture <?> resp = mock200Response (multipartClient , i + 1000 , transformerFactory );
109
139
futures .add (resp );
110
140
}
111
141
@@ -119,19 +149,7 @@ public void getObject_single500WithinMany200s_shouldNotRetryError() {
119
149
verify (1 , getRequestedFor (urlEqualTo (String .format ("/%s/%s?partNumber=1" , BUCKET , errorKey ))));
120
150
}
121
151
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 ) {
135
153
String runId = runNumber + " success" ;
136
154
137
155
stubFor (any (anyUrl ())
@@ -142,8 +160,20 @@ private CompletableFuture<ResponseBytes<GetObjectResponse>> mock200Response(S3As
142
160
.withHeader ("x-amz-request-id" , String .valueOf (UUID .randomUUID ()))
143
161
.withBody ("Hello World" )));
144
162
145
- return s3Client .getObject (r -> r .bucket (BUCKET ).key ("key" )
163
+ return s3Client .getObject (r -> r .bucket (BUCKET ).key (KEY )
146
164
.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." );
148
178
}
149
179
}
0 commit comments