16
16
17
17
import static org .assertj .core .api .Assertions .assertThat ;
18
18
import static org .junit .Assert .assertEquals ;
19
- import static software .amazon .awssdk .testutils .service .S3BucketUtils .temporaryBucketName ;
20
19
import static software .amazon .awssdk .utils .FunctionalUtils .invokeSafely ;
21
20
import static software .amazon .awssdk .utils .StringUtils .isEmpty ;
22
21
27
26
import java .util .Collections ;
28
27
import java .util .List ;
29
28
import java .util .Optional ;
30
- import org .junit .AfterClass ;
31
29
import org .junit .BeforeClass ;
32
30
import org .junit .Test ;
33
31
import software .amazon .awssdk .auth .signer .S3SignerExecutionAttribute ;
38
36
import software .amazon .awssdk .core .interceptor .Context ;
39
37
import software .amazon .awssdk .core .interceptor .ExecutionAttributes ;
40
38
import software .amazon .awssdk .core .interceptor .ExecutionInterceptor ;
39
+ import software .amazon .awssdk .core .retry .backoff .FixedDelayBackoffStrategy ;
41
40
import software .amazon .awssdk .core .sync .RequestBody ;
41
+ import software .amazon .awssdk .core .waiters .Waiter ;
42
+ import software .amazon .awssdk .core .waiters .WaiterAcceptor ;
42
43
import software .amazon .awssdk .http .HttpExecuteRequest ;
43
44
import software .amazon .awssdk .http .HttpExecuteResponse ;
44
45
import software .amazon .awssdk .http .SdkHttpMethod ;
48
49
import software .amazon .awssdk .services .s3 .S3Client ;
49
50
import software .amazon .awssdk .services .s3 .S3Configuration ;
50
51
import software .amazon .awssdk .services .s3 .model .Bucket ;
52
+ import software .amazon .awssdk .services .s3 .model .BucketAlreadyOwnedByYouException ;
51
53
import software .amazon .awssdk .services .s3 .model .NoSuchKeyException ;
52
54
import software .amazon .awssdk .services .s3 .model .PutObjectRequest ;
53
55
import software .amazon .awssdk .services .s3 .model .UploadPartRequest ;
54
56
import software .amazon .awssdk .services .s3 .presigner .S3Presigner ;
55
57
import software .amazon .awssdk .services .s3 .presigner .model .PresignedGetObjectRequest ;
56
- import software .amazon .awssdk .services .s3control .model .AsyncOperation ;
58
+ import software .amazon .awssdk .services .s3control .model .BucketAlreadyExistsException ;
57
59
import software .amazon .awssdk .services .s3control .model .CreateMultiRegionAccessPointInput ;
58
60
import software .amazon .awssdk .services .s3control .model .CreateMultiRegionAccessPointResponse ;
59
- import software .amazon .awssdk .services .s3control .model .DeleteMultiRegionAccessPointResponse ;
60
- import software .amazon .awssdk .services .s3control .model .DescribeMultiRegionAccessPointOperationResponse ;
61
61
import software .amazon .awssdk .services .s3control .model .GetMultiRegionAccessPointResponse ;
62
62
import software .amazon .awssdk .services .s3control .model .ListMultiRegionAccessPointsResponse ;
63
- import software .amazon .awssdk .services .s3control .model .MultiRegionAccessPointReport ;
64
63
import software .amazon .awssdk .services .s3control .model .MultiRegionAccessPointStatus ;
64
+ import software .amazon .awssdk .services .sts .StsClient ;
65
65
import software .amazon .awssdk .utils .IoUtils ;
66
+ import software .amazon .awssdk .utils .Logger ;
66
67
import software .amazon .awssdk .utils .StringInputStream ;
67
68
68
69
public class S3MrapIntegrationTest extends S3ControlIntegrationTestBase {
70
+ private static final Logger log = Logger .loggerFor (S3MrapIntegrationTest .class );
69
71
70
72
private static final String CHUNKED_PAYLOAD_SIGNING = "STREAMING-AWS4-ECDSA-P256-SHA256-PAYLOAD" ;
71
73
private static final String UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD" ;
72
74
73
75
private static final Region REGION = Region .US_WEST_2 ;
74
- private static final String BUCKET = temporaryBucketName ( S3MrapIntegrationTest . class ) ;
75
- private static final String MRAP_NAME = "javaintegtest" + System . currentTimeMillis () ;
76
+ private static String bucket ;
77
+ private static String mrapName ;
76
78
private static final String KEY = "aws-java-sdk-small-test-object" ;
77
79
private static final String CONTENT = "A short string for a small test object" ;
78
80
79
- private static final int RETRY_TIMES = 20 ;
80
- private static final int RETRY_DELAY_IN_MS = 15 * 1000 ;
81
+ private static final int RETRY_TIMES = 10 ;
82
+ private static final int RETRY_DELAY_IN_SECONDS = 30 ;
81
83
82
84
private static S3ControlClient s3control ;
83
85
private static CaptureRequestInterceptor captureInterceptor ;
84
86
private static String mrapAlias ;
87
+ private static StsClient stsClient ;
88
+ private static S3Client s3Client ;
85
89
86
90
@ BeforeClass
87
- public static void setupFixture () throws Exception {
91
+ public static void setupFixture () {
88
92
captureInterceptor = new CaptureRequestInterceptor ();
89
- createBucket (BUCKET );
90
93
91
94
s3control = S3ControlClient .builder ()
92
95
.region (REGION )
93
96
.credentialsProvider (CREDENTIALS_PROVIDER_CHAIN )
94
97
.build ();
95
98
96
- String resourceTokenArn = createMrap (MRAP_NAME );
97
- waitForResourceCreation (resourceTokenArn );
99
+ s3Client = S3Client .builder ()
100
+ .region (REGION )
101
+ .credentialsProvider (CREDENTIALS_PROVIDER_CHAIN )
102
+ .build ();
103
+
104
+ stsClient = StsClient .builder ()
105
+ .credentialsProvider (CREDENTIALS_PROVIDER_CHAIN )
106
+ .region (REGION )
107
+ .build ();
108
+ String accountId = getAccountId ();
109
+ bucket = "do-not-delete-s3mraptest-" + accountId ;
110
+ mrapName = "javaintegtest" + accountId ;
111
+ log .info (() -> "bucket " + bucket );
112
+ createBucketIfNotExist (bucket );
113
+ createMrapIfNotExist (mrapName );
114
+
98
115
mrapAlias = getMrapAliasAndVerify ();
99
116
}
100
117
101
- @ AfterClass
102
- public static void tearDown () throws Exception {
103
- String resourceTokenArn = deleteMrap (MRAP_NAME );
104
- waitForResourceDeletion (resourceTokenArn );
105
- deleteBucketAndAllContents (BUCKET );
118
+ private static void createBucketIfNotExist (String bucket ) {
119
+ try {
120
+ s3Client .createBucket (b -> b .bucket (bucket ));
121
+ s3Client .waiter ().waitUntilBucketExists (b -> b .bucket (bucket ));
122
+ } catch (BucketAlreadyOwnedByYouException | BucketAlreadyExistsException e ) {
123
+ // ignore
124
+ }
125
+ }
126
+
127
+ private static String getAccountId () {
128
+ return stsClient .getCallerIdentity ().account ();
106
129
}
107
130
108
131
public static String getMrapAliasAndVerify () {
109
- GetMultiRegionAccessPointResponse mrap = s3control .getMultiRegionAccessPoint (r -> r .accountId (accountId ).name (MRAP_NAME ));
132
+ GetMultiRegionAccessPointResponse mrap = s3control .getMultiRegionAccessPoint (r -> r .accountId (accountId ).name (mrapName ));
110
133
assertThat (mrap .accessPoint ()).isNotNull ();
111
- assertThat (mrap .accessPoint ().name ()).isEqualTo (MRAP_NAME );
112
- System . out . println ( "Alias: " + mrap .accessPoint ().alias ());
134
+ assertThat (mrap .accessPoint ().name ()).isEqualTo (mrapName );
135
+ log . info (() -> "Alias: " + mrap .accessPoint ().alias ());
113
136
return mrap .accessPoint ().alias ();
114
137
}
115
138
@@ -136,7 +159,7 @@ public void signingWorkflow(List<ExecutionInterceptor> interceptors, String payl
136
159
137
160
private void listAndVerify (S3Client s3 ) {
138
161
List <Bucket > buckets = s3 .listBuckets ().buckets ();
139
- assertThat (buckets .stream ().map (Bucket ::name )).contains (BUCKET );
162
+ assertThat (buckets .stream ().map (Bucket ::name )).contains (bucket );
140
163
verifySigv4SignedRequest (captureInterceptor .request ());
141
164
}
142
165
@@ -224,96 +247,36 @@ private S3Presigner s3Presigner() {
224
247
.build ();
225
248
}
226
249
227
- private static String createMrap (String mrapName ) {
250
+ private static void createMrapIfNotExist (String mrapName ) {
228
251
software .amazon .awssdk .services .s3control .model .Region mrapRegion =
229
- software .amazon .awssdk .services .s3control .model .Region .builder ().bucket (BUCKET ).build ();
230
-
231
- CreateMultiRegionAccessPointInput details = CreateMultiRegionAccessPointInput .builder ()
232
- .name (mrapName )
233
- .regions (mrapRegion )
234
- .build ();
235
- System .out .println ("Creating MRAP: " + mrapName );
236
- CreateMultiRegionAccessPointResponse response = s3control .createMultiRegionAccessPoint (r -> r .accountId (accountId )
237
- .details (details ));
238
- return response .requestTokenARN ();
239
- }
240
-
241
- private static String deleteMrap (String mrapName ) {
242
- System .out .println ("Deleting MRAP: " + mrapName + " with alias " + mrapAlias );
243
- DeleteMultiRegionAccessPointResponse response =
244
- s3control .deleteMultiRegionAccessPoint (r -> r .accountId (accountId ).details (d -> d .name (mrapName )));
245
-
246
- return response .requestTokenARN ();
247
- }
248
-
249
- private static void waitForResourceCreation (String resourceTokenArn ) throws InterruptedException , IllegalStateException {
250
- int retryCounter = 0 ;
251
- MultiRegionAccessPointStatus status = null ;
252
-
253
- System .out .println ("Polling status every " + RETRY_DELAY_IN_MS / 1000 + " s." );
254
-
255
- while (retryCounter ++ < RETRY_TIMES && !MultiRegionAccessPointStatus .READY .equals (status )) {
256
- Thread .sleep (RETRY_DELAY_IN_MS );
257
-
258
- System .out .println ("Async operation request status: " + getRequestStatus (resourceTokenArn ));
259
-
260
- Optional <MultiRegionAccessPointReport > testReport = getMrapReport (MRAP_NAME );
261
- if (testReport .isPresent ()) {
262
- status = testReport .get ().status ();
263
- }
264
- System .out .println ("MRAP status: " + status );
252
+ software .amazon .awssdk .services .s3control .model .Region .builder ().bucket (bucket ).build ();
253
+
254
+
255
+ if (s3control .listMultiRegionAccessPoints (r -> r .accountId (accountId ))
256
+ .accessPoints ().stream ().noneMatch (a -> a .name ().equals (S3MrapIntegrationTest .mrapName ))) {
257
+ CreateMultiRegionAccessPointInput details = CreateMultiRegionAccessPointInput .builder ()
258
+ .name (mrapName )
259
+ .regions (mrapRegion )
260
+ .build ();
261
+ log .info (() -> "Creating MRAP: " + mrapName );
262
+ CreateMultiRegionAccessPointResponse response = s3control .createMultiRegionAccessPoint (r -> r .accountId (accountId )
263
+ .details (details ));
264
+ waitForResourceCreation (mrapName );
265
265
}
266
-
267
- if (!MultiRegionAccessPointStatus .READY .equals (status )) {
268
- throw new IllegalStateException ("MRAP isn't in ready state, aborting" );
269
- }
270
- System .out .println ("Created MRAP in " + retryCounter * RETRY_DELAY_IN_MS / 1000 + " s." );
271
- }
272
-
273
- private static void waitForResourceDeletion (String resourceTokenArn ) throws InterruptedException , IllegalStateException {
274
- int retryCounter = 0 ;
275
- boolean deleted = false ;
276
-
277
- System .out .println ("Polling status every " + RETRY_DELAY_IN_MS / 1000 + " s." );
278
-
279
- while (retryCounter ++ < RETRY_TIMES && !deleted ) {
280
- Thread .sleep (RETRY_DELAY_IN_MS );
281
-
282
- System .out .println ("Async operation request status: " + getRequestStatus (resourceTokenArn ));
283
-
284
- Optional <MultiRegionAccessPointReport > testReport = getMrapReport (MRAP_NAME );
285
- MultiRegionAccessPointStatus status = null ;
286
- if (testReport .isPresent ()) {
287
- status = testReport .get ().status ();
288
- } else {
289
- deleted = true ;
290
- }
291
- System .out .println ("MRAP status: " + status );
292
- }
293
-
294
- if (!deleted ) {
295
- throw new IllegalStateException ("Something went wrong with deleting MRAP " + MRAP_NAME );
296
- }
297
- System .out .println ("Deleted MRAP in " + retryCounter * RETRY_DELAY_IN_MS / 1000 + " s." );
298
266
}
299
267
300
- private static String getRequestStatus (String resourceTokenArn ) {
301
- DescribeMultiRegionAccessPointOperationResponse response =
302
- s3control .describeMultiRegionAccessPointOperation (r -> r .accountId (accountId ).requestTokenARN (resourceTokenArn ));
303
- AsyncOperation operationDetails = response .asyncOperation ();
304
- return operationDetails .requestStatus ();
305
- }
268
+ private static void waitForResourceCreation (String mrapName ) throws IllegalStateException {
306
269
307
- private static Optional <MultiRegionAccessPointReport > getMrapReport (String name ) {
308
- List <MultiRegionAccessPointReport > mrapReports = getMrapReportList ();
309
- return mrapReports .stream ()
310
- .filter (mrap -> mrap .name ().equals (name ))
311
- .findFirst ();
312
- }
270
+ Waiter <ListMultiRegionAccessPointsResponse > waiter =
271
+ Waiter .builder (ListMultiRegionAccessPointsResponse .class )
272
+ .addAcceptor (WaiterAcceptor .successOnResponseAcceptor (r ->
273
+ r .accessPoints ().stream ().findFirst ().filter (mrap -> mrap .name ().equals (mrapName ) && mrap .status ().equals (MultiRegionAccessPointStatus .READY )).isPresent ()
274
+ ))
275
+ .addAcceptor (WaiterAcceptor .retryOnResponseAcceptor (i -> true ))
276
+ .overrideConfiguration (b -> b .maxAttempts (RETRY_TIMES ).backoffStrategy (FixedDelayBackoffStrategy .create (Duration .ofSeconds (RETRY_DELAY_IN_SECONDS ))))
277
+ .build ();
313
278
314
- private static List <MultiRegionAccessPointReport > getMrapReportList () {
315
- ListMultiRegionAccessPointsResponse listResponse = s3control .listMultiRegionAccessPoints (r -> r .accountId (accountId ));
316
- return listResponse .accessPoints ();
279
+ waiter .run (() -> s3control .listMultiRegionAccessPoints (r -> r .accountId (accountId )));
317
280
}
318
281
319
282
private String applyPresignedUrl (PresignedRequest presignedRequest , String content ) {
@@ -328,7 +291,7 @@ private String applyPresignedUrl(PresignedRequest presignedRequest, String conte
328
291
.map (stream -> invokeSafely (() -> IoUtils .toUtf8String (stream )))
329
292
.orElseThrow (() -> new IOException ("No input stream" ));
330
293
} catch (IOException e ) {
331
- e . printStackTrace ( );
294
+ log . error (() -> "Error occurred " , e );
332
295
}
333
296
return null ;
334
297
}
0 commit comments