26
26
import static software .amazon .awssdk .services .s3 .internal .crossregion .S3CrossRegionRedirectTestBase .X_AMZ_BUCKET_REGION ;
27
27
28
28
import java .net .URI ;
29
+ import java .time .Duration ;
29
30
import java .util .Arrays ;
30
31
import java .util .Collections ;
31
32
import java .util .List ;
32
33
import java .util .concurrent .CompletableFuture ;
33
34
import java .util .concurrent .CompletionException ;
35
+ import java .util .concurrent .ExecutionException ;
34
36
import java .util .function .Consumer ;
35
37
import java .util .stream .Collectors ;
36
38
import java .util .stream .Stream ;
80
82
81
83
class S3CrossRegionAsyncClientTest {
82
84
85
+ private static final String ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION_ERROR_CODE = "IllegalLocationConstraintException" ;
83
86
private static final String ERROR_RESPONSE_FORMAT = "<Error>\\ n\\ t<Code>%s</Code>\\ n</Error>" ;
84
87
private static final String BUCKET = "bucket" ;
85
88
private static final String KEY = "key" ;
@@ -97,26 +100,38 @@ void setUp() {
97
100
98
101
private static Stream <Arguments > stubSuccessfulRedirectResponses () {
99
102
Consumer <MockAsyncHttpClient > redirectStubConsumer = mockAsyncHttpClient ->
100
- mockAsyncHttpClient .stubResponses (customHttpResponseWithUnknownErrorCode (301 , CROSS_REGION .id ()), successHttpResponse ());
103
+ mockAsyncHttpClient .stubResponses (customHttpResponseWithUnknownErrorCode (301 , CROSS_REGION .id ()),
104
+ successHttpResponse ());
101
105
102
106
Consumer <MockAsyncHttpClient > successStubConsumer = mockAsyncHttpClient ->
103
107
mockAsyncHttpClient .stubResponses (successHttpResponse (), successHttpResponse ());
104
108
105
109
Consumer <MockAsyncHttpClient > tempRedirectStubConsumer = mockAsyncHttpClient ->
106
- mockAsyncHttpClient .stubResponses (customHttpResponseWithUnknownErrorCode (307 , CROSS_REGION .id ()), successHttpResponse ());
110
+ mockAsyncHttpClient .stubResponses (customHttpResponseWithUnknownErrorCode (307 , CROSS_REGION .id ()),
111
+ successHttpResponse ());
112
+
113
+ Consumer <MockAsyncHttpClient > locationConstraintExceptionConsumer = mockAsyncHttpClient ->
114
+ mockAsyncHttpClient .stubResponses (customHttpResponse (400 ,
115
+ ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION_ERROR_CODE ,
116
+ CROSS_REGION .id ()), successHttpResponse ());
117
+
107
118
108
119
return Stream .of (
109
120
Arguments .of (redirectStubConsumer , BucketEndpointProvider .class , "Redirect Error with region in x-amz-bucket-header" ),
110
- Arguments .of (successStubConsumer , BucketEndpointProvider .class , "Success response" ),
111
- Arguments .of (tempRedirectStubConsumer , BucketEndpointProvider .class , "Permanent redirect Error with region in x-amz-bucket-header" )
121
+ Arguments .of (successStubConsumer , BucketEndpointProvider .class , "Success response" ),
122
+ Arguments .of (tempRedirectStubConsumer , BucketEndpointProvider .class ,
123
+ "Permanent redirect Error with region in x-amz-bucket-header" ),
124
+ Arguments .of (locationConstraintExceptionConsumer , BucketEndpointProvider .class ,
125
+ "Redirect error: 400 IllegalLocationConstraintException with region in x-amz-bucket-header" )
112
126
);
113
127
}
114
128
115
129
116
130
private static Stream <Arguments > stubFailureResponses () {
117
131
118
132
List <SdkHttpMethod > noregionOnHeadBucketHttpMethodListMethodList = Arrays .asList (SdkHttpMethod .GET , SdkHttpMethod .HEAD );
119
- List <SdkHttpMethod > regionOnHeadBucketHttpMethodList = Arrays .asList (SdkHttpMethod .GET , SdkHttpMethod .HEAD , SdkHttpMethod .GET );
133
+ List <SdkHttpMethod > regionOnHeadBucketHttpMethodList = Arrays .asList (SdkHttpMethod .GET , SdkHttpMethod .HEAD ,
134
+ SdkHttpMethod .GET );
120
135
List <String > noRegionOnHeadBucket = Arrays .asList (OVERRIDE_CONFIGURED_REGION .toString (),
121
136
OVERRIDE_CONFIGURED_REGION .toString ());
122
137
@@ -129,7 +144,8 @@ private static Stream<Arguments> stubFailureResponses() {
129
144
customHttpResponseWithUnknownErrorCode (301 , null ),
130
145
successHttpResponse (), successHttpResponse ());
131
146
return Stream .of (
132
- Arguments .of (redirectFailedWithNoRegionFailure , 301 , 2 , noRegionOnHeadBucket , noregionOnHeadBucketHttpMethodListMethodList )
147
+ Arguments .of (redirectFailedWithNoRegionFailure , 301 , 2 , noRegionOnHeadBucket ,
148
+ noregionOnHeadBucketHttpMethodListMethodList )
133
149
);
134
150
}
135
151
@@ -159,8 +175,8 @@ public static HttpExecuteResponse customHttpResponse(int statusCode, String erro
159
175
@ ParameterizedTest (name = "{index} - {2}." )
160
176
@ MethodSource ("stubSuccessfulRedirectResponses" )
161
177
void given_CrossRegionClientWithNoOverrideConfig_when_StandardOperationIsPerformed_then_SuccessfullyIntercepts (Consumer <MockAsyncHttpClient > stubConsumer ,
162
- Class <?> endpointProviderType ,
163
- String testCase ) {
178
+ Class <?> endpointProviderType ,
179
+ String testCase ) {
164
180
stubConsumer .accept (mockAsyncHttpClient );
165
181
S3AsyncClient crossRegionClient = new S3CrossRegionAsyncClient (s3Client );
166
182
crossRegionClient .getObject (r -> r .bucket (BUCKET ).key (KEY ), AsyncResponseTransformer .toBytes ()).join ();
@@ -170,8 +186,9 @@ void given_CrossRegionClientWithNoOverrideConfig_when_StandardOperationIsPerform
170
186
@ ParameterizedTest (name = "{index} - {2}." )
171
187
@ MethodSource ("stubSuccessfulRedirectResponses" )
172
188
void given_CrossRegionClientWithExistingOverrideConfig_when_StandardOperationIsPerformed_then_SuccessfullyIntercepts (Consumer <MockAsyncHttpClient > stubConsumer ,
173
- Class <?> endpointProviderType ,
174
- String testCase ) {
189
+ Class <
190
+ ?> endpointProviderType ,
191
+ String testCase ) {
175
192
stubConsumer .accept (mockAsyncHttpClient );
176
193
S3AsyncClient crossRegionClient = new S3CrossRegionAsyncClient (s3Client );
177
194
GetObjectRequest request = GetObjectRequest .builder ()
@@ -187,8 +204,8 @@ void given_CrossRegionClientWithExistingOverrideConfig_when_StandardOperationIsP
187
204
@ ParameterizedTest (name = "{index} - {2}." )
188
205
@ MethodSource ("stubSuccessfulRedirectResponses" )
189
206
void given_CrossRegionClient_when_PaginatedOperationIsPerformed_then_DoesNotIntercept (Consumer <MockAsyncHttpClient > stubConsumer ,
190
- Class <?> endpointProviderType ,
191
- String testCase ) throws Exception {
207
+ Class <?> endpointProviderType ,
208
+ String testCase ) throws Exception {
192
209
stubConsumer .accept (mockAsyncHttpClient );
193
210
S3AsyncClient crossRegionClient = new S3CrossRegionAsyncClient (s3Client );
194
211
ListObjectsV2Publisher publisher =
@@ -201,8 +218,8 @@ void given_CrossRegionClient_when_PaginatedOperationIsPerformed_then_DoesNotInte
201
218
@ ParameterizedTest (name = "{index} - {2}." )
202
219
@ MethodSource ("stubSuccessfulRedirectResponses" )
203
220
void given_CrossRegionClientCreatedWithWrapping_when_OperationIsPerformed_then_SuccessfullyIntercepts (Consumer <MockAsyncHttpClient > stubConsumer ,
204
- Class <?> endpointProviderType ,
205
- String testCase ) {
221
+ Class <?> endpointProviderType ,
222
+ String testCase ) {
206
223
stubConsumer .accept (mockAsyncHttpClient );
207
224
S3AsyncClient crossRegionClient = clientBuilder ().crossRegionAccessEnabled (true ).build ();
208
225
crossRegionClient .getObject (r -> r .bucket (BUCKET ).key (KEY ), AsyncResponseTransformer .toBytes ()).join ();
@@ -264,7 +281,7 @@ void given_CrossRegionClient_when_CallsHeadObjectErrors_then_ShouldTerminateTheA
264
281
265
282
String errorMessage = String .format ("software.amazon.awssdk.services.s3.model.S3Exception: "
266
283
+ "(Service: S3, Status Code: %d, Request ID: null)"
267
- , statusCode );
284
+ , statusCode );
268
285
assertThatExceptionOfType (CompletionException .class )
269
286
.isThrownBy (() -> crossRegionClient .getObject (r -> r .bucket (BUCKET ).key (KEY ), AsyncResponseTransformer .toBytes ()).join ())
270
287
.withMessageContaining (errorMessage );
@@ -395,7 +412,6 @@ void given_CrossRegionClient_when_StandardOperation_then_ContainsUserAgent() {
395
412
}
396
413
397
414
398
-
399
415
@ ParameterizedTest (name = "{index} - {2}." )
400
416
@ MethodSource ("stubSuccessfulRedirectResponses" )
401
417
void given_CrossRegionAccessEnabled_when_SuccessfulResponse_then_EndpointIsUpdated (Consumer <MockAsyncHttpClient > stubConsumer ,
@@ -416,7 +432,7 @@ void given_SimpleClient_when_StandardOperation_then_DoesNotContainCrossRegionUse
416
432
}
417
433
418
434
@ Test
419
- void given_US_EAST_1_Client_resolvesToGlobalEndpoints_when_crossRegion_is_False (){
435
+ void given_US_EAST_1_Client_resolvesToGlobalEndpoints_when_crossRegion_is_False () {
420
436
mockAsyncHttpClient .stubResponses (successHttpResponse ());
421
437
S3AsyncClient s3Client = clientBuilder ().region (Region .US_EAST_1 ).build ();
422
438
s3Client .getObject (r -> r .bucket (BUCKET ).key (KEY ), AsyncResponseTransformer .toBytes ()).join ();
@@ -425,7 +441,7 @@ void given_US_EAST_1_Client_resolvesToGlobalEndpoints_when_crossRegion_is_False(
425
441
}
426
442
427
443
@ Test
428
- void given_US_EAST_1_Client_resolveToRegionalEndpoints_when_crossRegion_is_True (){
444
+ void given_US_EAST_1_Client_resolveToRegionalEndpoints_when_crossRegion_is_True () {
429
445
mockAsyncHttpClient .stubResponses (successHttpResponse ());
430
446
S3AsyncClient s3Client = clientBuilder ().crossRegionAccessEnabled (true ).region (Region .US_EAST_1 ).build ();
431
447
s3Client .getObject (r -> r .bucket (BUCKET ).key (KEY ), AsyncResponseTransformer .toBytes ()).join ();
@@ -478,6 +494,30 @@ void given_globalRegion_Client_Updates_region_to_useast1_and_useGlobalEndpointFl
478
494
479
495
}
480
496
497
+ @ Test
498
+ void given_CrossRegionClient_when400Error_WithoutIllegalLocationConstraint_DoesNotRedirect () {
499
+ String region = Region .AWS_GLOBAL .id ();
500
+ mockAsyncHttpClient .stubResponses (customHttpResponse (400 , "UnknownError" , null ));
501
+ S3EndpointProvider mockEndpointProvider = Mockito .mock (S3EndpointProvider .class );
502
+ when (mockEndpointProvider .resolveEndpoint (ArgumentMatchers .any (S3EndpointParams .class )))
503
+ .thenReturn (CompletableFuture .completedFuture (Endpoint .builder ().url (URI .create ("https://bucket.s3.amazonaws.com" )).build ()));
504
+
505
+ S3AsyncClient s3Client = clientBuilder ().crossRegionAccessEnabled (true )
506
+ .region (Region .of (region ))
507
+ .endpointProvider (mockEndpointProvider ).build ();
508
+
509
+ CompletableFuture <ResponseBytes <GetObjectResponse >> f =
510
+ s3Client .getObject (r -> r .bucket (BUCKET ).key (KEY ), AsyncResponseTransformer .toBytes ());
511
+
512
+ assertThat (f ).failsWithin (Duration .ofSeconds (5 ))
513
+ .withThrowableOfType (ExecutionException .class )
514
+ .withCauseInstanceOf (S3Exception .class )
515
+ .withMessageContaining ("Status Code: 400" );
516
+
517
+ assertThat (mockAsyncHttpClient .getRequests ()).hasSize (1 );
518
+ }
519
+
520
+
481
521
private S3AsyncClientBuilder clientBuilder () {
482
522
return S3AsyncClient .builder ()
483
523
.httpClient (mockAsyncHttpClient )
0 commit comments