From b05d8a72a81d0c40fff3ab0e3afd5d784c6d6804 Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 10 Aug 2021 09:00:37 -0400 Subject: [PATCH 1/4] wip --- services/build.gradle.kts | 28 ++++++++++++++++++++++++ services/s3/e2eTest/S3IntegrationTest.kt | 14 ++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 services/s3/e2eTest/S3IntegrationTest.kt diff --git a/services/build.gradle.kts b/services/build.gradle.kts index 3e743220c59..f17a867fc03 100644 --- a/services/build.gradle.kts +++ b/services/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.targets + /* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. @@ -81,6 +83,32 @@ subprojects { } apply(from = rootProject.file("gradle/publish.gradle")) + + if (project.file("e2eTest").exists()) { + + kotlin.target.compilations { + val main by getting + val e2eTest by creating { + defaultSourceSet { + kotlin.srcDir("e2eTest") + dependencies { + implementation(main.compileDependencyFiles + main.output.classesDirs) + implementation(kotlin("test")) + implementation(kotlin("test-junit5")) + } + } + + tasks.register("e2eTest") { + description = "Run e2e service tests" + group = "verification" + // classpath = kotlin.sourceSets.getByName("e2eTest").kotlin + classpath = compileDependencyFiles + runtimeDependencyFiles + testClassesDirs = output.classesDirs + useJUnitPlatform() + } + } + } + } } diff --git a/services/s3/e2eTest/S3IntegrationTest.kt b/services/s3/e2eTest/S3IntegrationTest.kt new file mode 100644 index 00000000000..f3f896bd0ed --- /dev/null +++ b/services/s3/e2eTest/S3IntegrationTest.kt @@ -0,0 +1,14 @@ +package aws.sdk.kotlin.e2etest + +import kotlin.test.Test + +abstract class E2eServiceTest { +} + +class S3IntegrationTest { + @Test + fun testPutObject() { + println("hello e2e tests") + } + +} \ No newline at end of file From accf3d09749d3f4a061a678d979cbdb0b368249e Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 17 Aug 2021 15:56:36 -0400 Subject: [PATCH 2/4] add s3 e2e test examples and test utils --- .../runtime/crt/ReadChannelBodyStream.kt | 4 +- .../runtime/testing/RandomInputStream.kt | 76 +++++++++++ .../kotlin/runtime/testing/RandomTempFile.kt | 119 ++++++++++++++++++ services/build.gradle.kts | 5 +- services/s3/e2eTest/S3IntegrationTest.kt | 105 +++++++++++++++- services/s3/e2eTest/S3TestUtils.kt | 92 ++++++++++++++ 6 files changed, 392 insertions(+), 9 deletions(-) create mode 100644 aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomInputStream.kt create mode 100644 aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomTempFile.kt create mode 100644 services/s3/e2eTest/S3TestUtils.kt diff --git a/aws-runtime/crt-util/common/src/aws/sdk/kotlin/runtime/crt/ReadChannelBodyStream.kt b/aws-runtime/crt-util/common/src/aws/sdk/kotlin/runtime/crt/ReadChannelBodyStream.kt index 080841a0f75..fb006aff295 100644 --- a/aws-runtime/crt-util/common/src/aws/sdk/kotlin/runtime/crt/ReadChannelBodyStream.kt +++ b/aws-runtime/crt-util/common/src/aws/sdk/kotlin/runtime/crt/ReadChannelBodyStream.kt @@ -28,7 +28,7 @@ internal expect fun transferRequestBody(outgoing: SdkBuffer, dest: MutableBuffer public class ReadChannelBodyStream( // the request body channel private val bodyChan: SdkByteReadChannel, - callContext: CoroutineContext + private val callContext: CoroutineContext ) : HttpRequestBodyStream, CoroutineScope { private val producerJob = Job(callContext.job) @@ -60,6 +60,8 @@ public class ReadChannelBodyStream( if (bufferChan.isClosedForReceive) { return true } + // ensure the request context hasn't been cancelled + callContext.ensureActive() outgoing = bufferChan.tryReceive().getOrNull() ?: return false } diff --git a/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomInputStream.kt b/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomInputStream.kt new file mode 100644 index 00000000000..0759be84331 --- /dev/null +++ b/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomInputStream.kt @@ -0,0 +1,76 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +package aws.sdk.kotlin.runtime.testing + +import java.io.IOException +import java.io.InputStream +import kotlin.random.Random + +/** + * Test utility InputStream implementation that generates random ASCII data when + * read, up to the size specified when constructed. + * NOTE: Adapted from + */ +public class RandomInputStream @JvmOverloads constructor( + /** The requested amount of data contained in this random stream. */ + protected val lengthInBytes: Long, + + /** Flag controlling whether binary or character data is used. */ + private val binaryData: Boolean = false +) : InputStream() { + + /** The number of bytes of data remaining in this random stream. */ + protected var remainingBytes: Long = lengthInBytes + + public val bytesRead: Long + get() = lengthInBytes - remainingBytes + + @Throws(IOException::class) + override fun read(b: ByteArray, off: Int, len: Int): Int { + // Signal that we're out of data if we've hit our limit + if (remainingBytes <= 0) { + return -1 + } + var bytesToRead = len + if (bytesToRead > remainingBytes) { + bytesToRead = remainingBytes.toInt() + } + remainingBytes -= bytesToRead.toLong() + if (binaryData) { + val bytes = ByteArray(bytesToRead) + Random.nextBytes(bytes) + System.arraycopy(bytes, 0, b, off, bytesToRead) + } else { + for (i in 0 until bytesToRead) { + b[off + i] = Random.nextInt(MIN_CHAR_CODE, MAX_CHAR_CODE + 1).toByte() + } + } + return bytesToRead + } + + @Throws(IOException::class) + override fun read(): Int { + // Signal that we're out of data if we've hit our limit + if (remainingBytes <= 0) { + return -1 + } + remainingBytes-- + return if (binaryData) { + val bytes = ByteArray(1) + Random.nextBytes(bytes) + bytes[0].toInt() + } else { + Random.nextInt(MIN_CHAR_CODE, MAX_CHAR_CODE + 1) + } + } + + public companion object { + /** The minimum ASCII code contained in the data in this stream. */ + private const val MIN_CHAR_CODE = 32 + + /** The maximum ASCII code contained in the data in this stream. */ + private const val MAX_CHAR_CODE = 125 + } +} diff --git a/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomTempFile.kt b/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomTempFile.kt new file mode 100644 index 00000000000..de0ee2152f2 --- /dev/null +++ b/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomTempFile.kt @@ -0,0 +1,119 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +package aws.sdk.kotlin.runtime.testing + +import java.io.BufferedOutputStream +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.util.* + +/** + * Extension of File that creates a temporary file with a specified name in + * Java's temporary directory, as declared in the JRE's system properties. The + * file is immediately filled with a specified amount of random ASCII data. + * + * @see RandomInputStream + */ +public class RandomTempFile : File { + /** Flag controlling whether binary or character data is used. */ + private val binaryData: Boolean + + /** + * Creates, and fills, a temp file with a randomly generated name and specified size of random ASCII data. + * + * @param sizeInBytes The amount of random ASCII data, in bytes, for the new temp + * file. + * @throws IOException If any problems were encountered creating the new temp file. + */ + public constructor(sizeInBytes: Long) : this(UUID.randomUUID().toString(), sizeInBytes, false) + + /** + * Creates, and fills, a temp file with the specified name and specified + * size of random ASCII data. + * + * @param filename + * The name for the new temporary file, within the Java temp + * directory as declared in the JRE's system properties. + * @param sizeInBytes + * The amount of random ASCII data, in bytes, for the new temp + * file. + * + * @throws IOException + * If any problems were encountered creating the new temp file. + */ + public constructor(filename: String, sizeInBytes: Int) : this(filename, sizeInBytes.toLong(), false) + + /** + * Creates, and fills, a temp file with the specified name and specified + * size of random binary or character data. + * + * @param filename + * The name for the new temporary file, within the Java temp + * directory as declared in the JRE's system properties. + * @param sizeInBytes + * The amount of random ASCII data, in bytes, for the new temp + * file. + * @param binaryData Whether to fill the file with binary or character data. + * + * @throws IOException + * If any problems were encountered creating the new temp file. + */ + /** + * Creates, and fills, a temp file with the specified name and specified + * size of random ASCII data. + * + * @param filename + * The name for the new temporary file, within the Java temp + * directory as declared in the JRE's system properties. + * @param sizeInBytes + * The amount of random ASCII data, in bytes, for the new temp + * file. + * + * @throws IOException + * If any problems were encountered creating the new temp file. + */ + @JvmOverloads + public constructor(filename: String, sizeInBytes: Long, binaryData: Boolean = false) : super( + TEMP_DIR + separator + System.currentTimeMillis().toString() + "-" + filename + ) { + this.binaryData = binaryData + createFile(sizeInBytes) + } + + public constructor(root: File?, filename: String?, sizeInBytes: Long) : super(root, filename) { + binaryData = false + createFile(sizeInBytes) + } + + @Throws(IOException::class) + public fun createFile(sizeInBytes: Long) { + deleteOnExit() + FileOutputStream(this).use { outputStream -> + BufferedOutputStream(outputStream).use { bufferedOutputStream -> + RandomInputStream(sizeInBytes, binaryData).use { inputStream -> + val buffer = ByteArray(1024) + var bytesRead: Int + while (inputStream.read(buffer).also { bytesRead = it } > -1) { + bufferedOutputStream.write(buffer, 0, bytesRead) + } + } + } + } + } + + override fun delete(): Boolean { + if (!super.delete()) { + throw RuntimeException("Could not delete: $absolutePath") + } + return true + } + + public companion object { + private val TEMP_DIR: String = System.getProperty("java.io.tmpdir") + public fun randomUncreatedFile(): File = + File(TEMP_DIR, UUID.randomUUID().toString()).also { it.deleteOnExit() } + } +} diff --git a/services/build.gradle.kts b/services/build.gradle.kts index f17a867fc03..14fe94aead2 100644 --- a/services/build.gradle.kts +++ b/services/build.gradle.kts @@ -92,16 +92,17 @@ subprojects { defaultSourceSet { kotlin.srcDir("e2eTest") dependencies { - implementation(main.compileDependencyFiles + main.output.classesDirs) + implementation(main.compileDependencyFiles + main.runtimeDependencyFiles + main.output.classesDirs) + implementation(kotlin("test")) implementation(kotlin("test-junit5")) + implementation(project(":aws-runtime:testing")) } } tasks.register("e2eTest") { description = "Run e2e service tests" group = "verification" - // classpath = kotlin.sourceSets.getByName("e2eTest").kotlin classpath = compileDependencyFiles + runtimeDependencyFiles testClassesDirs = output.classesDirs useJUnitPlatform() diff --git a/services/s3/e2eTest/S3IntegrationTest.kt b/services/s3/e2eTest/S3IntegrationTest.kt index f3f896bd0ed..986ceca02c5 100644 --- a/services/s3/e2eTest/S3IntegrationTest.kt +++ b/services/s3/e2eTest/S3IntegrationTest.kt @@ -1,14 +1,107 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ package aws.sdk.kotlin.e2etest +import aws.sdk.kotlin.runtime.testing.RandomTempFile +import aws.sdk.kotlin.runtime.testing.runSuspendTest +import aws.sdk.kotlin.services.s3.S3Client +import aws.sdk.kotlin.services.s3.model.* +import aws.smithy.kotlin.runtime.content.ByteStream +import aws.smithy.kotlin.runtime.content.decodeToString +import aws.smithy.kotlin.runtime.content.fromFile +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.TestInstance import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.time.Duration +import kotlin.time.ExperimentalTime -abstract class E2eServiceTest { -} +/** + * Tests for bucket operations + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class S3BucketOpsIntegrationTest { + companion object { + const val DEFAULT_REGION = "us-east-2" + } + + val client = S3Client { + region = DEFAULT_REGION + } + + lateinit var testBucket: String + + @BeforeAll + private fun createResources(): Unit = runBlocking { + testBucket = S3TestUtils.getTestBucket(client) + } + + @AfterAll + private fun cleanup() = runBlocking { + S3TestUtils.deleteBucketAndAllContents(client, testBucket) + } -class S3IntegrationTest { @Test - fun testPutObject() { - println("hello e2e tests") + fun testPutObjectFromMemory() = runSuspendTest { + val contents = """ + Are you suggesting coconuts migrate? + Not at all, they could be carried. + What -- a swallow carrying a coconut? + It could grip it by the husk. + It's not a question of where he grips it! It's a simple question of weight ratios! A five ounce bird could not carry a 1 pound coconut. + Well, it doesn't matter. Will you go and tell your master that Arthur from the Court of Camelot is here. + Listen, in order to maintain air-speed velocity, a swallow needs to beat its wings 43 times times every second, right? + ... + It could be carried by an African swallow! + Oh yeah, an African swallow maybe, but not a European swallow. That's my point. + Oh, yeah, I agree with that. + """.trimIndent() + + val keyName = "put-obj-from-memory.txt" + + client.putObject { + bucket = testBucket + key = keyName + body = ByteStream.fromString(contents) + } + + val req = GetObjectRequest { + bucket = testBucket + key = keyName + } + val roundTrippedContents = client.getObject(req) { it.body?.decodeToString() } + + assertEquals(contents, roundTrippedContents) } -} \ No newline at end of file + @OptIn(ExperimentalTime::class) + @Test + fun testPutObjectFromFile() = runSuspendTest { + val tempFile = RandomTempFile(1024) + val keyName = "put-obj-from-file.txt" + + // This test fails sporadically (by never completing) + // see https://github.com/awslabs/aws-sdk-kotlin/issues/282 + withTimeout(Duration.seconds(5)) { + client.putObject { + bucket = testBucket + key = keyName + body = ByteStream.fromFile(tempFile) + } + } + + val req = GetObjectRequest { + bucket = testBucket + key = keyName + } + val roundTrippedContents = client.getObject(req) { it.body?.decodeToString() } + + val contents = tempFile.readText() + assertEquals(contents, roundTrippedContents) + } +} diff --git a/services/s3/e2eTest/S3TestUtils.kt b/services/s3/e2eTest/S3TestUtils.kt new file mode 100644 index 00000000000..3e852de1301 --- /dev/null +++ b/services/s3/e2eTest/S3TestUtils.kt @@ -0,0 +1,92 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +package aws.sdk.kotlin.e2etest + +import aws.sdk.kotlin.services.s3.S3Client +import aws.sdk.kotlin.services.s3.model.* +import kotlinx.coroutines.delay +import java.util.* + +object S3TestUtils { + + const val TEST_BUCKET_PREFIX = "s3-test-bucket-" + + suspend fun getTestBucket(client: S3Client): String = getBucketWithPrefix(client, TEST_BUCKET_PREFIX) + + suspend fun getBucketWithPrefix(client: S3Client, prefix: String): String { + var testBucket = client.listBuckets {} + .buckets + ?.mapNotNull { it.name } + ?.firstOrNull { it.startsWith(prefix) } + + if (testBucket == null) { + testBucket = prefix + UUID.randomUUID() + client.createBucket { + bucket = testBucket + createBucketConfiguration { + locationConstraint = BucketLocationConstraint.fromValue(client.config.region!!) + } + } + + do { + val bucketExists = try { + client.headBucket { bucket = testBucket } + true + } catch (ex: NotFound) { + delay(300) + false + } + } while (!bucketExists) + } + + client.putBucketLifecycleConfiguration { + bucket = testBucket + lifecycleConfiguration { + rules = listOf( + LifecycleRule { + expiration { days = 1 } + filter = LifecycleRuleFilter.Prefix("") + status = ExpirationStatus.Enabled + id = "delete-old" + } + ) + } + } + + return testBucket + } + + suspend fun deleteBucketAndAllContents(client: S3Client, bucketName: String) { + try { + println("Deleting S3 bucket: $bucketName") + + var resp = client.listObjectsV2 { bucket = bucketName } + + do { + val objects = resp.contents + val truncated = resp.isTruncated + + objects?.forEach { + client.deleteObject { + bucket = bucketName + key = it.key + } + } + + if (truncated) { + resp = client.listObjectsV2 { + bucket = bucketName + continuationToken = resp.continuationToken + } + } + } while (truncated) + + client.deleteBucket { bucket = bucketName } + } catch (ex: Exception) { + println("Failed to delete bucket: $bucketName") + throw ex + } + } +} From 53d6fb777276ce469a1230726b3ced2bec833ed8 Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 17 Aug 2021 15:58:35 -0400 Subject: [PATCH 3/4] remove import --- services/build.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/build.gradle.kts b/services/build.gradle.kts index 14fe94aead2..ebe9b0e6875 100644 --- a/services/build.gradle.kts +++ b/services/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.targets - /* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. From 84d393323febe8c9a0180525d6178061beb01dc4 Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 17 Aug 2021 19:43:26 -0400 Subject: [PATCH 4/4] cleanup autoconverted files; add timeout; comply with laws and such --- .../runtime/testing/RandomInputStream.kt | 14 ++--- .../kotlin/runtime/testing/RandomTempFile.kt | 52 ++----------------- services/s3/e2eTest/S3IntegrationTest.kt | 16 ++---- services/s3/e2eTest/S3TestUtils.kt | 9 +++- 4 files changed, 21 insertions(+), 70 deletions(-) diff --git a/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomInputStream.kt b/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomInputStream.kt index 0759be84331..84d72ee8aac 100644 --- a/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomInputStream.kt +++ b/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomInputStream.kt @@ -11,11 +11,10 @@ import kotlin.random.Random /** * Test utility InputStream implementation that generates random ASCII data when * read, up to the size specified when constructed. - * NOTE: Adapted from */ -public class RandomInputStream @JvmOverloads constructor( +public class RandomInputStream constructor( /** The requested amount of data contained in this random stream. */ - protected val lengthInBytes: Long, + private val lengthInBytes: Long, /** Flag controlling whether binary or character data is used. */ private val binaryData: Boolean = false @@ -39,9 +38,8 @@ public class RandomInputStream @JvmOverloads constructor( } remainingBytes -= bytesToRead.toLong() if (binaryData) { - val bytes = ByteArray(bytesToRead) - Random.nextBytes(bytes) - System.arraycopy(bytes, 0, b, off, bytesToRead) + val endExclusive = off + bytesToRead + Random.nextBytes(b, off, endExclusive) } else { for (i in 0 until bytesToRead) { b[off + i] = Random.nextInt(MIN_CHAR_CODE, MAX_CHAR_CODE + 1).toByte() @@ -58,9 +56,7 @@ public class RandomInputStream @JvmOverloads constructor( } remainingBytes-- return if (binaryData) { - val bytes = ByteArray(1) - Random.nextBytes(bytes) - bytes[0].toInt() + Random.nextInt() } else { Random.nextInt(MIN_CHAR_CODE, MAX_CHAR_CODE + 1) } diff --git a/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomTempFile.kt b/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomTempFile.kt index de0ee2152f2..f554c7245cc 100644 --- a/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomTempFile.kt +++ b/aws-runtime/testing/jvm/src/aws/sdk/kotlin/runtime/testing/RandomTempFile.kt @@ -32,50 +32,17 @@ public class RandomTempFile : File { /** * Creates, and fills, a temp file with the specified name and specified - * size of random ASCII data. + * size of random data. * - * @param filename - * The name for the new temporary file, within the Java temp + * @param filename The name for the new temporary file, within the Java temp * directory as declared in the JRE's system properties. - * @param sizeInBytes - * The amount of random ASCII data, in bytes, for the new temp - * file. - * - * @throws IOException - * If any problems were encountered creating the new temp file. - */ - public constructor(filename: String, sizeInBytes: Int) : this(filename, sizeInBytes.toLong(), false) - - /** - * Creates, and fills, a temp file with the specified name and specified - * size of random binary or character data. - * - * @param filename - * The name for the new temporary file, within the Java temp - * directory as declared in the JRE's system properties. - * @param sizeInBytes - * The amount of random ASCII data, in bytes, for the new temp + * @param sizeInBytes The amount of random ASCII data, in bytes, for the new temp * file. * @param binaryData Whether to fill the file with binary or character data. * * @throws IOException * If any problems were encountered creating the new temp file. */ - /** - * Creates, and fills, a temp file with the specified name and specified - * size of random ASCII data. - * - * @param filename - * The name for the new temporary file, within the Java temp - * directory as declared in the JRE's system properties. - * @param sizeInBytes - * The amount of random ASCII data, in bytes, for the new temp - * file. - * - * @throws IOException - * If any problems were encountered creating the new temp file. - */ - @JvmOverloads public constructor(filename: String, sizeInBytes: Long, binaryData: Boolean = false) : super( TEMP_DIR + separator + System.currentTimeMillis().toString() + "-" + filename ) { @@ -83,22 +50,13 @@ public class RandomTempFile : File { createFile(sizeInBytes) } - public constructor(root: File?, filename: String?, sizeInBytes: Long) : super(root, filename) { - binaryData = false - createFile(sizeInBytes) - } - @Throws(IOException::class) public fun createFile(sizeInBytes: Long) { deleteOnExit() FileOutputStream(this).use { outputStream -> BufferedOutputStream(outputStream).use { bufferedOutputStream -> RandomInputStream(sizeInBytes, binaryData).use { inputStream -> - val buffer = ByteArray(1024) - var bytesRead: Int - while (inputStream.read(buffer).also { bytesRead = it } > -1) { - bufferedOutputStream.write(buffer, 0, bytesRead) - } + inputStream.copyTo(bufferedOutputStream) } } } @@ -113,7 +71,5 @@ public class RandomTempFile : File { public companion object { private val TEMP_DIR: String = System.getProperty("java.io.tmpdir") - public fun randomUncreatedFile(): File = - File(TEMP_DIR, UUID.randomUUID().toString()).also { it.deleteOnExit() } } } diff --git a/services/s3/e2eTest/S3IntegrationTest.kt b/services/s3/e2eTest/S3IntegrationTest.kt index 986ceca02c5..e6c88a4e236 100644 --- a/services/s3/e2eTest/S3IntegrationTest.kt +++ b/services/s3/e2eTest/S3IntegrationTest.kt @@ -49,17 +49,11 @@ class S3BucketOpsIntegrationTest { @Test fun testPutObjectFromMemory() = runSuspendTest { val contents = """ - Are you suggesting coconuts migrate? - Not at all, they could be carried. - What -- a swallow carrying a coconut? - It could grip it by the husk. - It's not a question of where he grips it! It's a simple question of weight ratios! A five ounce bird could not carry a 1 pound coconut. - Well, it doesn't matter. Will you go and tell your master that Arthur from the Court of Camelot is here. - Listen, in order to maintain air-speed velocity, a swallow needs to beat its wings 43 times times every second, right? - ... - It could be carried by an African swallow! - Oh yeah, an African swallow maybe, but not a European swallow. That's my point. - Oh, yeah, I agree with that. + A lep is a ball. + A tay is a hammer. + A korf is a tiger. + A flix is a comb. + A wogsin is a gift. """.trimIndent() val keyName = "put-obj-from-memory.txt" diff --git a/services/s3/e2eTest/S3TestUtils.kt b/services/s3/e2eTest/S3TestUtils.kt index 3e852de1301..d9ce2af700d 100644 --- a/services/s3/e2eTest/S3TestUtils.kt +++ b/services/s3/e2eTest/S3TestUtils.kt @@ -7,7 +7,11 @@ package aws.sdk.kotlin.e2etest import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.model.* import kotlinx.coroutines.delay +import kotlinx.coroutines.withTimeout import java.util.* +import kotlin.time.Duration +import kotlin.time.ExperimentalTime +import kotlin.time.seconds object S3TestUtils { @@ -15,7 +19,8 @@ object S3TestUtils { suspend fun getTestBucket(client: S3Client): String = getBucketWithPrefix(client, TEST_BUCKET_PREFIX) - suspend fun getBucketWithPrefix(client: S3Client, prefix: String): String { + @OptIn(ExperimentalTime::class) + suspend fun getBucketWithPrefix(client: S3Client, prefix: String): String = withTimeout(Duration.seconds(60)) { var testBucket = client.listBuckets {} .buckets ?.mapNotNull { it.name } @@ -55,7 +60,7 @@ object S3TestUtils { } } - return testBucket + testBucket } suspend fun deleteBucketAndAllContents(client: S3Client, bucketName: String) {