From 24e8ab905302b605952fd593d42dc87cb87e86b5 Mon Sep 17 00:00:00 2001 From: Ken Gilmer Date: Thu, 30 Dec 2021 16:19:26 -0800 Subject: [PATCH 1/2] Update codegen to generate base exception rather than UnknownServiceErrorException for #458 --- .../codegen/customization/s3/S3Generator.kt | 2 +- .../core/AwsHttpBindingProtocolGenerator.kt | 2 +- .../AwsHttpBindingProtocolGeneratorTest.kt | 128 ++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGeneratorTest.kt diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/s3/S3Generator.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/s3/S3Generator.kt index 4b687ef7307..46e59b06fb8 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/s3/S3Generator.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/s3/S3Generator.kt @@ -92,7 +92,7 @@ class S3Generator : RestXml() { } .dedent() .withBlock("} catch (ex: Exception) {", "}") { - withBlock("""throw #T("failed to parse response as ${ctx.protocol.name} error", ex).also {""", "}", AwsRuntimeTypes.Core.UnknownServiceErrorException) { + withBlock("""throw #T("Failed to parse response as '${ctx.protocol.name}' error", ex).also {""", "}", exceptionBaseSymbol) { write("#T(it, wrappedResponse, null)", setS3ErrorMetadata) } } diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGenerator.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGenerator.kt index f7a2ad34f12..9ea612715d4 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGenerator.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGenerator.kt @@ -136,7 +136,7 @@ abstract class AwsHttpBindingProtocolGenerator : HttpBindingProtocolGenerator() } .dedent() .withBlock("} catch (ex: Exception) {", "}") { - withBlock("""throw #T("failed to parse response as ${ctx.protocol.name} error", ex).also {""", "}", AwsRuntimeTypes.Core.UnknownServiceErrorException) { + withBlock("""throw #T("Failed to parse response as '${ctx.protocol.name}' error", ex).also {""", "}", exceptionBaseSymbol) { write("#T(it, wrappedResponse, null)", AwsRuntimeTypes.Http.setAseErrorMetadata) } } diff --git a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGeneratorTest.kt b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGeneratorTest.kt new file mode 100644 index 00000000000..eadae7b2dc7 --- /dev/null +++ b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGeneratorTest.kt @@ -0,0 +1,128 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +package aws.sdk.kotlin.codegen.protocols.core + +import software.amazon.smithy.kotlin.codegen.core.KotlinWriter +import software.amazon.smithy.kotlin.codegen.model.expectShape +import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpBindingResolver +import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerator +import software.amazon.smithy.kotlin.codegen.test.defaultSettings +import software.amazon.smithy.kotlin.codegen.test.newTestContext +import software.amazon.smithy.kotlin.codegen.test.shouldContainOnlyOnceWithDiff +import software.amazon.smithy.kotlin.codegen.test.toSmithyModel +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.Shape +import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.model.traits.TimestampFormatTrait +import kotlin.test.Test + +class AwsHttpBindingProtocolGeneratorTest { + + @Test + fun `it throws base service exception on error parse failure`() { + val model = """ + namespace com.test + use aws.protocols#restJson1 + + @restJson1 + service Example { + version: "1.0.0", + operations: [GetFoo] + } + + operation GetFoo { + errors: [FooError] + } + + @error("server") + structure FooError { + payload: String + } + """.toSmithyModel() + + // This is the value that produces the name of the service base exception type + val serviceSdkName = "SdkName" + + val testCtx = model.newTestContext( + serviceName = "Example", + settings = model.defaultSettings(sdkId = serviceSdkName) + ) + val writer = KotlinWriter("com.test") + val unit = TestableAwsHttpBindingProtocolGenerator() + val op = model.expectShape("com.test#GetFoo") + + unit.renderThrowOperationError(testCtx.generationCtx, op, writer) + + val actual = writer.toString() + val expected = """ + throw ${serviceSdkName}Exception("Failed to parse response as 'restJson1' error", ex).also { + """.trimIndent() + + actual.shouldContainOnlyOnceWithDiff(expected) + } + + // A concrete implementation of AwsHttpBindingProtocolGenerator to exercise renderThrowOperationError() + class TestableAwsHttpBindingProtocolGenerator : AwsHttpBindingProtocolGenerator() { + override fun renderDeserializeErrorDetails( + ctx: ProtocolGenerator.GenerationContext, + op: OperationShape, + writer: KotlinWriter + ) { + // NOP + } + + override val defaultTimestampFormat: TimestampFormatTrait.Format + get() = TODO("Unneeded for test") + + override fun getProtocolHttpBindingResolver(model: Model, serviceShape: ServiceShape): HttpBindingResolver { + TODO("Unneeded for test") + } + + override fun renderSerializeOperationBody( + ctx: ProtocolGenerator.GenerationContext, + op: OperationShape, + writer: KotlinWriter + ) { + TODO("Unneeded for test") + } + + override fun renderDeserializeOperationBody( + ctx: ProtocolGenerator.GenerationContext, + op: OperationShape, + writer: KotlinWriter + ) { + TODO("Unneeded for test") + } + + override fun renderSerializeDocumentBody( + ctx: ProtocolGenerator.GenerationContext, + shape: Shape, + writer: KotlinWriter + ) { + TODO("Unneeded for test") + } + + override fun renderDeserializeDocumentBody( + ctx: ProtocolGenerator.GenerationContext, + shape: Shape, + writer: KotlinWriter + ) { + TODO("Unneeded for test") + } + + override fun renderDeserializeException( + ctx: ProtocolGenerator.GenerationContext, + shape: Shape, + writer: KotlinWriter + ) { + TODO("Unneeded for test") + } + + override val protocol: ShapeId + get() = TODO("Unneeded for test") + } +} From 034ea588ca4385e51c2926b5e08b3f9ca36b7356 Mon Sep 17 00:00:00 2001 From: Ken Gilmer Date: Mon, 3 Jan 2022 16:34:57 -0800 Subject: [PATCH 2/2] Remove UnknownServiceErrorException --- .../src/aws/sdk/kotlin/runtime/Exceptions.kt | 15 --------------- .../aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt | 1 - .../codegen/customization/s3/S3Generator.kt | 1 - .../core/AwsHttpBindingProtocolGenerator.kt | 1 - .../core/AwsHttpBindingProtocolGeneratorTest.kt | 16 ++++++++-------- 5 files changed, 8 insertions(+), 26 deletions(-) diff --git a/aws-runtime/aws-core/common/src/aws/sdk/kotlin/runtime/Exceptions.kt b/aws-runtime/aws-core/common/src/aws/sdk/kotlin/runtime/Exceptions.kt index 2a1b5baa7aa..864925420a9 100644 --- a/aws-runtime/aws-core/common/src/aws/sdk/kotlin/runtime/Exceptions.kt +++ b/aws-runtime/aws-core/common/src/aws/sdk/kotlin/runtime/Exceptions.kt @@ -79,18 +79,3 @@ public open class ConfigurationException : ClientException { public constructor(cause: Throwable?) : super(cause) } - -/** - * An exception that is thrown when the returned (error) response is not known by this version of the SDK - * (i.e. the modeled error code is not known) - */ -public class UnknownServiceErrorException : AwsServiceException { - - public constructor() : super() - - public constructor(message: String?) : super(message) - - public constructor(message: String?, cause: Throwable?) : super(message, cause) - - public constructor(cause: Throwable?) : super(cause) -} diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt index 4d934c183cd..421227fbe72 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt @@ -21,7 +21,6 @@ object AwsRuntimeTypes { val AwsClientOption = runtimeSymbol("AwsClientOption", AwsKotlinDependency.AWS_CORE, "client") val AuthAttributes = runtimeSymbol("AuthAttributes", AwsKotlinDependency.AWS_CORE, "execution") val AwsErrorMetadata = runtimeSymbol("AwsErrorMetadata", AwsKotlinDependency.AWS_CORE) - val UnknownServiceErrorException = runtimeSymbol("UnknownServiceErrorException", AwsKotlinDependency.AWS_CORE) val ClientException = runtimeSymbol("ClientException", AwsKotlinDependency.AWS_CORE) } diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/s3/S3Generator.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/s3/S3Generator.kt index 46e59b06fb8..b27ee2c8193 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/s3/S3Generator.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/s3/S3Generator.kt @@ -65,7 +65,6 @@ class S3Generator : RestXml() { exceptionBaseSymbol, RuntimeTypes.Http.readAll, RuntimeTypes.Http.StatusCode, - AwsRuntimeTypes.Core.UnknownServiceErrorException, AwsRuntimeTypes.Http.withPayload, s3ErrorDetails, setS3ErrorMetadata, diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGenerator.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGenerator.kt index 9ea612715d4..1fcf631167c 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGenerator.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGenerator.kt @@ -121,7 +121,6 @@ abstract class AwsHttpBindingProtocolGenerator : HttpBindingProtocolGenerator() listOf( exceptionBaseSymbol, RuntimeTypes.Http.readAll, - AwsRuntimeTypes.Core.UnknownServiceErrorException, AwsRuntimeTypes.Http.withPayload, AwsRuntimeTypes.Http.setAseErrorMetadata, ).forEach(writer::addImport) diff --git a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGeneratorTest.kt b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGeneratorTest.kt index eadae7b2dc7..88b581d740f 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGeneratorTest.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpBindingProtocolGeneratorTest.kt @@ -76,10 +76,10 @@ class AwsHttpBindingProtocolGeneratorTest { } override val defaultTimestampFormat: TimestampFormatTrait.Format - get() = TODO("Unneeded for test") + get() = throw RuntimeException("Unneeded for test") override fun getProtocolHttpBindingResolver(model: Model, serviceShape: ServiceShape): HttpBindingResolver { - TODO("Unneeded for test") + throw RuntimeException("Unneeded for test") } override fun renderSerializeOperationBody( @@ -87,7 +87,7 @@ class AwsHttpBindingProtocolGeneratorTest { op: OperationShape, writer: KotlinWriter ) { - TODO("Unneeded for test") + throw RuntimeException("Unneeded for test") } override fun renderDeserializeOperationBody( @@ -95,7 +95,7 @@ class AwsHttpBindingProtocolGeneratorTest { op: OperationShape, writer: KotlinWriter ) { - TODO("Unneeded for test") + throw RuntimeException("Unneeded for test") } override fun renderSerializeDocumentBody( @@ -103,7 +103,7 @@ class AwsHttpBindingProtocolGeneratorTest { shape: Shape, writer: KotlinWriter ) { - TODO("Unneeded for test") + throw RuntimeException("Unneeded for test") } override fun renderDeserializeDocumentBody( @@ -111,7 +111,7 @@ class AwsHttpBindingProtocolGeneratorTest { shape: Shape, writer: KotlinWriter ) { - TODO("Unneeded for test") + throw RuntimeException("Unneeded for test") } override fun renderDeserializeException( @@ -119,10 +119,10 @@ class AwsHttpBindingProtocolGeneratorTest { shape: Shape, writer: KotlinWriter ) { - TODO("Unneeded for test") + throw RuntimeException("Unneeded for test") } override val protocol: ShapeId - get() = TODO("Unneeded for test") + get() = throw RuntimeException("Unneeded for test") } }