Skip to content

Commit 3517d82

Browse files
authored
chore: cleanup presign tests (#546)
1 parent 764701c commit 3517d82

File tree

3 files changed

+56
-76
lines changed

3 files changed

+56
-76
lines changed

services/build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ subprojects {
5757
testLogging {
5858
events("passed", "skipped", "failed")
5959
showStandardStreams = true
60+
showStackTraces = true
61+
showExceptions = true
62+
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
6063
}
6164
}
6265

@@ -131,6 +134,9 @@ subprojects {
131134
testLogging {
132135
events("passed", "skipped", "failed")
133136
showStandardStreams = true
137+
showStackTraces = true
138+
showExceptions = true
139+
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
134140
}
135141
}
136142
}

services/s3/e2eTest/S3PresignerTest.kt

Lines changed: 25 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@ import aws.sdk.kotlin.services.s3.S3Client
55
import aws.sdk.kotlin.services.s3.model.GetObjectRequest
66
import aws.sdk.kotlin.services.s3.model.PutObjectRequest
77
import aws.sdk.kotlin.services.s3.presigners.presign
8-
import aws.smithy.kotlin.runtime.content.ByteStream
98
import aws.smithy.kotlin.runtime.content.decodeToString
109
import aws.smithy.kotlin.runtime.http.response.complete
1110
import aws.smithy.kotlin.runtime.http.sdkHttpClient
1211
import aws.smithy.kotlin.runtime.http.toByteStream
13-
import kotlinx.coroutines.ExperimentalCoroutinesApi
14-
import kotlinx.coroutines.runBlocking
15-
import kotlinx.coroutines.test.runTest
12+
import kotlinx.coroutines.*
1613
import org.junit.jupiter.api.AfterAll
1714
import org.junit.jupiter.api.BeforeAll
1815
import org.junit.jupiter.api.TestInstance
@@ -27,8 +24,13 @@ class S3PresignerTest {
2724
const val DEFAULT_REGION = "us-east-2"
2825
}
2926

27+
private val engine = CrtHttpEngine {
28+
maxConnections = 64u
29+
}
30+
3031
private val client = S3Client {
3132
region = DEFAULT_REGION
33+
httpClientEngine = engine
3234
}
3335

3436
private lateinit var testBucket: String
@@ -39,58 +41,36 @@ class S3PresignerTest {
3941
}
4042

