From 8cc53c3ee5c6d1547dec7c2835f749da3103d490 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Tue, 8 Oct 2024 17:22:20 -0400 Subject: [PATCH 01/16] misc: support additional smoke test vendor params --- .../kotlin/codegen/core/KotlinDependency.kt | 1 + .../kotlin/codegen/core/RuntimeTypes.kt | 4 + .../smoketests/SmokeTestsRunnerGenerator.kt | 98 +++++++++++++++++-- 3 files changed, 94 insertions(+), 9 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinDependency.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinDependency.kt index 524e1924a6..17faf0ad48 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinDependency.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinDependency.kt @@ -129,6 +129,7 @@ data class KotlinDependency( val IDENTITY_API = KotlinDependency(GradleConfiguration.Implementation, "$RUNTIME_ROOT_NS", RUNTIME_GROUP, "identity-api", RUNTIME_VERSION) val SMITHY_RPCV2_PROTOCOLS = KotlinDependency(GradleConfiguration.Implementation, "$RUNTIME_ROOT_NS.awsprotocol.rpcv2", RUNTIME_GROUP, "smithy-rpcv2-protocols", RUNTIME_VERSION) val SMITHY_RPCV2_PROTOCOLS_CBOR = KotlinDependency(GradleConfiguration.Implementation, "$RUNTIME_ROOT_NS.awsprotocol.rpcv2.cbor", RUNTIME_GROUP, "smithy-rpcv2-protocols", RUNTIME_VERSION) + val AWS_SIGNING_CRT = KotlinDependency(GradleConfiguration.Implementation, "$RUNTIME_ROOT_NS.auth.awssigning.crt", RUNTIME_GROUP, "aws-signing-crt", RUNTIME_VERSION) // External third-party dependencies val KOTLIN_STDLIB = KotlinDependency(GradleConfiguration.Implementation, "kotlin", "org.jetbrains.kotlin", "kotlin-stdlib", KOTLIN_COMPILER_VERSION) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt index d37e47737a..314845aeb8 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt @@ -378,6 +378,10 @@ object RuntimeTypes { val sigV4 = symbol("sigV4") val sigV4A = symbol("sigV4A") } + + object AwsSigningCrt : RuntimeTypePackage(KotlinDependency.AWS_SIGNING_CRT) { + val CrtAwsSigner = symbol("CrtAwsSigner") + } } object Observability { diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index edcf8b7b2d..ba6d536464 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -3,8 +3,13 @@ package software.amazon.smithy.kotlin.codegen.rendering.smoketests import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.kotlin.codegen.core.* import software.amazon.smithy.kotlin.codegen.integration.SectionId +import software.amazon.smithy.kotlin.codegen.integration.SectionKey import software.amazon.smithy.kotlin.codegen.model.getTrait import software.amazon.smithy.kotlin.codegen.model.hasTrait +import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointParametersGenerator +import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointProviderGenerator +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestUriValue.EndpointParameters +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestUriValue.EndpointProvider import software.amazon.smithy.kotlin.codegen.rendering.util.format import software.amazon.smithy.kotlin.codegen.utils.dq import software.amazon.smithy.kotlin.codegen.utils.toCamelCase @@ -18,7 +23,21 @@ object SmokeTestsRunner : SectionId object SmokeTestAdditionalEnvVars : SectionId object SmokeTestDefaultConfig : SectionId object SmokeTestRegionDefault : SectionId +object SmokeTestUseDualStackKey : SectionId +object SmokeTestSigv4aRegionSetKey : SectionId +object SmokeTestSigv4aRegionSetValue : SectionId +object SmokeTestAccountIdBasedRoutingKey : SectionId +object SmokeTestAccountIdBasedRoutingValue : SectionId object SmokeTestHttpEngineOverride : SectionId +object SmokeTestUseAccelerateKey : SectionId +object SmokeTestUseMultiRegionAccessPointsKey : SectionId +object SmokeTestUseMultiRegionAccessPointsValue : SectionId +object SmokeTestUseGlobalEndpoint : SectionId +object SmokeTestUriKey : SectionId +object SmokeTestUriValue : SectionId { + val EndpointProvider: SectionKey = SectionKey("EndpointProvider") + val EndpointParameters: SectionKey = SectionKey("EndpointParameters") +} const val SKIP_TAGS = "AWS_SMOKE_TEST_SKIP_TAGS" const val SERVICE_FILTER = "AWS_SMOKE_TEST_SERVICE_IDS" @@ -31,10 +50,11 @@ class SmokeTestsRunnerGenerator( ctx: CodegenContext, ) { private val model = ctx.model - private val sdkId = ctx.settings.sdkId + private val settings = ctx.settings + private val sdkId = settings.sdkId private val symbolProvider = ctx.symbolProvider - private val service = symbolProvider.toSymbol(model.expectShape(ctx.settings.service)) - private val operations = ctx.model.topDownOperations(ctx.settings.service).filter { it.hasTrait() } + private val service = symbolProvider.toSymbol(model.expectShape(settings.service)) + private val operations = model.topDownOperations(settings.service).filter { it.hasTrait() } internal fun render() { writer.declareSection(SmokeTestsRunner) { @@ -108,12 +128,72 @@ class SmokeTestsRunnerGenerator( writer.withInlineBlock("#L {", "}", service) { if (testCase.vendorParams.isPresent) { testCase.vendorParams.get().members.forEach { vendorParam -> - if (vendorParam.key.value == "region") { - writeInline("#L = ", vendorParam.key.value.toCamelCase()) - declareSection(SmokeTestRegionDefault) - write("#L", vendorParam.value.format()) - } else { - write("#L = #L", vendorParam.key.value.toCamelCase(), vendorParam.value.format()) + when (vendorParam.key.value) { + "region" -> { + writeInline("#L = ", vendorParam.key.value.toCamelCase()) + declareSection(SmokeTestRegionDefault) + write("#L", vendorParam.value.format()) + } + "sigv4aRegionSet" -> { + declareSection(SmokeTestSigv4aRegionSetKey) { + writeInline("#L", vendorParam.key.value.toCamelCase()) + } + writeInline(" = ") + declareSection(SmokeTestSigv4aRegionSetValue) { + write("#L", vendorParam.value.format()) + } + } + "uri" -> { + declareSection(SmokeTestUriKey) { + writeInline("#L", vendorParam.key.value.toCamelCase()) + } + writeInline(" = ") + declareSection( + SmokeTestUriValue, + mapOf( + EndpointProvider to EndpointProviderGenerator.getSymbol(settings), + EndpointParameters to EndpointParametersGenerator.getSymbol(settings), + ), + ) { + write("#L", vendorParam.value.format()) + } + } + "useDualstack" -> { + declareSection(SmokeTestUseDualStackKey) { + writeInline("#L", vendorParam.key.value.toCamelCase()) + } + write(" = #L", vendorParam.value.format()) + } + "useAccountIdRouting" -> { + declareSection(SmokeTestAccountIdBasedRoutingKey) { + writeInline("#L", vendorParam.key.value.toCamelCase()) + } + writeInline(" = ") + declareSection(SmokeTestAccountIdBasedRoutingValue) { + write("#L", vendorParam.value.format()) + } + } + "useAccelerate" -> { + declareSection(SmokeTestUseAccelerateKey) { + writeInline("#L", vendorParam.key.value.toCamelCase()) + } + write(" = #L", vendorParam.value.format()) + } + "useMultiRegionAccessPoints" -> { + declareSection(SmokeTestUseMultiRegionAccessPointsKey) { + writeInline("#L", vendorParam.key.value.toCamelCase()) + } + writeInline(" = ") + declareSection(SmokeTestUseMultiRegionAccessPointsValue) { + write("#L", vendorParam.value.format()) + } + } + "useGlobalEndpoint" -> { + declareSection(SmokeTestUseGlobalEndpoint) { + write("#L = #L", vendorParam.key.value.toCamelCase(), vendorParam.value.format()) + } + } + else -> write("#L = #L", vendorParam.key.value.toCamelCase(), vendorParam.value.format()) } } } else { From d1fee9e5cfb141c4d591750746d18debcf846028 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Tue, 8 Oct 2024 18:13:19 -0400 Subject: [PATCH 02/16] Add failed smoke test logging --- .../smithy/kotlin/codegen/core/RuntimeTypes.kt | 1 + .../smoketests/SmokeTestsRunnerGenerator.kt | 1 + .../smoketests/SmokeTestsRunnerGeneratorTest.kt | 3 +++ runtime/protocol/http-client/api/http-client.api | 4 ++-- .../http/interceptors/SmokeTestsInterceptor.kt | 12 ++++++------ runtime/runtime-core/api/runtime-core.api | 4 ++++ .../runtime/smoketests/SmokeTestsFunctions.kt | 16 ++++++++++++++++ 7 files changed, 33 insertions(+), 8 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt index 314845aeb8..3616934407 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt @@ -116,6 +116,7 @@ object RuntimeTypes { object SmokeTests : RuntimeTypePackage(KotlinDependency.CORE, "smoketests") { val exitProcess = symbol("exitProcess") + val printExceptionStackTrace = symbol("printExceptionStackTrace") } object Collections : RuntimeTypePackage(KotlinDependency.CORE, "collections") { diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index ba6d536464..f2651da97d 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -236,6 +236,7 @@ class SmokeTestsRunnerGenerator( testCase.expectation.isFailure, writer, ) + writer.write("if (!success) #T(e)", RuntimeTypes.Core.SmokeTests.printExceptionStackTrace) writer.write("if (!success) exitCode = 1") } diff --git a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGeneratorTest.kt b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGeneratorTest.kt index ddb5b3c1db..540a1d3fec 100644 --- a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGeneratorTest.kt +++ b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGeneratorTest.kt @@ -122,6 +122,7 @@ class SmokeTestsRunnerGeneratorTest { val success = e is SmokeTestsSuccessException val status = if (success) "ok" else "not ok" println("${'$'}status Test SuccessTest - no error expected from service ") + if (!success) printExceptionStackTrace(e) if (!success) exitCode = 1 } } @@ -155,6 +156,7 @@ class SmokeTestsRunnerGeneratorTest { val success = e is InvalidMessageError val status = if (success) "ok" else "not ok" println("${'$'}status Test InvalidMessageErrorTest - error expected from service ") + if (!success) printExceptionStackTrace(e) if (!success) exitCode = 1 } } @@ -189,6 +191,7 @@ class SmokeTestsRunnerGeneratorTest { val success = e is SmokeTestsFailureException val status = if (success) "ok" else "not ok" println("${'$'}status Test FailureTest - error expected from service ") + if (!success) printExceptionStackTrace(e) if (!success) exitCode = 1 } } diff --git a/runtime/protocol/http-client/api/http-client.api b/runtime/protocol/http-client/api/http-client.api index c15a33b0b1..7e22ab9c6b 100644 --- a/runtime/protocol/http-client/api/http-client.api +++ b/runtime/protocol/http-client/api/http-client.api @@ -425,7 +425,7 @@ public final class aws/smithy/kotlin/runtime/http/interceptors/ResponseLengthVal } public final class aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsFailureException : java/lang/Exception { - public fun ()V + public fun (Ljava/lang/String;)V } public final class aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterceptor : aws/smithy/kotlin/runtime/client/Interceptor { @@ -452,7 +452,7 @@ public final class aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterce } public final class aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsSuccessException : java/lang/Exception { - public fun ()V + public fun (Ljava/lang/String;)V } public final class aws/smithy/kotlin/runtime/http/middleware/DefaultValidateResponse : aws/smithy/kotlin/runtime/http/operation/ReceiveMiddleware { diff --git a/runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterceptor.kt b/runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterceptor.kt index 63848ffe24..8c53468de3 100644 --- a/runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterceptor.kt +++ b/runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterceptor.kt @@ -16,14 +16,14 @@ public class SmokeTestsInterceptor : HttpInterceptor { override fun readBeforeDeserialization(context: ProtocolResponseInterceptorContext) { val status = context.protocolResponse.status.value when (status) { - in 400..599 -> throw SmokeTestsFailureException() - in 200..299 -> throw SmokeTestsSuccessException() - else -> throw SmokeTestsUnexpectedException() + in 400..599 -> throw SmokeTestsFailureException("Smoke test failed with HTTP status code: $status") + in 200..299 -> throw SmokeTestsSuccessException("Smoke test succeeded with HTTP status code: $status") + else -> throw SmokeTestsUnexpectedException("Smoke test returned HTTP status code: $status") } } } -@InternalApi public class SmokeTestsFailureException : Exception() +@InternalApi public class SmokeTestsFailureException(message: String) : Exception(message) -@InternalApi public class SmokeTestsSuccessException : Exception() -private class SmokeTestsUnexpectedException : Exception() +@InternalApi public class SmokeTestsSuccessException(message: String) : Exception(message) +private class SmokeTestsUnexpectedException(message: String) : Exception(message) diff --git a/runtime/runtime-core/api/runtime-core.api b/runtime/runtime-core/api/runtime-core.api index d1ba553de5..45f5ffdbe8 100644 --- a/runtime/runtime-core/api/runtime-core.api +++ b/runtime/runtime-core/api/runtime-core.api @@ -2048,6 +2048,10 @@ public final class aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctionsJVMKt public static final fun exitProcess (I)Ljava/lang/Void; } +public final class aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctionsKt { + public static final fun printExceptionStackTrace (Ljava/lang/Exception;)V +} + public final class aws/smithy/kotlin/runtime/text/Scanner { public fun (Ljava/lang/String;)V public final fun getText ()Ljava/lang/String; diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctions.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctions.kt index f996632e99..6e2e51b2d1 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctions.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctions.kt @@ -1,3 +1,19 @@ package aws.smithy.kotlin.runtime.smoketests public expect fun exitProcess(status: Int): Nothing + +/** + * Prints an exceptions stack trace using test anything protocol (TAP) format e.g. + * + * #java.lang.ArithmeticException: / by zero + * # at FileKt.main(File.kt:3) + * # at FileKt.main(File.kt) + * # at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + * # at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) + * # at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) + * # at java.base/java.lang.reflect.Method.invoke(Unknown Source) + * # at executors.JavaRunnerExecutor$Companion.main(JavaRunnerExecutor.kt:27) + * # at executors.JavaRunnerExecutor.main(JavaRunnerExecutor.kt) + */ +public fun printExceptionStackTrace(exception: Exception): Unit = + println(exception.stackTraceToString().split("\n").joinToString("\n") { "#$it" }) From 31c0a8f32ec7cda259c3118b33e39e64f2b36d94 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 9 Oct 2024 09:30:08 -0400 Subject: [PATCH 03/16] Changelog --- .changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json diff --git a/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json b/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json new file mode 100644 index 0000000000..6571cee336 --- /dev/null +++ b/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json @@ -0,0 +1,5 @@ +{ + "id": "c376a9ee-568d-4638-8f4f-2e9a54f2869c", + "type": "misc", + "description": "Better smoke tests runner logging - Failed smoke tests now print exception stack trace" +} \ No newline at end of file From 2c6edb6903562b7abaeeb812c59e919121676d85 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 9 Oct 2024 10:07:18 -0400 Subject: [PATCH 04/16] Fix api breakage --- runtime/protocol/http-client/api/http-client.api | 2 ++ .../runtime/http/interceptors/SmokeTestsInterceptor.kt | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/runtime/protocol/http-client/api/http-client.api b/runtime/protocol/http-client/api/http-client.api index 7e22ab9c6b..6e91f528f2 100644 --- a/runtime/protocol/http-client/api/http-client.api +++ b/runtime/protocol/http-client/api/http-client.api @@ -425,6 +425,7 @@ public final class aws/smithy/kotlin/runtime/http/interceptors/ResponseLengthVal } public final class aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsFailureException : java/lang/Exception { + public fun ()V public fun (Ljava/lang/String;)V } @@ -452,6 +453,7 @@ public final class aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterce } public final class aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsSuccessException : java/lang/Exception { + public fun ()V public fun (Ljava/lang/String;)V } diff --git a/runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterceptor.kt b/runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterceptor.kt index 8c53468de3..c8d6012d6d 100644 --- a/runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterceptor.kt +++ b/runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/interceptors/SmokeTestsInterceptor.kt @@ -23,7 +23,12 @@ public class SmokeTestsInterceptor : HttpInterceptor { } } -@InternalApi public class SmokeTestsFailureException(message: String) : Exception(message) +@InternalApi public class SmokeTestsFailureException(message: String) : Exception(message) { + public constructor() : this("Smoke test failed with HTTP status code in the inclusive range: 400-599") +} + +@InternalApi public class SmokeTestsSuccessException(message: String) : Exception(message) { + public constructor() : this("Smoke test succeeded with HTTP status code in the inclusive range: 200-599") +} -@InternalApi public class SmokeTestsSuccessException(message: String) : Exception(message) private class SmokeTestsUnexpectedException(message: String) : Exception(message) From 73d7badfdf0ed1f4d0785506ddef41ddc74c8187 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 9 Oct 2024 10:11:32 -0400 Subject: [PATCH 05/16] Update changelog --- .changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json b/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json index 6571cee336..8697d810d5 100644 --- a/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json +++ b/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json @@ -1,5 +1,5 @@ { "id": "c376a9ee-568d-4638-8f4f-2e9a54f2869c", "type": "misc", - "description": "Better smoke tests runner logging - Failed smoke tests now print exception stack trace" + "description": "Failed smoke tests now print exception stack trace" } \ No newline at end of file From 434eb22d8acbefe776d464a13316d6fd50da3b3c Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 9 Oct 2024 10:15:59 -0400 Subject: [PATCH 06/16] Update changelog again --- .changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json b/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json index 8697d810d5..338050231e 100644 --- a/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json +++ b/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json @@ -1,5 +1,5 @@ { "id": "c376a9ee-568d-4638-8f4f-2e9a54f2869c", - "type": "misc", + "type": "feature", "description": "Failed smoke tests now print exception stack trace" } \ No newline at end of file From 2f47ed39b32ff7386c005b2198f9a4ea0a9ad7a6 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 9 Oct 2024 11:03:42 -0400 Subject: [PATCH 07/16] Fix bug caused by smithy test case params not being nullable --- .../rendering/smoketests/SmokeTestsRunnerGenerator.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index f2651da97d..cdfafb7d46 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -213,8 +213,10 @@ class SmokeTestsRunnerGenerator( writer.withBlock(".#T { client ->", "}", RuntimeTypes.Core.IO.use) { withBlock("client.#L(", ")", operation.defaultName()) { withBlock("#L {", "}", operationSymbol) { - testCase.params.get().members.forEach { member -> - write("#L = #L", member.key.value.toCamelCase(), member.value.format()) + if (testCase.params.isPresent) { + testCase.params.get().members.forEach { member -> + write("#L = #L", member.key.value.toCamelCase(), member.value.format()) + } } } } From e7ac93fd4cb005f747b42182036459f6ec92188b Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 30 Oct 2024 11:07:19 -0400 Subject: [PATCH 08/16] Checkpoint for smoke tests code generation bug fixes --- .../smoketests/SmokeTestsRunnerGenerator.kt | 91 +++++++++++++++---- 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index cdfafb7d46..c6dc5ea070 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -8,17 +8,24 @@ import software.amazon.smithy.kotlin.codegen.model.getTrait import software.amazon.smithy.kotlin.codegen.model.hasTrait import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointParametersGenerator import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointProviderGenerator +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.ParamName +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.ParamShape +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.Parameter import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestUriValue.EndpointParameters import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestUriValue.EndpointProvider import software.amazon.smithy.kotlin.codegen.rendering.util.format import software.amazon.smithy.kotlin.codegen.utils.dq import software.amazon.smithy.kotlin.codegen.utils.toCamelCase import software.amazon.smithy.kotlin.codegen.utils.topDownOperations +import software.amazon.smithy.model.node.Node +import software.amazon.smithy.model.node.StringNode import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.smoketests.traits.SmokeTestCase import software.amazon.smithy.smoketests.traits.SmokeTestsTrait import kotlin.jvm.optionals.getOrNull +// TODO: Organize all these section IDs object SmokeTestsRunner : SectionId object SmokeTestAdditionalEnvVars : SectionId object SmokeTestDefaultConfig : SectionId @@ -39,6 +46,12 @@ object SmokeTestUriValue : SectionId { val EndpointParameters: SectionKey = SectionKey("EndpointParameters") } +object Param : SectionId { + val ParamShape: SectionKey = SectionKey("SmokeTestsOperationParamKey2") // TODO: Rename section keys + val Parameter: SectionKey = SectionKey("SmokeTestsOperationParamKey3") + val ParamName: SectionKey = SectionKey("SmokeTestsOperationParamKey4") +} + const val SKIP_TAGS = "AWS_SMOKE_TEST_SKIP_TAGS" const val SERVICE_FILTER = "AWS_SMOKE_TEST_SERVICE_IDS" @@ -118,7 +131,7 @@ class SmokeTestsRunnerGenerator( renderClient(testCase) renderOperation(operation, testCase) } - withBlock("catch (e: Exception) {", "}") { + withBlock("catch (exception: Exception) {", "}") { renderCatchBlock(testCase) } } @@ -128,6 +141,7 @@ class SmokeTestsRunnerGenerator( writer.withInlineBlock("#L {", "}", service) { if (testCase.vendorParams.isPresent) { testCase.vendorParams.get().members.forEach { vendorParam -> + // TODO: Fix this to only use two sections when (vendorParam.key.value) { "region" -> { writeInline("#L = ", vendorParam.key.value.toCamelCase()) @@ -213,33 +227,56 @@ class SmokeTestsRunnerGenerator( writer.withBlock(".#T { client ->", "}", RuntimeTypes.Core.IO.use) { withBlock("client.#L(", ")", operation.defaultName()) { withBlock("#L {", "}", operationSymbol) { - if (testCase.params.isPresent) { - testCase.params.get().members.forEach { member -> - write("#L = #L", member.key.value.toCamelCase(), member.value.format()) - } - } + renderOperationParameters(operation, testCase) } } } } + private fun renderOperationParameters(operation: OperationShape, testCase: SmokeTestCase) { + if (!testCase.operationParametersArePresent) return + + val paramsToShapes = mapOperationParametersToModeledShapes(operation) + + testCase.operationParameters.forEach { param -> + val name = param.key.value.toCamelCase() + val value = param.value.format() + + writer.writeInline("#S = ", name) + writer.declareSection( + Param, + mapOf( + ParamName to name, + ParamShape to paramsToShapes[name], + Parameter to param.value, + ), + ) { + writer.write("#L", value ) + } + } + } + private fun renderCatchBlock(testCase: SmokeTestCase) { - val expected = if (testCase.expectation.isFailure) { + val expectedException = if (testCase.expectation.isFailure) { getFailureCriterion(testCase) } else { RuntimeTypes.HttpClient.Interceptors.SmokeTestsSuccessException } - writer.write("val success = e is #T", expected) - writer.write("val status = if (success) #S else #S", "ok", "not ok") + writer.write("val success: Boolean = exception is #T", expectedException) + writer.write("val status: String = if (success) #S else #S", "ok", "not ok") + printTestResult( sdkId.filter { !it.isWhitespace() }, testCase.id, testCase.expectation.isFailure, writer, ) - writer.write("if (!success) #T(e)", RuntimeTypes.Core.SmokeTests.printExceptionStackTrace) - writer.write("if (!success) exitCode = 1") + + writer.withBlock("if (!success) {", "}") { + write("#T(exception)", RuntimeTypes.Core.SmokeTests.printExceptionStackTrace) + write("exitCode = 1") + } } /** @@ -267,10 +304,30 @@ class SmokeTestsRunnerGenerator( val testResult = "$status $service $testCase - $expectation $directive" writer.write("println(#S)", testResult) } -} -/** - * Derives a function name for a [SmokeTestCase] - */ -private val SmokeTestCase.functionName: String - get() = this.id.toCamelCase() + /** + * TODO: + */ + private fun mapOperationParametersToModeledShapes(operation: OperationShape): Map = + model.getShape(operation.inputShape).get().allMembers.map { (key, value) -> + key.toCamelCase() to model.getShape(value.target).get() + }.toMap() + + /** + * Derives a function name for a [SmokeTestCase] + */ + private val SmokeTestCase.functionName: String + get() = this.id.toCamelCase() + + /** + * TODO: + */ + private val SmokeTestCase.operationParameters: Map + get() = this.params.get().members + + /** + * TODO: + */ + private val SmokeTestCase.operationParametersArePresent: Boolean + get() = this.params.isPresent +} From b298270470b4e50db2990639fafd8a1951f4c999 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Fri, 1 Nov 2024 10:37:31 -0400 Subject: [PATCH 09/16] Checkpoint --- .../smoketests/SmokeTestsRunnerGenerator.kt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index c6dc5ea070..90cd33615e 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -1,6 +1,7 @@ package software.amazon.smithy.kotlin.codegen.rendering.smoketests import software.amazon.smithy.codegen.core.Symbol +import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.kotlin.codegen.core.* import software.amazon.smithy.kotlin.codegen.integration.SectionId import software.amazon.smithy.kotlin.codegen.integration.SectionKey @@ -11,6 +12,7 @@ import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointProvide import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.ParamName import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.ParamShape import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.Parameter +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.SymbolProvider import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestUriValue.EndpointParameters import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestUriValue.EndpointProvider import software.amazon.smithy.kotlin.codegen.rendering.util.format @@ -50,6 +52,7 @@ object Param : SectionId { val ParamShape: SectionKey = SectionKey("SmokeTestsOperationParamKey2") // TODO: Rename section keys val Parameter: SectionKey = SectionKey("SmokeTestsOperationParamKey3") val ParamName: SectionKey = SectionKey("SmokeTestsOperationParamKey4") + val SymbolProvider: SectionKey = SectionKey("SmokeTestsOperationParamKey5") } const val SKIP_TAGS = "AWS_SMOKE_TEST_SKIP_TAGS" @@ -242,13 +245,15 @@ class SmokeTestsRunnerGenerator( val name = param.key.value.toCamelCase() val value = param.value.format() - writer.writeInline("#S = ", name) - writer.declareSection( + writer.writeInline("#L = ", name) + + writer.declareSection( // TODO: Finish this Param, mapOf( ParamName to name, ParamShape to paramsToShapes[name], Parameter to param.value, + SymbolProvider to symbolProvider, ), ) { writer.write("#L", value ) @@ -306,7 +311,7 @@ class SmokeTestsRunnerGenerator( } /** - * TODO: + * Maps an operations parameters to their shapes */ private fun mapOperationParametersToModeledShapes(operation: OperationShape): Map = model.getShape(operation.inputShape).get().allMembers.map { (key, value) -> @@ -319,15 +324,9 @@ class SmokeTestsRunnerGenerator( private val SmokeTestCase.functionName: String get() = this.id.toCamelCase() - /** - * TODO: - */ private val SmokeTestCase.operationParameters: Map get() = this.params.get().members - /** - * TODO: - */ private val SmokeTestCase.operationParametersArePresent: Boolean get() = this.params.isPresent } From 5442f76a8ed94341202bf8cb50e8970251835247 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Tue, 5 Nov 2024 00:45:23 -0500 Subject: [PATCH 10/16] PR feedback and added more robust operation parameter renderer --- .changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json diff --git a/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json b/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json deleted file mode 100644 index 338050231e..0000000000 --- a/.changes/c376a9ee-568d-4638-8f4f-2e9a54f2869c.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "c376a9ee-568d-4638-8f4f-2e9a54f2869c", - "type": "feature", - "description": "Failed smoke tests now print exception stack trace" -} \ No newline at end of file From ffa8c5038ed2d2959e7cb5ffedc7f1aa3d3cf15c Mon Sep 17 00:00:00 2001 From: 0marperez Date: Tue, 5 Nov 2024 00:46:46 -0500 Subject: [PATCH 11/16] PR feedback and added more robust operation parameter renderer --- .../smoketests/SmokeTestsRunnerGenerator.kt | 337 +++++++++--------- .../SmokeTestsRunnerGeneratorTest.kt | 43 ++- 2 files changed, 194 insertions(+), 186 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index 90cd33615e..cfd0e2502c 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -1,63 +1,29 @@ package software.amazon.smithy.kotlin.codegen.rendering.smoketests import software.amazon.smithy.codegen.core.Symbol -import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.kotlin.codegen.core.* import software.amazon.smithy.kotlin.codegen.integration.SectionId import software.amazon.smithy.kotlin.codegen.integration.SectionKey import software.amazon.smithy.kotlin.codegen.model.getTrait import software.amazon.smithy.kotlin.codegen.model.hasTrait +import software.amazon.smithy.kotlin.codegen.model.isStringEnumShape import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointParametersGenerator import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointProviderGenerator -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.ParamName -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.ParamShape -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.Parameter -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.Param.SymbolProvider -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestUriValue.EndpointParameters -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestUriValue.EndpointProvider +import software.amazon.smithy.kotlin.codegen.rendering.protocol.stringToNumber +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsRunnerGenerator.ClientConfig.EndpointParams +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsRunnerGenerator.ClientConfig.EndpointProvider +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsRunnerGenerator.ClientConfig.Name +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsRunnerGenerator.ClientConfig.Value import software.amazon.smithy.kotlin.codegen.rendering.util.format import software.amazon.smithy.kotlin.codegen.utils.dq import software.amazon.smithy.kotlin.codegen.utils.toCamelCase import software.amazon.smithy.kotlin.codegen.utils.topDownOperations -import software.amazon.smithy.model.node.Node -import software.amazon.smithy.model.node.StringNode -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.Shape +import software.amazon.smithy.model.node.* +import software.amazon.smithy.model.shapes.* import software.amazon.smithy.smoketests.traits.SmokeTestCase import software.amazon.smithy.smoketests.traits.SmokeTestsTrait import kotlin.jvm.optionals.getOrNull -// TODO: Organize all these section IDs -object SmokeTestsRunner : SectionId -object SmokeTestAdditionalEnvVars : SectionId -object SmokeTestDefaultConfig : SectionId -object SmokeTestRegionDefault : SectionId -object SmokeTestUseDualStackKey : SectionId -object SmokeTestSigv4aRegionSetKey : SectionId -object SmokeTestSigv4aRegionSetValue : SectionId -object SmokeTestAccountIdBasedRoutingKey : SectionId -object SmokeTestAccountIdBasedRoutingValue : SectionId -object SmokeTestHttpEngineOverride : SectionId -object SmokeTestUseAccelerateKey : SectionId -object SmokeTestUseMultiRegionAccessPointsKey : SectionId -object SmokeTestUseMultiRegionAccessPointsValue : SectionId -object SmokeTestUseGlobalEndpoint : SectionId -object SmokeTestUriKey : SectionId -object SmokeTestUriValue : SectionId { - val EndpointProvider: SectionKey = SectionKey("EndpointProvider") - val EndpointParameters: SectionKey = SectionKey("EndpointParameters") -} - -object Param : SectionId { - val ParamShape: SectionKey = SectionKey("SmokeTestsOperationParamKey2") // TODO: Rename section keys - val Parameter: SectionKey = SectionKey("SmokeTestsOperationParamKey3") - val ParamName: SectionKey = SectionKey("SmokeTestsOperationParamKey4") - val SymbolProvider: SectionKey = SectionKey("SmokeTestsOperationParamKey5") -} - -const val SKIP_TAGS = "AWS_SMOKE_TEST_SKIP_TAGS" -const val SERVICE_FILTER = "AWS_SMOKE_TEST_SERVICE_IDS" - /** * Renders smoke tests runner for a service */ @@ -65,37 +31,45 @@ class SmokeTestsRunnerGenerator( private val writer: KotlinWriter, ctx: CodegenContext, ) { - private val model = ctx.model - private val settings = ctx.settings - private val sdkId = settings.sdkId - private val symbolProvider = ctx.symbolProvider - private val service = symbolProvider.toSymbol(model.expectShape(settings.service)) - private val operations = model.topDownOperations(settings.service).filter { it.hasTrait() } - internal fun render() { - writer.declareSection(SmokeTestsRunner) { - write("private var exitCode = 0") - write( - "private val skipTags = #T.System.getenv(#S)?.let { it.split(#S).map { it.trim() }.toSet() } ?: emptySet()", - RuntimeTypes.Core.Utils.PlatformProvider, - SKIP_TAGS, - ",", - ) - write( - "private val serviceFilter = #T.System.getenv(#S)?.let { it.split(#S).map { it.trim() }.toSet() } ?: emptySet()", - RuntimeTypes.Core.Utils.PlatformProvider, - SERVICE_FILTER, - ",", - ) - declareSection(SmokeTestAdditionalEnvVars) - write("") - withBlock("public suspend fun main() {", "}") { - renderFunctionCalls() - write("#T(exitCode)", RuntimeTypes.Core.SmokeTests.exitProcess) - } - write("") - renderFunctions() + writer.write("private var exitCode = 0") + renderEnvironmentVariables() + writer.declareSection(AdditionalEnvironmentVariables) + writer.write("") + writer.withBlock("public suspend fun main() {", "}") { + renderFunctionCalls() + write("#T(exitCode)", RuntimeTypes.Core.SmokeTests.exitProcess) + } + writer.write("") + renderFunctions() + } + + private fun renderEnvironmentVariables() { + // Skip tags + writer.writeInline( + "private val skipTags = #T.System.getenv(", + RuntimeTypes.Core.Utils.PlatformProvider, + ) + writer.declareSection(SkipTags) { + writer.writeInline("#S", SKIP_TAGS) + } + writer.write( + ")?.let { it.split(#S).map { it.trim() }.toSet() } ?: emptySet()", + ",", + ) + + // Service filter + writer.writeInline( + "private val serviceFilter = #T.System.getenv(", + RuntimeTypes.Core.Utils.PlatformProvider, + ) + writer.declareSection(ServiceFilter) { + writer.writeInline("#S", SERVICE_FILTER) } + writer.write( + ")?.let { it.split(#S).map { it.trim() }.toSet() } ?: emptySet()", + ",", + ) } private fun renderFunctionCalls() { @@ -142,85 +116,37 @@ class SmokeTestsRunnerGenerator( private fun renderClient(testCase: SmokeTestCase) { writer.withInlineBlock("#L {", "}", service) { - if (testCase.vendorParams.isPresent) { - testCase.vendorParams.get().members.forEach { vendorParam -> - // TODO: Fix this to only use two sections - when (vendorParam.key.value) { - "region" -> { - writeInline("#L = ", vendorParam.key.value.toCamelCase()) - declareSection(SmokeTestRegionDefault) - write("#L", vendorParam.value.format()) - } - "sigv4aRegionSet" -> { - declareSection(SmokeTestSigv4aRegionSetKey) { - writeInline("#L", vendorParam.key.value.toCamelCase()) - } - writeInline(" = ") - declareSection(SmokeTestSigv4aRegionSetValue) { - write("#L", vendorParam.value.format()) - } - } - "uri" -> { - declareSection(SmokeTestUriKey) { - writeInline("#L", vendorParam.key.value.toCamelCase()) - } - writeInline(" = ") - declareSection( - SmokeTestUriValue, - mapOf( - EndpointProvider to EndpointProviderGenerator.getSymbol(settings), - EndpointParameters to EndpointParametersGenerator.getSymbol(settings), - ), - ) { - write("#L", vendorParam.value.format()) - } - } - "useDualstack" -> { - declareSection(SmokeTestUseDualStackKey) { - writeInline("#L", vendorParam.key.value.toCamelCase()) - } - write(" = #L", vendorParam.value.format()) - } - "useAccountIdRouting" -> { - declareSection(SmokeTestAccountIdBasedRoutingKey) { - writeInline("#L", vendorParam.key.value.toCamelCase()) - } - writeInline(" = ") - declareSection(SmokeTestAccountIdBasedRoutingValue) { - write("#L", vendorParam.value.format()) - } - } - "useAccelerate" -> { - declareSection(SmokeTestUseAccelerateKey) { - writeInline("#L", vendorParam.key.value.toCamelCase()) - } - write(" = #L", vendorParam.value.format()) - } - "useMultiRegionAccessPoints" -> { - declareSection(SmokeTestUseMultiRegionAccessPointsKey) { - writeInline("#L", vendorParam.key.value.toCamelCase()) - } - writeInline(" = ") - declareSection(SmokeTestUseMultiRegionAccessPointsValue) { - write("#L", vendorParam.value.format()) - } - } - "useGlobalEndpoint" -> { - declareSection(SmokeTestUseGlobalEndpoint) { - write("#L = #L", vendorParam.key.value.toCamelCase(), vendorParam.value.format()) - } - } - else -> write("#L = #L", vendorParam.key.value.toCamelCase(), vendorParam.value.format()) - } - } - } else { - declareSection(SmokeTestDefaultConfig) - } - val expectingSpecificError = testCase.expectation.failure.getOrNull()?.errorId?.getOrNull() != null - if (!expectingSpecificError) { - write("interceptors.add(#T())", RuntimeTypes.HttpClient.Interceptors.SmokeTestsInterceptor) + renderClientConfig(testCase) + } + } + + private fun renderClientConfig(testCase: SmokeTestCase) { + if (!testCase.expectingSpecificError) { + writer.write("interceptors.add(#T())", RuntimeTypes.HttpClient.Interceptors.SmokeTestsInterceptor) + } + + writer.declareSection(HttpEngineOverride) + + if (!testCase.hasClientConfig) { + writer.declareSection(DefaultClientConfig) + return + } + + testCase.clientConfig!!.forEach { config -> + val name = config.key.value.toCamelCase() + val value = config.value.format() + + writer.declareSection( + ClientConfig, + mapOf( + Name to name, + Value to value, + EndpointProvider to EndpointProviderGenerator.getSymbol(settings), + EndpointParams to EndpointParametersGenerator.getSymbol(settings), + ), + ) { + writer.writeInline("#L = #L", name, value) } - declareSection(SmokeTestHttpEngineOverride) } } @@ -237,27 +163,14 @@ class SmokeTestsRunnerGenerator( } private fun renderOperationParameters(operation: OperationShape, testCase: SmokeTestCase) { - if (!testCase.operationParametersArePresent) return + if (!testCase.hasOperationParameters) return val paramsToShapes = mapOperationParametersToModeledShapes(operation) testCase.operationParameters.forEach { param -> - val name = param.key.value.toCamelCase() - val value = param.value.format() - - writer.writeInline("#L = ", name) - - writer.declareSection( // TODO: Finish this - Param, - mapOf( - ParamName to name, - ParamShape to paramsToShapes[name], - Parameter to param.value, - SymbolProvider to symbolProvider, - ), - ) { - writer.write("#L", value ) - } + val paramName = param.key.value.toCamelCase() + writer.writeInline("#L = ", paramName) + renderOperationParameter(paramName, param.value, paramsToShapes, testCase) } } @@ -284,6 +197,38 @@ class SmokeTestsRunnerGenerator( } } + // Helpers + /** + * Renders a [SmokeTestCase] operation parameter + */ + private fun renderOperationParameter( + paramName: String, + node: Node, + shapes: Map, + testCase: SmokeTestCase, + ): String { + val shape = shapes[paramName] ?: throw Exception("Unable to find shape for operation parameter '$paramName' in smoke test '${testCase.functionName}'") + when { + // String enum + node is StringNode && shape.isStringEnumShape -> { + val enumSymbol = symbolProvider.toSymbol(shape) + val enumValue = node.value + writer.write("#T.#L", enumSymbol, enumValue) + } + // Int enum + node is NumberNode && shape is IntEnumShape -> { + val enumSymbol = symbolProvider.toSymbol(shape) + val enumValue = node.format() + writer.write("#T.fromValue(#L.toInt())", enumSymbol, enumValue) + } + // Number + node is NumberNode && shape is NumberShape -> writer.write("#L.#L", node.format(), stringToNumber(shape)) + // Everything else + else -> writer.write("#L", node.format()) + } + return writer.rawString() + } + /** * Tries to get the specific exception required in the failure criterion of a test. * If no specific exception is required we default to the generic smoke tests failure exception. @@ -324,9 +269,67 @@ class SmokeTestsRunnerGenerator( private val SmokeTestCase.functionName: String get() = this.id.toCamelCase() + /** + * Get the operation parameters for a [SmokeTestCase] + */ private val SmokeTestCase.operationParameters: Map get() = this.params.get().members - private val SmokeTestCase.operationParametersArePresent: Boolean + /** + * Checks if there are operation parameters for a [SmokeTestCase] + */ + private val SmokeTestCase.hasOperationParameters: Boolean get() = this.params.isPresent + + /** + * Check if a [SmokeTestCase] is expecting a specific error + */ + private val SmokeTestCase.expectingSpecificError: Boolean + get() = this.expectation.failure.getOrNull()?.errorId?.getOrNull() != null + + /** + * Checks if a [SmokeTestCase] requires client configuration + */ + private val SmokeTestCase.hasClientConfig: Boolean + get() = this.vendorParams.isPresent + + /** + * Get the client configuration required for a [SmokeTestCase] + */ + private val SmokeTestCase.clientConfig: MutableMap? + get() = this.vendorParams.get().members + + // Section IDs + object AdditionalEnvironmentVariables : SectionId + object DefaultClientConfig : SectionId + object HttpEngineOverride : SectionId + object ServiceFilter : SectionId + object SkipTags : SectionId + object ClientConfig : SectionId { + val Name: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigName") + val Value: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigValue") + val EndpointProvider: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestEndpointProvider") + val EndpointParams: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientEndpointParams") + } + + // Constants + private val model = ctx.model + private val settings = ctx.settings + private val sdkId = settings.sdkId + private val symbolProvider = ctx.symbolProvider + private val service = symbolProvider.toSymbol(model.expectShape(settings.service)) + private val operations = model.topDownOperations(settings.service).filter { it.hasTrait() } } + +/** + * Env var for smoke test runners. + * Should be a comma-delimited list of strings that correspond to tags on the test cases. + * If a test case is tagged with one of the tags indicated by SMOKE_TEST_SKIP_TAGS, it MUST be skipped by the smoke test runner. + */ +const val SKIP_TAGS = "SMOKE_TEST_SKIP_TAGS" + +/** + * Env var for smoke test runners. + * Should be a comma-separated list of service identifiers to test. + */ +const val SERVICE_FILTER = "SMOKE_TEST_SERVICE_IDS" diff --git a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGeneratorTest.kt b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGeneratorTest.kt index 540a1d3fec..0f1d469eb5 100644 --- a/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGeneratorTest.kt +++ b/codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGeneratorTest.kt @@ -74,8 +74,8 @@ class SmokeTestsRunnerGeneratorTest { generatedCode.shouldContainOnlyOnceWithDiff( """ private var exitCode = 0 - private val skipTags = PlatformProvider.System.getenv("AWS_SMOKE_TEST_SKIP_TAGS")?.let { it.split(",").map { it.trim() }.toSet() } ?: emptySet() - private val serviceFilter = PlatformProvider.System.getenv("AWS_SMOKE_TEST_SERVICE_IDS")?.let { it.split(",").map { it.trim() }.toSet() } + private val skipTags = PlatformProvider.System.getenv("SMOKE_TEST_SKIP_TAGS")?.let { it.split(",").map { it.trim() }.toSet() } ?: emptySet() + private val serviceFilter = PlatformProvider.System.getenv("SMOKE_TEST_SERVICE_IDS")?.let { it.split(",").map { it.trim() }.toSet() } """.trimIndent(), ) } @@ -107,9 +107,8 @@ class SmokeTestsRunnerGeneratorTest { try { com.test.TestClient { - region = "eu-central-1" interceptors.add(SmokeTestsInterceptor()) - + region = "eu-central-1" }.use { client -> client.testOperation( com.test.model.TestOperationRequest { @@ -118,12 +117,14 @@ class SmokeTestsRunnerGeneratorTest { ) } - } catch (e: Exception) { - val success = e is SmokeTestsSuccessException - val status = if (success) "ok" else "not ok" + } catch (exception: Exception) { + val success: Boolean = exception is SmokeTestsSuccessException + val status: String = if (success) "ok" else "not ok" println("${'$'}status Test SuccessTest - no error expected from service ") - if (!success) printExceptionStackTrace(e) - if (!success) exitCode = 1 + if (!success) { + printExceptionStackTrace(exception) + exitCode = 1 + } } } """.trimIndent(), @@ -152,12 +153,14 @@ class SmokeTestsRunnerGeneratorTest { ) } - } catch (e: Exception) { - val success = e is InvalidMessageError - val status = if (success) "ok" else "not ok" + } catch (exception: Exception) { + val success: Boolean = exception is InvalidMessageError + val status: String = if (success) "ok" else "not ok" println("${'$'}status Test InvalidMessageErrorTest - error expected from service ") - if (!success) printExceptionStackTrace(e) - if (!success) exitCode = 1 + if (!success) { + printExceptionStackTrace(exception) + exitCode = 1 + } } } """.trimIndent(), @@ -187,12 +190,14 @@ class SmokeTestsRunnerGeneratorTest { ) } - } catch (e: Exception) { - val success = e is SmokeTestsFailureException - val status = if (success) "ok" else "not ok" + } catch (exception: Exception) { + val success: Boolean = exception is SmokeTestsFailureException + val status: String = if (success) "ok" else "not ok" println("${'$'}status Test FailureTest - error expected from service ") - if (!success) printExceptionStackTrace(e) - if (!success) exitCode = 1 + if (!success) { + printExceptionStackTrace(exception) + exitCode = 1 + } } } """.trimIndent(), From 1336afb9f6351ad37b33f9d98ec8252453455242 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Tue, 5 Nov 2024 09:50:36 -0500 Subject: [PATCH 12/16] Fix enums --- .../codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index cfd0e2502c..d99f8e0698 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -17,6 +17,7 @@ import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsRunn import software.amazon.smithy.kotlin.codegen.rendering.util.format import software.amazon.smithy.kotlin.codegen.utils.dq import software.amazon.smithy.kotlin.codegen.utils.toCamelCase +import software.amazon.smithy.kotlin.codegen.utils.toPascalCase import software.amazon.smithy.kotlin.codegen.utils.topDownOperations import software.amazon.smithy.model.node.* import software.amazon.smithy.model.shapes.* @@ -212,7 +213,7 @@ class SmokeTestsRunnerGenerator( // String enum node is StringNode && shape.isStringEnumShape -> { val enumSymbol = symbolProvider.toSymbol(shape) - val enumValue = node.value + val enumValue = node.value.toPascalCase() writer.write("#T.#L", enumSymbol, enumValue) } // Int enum From 82c46e9c5b65865ab7cd9d7a9f45caebdcc85bdb Mon Sep 17 00:00:00 2001 From: 0marperez Date: Tue, 5 Nov 2024 11:26:29 -0500 Subject: [PATCH 13/16] Fix objects and lists --- .../smoketests/SmokeTestsRunnerGenerator.kt | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index d99f8e0698..edd8ae51bc 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -4,6 +4,7 @@ import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.kotlin.codegen.core.* import software.amazon.smithy.kotlin.codegen.integration.SectionId import software.amazon.smithy.kotlin.codegen.integration.SectionKey +import software.amazon.smithy.kotlin.codegen.model.expectShape import software.amazon.smithy.kotlin.codegen.model.getTrait import software.amazon.smithy.kotlin.codegen.model.hasTrait import software.amazon.smithy.kotlin.codegen.model.isStringEnumShape @@ -207,8 +208,9 @@ class SmokeTestsRunnerGenerator( node: Node, shapes: Map, testCase: SmokeTestCase, - ): String { - val shape = shapes[paramName] ?: throw Exception("Unable to find shape for operation parameter '$paramName' in smoke test '${testCase.functionName}'") + shapeOverride: Shape? = null, + ) { + val shape = shapeOverride ?: shapes[paramName] ?: throw Exception("Unable to find shape for operation parameter '$paramName' in smoke test '${testCase.functionName}'.") when { // String enum node is StringNode && shape.isStringEnumShape -> { @@ -224,10 +226,30 @@ class SmokeTestsRunnerGenerator( } // Number node is NumberNode && shape is NumberShape -> writer.write("#L.#L", node.format(), stringToNumber(shape)) + // Object + node is ObjectNode -> { + val shapeSymbol = symbolProvider.toSymbol(shape) + writer.withBlock("#T {", "}", shapeSymbol) { + node.members.forEach { member -> + val memberName = member.key.value.toCamelCase() + val memberShape = shape.allMembers[member.key.value] ?: throw Exception("Unable to find shape for operation parameter '$paramName' in smoke test '${testCase.functionName}'.") + writer.writeInline("#L = ", memberName) + renderOperationParameter(memberName, member.value, mapOf(memberName to memberShape), testCase) + } + } + } + // List + node is ArrayNode && shape is CollectionShape -> { + writer.withBlock("listOf(", ")") { + node.elements.forEach { element -> + renderOperationParameter(paramName, element, mapOf(), testCase, model.expectShape(shape.member.target)) + writer.write(",") + } + } + } // Everything else else -> writer.write("#L", node.format()) } - return writer.rawString() } /** From d3abccaad78f554368ab636230dd1643c08140cc Mon Sep 17 00:00:00 2001 From: 0marperez Date: Tue, 5 Nov 2024 12:31:41 -0500 Subject: [PATCH 14/16] Activate smoke tests integration --- ...e.amazon.smithy.kotlin.codegen.integration.KotlinIntegration | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/resources/META-INF/services/software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration b/codegen/smithy-kotlin-codegen/src/main/resources/META-INF/services/software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration index b4aac4e4f6..0d02b51187 100644 --- a/codegen/smithy-kotlin-codegen/src/main/resources/META-INF/services/software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration +++ b/codegen/smithy-kotlin-codegen/src/main/resources/META-INF/services/software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration @@ -12,4 +12,4 @@ software.amazon.smithy.kotlin.codegen.rendering.endpoints.discovery.EndpointDisc software.amazon.smithy.kotlin.codegen.rendering.endpoints.SdkEndpointBuiltinIntegration software.amazon.smithy.kotlin.codegen.rendering.compression.RequestCompressionIntegration software.amazon.smithy.kotlin.codegen.rendering.auth.SigV4AsymmetricAuthSchemeIntegration -# software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsIntegration +software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsIntegration From 44dfed5e6571c15b04d58634a7e6ab0a76522808 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 6 Nov 2024 10:14:56 -0500 Subject: [PATCH 15/16] PR feedback --- .../smoketests/SmokeTestsRunnerGenerator.kt | 74 +++++++++---------- .../kotlin/codegen/rendering/util/Node.kt | 2 +- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index edd8ae51bc..1fa00383e1 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -4,17 +4,16 @@ import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.kotlin.codegen.core.* import software.amazon.smithy.kotlin.codegen.integration.SectionId import software.amazon.smithy.kotlin.codegen.integration.SectionKey -import software.amazon.smithy.kotlin.codegen.model.expectShape import software.amazon.smithy.kotlin.codegen.model.getTrait import software.amazon.smithy.kotlin.codegen.model.hasTrait import software.amazon.smithy.kotlin.codegen.model.isStringEnumShape import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointParametersGenerator import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointProviderGenerator import software.amazon.smithy.kotlin.codegen.rendering.protocol.stringToNumber -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsRunnerGenerator.ClientConfig.EndpointParams -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsRunnerGenerator.ClientConfig.EndpointProvider -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsRunnerGenerator.ClientConfig.Name -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestsRunnerGenerator.ClientConfig.Value +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.ClientConfig.EndpointParams +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.ClientConfig.EndpointProvider +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.ClientConfig.Name +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.ClientConfig.Value import software.amazon.smithy.kotlin.codegen.rendering.util.format import software.amazon.smithy.kotlin.codegen.utils.dq import software.amazon.smithy.kotlin.codegen.utils.toCamelCase @@ -26,6 +25,32 @@ import software.amazon.smithy.smoketests.traits.SmokeTestCase import software.amazon.smithy.smoketests.traits.SmokeTestsTrait import kotlin.jvm.optionals.getOrNull +// Section IDs +object AdditionalEnvironmentVariables : SectionId +object DefaultClientConfig : SectionId +object HttpEngineOverride : SectionId +object ServiceFilter : SectionId +object SkipTags : SectionId +object ClientConfig : SectionId { + val Name: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigName") + val Value: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigValue") + val EndpointProvider: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestEndpointProvider") + val EndpointParams: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientEndpointParams") +} + +/** + * Env var for smoke test runners. + * Should be a comma-delimited list of strings that correspond to tags on the test cases. + * If a test case is tagged with one of the tags indicated by SMOKE_TEST_SKIP_TAGS, it MUST be skipped by the smoke test runner. + */ +const val SKIP_TAGS = "SMOKE_TEST_SKIP_TAGS" + +/** + * Env var for smoke test runners. + * Should be a comma-separated list of service identifiers to test. + */ +const val SERVICE_FILTER = "SMOKE_TEST_SERVICE_IDS" + /** * Renders smoke tests runner for a service */ @@ -172,7 +197,8 @@ class SmokeTestsRunnerGenerator( testCase.operationParameters.forEach { param -> val paramName = param.key.value.toCamelCase() writer.writeInline("#L = ", paramName) - renderOperationParameter(paramName, param.value, paramsToShapes, testCase) + val paramShape = paramsToShapes[paramName] ?: throw IllegalArgumentException("Unable to find shape for operation parameter '$paramName' in smoke test '${testCase.functionName}'.") + renderOperationParameter(paramName, param.value, paramShape, testCase) } } @@ -206,11 +232,9 @@ class SmokeTestsRunnerGenerator( private fun renderOperationParameter( paramName: String, node: Node, - shapes: Map, + shape: Shape, testCase: SmokeTestCase, - shapeOverride: Shape? = null, ) { - val shape = shapeOverride ?: shapes[paramName] ?: throw Exception("Unable to find shape for operation parameter '$paramName' in smoke test '${testCase.functionName}'.") when { // String enum node is StringNode && shape.isStringEnumShape -> { @@ -232,9 +256,9 @@ class SmokeTestsRunnerGenerator( writer.withBlock("#T {", "}", shapeSymbol) { node.members.forEach { member -> val memberName = member.key.value.toCamelCase() - val memberShape = shape.allMembers[member.key.value] ?: throw Exception("Unable to find shape for operation parameter '$paramName' in smoke test '${testCase.functionName}'.") + val memberShape = shape.allMembers[member.key.value] ?: throw IllegalArgumentException("Unable to find shape for operation parameter '$paramName' in smoke test '${testCase.functionName}'.") writer.writeInline("#L = ", memberName) - renderOperationParameter(memberName, member.value, mapOf(memberName to memberShape), testCase) + renderOperationParameter(memberName, member.value, memberShape, testCase) } } } @@ -242,7 +266,7 @@ class SmokeTestsRunnerGenerator( node is ArrayNode && shape is CollectionShape -> { writer.withBlock("listOf(", ")") { node.elements.forEach { element -> - renderOperationParameter(paramName, element, mapOf(), testCase, model.expectShape(shape.member.target)) + renderOperationParameter(paramName, element, model.expectShape(shape.member.target), testCase) writer.write(",") } } @@ -322,19 +346,6 @@ class SmokeTestsRunnerGenerator( private val SmokeTestCase.clientConfig: MutableMap? get() = this.vendorParams.get().members - // Section IDs - object AdditionalEnvironmentVariables : SectionId - object DefaultClientConfig : SectionId - object HttpEngineOverride : SectionId - object ServiceFilter : SectionId - object SkipTags : SectionId - object ClientConfig : SectionId { - val Name: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigName") - val Value: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigValue") - val EndpointProvider: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestEndpointProvider") - val EndpointParams: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientEndpointParams") - } - // Constants private val model = ctx.model private val settings = ctx.settings @@ -343,16 +354,3 @@ class SmokeTestsRunnerGenerator( private val service = symbolProvider.toSymbol(model.expectShape(settings.service)) private val operations = model.topDownOperations(settings.service).filter { it.hasTrait() } } - -/** - * Env var for smoke test runners. - * Should be a comma-delimited list of strings that correspond to tags on the test cases. - * If a test case is tagged with one of the tags indicated by SMOKE_TEST_SKIP_TAGS, it MUST be skipped by the smoke test runner. - */ -const val SKIP_TAGS = "SMOKE_TEST_SKIP_TAGS" - -/** - * Env var for smoke test runners. - * Should be a comma-separated list of service identifiers to test. - */ -const val SERVICE_FILTER = "SMOKE_TEST_SERVICE_IDS" diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/util/Node.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/util/Node.kt index 1e7d3103c8..73b9a041f9 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/util/Node.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/util/Node.kt @@ -23,5 +23,5 @@ fun Node.format(): String = when (this) { is ObjectNode -> stringMap.entries.joinToString(", ", "mapOf(", ")") { (key, value) -> "${key.dq()} to ${value.format()}" } - else -> throw Exception("Unexpected node type: $this") + else -> throw IllegalStateException("Unexpected node type: $this") } From 04933e0f25a63cafdc4a473578fd9547986751e9 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 6 Nov 2024 11:13:10 -0500 Subject: [PATCH 16/16] PR feedback #2 --- .../kotlin/codegen/core/RuntimeTypes.kt | 1 + .../smoketests/SmokeTestsRunnerGenerator.kt | 42 ++++++++++--------- runtime/runtime-core/api/runtime-core.api | 4 ++ .../runtime/smoketests/SmokeTestsFunctions.kt | 2 + 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt index 3616934407..e42612b0b5 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt @@ -117,6 +117,7 @@ object RuntimeTypes { object SmokeTests : RuntimeTypePackage(KotlinDependency.CORE, "smoketests") { val exitProcess = symbol("exitProcess") val printExceptionStackTrace = symbol("printExceptionStackTrace") + val SmokeTestsException = symbol("SmokeTestsException") } object Collections : RuntimeTypePackage(KotlinDependency.CORE, "collections") { diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt index 1fa00383e1..1b9aa80324 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/smoketests/SmokeTestsRunnerGenerator.kt @@ -10,10 +10,10 @@ import software.amazon.smithy.kotlin.codegen.model.isStringEnumShape import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointParametersGenerator import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointProviderGenerator import software.amazon.smithy.kotlin.codegen.rendering.protocol.stringToNumber -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.ClientConfig.EndpointParams -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.ClientConfig.EndpointProvider -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.ClientConfig.Name -import software.amazon.smithy.kotlin.codegen.rendering.smoketests.ClientConfig.Value +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestSectionIds.ClientConfig.EndpointParams +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestSectionIds.ClientConfig.EndpointProvider +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestSectionIds.ClientConfig.Name +import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestSectionIds.ClientConfig.Value import software.amazon.smithy.kotlin.codegen.rendering.util.format import software.amazon.smithy.kotlin.codegen.utils.dq import software.amazon.smithy.kotlin.codegen.utils.toCamelCase @@ -26,16 +26,18 @@ import software.amazon.smithy.smoketests.traits.SmokeTestsTrait import kotlin.jvm.optionals.getOrNull // Section IDs -object AdditionalEnvironmentVariables : SectionId -object DefaultClientConfig : SectionId -object HttpEngineOverride : SectionId -object ServiceFilter : SectionId -object SkipTags : SectionId -object ClientConfig : SectionId { - val Name: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigName") - val Value: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigValue") - val EndpointProvider: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestEndpointProvider") - val EndpointParams: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientEndpointParams") +object SmokeTestSectionIds { + object AdditionalEnvironmentVariables : SectionId + object DefaultClientConfig : SectionId + object HttpEngineOverride : SectionId + object ServiceFilter : SectionId + object SkipTags : SectionId + object ClientConfig : SectionId { + val Name: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigName") + val Value: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientConfigValue") + val EndpointProvider: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestEndpointProvider") + val EndpointParams: SectionKey = SectionKey("aws.smithy.kotlin#SmokeTestClientEndpointParams") + } } /** @@ -61,7 +63,7 @@ class SmokeTestsRunnerGenerator( internal fun render() { writer.write("private var exitCode = 0") renderEnvironmentVariables() - writer.declareSection(AdditionalEnvironmentVariables) + writer.declareSection(SmokeTestSectionIds.AdditionalEnvironmentVariables) writer.write("") writer.withBlock("public suspend fun main() {", "}") { renderFunctionCalls() @@ -77,7 +79,7 @@ class SmokeTestsRunnerGenerator( "private val skipTags = #T.System.getenv(", RuntimeTypes.Core.Utils.PlatformProvider, ) - writer.declareSection(SkipTags) { + writer.declareSection(SmokeTestSectionIds.SkipTags) { writer.writeInline("#S", SKIP_TAGS) } writer.write( @@ -90,7 +92,7 @@ class SmokeTestsRunnerGenerator( "private val serviceFilter = #T.System.getenv(", RuntimeTypes.Core.Utils.PlatformProvider, ) - writer.declareSection(ServiceFilter) { + writer.declareSection(SmokeTestSectionIds.ServiceFilter) { writer.writeInline("#S", SERVICE_FILTER) } writer.write( @@ -152,10 +154,10 @@ class SmokeTestsRunnerGenerator( writer.write("interceptors.add(#T())", RuntimeTypes.HttpClient.Interceptors.SmokeTestsInterceptor) } - writer.declareSection(HttpEngineOverride) + writer.declareSection(SmokeTestSectionIds.HttpEngineOverride) if (!testCase.hasClientConfig) { - writer.declareSection(DefaultClientConfig) + writer.declareSection(SmokeTestSectionIds.DefaultClientConfig) return } @@ -164,7 +166,7 @@ class SmokeTestsRunnerGenerator( val value = config.value.format() writer.declareSection( - ClientConfig, + SmokeTestSectionIds.ClientConfig, mapOf( Name to name, Value to value, diff --git a/runtime/runtime-core/api/runtime-core.api b/runtime/runtime-core/api/runtime-core.api index 04fc1721ed..237aac6f76 100644 --- a/runtime/runtime-core/api/runtime-core.api +++ b/runtime/runtime-core/api/runtime-core.api @@ -2046,6 +2046,10 @@ public final class aws/smithy/kotlin/runtime/retries/policy/SuccessAcceptor : aw public final fun getSuccess ()Z } +public final class aws/smithy/kotlin/runtime/smoketests/SmokeTestsException : java/lang/Exception { + public fun (Ljava/lang/String;)V +} + public final class aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctionsJVMKt { public static final fun exitProcess (I)Ljava/lang/Void; } diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctions.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctions.kt index 6e2e51b2d1..682817193d 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctions.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/smoketests/SmokeTestsFunctions.kt @@ -17,3 +17,5 @@ public expect fun exitProcess(status: Int): Nothing */ public fun printExceptionStackTrace(exception: Exception): Unit = println(exception.stackTraceToString().split("\n").joinToString("\n") { "#$it" }) + +public class SmokeTestsException(message: String) : Exception(message)