Skip to content

Commit 9cc4bdf

Browse files
committed
Async Exception checged to completableException
1 parent 72c74fa commit 9cc4bdf

File tree

6 files changed

+165
-14
lines changed

6 files changed

+165
-14
lines changed

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ private CompletableFuture<Region> regionCompletableFuture(String bucketName) {
8989
.bucket(bucketName)
9090
.build())
9191
.exceptionally(exception -> {
92-
if (isS3RedirectException(exception)) {
92+
if (isS3RedirectException(exception.getCause())) {
9393
getBucketRegionFromException(
94-
(S3Exception) exception).ifPresent(
94+
(S3Exception) exception.getCause()).ifPresent(
9595
stringBuilder::append);
9696
} else {
9797
CompletableFutureUtils.failedFuture(exception);

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClientRedirectTest.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.awssdk.services.s3.internal.crossregion;
1717

18+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
1819
import static org.mockito.ArgumentMatchers.any;
1920
import static org.mockito.Mockito.times;
2021
import static org.mockito.Mockito.verify;
@@ -31,6 +32,7 @@
3132
import software.amazon.awssdk.services.s3.model.ListBucketsResponse;
3233
import software.amazon.awssdk.services.s3.model.ListObjectsRequest;
3334
import software.amazon.awssdk.services.s3.model.ListObjectsResponse;
35+
import software.amazon.awssdk.services.s3.model.S3Exception;
3436
import software.amazon.awssdk.utils.CompletableFutureUtils;
3537

3638
public class S3CrossRegionAsyncClientRedirectTest extends S3DecoratorRedirectBaseTest {
@@ -85,11 +87,7 @@ protected void verifyNoBucketApiCall(int times, ArgumentCaptor<ListBucketsReques
8587

8688
@Override
8789
protected ListBucketsResponse noBucketCallToService() throws Throwable {
88-
try {
89-
return decoratedS3AsyncClient.listBuckets(ListBucketsRequest.builder().build()).join();
90-
} catch (CompletionException exception) {
91-
throw exception.getCause();
92-
}
90+
return decoratedS3AsyncClient.listBuckets(ListBucketsRequest.builder().build()).join();
9391
}
9492

9593
@Override
@@ -103,7 +101,7 @@ protected void stubApiWithNoBucketField() {
103101
@Override
104102
protected void stubHeadBucketRedirect() {
105103
when(mockDelegateAsyncClient.headBucket(any(HeadBucketRequest.class)))
106-
.thenReturn(CompletableFutureUtils.failedFuture(redirectException(301, CROSS_REGION, null, null)));
104+
.thenReturn(CompletableFutureUtils.failedFuture(new CompletionException(redirectException(301, CROSS_REGION, null, null))));
107105
}
108106

109107
@Override
@@ -125,4 +123,14 @@ protected void stubRedirectThenError() {
125123
protected void verifyHeadBucketServiceCall(int times) {
126124
verify(mockDelegateAsyncClient, times(times)).headBucket(any(HeadBucketRequest.class));
127125
}
126+
127+
@Override
128+
protected void verifyNoBucketCall() {
129+
assertThatExceptionOfType(CompletionException.class)
130+
.isThrownBy(
131+
() -> noBucketCallToService())
132+
133+
.withCauseInstanceOf(S3Exception.class)
134+
.withMessage("software.amazon.awssdk.services.s3.model.S3Exception: Redirect (Service: S3, Status Code: 301, Request ID: 1, Extended Request ID: A1)");
135+
}
128136
}

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionAsyncClientTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
import static software.amazon.awssdk.services.s3.internal.crossregion.S3DecoratorRedirectBaseTest.X_AMZ_BUCKET_REGION;
2121

2222
import java.net.URI;
23+
import java.util.Arrays;
24+
import java.util.List;
2325
import java.util.concurrent.CompletableFuture;
2426
import java.util.function.Consumer;
27+
import java.util.stream.Collectors;
2528
import java.util.stream.Stream;
2629
import org.junit.jupiter.api.BeforeEach;
2730
import org.junit.jupiter.api.Test;
@@ -37,9 +40,13 @@
3740
import software.amazon.awssdk.http.AbortableInputStream;
3841
import software.amazon.awssdk.http.HttpExecuteResponse;
3942
import software.amazon.awssdk.http.SdkHttpFullResponse;
43+
import software.amazon.awssdk.http.SdkHttpMethod;
44+
import software.amazon.awssdk.http.SdkHttpRequest;
4045
import software.amazon.awssdk.http.SdkHttpResponse;
46+
import software.amazon.awssdk.regions.Region;
4147
import software.amazon.awssdk.services.s3.S3AsyncClient;
4248
import software.amazon.awssdk.services.s3.S3AsyncClientBuilder;
49+
import software.amazon.awssdk.services.s3.S3Client;
4350
import software.amazon.awssdk.services.s3.endpoints.internal.DefaultS3EndpointProvider;
4451
import software.amazon.awssdk.services.s3.internal.crossregion.endpointprovider.BucketEndpointProvider;
4552
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
@@ -128,6 +135,45 @@ void crossRegionClient_createdWithWrapping_SuccessfullyIntercepts(Consumer<MockA
128135
assertThat(captureInterceptor.endpointProvider).isInstanceOf(endpointProviderType);
129136
}
130137

138+
@Test
139+
void crossRegionClient_CallsHeadObject_when_regionNameNotPresentInFallBackCall() {
140+
mockAsyncHttpClient.stubResponses(customHttpResponse(301, null ),
141+
customHttpResponse(301, CROSS_REGION ),
142+
successHttpResponse(), successHttpResponse());
143+
S3AsyncClient crossRegionClient =
144+
clientBuilder().endpointOverride(null).region(Region.US_WEST_2).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build();
145+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join();
146+
assertThat(captureInterceptor.endpointProvider).isInstanceOf(BucketEndpointProvider.class);
147+
148+
List<SdkHttpRequest> requests = mockAsyncHttpClient.getRequests();
149+
assertThat(requests).hasSize(3);
150+
151+
assertThat(requests.stream().map(req -> req.host().substring(10,req.host().length() - 14 )).collect(Collectors.toList()))
152+
.isEqualTo(Arrays.asList(Region.US_WEST_2.toString(),
153+
Region.US_WEST_2.toString(),
154+
CROSS_REGION));
155+
156+
assertThat(requests.stream().map(req -> req.method()).collect(Collectors.toList()))
157+
.isEqualTo(Arrays.asList(SdkHttpMethod.GET,
158+
SdkHttpMethod.HEAD,
159+
SdkHttpMethod.GET));
160+
161+
// Resetting the mock client to capture the new API request for second S3 Call.
162+
mockAsyncHttpClient.reset();
163+
mockAsyncHttpClient.stubResponses(successHttpResponse(), successHttpResponse());
164+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY), AsyncResponseTransformer.toBytes()).join();
165+
List<SdkHttpRequest> postCacheRequests = mockAsyncHttpClient.getRequests();
166+
167+
assertThat(postCacheRequests.stream()
168+
.map(req -> req.host().substring(10,req.host().length() - 14 ))
169+
.collect(Collectors.toList()))
170+
.isEqualTo(Arrays.asList(CROSS_REGION));
171+
assertThat(postCacheRequests.stream().map(req -> req.method()).collect(Collectors.toList()))
172+
.isEqualTo(Arrays.asList(SdkHttpMethod.GET));
173+
assertThat(captureInterceptor.endpointProvider).isInstanceOf(BucketEndpointProvider.class);
174+
175+
}
176+
131177
private S3AsyncClientBuilder clientBuilder() {
132178
return S3AsyncClient.builder()
133179
.httpClient(mockAsyncHttpClient)

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionSyncClientRedirectTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.awssdk.services.s3.internal.crossregion;
1717

18+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
1819
import static org.mockito.ArgumentMatchers.any;
1920
import static org.mockito.Mockito.times;
2021
import static org.mockito.Mockito.verify;
@@ -30,6 +31,7 @@
3031
import software.amazon.awssdk.services.s3.model.ListBucketsResponse;
3132
import software.amazon.awssdk.services.s3.model.ListObjectsRequest;
3233
import software.amazon.awssdk.services.s3.model.ListObjectsResponse;
34+
import software.amazon.awssdk.services.s3.model.S3Exception;
3335

3436
public class S3CrossRegionSyncClientRedirectTest extends S3DecoratorRedirectBaseTest {
3537

@@ -41,6 +43,16 @@ public void setup() {
4143
mockDelegateClient = Mockito.mock(S3Client.class);
4244
decoratedS3Client = new S3CrossRegionSyncClient(mockDelegateClient);
4345
}
46+
47+
@Override
48+
protected void verifyNoBucketCall() {
49+
assertThatExceptionOfType(S3Exception.class)
50+
.isThrownBy(
51+
() -> noBucketCallToService())
52+
.withMessage("Redirect (Service: S3, Status Code: 301, Request ID: 1, "
53+
+ "Extended Request ID: A1)");
54+
}
55+
4456
@Override
4557
protected void verifyNoBucketApiCall(int times, ArgumentCaptor<ListBucketsRequest> requestArgumentCaptor) {
4658
verify(mockDelegateClient, times(times)).listBuckets(requestArgumentCaptor.capture());

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3CrossRegionSyncClientTest.java

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515

1616
package software.amazon.awssdk.services.s3.internal.crossregion;
1717

18+
import static org.assertj.core.api.Assertions.as;
1819
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.mockito.Mockito.verify;
1921
import static software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionAsyncClientTest.customHttpResponse;
2022
import static software.amazon.awssdk.services.s3.internal.crossregion.S3CrossRegionAsyncClientTest.successHttpResponse;
2123
import static software.amazon.awssdk.services.s3.internal.crossregion.S3DecoratorRedirectBaseTest.CROSS_REGION;
@@ -27,20 +29,26 @@
2729
import java.util.List;
2830
import java.util.function.Consumer;
2931
import java.util.function.Supplier;
32+
import java.util.stream.Collectors;
3033
import java.util.stream.Stream;
3134
import org.junit.jupiter.api.BeforeEach;
3235
import org.junit.jupiter.api.Test;
3336
import org.junit.jupiter.params.ParameterizedTest;
3437
import org.junit.jupiter.params.provider.Arguments;
3538
import org.junit.jupiter.params.provider.MethodSource;
39+
import org.mockito.ArgumentCaptor;
3640
import software.amazon.awssdk.core.interceptor.Context;
3741
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
3842
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
3943
import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
4044
import software.amazon.awssdk.endpoints.EndpointProvider;
4145
import software.amazon.awssdk.http.AbortableInputStream;
46+
import software.amazon.awssdk.http.HttpExecuteRequest;
4247
import software.amazon.awssdk.http.HttpExecuteResponse;
48+
import software.amazon.awssdk.http.SdkHttpMethod;
49+
import software.amazon.awssdk.http.SdkHttpRequest;
4350
import software.amazon.awssdk.http.SdkHttpResponse;
51+
import software.amazon.awssdk.regions.Region;
4452
import software.amazon.awssdk.services.s3.S3Client;
4553
import software.amazon.awssdk.services.s3.S3ClientBuilder;
4654
import software.amazon.awssdk.services.s3.endpoints.S3EndpointProvider;
@@ -129,10 +137,89 @@ void crossRegionClient_createdWithWrapping_SuccessfullyIntercepts(Consumer<MockS
129137
assertThat(captureInterceptor.endpointProvider).isInstanceOf(endpointProviderType);
130138
}
131139

140+
141+
@Test
142+
void crossRegionClient_CallsHeadObject_when_regionNameNotPresentInFallBackCall() {
143+
mockSyncHttpClient.stubResponses(customHttpResponse(301, null ),
144+
customHttpResponse(301, CROSS_REGION ),
145+
successHttpResponse(), successHttpResponse());
146+
S3Client crossRegionClient =
147+
clientBuilder().endpointOverride(null).region(Region.US_WEST_2).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build();
148+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY));
149+
assertThat(captureInterceptor.endpointProvider).isInstanceOf(BucketEndpointProvider.class);
150+
151+
List<SdkHttpRequest> requests = mockSyncHttpClient.getRequests();
152+
assertThat(requests).hasSize(3);
153+
154+
assertThat(requests.stream().map(req -> req.host().substring(10,req.host().length() - 14 )).collect(Collectors.toList()))
155+
.isEqualTo(Arrays.asList(Region.US_WEST_2.toString(),
156+
Region.US_WEST_2.toString(),
157+
CROSS_REGION));
158+
159+
assertThat(requests.stream().map(req -> req.method()).collect(Collectors.toList()))
160+
.isEqualTo(Arrays.asList(SdkHttpMethod.GET,
161+
SdkHttpMethod.HEAD,
162+
SdkHttpMethod.GET));
163+
164+
// Resetting the mock client to capture the new API request for second S3 Call.
165+
mockSyncHttpClient.reset();
166+
mockSyncHttpClient.stubResponses(successHttpResponse(), successHttpResponse());
167+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY));
168+
List<SdkHttpRequest> postCacheRequests = mockSyncHttpClient.getRequests();
169+
170+
assertThat(postCacheRequests.stream()
171+
.map(req -> req.host().substring(10,req.host().length() - 14 ))
172+
.collect(Collectors.toList()))
173+
.isEqualTo(Arrays.asList(CROSS_REGION));
174+
assertThat(postCacheRequests.stream().map(req -> req.method()).collect(Collectors.toList()))
175+
.isEqualTo(Arrays.asList(SdkHttpMethod.GET));
176+
assertThat(captureInterceptor.endpointProvider).isInstanceOf(BucketEndpointProvider.class);
177+
178+
}
179+
180+
181+
@Test
182+
void crossRegionClient_CallsHeadObjectErrors_shouldTeminateTheAPI() {
183+
mockSyncHttpClient.stubResponses(customHttpResponse(301, null ),
184+
customHttpResponse(301, CROSS_REGION ),
185+
successHttpResponse(), successHttpResponse());
186+
S3Client crossRegionClient =
187+
clientBuilder().endpointOverride(null).region(Region.US_WEST_2).serviceConfiguration(c -> c.crossRegionAccessEnabled(true)).build();
188+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY));
189+
assertThat(captureInterceptor.endpointProvider).isInstanceOf(BucketEndpointProvider.class);
190+
191+
List<SdkHttpRequest> requests = mockSyncHttpClient.getRequests();
192+
assertThat(requests).hasSize(3);
193+
194+
assertThat(requests.stream().map(req -> req.host().substring(10,req.host().length() - 14 )).collect(Collectors.toList()))
195+
.isEqualTo(Arrays.asList(Region.US_WEST_2.toString(),
196+
Region.US_WEST_2.toString(),
197+
CROSS_REGION));
198+
199+
assertThat(requests.stream().map(req -> req.method()).collect(Collectors.toList()))
200+
.isEqualTo(Arrays.asList(SdkHttpMethod.GET,
201+
SdkHttpMethod.HEAD,
202+
SdkHttpMethod.GET));
203+
204+
// Resetting the mock client to capture the new API request for second S3 Call.
205+
mockSyncHttpClient.reset();
206+
mockSyncHttpClient.stubResponses(successHttpResponse(), successHttpResponse());
207+
crossRegionClient.getObject(r -> r.bucket(BUCKET).key(KEY));
208+
List<SdkHttpRequest> postCacheRequests = mockSyncHttpClient.getRequests();
209+
210+
assertThat(postCacheRequests.stream()
211+
.map(req -> req.host().substring(10,req.host().length() - 14 ))
212+
.collect(Collectors.toList()))
213+
.isEqualTo(Arrays.asList(CROSS_REGION));
214+
assertThat(postCacheRequests.stream().map(req -> req.method()).collect(Collectors.toList()))
215+
.isEqualTo(Arrays.asList(SdkHttpMethod.GET));
216+
assertThat(captureInterceptor.endpointProvider).isInstanceOf(BucketEndpointProvider.class);
217+
218+
}
219+
132220
private S3ClientBuilder clientBuilder() {
133221
return S3Client.builder()
134222
.httpClient(mockSyncHttpClient)
135-
.endpointOverride(URI.create("http://localhost"))
136223
.overrideConfiguration(c -> c.addExecutionInterceptor(captureInterceptor));
137224
}
138225

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crossregion/S3DecoratorRedirectBaseTest.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,17 +146,15 @@ void requestsAreNotOverridden_when_NoBucketInRequest() throws Throwable {
146146
stubServiceClientConfiguration();
147147
stubApiWithNoBucketField();
148148
stubHeadBucketRedirect();
149-
assertThatExceptionOfType(S3Exception.class)
150-
.isThrownBy(
151-
() -> noBucketCallToService())
152-
.withMessage("Redirect (Service: S3, Status Code: 301, Request ID: 1, "
153-
+ "Extended Request ID: A1)");
149+
verifyNoBucketCall();
154150
ArgumentCaptor<ListBucketsRequest> requestArgumentCaptor = ArgumentCaptor.forClass(ListBucketsRequest.class);
155151
verifyHeadBucketServiceCall(0);
156152
verifyNoBucketApiCall(1, requestArgumentCaptor);
157153
assertThat(requestArgumentCaptor.getAllValues().get(0).overrideConfiguration()).isNotPresent();
158154
}
159155

156+
protected abstract void verifyNoBucketCall();
157+
160158
protected abstract void verifyNoBucketApiCall(int i, ArgumentCaptor<ListBucketsRequest> requestArgumentCaptor);
161159

162160
protected abstract ListBucketsResponse noBucketCallToService() throws Throwable;

0 commit comments

Comments
 (0)