4143
@AfterAll
42-
private fun cleanup() = runBlocking {
44+
private fun cleanup(): Unit = runBlocking {
4345
S3TestUtils.deleteBucketAndAllContents(client, testBucket)
46+
client.close()
47+
engine.close()
4448
}
4549

4650
@Test
47-
fun testPutObjectPresigner() = runTest {
51+
fun testRoundTripBlns() = runBlocking {
4852
val contents = "presign-test"
53+
val dispatcher = Dispatchers.IO.limitedParallelism(64)
54+
val httpClient = sdkHttpClient(engine)
4955

50-
// FIXME - run these concurrently, test takes forever
5156
testKeyNames.forEach { keyName ->
52-
val presignedRequest = PutObjectRequest {
53-
bucket = testBucket
54-
key = keyName
55-
}.presign(client.config, 60.seconds)
56-
57-
S3TestUtils.responseCodeFromPut(presignedRequest, contents)
58-
59-
val req = GetObjectRequest {
60-
bucket = testBucket
61-
key = keyName
62-
}
63-
val roundTrippedContents = client.getObject(req) { it.body?.decodeToString() }
64-
65-
assertEquals(contents, roundTrippedContents)
66-
}
67-
}
57+
launch(dispatcher) {
58+
val presignedPutRequest = PutObjectRequest {
59+
bucket = testBucket
60+
key = keyName
61+
}.presign(client.config, 60.seconds)
6862

69-
@Test
70-
fun testGetObjectPresigner() = runTest {
71-
val contents = "presign-test"
72-
73-
// FIXME - run these concurrently, test takes forever
74-
testKeyNames.reversed().forEach { keyName ->
75-
client.putObject {
76-
bucket = testBucket
77-
key = keyName
78-
body = ByteStream.fromString(contents)
79-
}
63+
S3TestUtils.responseCodeFromPut(presignedPutRequest, contents)
8064

81-
val presignedRequest = GetObjectRequest {
82-
bucket = testBucket
83-
key = keyName
84-
}.presign(client.config, 60.seconds)
65+
val presignedGetRequest = GetObjectRequest {
66+
bucket = testBucket
67+
key = keyName
68+
}.presign(client.config, 60.seconds)
8569

86-
CrtHttpEngine().use { engine ->
87-
val httpClient = sdkHttpClient(engine)
88-
89-
val call = httpClient.call(presignedRequest)
70+
val call = httpClient.call(presignedGetRequest)
71+
val body = call.response.body.toByteStream()?.decodeToString()
9072
call.complete()
91-
9273
assertEquals(200, call.response.status.value)
93-
val body = call.response.body.toByteStream()?.decodeToString()
9474
assertEquals(contents, body)
9575
}
9676
}
@@ -248,7 +228,7 @@ val testKeyNames: List<String>
248228
# Unicode additional control characters: all of the characters with
249229
# general category Cf (in Unicode 8.0.0).
250230
# The next line may appear to be blank or mojibake in some viewers.
251-
­؀؁؂؃؄؅؜۝܏᠎​‌‍‎‏‪‫‬‭‮⁠⁡⁢⁣⁤⁦⁧⁨⁩𑂽𛲠𛲡𛲢𛲣𝅳𝅴𝅵𝅶𝅷𝅸𝅹𝅺󠀁󠀠󠀡󠀢󠀣󠀤󠀥󠀦󠀧󠀨󠀩󠀪󠀫󠀬󠀭󠀮󠀯󠀰󠀱󠀲󠀳󠀴󠀵󠀶󠀷󠀸󠀹󠀺󠀻󠀼󠀽󠀾󠀿󠁀󠁁󠁂󠁃󠁄󠁅󠁆󠁇󠁈󠁉󠁊󠁋󠁌󠁍󠁎󠁏󠁐󠁑󠁒󠁓󠁔󠁕󠁖󠁗󠁘󠁙󠁚󠁛󠁜󠁝󠁞󠁟󠁠󠁡󠁢󠁣󠁤󠁥󠁦󠁧󠁨󠁩󠁪󠁫󠁬󠁭󠁮󠁯󠁰󠁱󠁲󠁳󠁴󠁵󠁶󠁷󠁸󠁹󠁺󠁻󠁼󠁽󠁾󠁿
231+
­؀؁؂؃؄؅؜۝܏᠎​‌‍‎‏‪‫‬‭‮⁠⁡⁢⁣⁤⁦⁧⁨⁩𑂽𛲠𛲡𛲢𛲣𝅳𝅴𝅵𝅶𝅷𝅸𝅹𝅺󠀁󠀠󠀡󠀢󠀣󠀤󠀥󠀦󠀧󠀨󠀩󠀪󠀫󠀬󠀭󠀮󠀯󠀰󠀱󠀲󠀳󠀴󠀵󠀶󠀷󠀸󠀹󠀺󠀻󠀼󠀽󠀾󠀿󠁀󠁁󠁂󠁃󠁄󠁅󠁆󠁇󠁈󠁉󠁊󠁋󠁌󠁍󠁎󠁏󠁐󠁑󠁒󠁓󠁔󠁕󠁖󠁗󠁘󠁙󠁚󠁛󠁜󠁝󠁞󠁟󠁠󠁡󠁢󠁣󠁤󠁥󠁦󠁧󠁨󠁩󠁪󠁫󠁬󠁭󠁮󠁯󠁰󠁱󠁲󠁳󠁴󠁵󠁶󠁷󠁸󠁹󠁺󠁻󠁼󠁽󠁾󠁿
252232
253233
# "Byte order marks", U+FEFF and U+FFFE, each on its own line.
254234
# The next two lines may appear to be blank or mojibake in some viewers.

services/s3/e2eTest/S3TestUtils.kt

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import aws.sdk.kotlin.services.s3.model.BucketLocationConstraint
99
import aws.sdk.kotlin.services.s3.model.ExpirationStatus
1010
import aws.sdk.kotlin.services.s3.model.LifecycleRule
1111
import aws.sdk.kotlin.services.s3.model.LifecycleRuleFilter
12-
import aws.sdk.kotlin.services.s3.model.NotFound
12+
import aws.sdk.kotlin.services.s3.paginators.listObjectsV2Paginated
13+
import aws.sdk.kotlin.services.s3.waiters.waitUntilBucketExists
1314
import aws.smithy.kotlin.runtime.http.request.HttpRequest
14-
import kotlinx.coroutines.delay
15-
import kotlinx.coroutines.withTimeout
15+
import kotlinx.coroutines.*
16+
import kotlinx.coroutines.flow.*
1617
import java.io.OutputStreamWriter
1718
import java.net.URL
1819
import java.util.*
@@ -40,15 +41,7 @@ object S3TestUtils {
4041
}
4142
}
4243

43-
do {
44-
val bucketExists = try {
45-
client.headBucket { bucket = testBucket }
46-
true
47-
} catch (ex: NotFound) {
48-
delay(300)
49-
false
50-
}
51-
} while (!bucketExists)
44+
client.waitUntilBucketExists { bucket = testBucket }
5245
}
5346

5447
client.putBucketLifecycleConfiguration {
@@ -68,30 +61,31 @@ object S3TestUtils {
6861
testBucket
6962
}
7063

71-
suspend fun deleteBucketAndAllContents(client: S3Client, bucketName: String) {
64+
@OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)
65+
suspend fun deleteBucketAndAllContents(client: S3Client, bucketName: String): Unit = coroutineScope {
66+
val scope = this
67+
7268
try {
7369
println("Deleting S3 bucket: $bucketName")
74-
75-
var resp = client.listObjectsV2 { bucket = bucketName }
76-
77-
do {
78-
val objects = resp.contents
79-
val truncated = resp.isTruncated
80-
81-
objects?.forEach {
82-
client.deleteObject {
83-
bucket = bucketName
84-
key = it.key
70+
val dispatcher = Dispatchers.Default.limitedParallelism(64)
71+
val jobs = mutableListOf<Job>()
72+
73+
// FIXME - this should use the batch `DeleteObjects` request and delete by page rather than individual key
74+
// However the current XML serializer chokes on the BLNS keys used by the presign tests. Update after
75+
// new XML implementation is available
76+
client.listObjectsV2Paginated { bucket = bucketName }
77+
.flatMapConcat { it.contents?.asFlow() ?: flowOf() }
78+
.collect { obj ->
79+
val job = scope.launch(dispatcher) {
80+
client.deleteObject {
81+
bucket = bucketName
82+
key = obj.key
83+
}
8584
}
85+
jobs.add(job)
8686
}
8787

88-
if (truncated) {
89-
resp = client.listObjectsV2 {
90-
bucket = bucketName
91-
continuationToken = resp.continuationToken
92-
}
93-
}
94-
} while (truncated)
88+
jobs.joinAll()
9589

9690
client.deleteBucket { bucket = bucketName }
9791
} catch (ex: Exception) {

0 commit comments

Comments
 (0)