@@ -26,13 +26,16 @@ import software.amazon.awssdk.awscore.exception.AwsServiceException
2626import software.amazon.awssdk.services.s3.S3Client
2727import software.amazon.awssdk.services.s3.model.AbortIncompleteMultipartUpload
2828import software.amazon.awssdk.services.s3.model.BucketLifecycleConfiguration
29+ import software.amazon.awssdk.services.s3.model.BucketType
2930import software.amazon.awssdk.services.s3.model.BucketVersioningStatus
31+ import software.amazon.awssdk.services.s3.model.DataRedundancy
3032import software.amazon.awssdk.services.s3.model.DeleteBucketRequest
3133import software.amazon.awssdk.services.s3.model.ExpirationStatus
3234import software.amazon.awssdk.services.s3.model.GetBucketLifecycleConfigurationRequest
3335import software.amazon.awssdk.services.s3.model.LifecycleExpiration
3436import software.amazon.awssdk.services.s3.model.LifecycleRule
3537import software.amazon.awssdk.services.s3.model.LifecycleRuleFilter
38+ import software.amazon.awssdk.services.s3.model.LocationType
3639import software.amazon.awssdk.services.s3.model.MFADelete
3740import software.amazon.awssdk.services.s3.model.MFADeleteStatus
3841import software.amazon.awssdk.services.s3.model.NoSuchBucketException
@@ -68,6 +71,35 @@ internal class BucketIT : S3TestBase() {
6871 }
6972 }
7073
74+ @Test
75+ @S3VerifiedSuccess(year = 2025 )
76+ fun `creating a bucket with configuration is successful` (testInfo : TestInfo ) {
77+ val bucketName = bucketName(testInfo)
78+ val createBucketResponse = s3Client.createBucket {
79+ it.bucket(bucketName)
80+ it.createBucketConfiguration {
81+ it.locationConstraint(" ap-southeast-5" )
82+ it.bucket {
83+ it.dataRedundancy(DataRedundancy .SINGLE_AVAILABILITY_ZONE )
84+ it.type(BucketType .DIRECTORY )
85+ }
86+ it.location {
87+ it.name(" SomeName" )
88+ it.type(LocationType .AVAILABILITY_ZONE )
89+ }
90+ }
91+ }
92+ assertThat(createBucketResponse.sdkHttpResponse().statusCode()).isEqualTo(200 )
93+ assertThat(createBucketResponse.location()).isEqualTo(" /$bucketName " )
94+
95+ val bucketCreated = s3Client.waiter().waitUntilBucketExists { it.bucket(bucketName) }
96+ val bucketCreatedResponse = bucketCreated.matched().response().get()
97+ assertThat(bucketCreatedResponse).isNotNull
98+
99+ // does not throw exception if bucket exists.
100+ s3Client.headBucket { it.bucket(bucketName) }
101+ }
102+
71103 @Test
72104 @S3VerifiedSuccess(year = 2025 )
73105 fun `deleting a non-empty bucket fails` (testInfo : TestInfo ) {
@@ -94,20 +126,113 @@ internal class BucketIT : S3TestBase() {
94126 // and account for a clock-skew in the Docker container of up to a minute.
95127 val creationDate = Instant .now().minus(1 , ChronoUnit .MINUTES )
96128
97- s3Client.listBuckets{
129+ s3Client.listBuckets { }.also {
130+ assertThat(it.hasBuckets()).isTrue
131+ it.buckets().also {
132+ assertThat(it.size).isEqualTo(5 )
133+ assertThat(it.map { b -> b.name() }).containsExactly(
134+ // the default buckets
135+ " bucket-a" ,
136+ " bucket-b" ,
137+ // the buckets we created in this test
138+ " ${bucketName} -1" ,
139+ " ${bucketName} -2" ,
140+ " ${bucketName} -3"
141+ )
142+ assertThat(it[2 ].creationDate()).isAfterOrEqualTo(creationDate)
143+ assertThat(it[3 ].creationDate()).isAfterOrEqualTo(creationDate)
144+ assertThat(it[4 ].creationDate()).isAfterOrEqualTo(creationDate)
145+ }
146+ assertThat(it.prefix()).isNull()
147+ assertThat(it.continuationToken()).isNull()
148+ assertThat(it.owner().displayName()).isEqualTo(" s3-mock-file-store" )
149+ assertThat(it.owner().id()).isEqualTo(" 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" )
150+ }
151+ }
152+
153+ @Test
154+ @S3VerifiedFailure(year = 2025 ,
155+ reason = " Default owner does not exist in S3." )
156+ fun `creating and listing multiple buckets limiting by prefix is successful` (testInfo : TestInfo ) {
157+ val bucketName = bucketName(testInfo)
158+ givenBucket(" ${bucketName} -1" )
159+ givenBucket(" ${bucketName} -2" )
160+ givenBucket(" ${bucketName} -3" )
161+ // the returned creation date might strip off the millisecond-part, resulting in rounding down
162+ // and account for a clock-skew in the Docker container of up to a minute.
163+ val creationDate = Instant .now().minus(1 , ChronoUnit .MINUTES )
164+
165+ s3Client.listBuckets {
98166 it.prefix(bucketName)
99167 }.also {
100168 assertThat(it.hasBuckets()).isTrue
101- // TODO: ListBuckets API currently ignores the prefix argument, see #2340
102- it.buckets()
103- .filter { b -> b.name().startsWith(bucketName) }.also { filteredBuckets ->
104- assertThat(filteredBuckets.size).isEqualTo(3 )
105- assertThat(filteredBuckets.map { b -> b.name() })
106- .containsExactlyInAnyOrder(" ${bucketName} -1" , " ${bucketName} -2" , " ${bucketName} -3" )
107- assertThat(filteredBuckets[0 ].creationDate()).isAfterOrEqualTo(creationDate)
108- assertThat(filteredBuckets[1 ].creationDate()).isAfterOrEqualTo(creationDate)
109- assertThat(filteredBuckets[2 ].creationDate()).isAfterOrEqualTo(creationDate)
110- }
169+ it.buckets().also {
170+ assertThat(it.size).isEqualTo(3 )
171+ assertThat(it.map { b -> b.name() }).containsExactly(
172+ // the buckets we created in this test
173+ " ${bucketName} -1" ,
174+ " ${bucketName} -2" ,
175+ " ${bucketName} -3"
176+ )
177+ assertThat(it[0 ].creationDate()).isAfterOrEqualTo(creationDate)
178+ assertThat(it[1 ].creationDate()).isAfterOrEqualTo(creationDate)
179+ assertThat(it[2 ].creationDate()).isAfterOrEqualTo(creationDate)
180+ }
181+ assertThat(it.prefix()).isEqualTo(bucketName)
182+ assertThat(it.continuationToken()).isNull()
183+ assertThat(it.owner().displayName()).isEqualTo(" s3-mock-file-store" )
184+ assertThat(it.owner().id()).isEqualTo(" 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" )
185+ }
186+ }
187+
188+ @Test
189+ @S3VerifiedFailure(year = 2025 ,
190+ reason = " Default owner does not exist in S3." )
191+ fun `creating and listing multiple buckets limiting by maxBuckets is successful` (testInfo : TestInfo ) {
192+ val bucketName = bucketName(testInfo)
193+ givenBucket(" ${bucketName} -1" )
194+ givenBucket(" ${bucketName} -2" )
195+ givenBucket(" ${bucketName} -3" )
196+ // the returned creation date might strip off the millisecond-part, resulting in rounding down
197+ // and account for a clock-skew in the Docker container of up to a minute.
198+ val creationDate = Instant .now().minus(1 , ChronoUnit .MINUTES )
199+
200+ val continuationToken = s3Client.listBuckets {
201+ it.maxBuckets(4 )
202+ }.also {
203+ assertThat(it.hasBuckets()).isTrue
204+ it.buckets().also {
205+ assertThat(it.size).isEqualTo(4 )
206+ assertThat(it.map { b -> b.name() }).containsExactly(
207+ // the default buckets
208+ " bucket-a" ,
209+ " bucket-b" ,
210+ // the buckets we created in this test
211+ " ${bucketName} -1" ,
212+ " ${bucketName} -2"
213+ )
214+ assertThat(it[2 ].creationDate()).isAfterOrEqualTo(creationDate)
215+ assertThat(it[3 ].creationDate()).isAfterOrEqualTo(creationDate)
216+ }
217+ assertThat(it.prefix()).isNull()
218+ assertThat(it.continuationToken()).isNotNull
219+ assertThat(it.owner().displayName()).isEqualTo(" s3-mock-file-store" )
220+ assertThat(it.owner().id()).isEqualTo(" 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" )
221+ }.continuationToken()
222+
223+ s3Client.listBuckets {
224+ it.continuationToken(continuationToken)
225+ }.also {
226+ assertThat(it.hasBuckets()).isTrue
227+ it.buckets().also {
228+ assertThat(it.size).isEqualTo(1 )
229+ assertThat(it.map { b -> b.name() }).containsExactly(
230+ " ${bucketName} -3"
231+ )
232+ assertThat(it[0 ].creationDate()).isAfterOrEqualTo(creationDate)
233+ }
234+ assertThat(it.prefix()).isNull()
235+ assertThat(it.continuationToken()).isNull()
111236 assertThat(it.owner().displayName()).isEqualTo(" s3-mock-file-store" )
112237 assertThat(it.owner().id()).isEqualTo(" 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" )
113238 }
@@ -121,7 +246,7 @@ internal class BucketIT : S3TestBase() {
121246 assertThat(it.buckets())
122247 .hasSize(2 )
123248 .extracting(" name" )
124- .containsExactlyInAnyOrder (INITIAL_BUCKET_NAMES .first(), INITIAL_BUCKET_NAMES .last())
249+ .containsExactly (INITIAL_BUCKET_NAMES .first(), INITIAL_BUCKET_NAMES .last())
125250 }
126251 }
127252
0 commit comments