From 53e25af60d38583ab02697550cdffa0bd18ebb4d Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 14 Dec 2022 14:40:22 -0800 Subject: [PATCH 01/19] Move the allow lints customization into `codegen-core` --- .../smithy/customize/RequiredCustomizations.kt | 5 ++--- .../customizations/AllowLintsCustomization.kt | 16 ++++++++-------- .../ServerRequiredCustomizations.kt | 4 ++-- 3 files changed, 12 insertions(+), 13 deletions(-) rename codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/AllowLintsGenerator.kt => codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt (86%) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt index 926259e42ea..61f82854680 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt @@ -7,7 +7,6 @@ package software.amazon.smithy.rust.codegen.client.smithy.customize import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.customizations.AllowLintsGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.CrateVersionGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.EndpointPrefixGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpChecksumRequiredGenerator @@ -19,6 +18,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.customizations.pubUseSm import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.core.rustlang.Feature import software.amazon.smithy.rust.codegen.core.smithy.RustCrate +import software.amazon.smithy.rust.codegen.core.smithy.customizations.AllowLintsCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization @@ -52,8 +52,7 @@ class RequiredCustomizations : ClientCodegenDecorator { codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = - baseCustomizations + CrateVersionGenerator() + - AllowLintsGenerator() + baseCustomizations + CrateVersionGenerator() + AllowLintsCustomization() override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { // Add rt-tokio feature for `ByteStream::from_path` diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/AllowLintsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt similarity index 86% rename from codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/AllowLintsGenerator.kt rename to codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt index f5755d9a730..0fc88f7a1c3 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/AllowLintsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt @@ -3,19 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.client.smithy.customizations +package software.amazon.smithy.rust.codegen.core.smithy.customizations import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection -val AllowedRustcLints = listOf( +private val allowedRustcLints = listOf( // Deprecated items should be safe to compile, so don't block the compilation. "deprecated", ) -val AllowedClippyLints = listOf( +private val allowedClippyLints = listOf( // Sometimes operations are named the same as our module e.g. output leading to `output::output`. "module_inception", @@ -54,16 +54,16 @@ val AllowedClippyLints = listOf( // "result_large_err", ) -val AllowedRustdocLints = listOf( +private val allowedRustdocLints = listOf( // Rust >=1.53.0 requires links to be wrapped in ``. This is extremely hard to enforce for // docs that come from the modeled documentation, so we need to disable this lint "bare_urls", ) -class AllowLintsGenerator( - private val rustcLints: List = AllowedRustcLints, - private val clippyLints: List = AllowedClippyLints, - private val rustdocLints: List = AllowedRustdocLints, +class AllowLintsCustomization( + private val rustcLints: List = allowedRustcLints, + private val clippyLints: List = allowedClippyLints, + private val rustdocLints: List = allowedRustdocLints, ) : LibRsCustomization() { override fun section(section: LibRsSection) = when (section) { is LibRsSection.Attributes -> writable { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt index 2949d605de4..490bdd6843e 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt @@ -5,11 +5,11 @@ package software.amazon.smithy.rust.codegen.server.smithy.customizations -import software.amazon.smithy.rust.codegen.client.smithy.customizations.AllowLintsGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.CrateVersionGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.pubUseSmithyTypes import software.amazon.smithy.rust.codegen.core.rustlang.Feature import software.amazon.smithy.rust.codegen.core.smithy.RustCrate +import software.amazon.smithy.rust.codegen.core.smithy.customizations.AllowLintsCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.customize.ServerCodegenDecorator @@ -29,7 +29,7 @@ class ServerRequiredCustomizations : ServerCodegenDecorator { codegenContext: ServerCodegenContext, baseCustomizations: List, ): List = - baseCustomizations + CrateVersionGenerator() + AllowLintsGenerator() + baseCustomizations + CrateVersionGenerator() + AllowLintsCustomization() override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { // Add rt-tokio feature for `ByteStream::from_path` From ed84f250d9c2f2bda13fc8701767ebc38bcf7b92 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 14 Dec 2022 14:48:41 -0800 Subject: [PATCH 02/19] Move the crate version customization into `codegen-core` --- .../codegen/client/smithy/customize/RequiredCustomizations.kt | 4 ++-- .../core/smithy/customizations/CrateVersionCustomization.kt | 4 ++-- .../smithy/customizations/ServerRequiredCustomizations.kt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/CrateVersionGenerator.kt => codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/CrateVersionCustomization.kt (87%) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt index 61f82854680..537bf1dccc8 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt @@ -7,7 +7,6 @@ package software.amazon.smithy.rust.codegen.client.smithy.customize import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.customizations.CrateVersionGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.EndpointPrefixGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpChecksumRequiredGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpVersionListCustomization @@ -19,6 +18,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.generators.config.Confi import software.amazon.smithy.rust.codegen.core.rustlang.Feature import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.customizations.AllowLintsCustomization +import software.amazon.smithy.rust.codegen.core.smithy.customizations.CrateVersionCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization @@ -52,7 +52,7 @@ class RequiredCustomizations : ClientCodegenDecorator { codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = - baseCustomizations + CrateVersionGenerator() + AllowLintsCustomization() + baseCustomizations + CrateVersionCustomization() + AllowLintsCustomization() override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { // Add rt-tokio feature for `ByteStream::from_path` diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/CrateVersionGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/CrateVersionCustomization.kt similarity index 87% rename from codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/CrateVersionGenerator.kt rename to codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/CrateVersionCustomization.kt index d3b350ed025..eca55030506 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/CrateVersionGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/CrateVersionCustomization.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.client.smithy.customizations +package software.amazon.smithy.rust.codegen.core.smithy.customizations import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.writable @@ -13,7 +13,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection /** * Add `PGK_VERSION` const in lib.rs to enable knowing the version of the current module */ -class CrateVersionGenerator : LibRsCustomization() { +class CrateVersionCustomization : LibRsCustomization() { override fun section(section: LibRsSection) = writable { if (section is LibRsSection.Body) { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt index 490bdd6843e..3778a743135 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt @@ -5,11 +5,11 @@ package software.amazon.smithy.rust.codegen.server.smithy.customizations -import software.amazon.smithy.rust.codegen.client.smithy.customizations.CrateVersionGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.pubUseSmithyTypes import software.amazon.smithy.rust.codegen.core.rustlang.Feature import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.customizations.AllowLintsCustomization +import software.amazon.smithy.rust.codegen.core.smithy.customizations.CrateVersionCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.customize.ServerCodegenDecorator @@ -29,7 +29,7 @@ class ServerRequiredCustomizations : ServerCodegenDecorator { codegenContext: ServerCodegenContext, baseCustomizations: List, ): List = - baseCustomizations + CrateVersionGenerator() + AllowLintsCustomization() + baseCustomizations + CrateVersionCustomization() + AllowLintsCustomization() override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { // Add rt-tokio feature for `ByteStream::from_path` From bc804ce99cfdc584e423f24d9ea0dffb2d251e18 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 14 Dec 2022 14:56:44 -0800 Subject: [PATCH 03/19] Move "pub use" extra into `codegen-core` --- .../customize/RequiredCustomizations.kt | 2 +- .../customizations/SmithyTypesPubUseExtra.kt | 24 ++++++++----------- .../SmithyTypesPubUseGeneratorTest.kt | 3 +-- .../ServerRequiredCustomizations.kt | 2 +- 4 files changed, 13 insertions(+), 18 deletions(-) rename codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SmithyTypesPubUseGenerator.kt => codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt (80%) rename {codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client => codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy}/customizations/SmithyTypesPubUseGeneratorTest.kt (97%) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt index 537bf1dccc8..be75256799b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt @@ -13,12 +13,12 @@ import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpVers import software.amazon.smithy.rust.codegen.client.smithy.customizations.IdempotencyTokenGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.ResiliencyConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.customizations.ResiliencyReExportCustomization -import software.amazon.smithy.rust.codegen.client.smithy.customizations.pubUseSmithyTypes import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.core.rustlang.Feature import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.customizations.AllowLintsCustomization import software.amazon.smithy.rust.codegen.core.smithy.customizations.CrateVersionCustomization +import software.amazon.smithy.rust.codegen.core.smithy.customizations.pubUseSmithyTypes import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SmithyTypesPubUseGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt similarity index 80% rename from codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SmithyTypesPubUseGenerator.kt rename to codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt index 2f2c72ab15a..3a37fa0a9be 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SmithyTypesPubUseGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt @@ -3,9 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.client.smithy.customizations +package software.amazon.smithy.rust.codegen.core.smithy.customizations import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -30,23 +31,18 @@ private fun hasStreamingOperations(model: Model): Boolean { } } -/** Returns true if the model has any blob shapes or members */ -private fun hasBlobs(model: Model): Boolean { - return model.structureShapes.any { structure -> - structure.members().any { member -> model.expectShape(member.target).isBlobShape } +private fun structUnionMembersMatchPredicate(model: Model, predicate: (Shape) -> Boolean): Boolean = + model.structureShapes.any { structure -> + structure.members().any { member -> predicate(model.expectShape(member.target)) } } || model.unionShapes.any { union -> - union.members().any { member -> model.expectShape(member.target).isBlobShape } + union.members().any { member -> predicate(model.expectShape(member.target)) } } -} + +/** Returns true if the model has any blob shapes or members */ +private fun hasBlobs(model: Model): Boolean = structUnionMembersMatchPredicate(model, Shape::isBlobShape) /** Returns true if the model has any timestamp shapes or members */ -private fun hasDateTimes(model: Model): Boolean { - return model.structureShapes.any { structure -> - structure.members().any { member -> model.expectShape(member.target).isTimestampShape } - } || model.unionShapes.any { union -> - union.members().any { member -> model.expectShape(member.target).isTimestampShape } - } -} +private fun hasDateTimes(model: Model): Boolean = structUnionMembersMatchPredicate(model, Shape::isTimestampShape) /** Returns a list of types that should be re-exported for the given model */ internal fun pubUseTypes(runtimeConfig: RuntimeConfig, model: Model): List { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/customizations/SmithyTypesPubUseGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseGeneratorTest.kt similarity index 97% rename from codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/customizations/SmithyTypesPubUseGeneratorTest.kt rename to codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseGeneratorTest.kt index 6a7ca5be25f..c147567d712 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/customizations/SmithyTypesPubUseGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseGeneratorTest.kt @@ -3,11 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.client.customizations +package software.amazon.smithy.rust.codegen.core.smithy.customizations import org.junit.jupiter.api.Test import software.amazon.smithy.model.Model -import software.amazon.smithy.rust.codegen.client.smithy.customizations.pubUseTypes import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt index 3778a743135..90b3550b981 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt @@ -5,11 +5,11 @@ package software.amazon.smithy.rust.codegen.server.smithy.customizations -import software.amazon.smithy.rust.codegen.client.smithy.customizations.pubUseSmithyTypes import software.amazon.smithy.rust.codegen.core.rustlang.Feature import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.customizations.AllowLintsCustomization import software.amazon.smithy.rust.codegen.core.smithy.customizations.CrateVersionCustomization +import software.amazon.smithy.rust.codegen.core.smithy.customizations.pubUseSmithyTypes import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.customize.ServerCodegenDecorator From 46494d423934fa760c23d004e5c3eb47922945e9 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 14 Dec 2022 15:02:05 -0800 Subject: [PATCH 04/19] Move `EventStreamSymbolProvider` into `codegen-core` --- .../rust/codegen/client/smithy/RustClientCodegenPlugin.kt | 1 + .../client/smithy/EventStreamSymbolProviderTest.kt | 1 + .../codegen/core}/smithy/EventStreamSymbolProvider.kt | 8 +------- .../server/python/smithy/PythonCodegenServerPlugin.kt | 2 +- .../rust/codegen/server/smithy/RustCodegenServerPlugin.kt | 2 +- 5 files changed, 5 insertions(+), 9 deletions(-) rename {codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client => codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core}/smithy/EventStreamSymbolProvider.kt (89%) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index 005eaa8bf60..62096e30364 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -20,6 +20,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.Non import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.BaseSymbolMetadataProvider import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitorConfig import java.util.logging.Level diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProviderTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProviderTest.kt index a6660f43876..5fb38e58e31 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProviderTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProviderTest.kt @@ -12,6 +12,7 @@ import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.core.rustlang.RustType import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.smithy.transformers.OperationNormalizer diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProvider.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/EventStreamSymbolProvider.kt similarity index 89% rename from codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProvider.kt rename to codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/EventStreamSymbolProvider.kt index 7a885d91aec..54b43f722b0 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProvider.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/EventStreamSymbolProvider.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.client.smithy +package software.amazon.smithy.rust.codegen.core.smithy import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model @@ -14,13 +14,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustType import software.amazon.smithy.rust.codegen.core.rustlang.render import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter -import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.generators.error.eventStreamErrorSymbol -import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticInputTrait import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticOutputTrait import software.amazon.smithy.rust.codegen.core.smithy.transformers.eventStreamErrors diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonCodegenServerPlugin.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonCodegenServerPlugin.kt index 446260ae963..3d8a57ef6ba 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonCodegenServerPlugin.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonCodegenServerPlugin.kt @@ -10,10 +10,10 @@ import software.amazon.smithy.build.SmithyBuildPlugin import software.amazon.smithy.codegen.core.ReservedWordSymbolProvider import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.rust.codegen.client.smithy.EventStreamSymbolProvider import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.BaseSymbolMetadataProvider import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitorConfig import software.amazon.smithy.rust.codegen.server.python.smithy.customizations.DECORATORS diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCodegenServerPlugin.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCodegenServerPlugin.kt index 1da7d944fa4..d41403789ca 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCodegenServerPlugin.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCodegenServerPlugin.kt @@ -10,12 +10,12 @@ import software.amazon.smithy.build.SmithyBuildPlugin import software.amazon.smithy.codegen.core.ReservedWordSymbolProvider import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.rust.codegen.client.smithy.EventStreamSymbolProvider import software.amazon.smithy.rust.codegen.client.smithy.StreamingShapeMetadataProvider import software.amazon.smithy.rust.codegen.client.smithy.StreamingShapeSymbolProvider import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.BaseSymbolMetadataProvider import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitorConfig import software.amazon.smithy.rust.codegen.server.smithy.customizations.ServerRequiredCustomizations From 40f876a5e70686f567828899dcdb453795a5537f Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 14 Dec 2022 15:04:25 -0800 Subject: [PATCH 05/19] Move the streaming shape providers into `codegen-core` --- .../codegen/client/smithy/RustClientCodegenPlugin.kt | 2 ++ .../codegen/core}/smithy/StreamingTraitSymbolProvider.kt | 9 +-------- .../codegen/server/smithy/RustCodegenServerPlugin.kt | 4 ++-- 3 files changed, 5 insertions(+), 10 deletions(-) rename {codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client => codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core}/smithy/StreamingTraitSymbolProvider.kt (86%) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index 62096e30364..9993980eb93 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -21,6 +21,8 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolP import software.amazon.smithy.rust.codegen.core.smithy.BaseSymbolMetadataProvider import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeMetadataProvider +import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitorConfig import java.util.logging.Level diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingTraitSymbolProvider.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/StreamingTraitSymbolProvider.kt similarity index 86% rename from codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingTraitSymbolProvider.kt rename to codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/StreamingTraitSymbolProvider.kt index 3203e96a22f..2e91ee5fba7 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingTraitSymbolProvider.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/StreamingTraitSymbolProvider.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.client.smithy +package software.amazon.smithy.rust.codegen.core.smithy import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model @@ -14,13 +14,6 @@ import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata -import software.amazon.smithy.rust.codegen.core.smithy.Default -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.SymbolMetadataProvider -import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.expectRustMetadata -import software.amazon.smithy.rust.codegen.core.smithy.setDefault import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticInputTrait import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticOutputTrait import software.amazon.smithy.rust.codegen.core.util.hasStreamingMember diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCodegenServerPlugin.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCodegenServerPlugin.kt index d41403789ca..98e875f3cca 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCodegenServerPlugin.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCodegenServerPlugin.kt @@ -10,12 +10,12 @@ import software.amazon.smithy.build.SmithyBuildPlugin import software.amazon.smithy.codegen.core.ReservedWordSymbolProvider import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.rust.codegen.client.smithy.StreamingShapeMetadataProvider -import software.amazon.smithy.rust.codegen.client.smithy.StreamingShapeSymbolProvider import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.BaseSymbolMetadataProvider import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeMetadataProvider +import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitorConfig import software.amazon.smithy.rust.codegen.server.smithy.customizations.ServerRequiredCustomizations From 608f1c4815c40ecc8e23a25c122c256a52cfb526 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 14 Dec 2022 17:15:25 -0800 Subject: [PATCH 06/19] Refactor event stream marshall/unmarshall tests --- .../EventStreamUnmarshallerGeneratorTest.kt | 49 + .../EventStreamMarshallerGeneratorTest.kt | 51 ++ .../core/testutil/EventStreamTestTools.kt | 855 ++++++++++++++++++ .../smithy/protocols/EventStreamTestTools.kt | 407 --------- .../EventStreamUnmarshallerGeneratorTest.kt | 313 +------ .../EventStreamMarshallerGeneratorTest.kt | 255 +----- 6 files changed, 1016 insertions(+), 914 deletions(-) create mode 100644 codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt create mode 100644 codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt create mode 100644 codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt delete mode 100644 codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/EventStreamTestTools.kt diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt new file mode 100644 index 00000000000..e23dec720d7 --- /dev/null +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt @@ -0,0 +1,49 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.client.smithy.protocols.parse + +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import org.junit.jupiter.params.provider.ArgumentsSource +import software.amazon.smithy.codegen.core.Symbol +import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.generators.builderSymbol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.EventStreamUnmarshallerGenerator +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools +import java.util.stream.Stream + +class UnmarshallTestCasesProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream = + EventStreamTestModels.TEST_CASES.map { Arguments.of(it) }.stream() +} + +class EventStreamUnmarshallerGeneratorTest { + @ParameterizedTest + @ArgumentsSource(UnmarshallTestCasesProvider::class) + fun test(testCase: EventStreamTestModels.TestCase) { + EventStreamTestTools.runTestCase( + testCase, + CodegenTarget.CLIENT, + { model -> testSymbolProvider(model) }, + { codegenContext, test, protocol -> + fun builderSymbol(shape: StructureShape): Symbol = shape.builderSymbol(codegenContext.symbolProvider) + EventStreamUnmarshallerGenerator( + protocol, + codegenContext, + test.operationShape, + test.streamShape, + ::builderSymbol, + ).render() + }, + marshall = false, + ) + } +} diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt new file mode 100644 index 00000000000..aedf0a68a8f --- /dev/null +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.client.smithy.protocols.serialize + +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import org.junit.jupiter.params.provider.ArgumentsSource +import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.EventStreamMarshallerGenerator +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools +import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig +import java.util.stream.Stream + +class MarshallTestCasesProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream = + // Don't include awsQuery or ec2Query for now since marshall support for them is unimplemented + EventStreamTestModels.TEST_CASES + .filter { testCase -> !testCase.protocolShapeId.contains("Query") } + .map { Arguments.of(it) }.stream() +} + +class EventStreamMarshallerGeneratorTest { + @ParameterizedTest + @ArgumentsSource(MarshallTestCasesProvider::class) + fun test(testCase: EventStreamTestModels.TestCase) { + EventStreamTestTools.runTestCase( + testCase, + CodegenTarget.CLIENT, + { model -> testSymbolProvider(model) }, + { _, test, protocol -> + EventStreamMarshallerGenerator( + test.model, + CodegenTarget.CLIENT, + TestRuntimeConfig, + test.symbolProvider, + test.streamShape, + protocol.structuredDataSerializer(test.operationShape), + testCase.requestContentType, + ).render() + }, + marshall = true, + ) + } +} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt new file mode 100644 index 00000000000..73bd622b3ae --- /dev/null +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt @@ -0,0 +1,855 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.core.testutil + +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.shapes.StructureShape +import software.amazon.smithy.model.shapes.UnionShape +import software.amazon.smithy.model.traits.ErrorTrait +import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.core.rustlang.DependencyScope +import software.amazon.smithy.rust.codegen.core.rustlang.RustModule +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.rustlang.rust +import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate +import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext +import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.ErrorsModule +import software.amazon.smithy.rust.codegen.core.smithy.ModelsModule +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerator +import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator +import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator +import software.amazon.smithy.rust.codegen.core.smithy.generators.error.CombinedErrorGenerator +import software.amazon.smithy.rust.codegen.core.smithy.generators.error.ServerCombinedErrorGenerator +import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock +import software.amazon.smithy.rust.codegen.core.smithy.generators.renderUnknownVariant +import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJson +import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJsonVersion +import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsQueryProtocol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.Ec2QueryProtocol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestJson +import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestXml +import software.amazon.smithy.rust.codegen.core.smithy.transformers.EventStreamNormalizer +import software.amazon.smithy.rust.codegen.core.smithy.transformers.OperationNormalizer +import software.amazon.smithy.rust.codegen.core.util.dq +import software.amazon.smithy.rust.codegen.core.util.hasTrait +import software.amazon.smithy.rust.codegen.core.util.lookup +import software.amazon.smithy.rust.codegen.core.util.outputShape +import kotlin.streams.toList + +private fun fillInBaseModel( + protocolName: String, + extraServiceAnnotations: String = "", +): String = """ + namespace test + + use aws.protocols#$protocolName + + union TestUnion { + Foo: String, + Bar: Integer, + } + structure TestStruct { + someString: String, + someInt: Integer, + } + + @error("client") + structure SomeError { + Message: String, + } + + structure MessageWithBlob { @eventPayload data: Blob } + structure MessageWithString { @eventPayload data: String } + structure MessageWithStruct { @eventPayload someStruct: TestStruct } + structure MessageWithUnion { @eventPayload someUnion: TestUnion } + structure MessageWithHeaders { + @eventHeader blob: Blob, + @eventHeader boolean: Boolean, + @eventHeader byte: Byte, + @eventHeader int: Integer, + @eventHeader long: Long, + @eventHeader short: Short, + @eventHeader string: String, + @eventHeader timestamp: Timestamp, + } + structure MessageWithHeaderAndPayload { + @eventHeader header: String, + @eventPayload payload: Blob, + } + structure MessageWithNoHeaderPayloadTraits { + someInt: Integer, + someString: String, + } + + @streaming + union TestStream { + MessageWithBlob: MessageWithBlob, + MessageWithString: MessageWithString, + MessageWithStruct: MessageWithStruct, + MessageWithUnion: MessageWithUnion, + MessageWithHeaders: MessageWithHeaders, + MessageWithHeaderAndPayload: MessageWithHeaderAndPayload, + MessageWithNoHeaderPayloadTraits: MessageWithNoHeaderPayloadTraits, + SomeError: SomeError, + } + structure TestStreamInputOutput { @httpPayload @required value: TestStream } + operation TestStreamOp { + input: TestStreamInputOutput, + output: TestStreamInputOutput, + errors: [SomeError], + } + $extraServiceAnnotations + @$protocolName + service TestService { version: "123", operations: [TestStreamOp] } +""" + +object EventStreamTestModels { + private fun restJson1(): Model = fillInBaseModel("restJson1").asSmithyModel() + private fun restXml(): Model = fillInBaseModel("restXml").asSmithyModel() + private fun awsJson11(): Model = fillInBaseModel("awsJson1_1").asSmithyModel() + private fun awsQuery(): Model = + fillInBaseModel("awsQuery", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() + private fun ec2Query(): Model = + fillInBaseModel("ec2Query", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() + + data class TestCase( + val protocolShapeId: String, + val model: Model, + val requestContentType: String, + val responseContentType: String, + val validTestStruct: String, + val validMessageWithNoHeaderPayloadTraits: String, + val validTestUnion: String, + val validSomeError: String, + val validUnmodeledError: String, + val protocolBuilder: (CodegenContext) -> Protocol, + ) { + override fun toString(): String = protocolShapeId + } + + val TEST_CASES = listOf( + // + // restJson1 + // + TestCase( + protocolShapeId = "aws.protocols#restJson1", + model = restJson1(), + requestContentType = "application/json", + responseContentType = "application/json", + validTestStruct = """{"someString":"hello","someInt":5}""", + validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", + validTestUnion = """{"Foo":"hello"}""", + validSomeError = """{"Message":"some error"}""", + validUnmodeledError = """{"Message":"unmodeled error"}""", + ) { RestJson(it) }, + + // + // awsJson1_1 + // + TestCase( + protocolShapeId = "aws.protocols#awsJson1_1", + model = awsJson11(), + requestContentType = "application/x-amz-json-1.1", + responseContentType = "application/x-amz-json-1.1", + validTestStruct = """{"someString":"hello","someInt":5}""", + validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", + validTestUnion = """{"Foo":"hello"}""", + validSomeError = """{"Message":"some error"}""", + validUnmodeledError = """{"Message":"unmodeled error"}""", + ) { AwsJson(it, AwsJsonVersion.Json11) }, + + // + // restXml + // + TestCase( + protocolShapeId = "aws.protocols#restXml", + model = restXml(), + requestContentType = "application/xml", + responseContentType = "application/xml", + validTestStruct = """ + + hello + 5 + + """.trimIndent(), + validMessageWithNoHeaderPayloadTraits = """ + + hello + 5 + + """.trimIndent(), + validTestUnion = "hello", + validSomeError = """ + + + SomeError + SomeError + some error + + + """.trimIndent(), + validUnmodeledError = """ + + + UnmodeledError + UnmodeledError + unmodeled error + + + """.trimIndent(), + ) { RestXml(it) }, + + // + // awsQuery + // + TestCase( + protocolShapeId = "aws.protocols#awsQuery", + model = awsQuery(), + requestContentType = "application/x-www-form-urlencoded", + responseContentType = "text/xml", + validTestStruct = """ + + hello + 5 + + """.trimIndent(), + validMessageWithNoHeaderPayloadTraits = """ + + hello + 5 + + """.trimIndent(), + validTestUnion = "hello", + validSomeError = """ + + + SomeError + SomeError + some error + + + """.trimIndent(), + validUnmodeledError = """ + + + UnmodeledError + UnmodeledError + unmodeled error + + + """.trimIndent(), + ) { AwsQueryProtocol(it) }, + + // + // ec2Query + // + TestCase( + protocolShapeId = "aws.protocols#ec2Query", + model = ec2Query(), + requestContentType = "application/x-www-form-urlencoded", + responseContentType = "text/xml", + validTestStruct = """ + + hello + 5 + + """.trimIndent(), + validMessageWithNoHeaderPayloadTraits = """ + + hello + 5 + + """.trimIndent(), + validTestUnion = "hello", + validSomeError = """ + + + + SomeError + SomeError + some error + + + + """.trimIndent(), + validUnmodeledError = """ + + + + UnmodeledError + UnmodeledError + unmodeled error + + + + """.trimIndent(), + ) { Ec2QueryProtocol(it) }, + ) +} + +data class TestEventStreamProject( + val model: Model, + val serviceShape: ServiceShape, + val operationShape: OperationShape, + val streamShape: UnionShape, + val symbolProvider: RustSymbolProvider, + val project: TestWriterDelegator, +) + +object EventStreamTestTools { + fun runTestCase( + testCase: EventStreamTestModels.TestCase, + codegenTarget: CodegenTarget, + createSymbolProvider: (Model) -> RustSymbolProvider, + renderGenerator: (CodegenContext, TestEventStreamProject, Protocol) -> RuntimeType, + marshall: Boolean, + ) { + val test = generateTestProject(testCase, codegenTarget, createSymbolProvider) + + val codegenContext = CodegenContext( + test.model, + test.symbolProvider, + test.serviceShape, + ShapeId.from(testCase.protocolShapeId), + testRustSettings(), + target = codegenTarget, + ) + val protocol = testCase.protocolBuilder(codegenContext) + val generator = renderGenerator(codegenContext, test, protocol) + + test.project.lib { + if (marshall) { + writeMarshallTestCases(testCase, generator) + } else { + writeUnmarshallTestCases(testCase, codegenTarget, generator) + } + } + test.project.compileAndTest() + } + + private fun generateTestProject( + testCase: EventStreamTestModels.TestCase, + codegenTarget: CodegenTarget, + createSymbolProvider: (Model) -> RustSymbolProvider, + ): TestEventStreamProject { + val model = EventStreamNormalizer.transform(OperationNormalizer.transform(testCase.model)) + val serviceShape = model.expectShape(ShapeId.from("test#TestService")) as ServiceShape + val operationShape = model.expectShape(ShapeId.from("test#TestStreamOp")) as OperationShape + val unionShape = model.expectShape(ShapeId.from("test#TestStream")) as UnionShape + + val symbolProvider = createSymbolProvider(model) + val project = TestWorkspace.testProject(symbolProvider) + val operationSymbol = symbolProvider.toSymbol(operationShape) + project.withModule(ErrorsModule) { + val errors = model.shapes() + .filter { shape -> shape.isStructureShape && shape.hasTrait() } + .map { it.asStructureShape().get() } + .toList() + when (codegenTarget) { + CodegenTarget.CLIENT -> CombinedErrorGenerator(model, symbolProvider, operationSymbol, errors).render(this) + CodegenTarget.SERVER -> ServerCombinedErrorGenerator(model, symbolProvider, operationSymbol, errors).render(this) + } + for (shape in model.shapes().filter { shape -> shape.isStructureShape && shape.hasTrait() }) { + StructureGenerator(model, symbolProvider, this, shape as StructureShape).render(codegenTarget) + val builderGen = BuilderGenerator(model, symbolProvider, shape) + builderGen.render(this) + implBlock(shape, symbolProvider) { + builderGen.renderConvenienceMethod(this) + } + } + } + project.withModule(ModelsModule) { + val inputOutput = model.lookup("test#TestStreamInputOutput") + recursivelyGenerateModels(model, symbolProvider, inputOutput, this, codegenTarget) + } + project.withModule(RustModule.Output) { + operationShape.outputShape(model).renderWithModelBuilder(model, symbolProvider, this) + } + return TestEventStreamProject(model, serviceShape, operationShape, unionShape, symbolProvider, project) + } + + private fun recursivelyGenerateModels( + model: Model, + symbolProvider: RustSymbolProvider, + shape: Shape, + writer: RustWriter, + mode: CodegenTarget, + ) { + for (member in shape.members()) { + val target = model.expectShape(member.target) + if (target is StructureShape || target is UnionShape) { + if (target is StructureShape) { + target.renderWithModelBuilder(model, symbolProvider, writer) + } else if (target is UnionShape) { + UnionGenerator(model, symbolProvider, writer, target, renderUnknownVariant = mode.renderUnknownVariant()).render() + } + recursivelyGenerateModels(model, symbolProvider, target, writer, mode) + } + } + } + + private fun RustWriter.writeUnmarshallTestCases( + testCase: EventStreamTestModels.TestCase, + codegenTarget: CodegenTarget, + generator: RuntimeType, + ) { + rust( + """ + use aws_smithy_eventstream::frame::{Header, HeaderValue, Message, UnmarshallMessage, UnmarshalledMessage}; + use aws_smithy_types::{Blob, DateTime}; + use crate::error::*; + use crate::model::*; + + fn msg( + message_type: &'static str, + event_type: &'static str, + content_type: &'static str, + payload: &'static [u8], + ) -> Message { + let message = Message::new(payload) + .add_header(Header::new(":message-type", HeaderValue::String(message_type.into()))) + .add_header(Header::new(":content-type", HeaderValue::String(content_type.into()))); + if message_type == "event" { + message.add_header(Header::new(":event-type", HeaderValue::String(event_type.into()))) + } else { + message.add_header(Header::new(":exception-type", HeaderValue::String(event_type.into()))) + } + } + fn expect_event(unmarshalled: UnmarshalledMessage) -> T { + match unmarshalled { + UnmarshalledMessage::Event(event) => event, + _ => panic!("expected event, got: {:?}", unmarshalled), + } + } + fn expect_error(unmarshalled: UnmarshalledMessage) -> E { + match unmarshalled { + UnmarshalledMessage::Error(error) => error, + _ => panic!("expected error, got: {:?}", unmarshalled), + } + } + """, + ) + + unitTest( + name = "message_with_blob", + test = """ + let message = msg("event", "MessageWithBlob", "application/octet-stream", b"hello, world!"); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithBlob( + MessageWithBlob::builder().data(Blob::new(&b"hello, world!"[..])).build() + ), + expect_event(result.unwrap()) + ); + """, + ) + + if (codegenTarget == CodegenTarget.CLIENT) { + unitTest( + "unknown_message", + """ + let message = msg("event", "NewUnmodeledMessageType", "application/octet-stream", b"hello, world!"); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::Unknown, + expect_event(result.unwrap()) + ); + """, + ) + } + + unitTest( + "message_with_string", + """ + let message = msg("event", "MessageWithString", "text/plain", b"hello, world!"); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithString(MessageWithString::builder().data("hello, world!").build()), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_struct", + """ + let message = msg( + "event", + "MessageWithStruct", + "${testCase.responseContentType}", + br#"${testCase.validTestStruct}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithStruct(MessageWithStruct::builder().some_struct( + TestStruct::builder() + .some_string("hello") + .some_int(5) + .build() + ).build()), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_union", + """ + let message = msg( + "event", + "MessageWithUnion", + "${testCase.responseContentType}", + br#"${testCase.validTestUnion}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithUnion(MessageWithUnion::builder().some_union( + TestUnion::Foo("hello".into()) + ).build()), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_headers", + """ + let message = msg("event", "MessageWithHeaders", "application/octet-stream", b"") + .add_header(Header::new("blob", HeaderValue::ByteArray((&b"test"[..]).into()))) + .add_header(Header::new("boolean", HeaderValue::Bool(true))) + .add_header(Header::new("byte", HeaderValue::Byte(55i8))) + .add_header(Header::new("int", HeaderValue::Int32(100_000i32))) + .add_header(Header::new("long", HeaderValue::Int64(9_000_000_000i64))) + .add_header(Header::new("short", HeaderValue::Int16(16_000i16))) + .add_header(Header::new("string", HeaderValue::String("test".into()))) + .add_header(Header::new("timestamp", HeaderValue::Timestamp(DateTime::from_secs(5)))); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithHeaders(MessageWithHeaders::builder() + .blob(Blob::new(&b"test"[..])) + .boolean(true) + .byte(55i8) + .int(100_000i32) + .long(9_000_000_000i64) + .short(16_000i16) + .string("test") + .timestamp(DateTime::from_secs(5)) + .build() + ), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_header_and_payload", + """ + let message = msg("event", "MessageWithHeaderAndPayload", "application/octet-stream", b"payload") + .add_header(Header::new("header", HeaderValue::String("header".into()))); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithHeaderAndPayload(MessageWithHeaderAndPayload::builder() + .header("header") + .payload(Blob::new(&b"payload"[..])) + .build() + ), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_no_header_payload_traits", + """ + let message = msg( + "event", + "MessageWithNoHeaderPayloadTraits", + "${testCase.responseContentType}", + br#"${testCase.validMessageWithNoHeaderPayloadTraits}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithNoHeaderPayloadTraits(MessageWithNoHeaderPayloadTraits::builder() + .some_int(5) + .some_string("hello") + .build() + ), + expect_event(result.unwrap()) + ); + """, + ) + + val (someError, kindSuffix) = when (codegenTarget) { + CodegenTarget.CLIENT -> listOf("TestStreamErrorKind::SomeError", ".kind") + CodegenTarget.SERVER -> listOf("TestStreamError::SomeError", "") + } + unitTest( + "some_error", + """ + let message = msg( + "exception", + "SomeError", + "${testCase.responseContentType}", + br#"${testCase.validSomeError}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + match expect_error(result.unwrap())$kindSuffix { + $someError(err) => assert_eq!(Some("some error"), err.message()), + kind => panic!("expected SomeError, but got {:?}", kind), + } + """, + ) + + if (codegenTarget == CodegenTarget.CLIENT) { + unitTest( + "generic_error", + """ + let message = msg( + "exception", + "UnmodeledError", + "${testCase.responseContentType}", + br#"${testCase.validUnmodeledError}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + match expect_error(result.unwrap())$kindSuffix { + TestStreamErrorKind::Unhandled(err) => { + let message = format!("{}", aws_smithy_types::error::display::DisplayErrorContext(&err)); + let expected = "message: \"unmodeled error\""; + assert!(message.contains(expected), "Expected '{message}' to contain '{expected}'"); + } + kind => panic!("expected generic error, but got {:?}", kind), + } + """, + ) + } + + unitTest( + "bad_content_type", + """ + let message = msg( + "event", + "MessageWithBlob", + "wrong-content-type", + br#"${testCase.validTestStruct}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_err(), "expected error, got: {:?}", result); + assert!(format!("{}", result.err().unwrap()).contains("expected :content-type to be")); + """, + ) + } + + private fun RustWriter.writeMarshallTestCases( + testCase: EventStreamTestModels.TestCase, + generator: RuntimeType, + ) { + val protocolTestHelpers = CargoDependency.smithyProtocolTestHelpers(TestRuntimeConfig) + .copy(scope = DependencyScope.Compile) + rustTemplate( + """ + use aws_smithy_eventstream::frame::{Message, Header, HeaderValue, MarshallMessage}; + use std::collections::HashMap; + use aws_smithy_types::{Blob, DateTime}; + use crate::error::*; + use crate::model::*; + + use #{validate_body}; + use #{MediaType}; + + fn headers_to_map<'a>(headers: &'a [Header]) -> HashMap { + let mut map = HashMap::new(); + for header in headers { + map.insert(header.name().as_str().to_string(), header.value()); + } + map + } + + fn str_header(value: &'static str) -> HeaderValue { + HeaderValue::String(value.into()) + } + """, + "validate_body" to protocolTestHelpers.toType().resolve("validate_body"), + "MediaType" to protocolTestHelpers.toType().resolve("MediaType"), + ) + + unitTest( + "message_with_blob", + """ + let event = TestStream::MessageWithBlob( + MessageWithBlob::builder().data(Blob::new(&b"hello, world!"[..])).build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithBlob"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header("application/octet-stream"), *headers.get(":content-type").unwrap()); + assert_eq!(&b"hello, world!"[..], message.payload()); + """, + ) + + unitTest( + "message_with_string", + """ + let event = TestStream::MessageWithString( + MessageWithString::builder().data("hello, world!").build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithString"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header("text/plain"), *headers.get(":content-type").unwrap()); + assert_eq!(&b"hello, world!"[..], message.payload()); + """, + ) + + unitTest( + "message_with_struct", + """ + let event = TestStream::MessageWithStruct( + MessageWithStruct::builder().some_struct( + TestStruct::builder() + .some_string("hello") + .some_int(5) + .build() + ).build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithStruct"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); + + validate_body( + message.payload(), + ${testCase.validTestStruct.dq()}, + MediaType::from(${testCase.requestContentType.dq()}) + ).unwrap(); + """, + ) + + unitTest( + "message_with_union", + """ + let event = TestStream::MessageWithUnion(MessageWithUnion::builder().some_union( + TestUnion::Foo("hello".into()) + ).build()); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithUnion"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); + + validate_body( + message.payload(), + ${testCase.validTestUnion.dq()}, + MediaType::from(${testCase.requestContentType.dq()}) + ).unwrap(); + """, + ) + + unitTest( + "message_with_headers", + """ + let event = TestStream::MessageWithHeaders(MessageWithHeaders::builder() + .blob(Blob::new(&b"test"[..])) + .boolean(true) + .byte(55i8) + .int(100_000i32) + .long(9_000_000_000i64) + .short(16_000i16) + .string("test") + .timestamp(DateTime::from_secs(5)) + .build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let actual_message = result.unwrap(); + let expected_message = Message::new(&b""[..]) + .add_header(Header::new(":message-type", HeaderValue::String("event".into()))) + .add_header(Header::new(":event-type", HeaderValue::String("MessageWithHeaders".into()))) + .add_header(Header::new("blob", HeaderValue::ByteArray((&b"test"[..]).into()))) + .add_header(Header::new("boolean", HeaderValue::Bool(true))) + .add_header(Header::new("byte", HeaderValue::Byte(55i8))) + .add_header(Header::new("int", HeaderValue::Int32(100_000i32))) + .add_header(Header::new("long", HeaderValue::Int64(9_000_000_000i64))) + .add_header(Header::new("short", HeaderValue::Int16(16_000i16))) + .add_header(Header::new("string", HeaderValue::String("test".into()))) + .add_header(Header::new("timestamp", HeaderValue::Timestamp(DateTime::from_secs(5)))); + assert_eq!(expected_message, actual_message); + """, + ) + + unitTest( + "message_with_header_and_payload", + """ + let event = TestStream::MessageWithHeaderAndPayload(MessageWithHeaderAndPayload::builder() + .header("header") + .payload(Blob::new(&b"payload"[..])) + .build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let actual_message = result.unwrap(); + let expected_message = Message::new(&b"payload"[..]) + .add_header(Header::new(":message-type", HeaderValue::String("event".into()))) + .add_header(Header::new(":event-type", HeaderValue::String("MessageWithHeaderAndPayload".into()))) + .add_header(Header::new("header", HeaderValue::String("header".into()))) + .add_header(Header::new(":content-type", HeaderValue::String("application/octet-stream".into()))); + assert_eq!(expected_message, actual_message); + """, + ) + + unitTest( + "message_with_no_header_payload_traits", + """ + let event = TestStream::MessageWithNoHeaderPayloadTraits(MessageWithNoHeaderPayloadTraits::builder() + .some_int(5) + .some_string("hello") + .build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithNoHeaderPayloadTraits"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); + + validate_body( + message.payload(), + ${testCase.validMessageWithNoHeaderPayloadTraits.dq()}, + MediaType::from(${testCase.requestContentType.dq()}) + ).unwrap(); + """, + ) + } +} diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/EventStreamTestTools.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/EventStreamTestTools.kt deleted file mode 100644 index 71e425eb384..00000000000 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/EventStreamTestTools.kt +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rust.codegen.server.smithy.protocols - -import org.junit.jupiter.api.extension.ExtensionContext -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.ArgumentsProvider -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.shapes.StructureShape -import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.ErrorTrait -import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider -import software.amazon.smithy.rust.codegen.core.rustlang.RustModule -import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter -import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext -import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget -import software.amazon.smithy.rust.codegen.core.smithy.ErrorsModule -import software.amazon.smithy.rust.codegen.core.smithy.ModelsModule -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerator -import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator -import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator -import software.amazon.smithy.rust.codegen.core.smithy.generators.error.CombinedErrorGenerator -import software.amazon.smithy.rust.codegen.core.smithy.generators.error.ServerCombinedErrorGenerator -import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock -import software.amazon.smithy.rust.codegen.core.smithy.generators.renderUnknownVariant -import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJson -import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJsonVersion -import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsQueryProtocol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.Ec2QueryProtocol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestJson -import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestXml -import software.amazon.smithy.rust.codegen.core.smithy.transformers.EventStreamNormalizer -import software.amazon.smithy.rust.codegen.core.smithy.transformers.OperationNormalizer -import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace -import software.amazon.smithy.rust.codegen.core.testutil.TestWriterDelegator -import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel -import software.amazon.smithy.rust.codegen.core.testutil.renderWithModelBuilder -import software.amazon.smithy.rust.codegen.core.util.hasTrait -import software.amazon.smithy.rust.codegen.core.util.lookup -import software.amazon.smithy.rust.codegen.core.util.outputShape -import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider -import java.util.stream.Stream -import kotlin.streams.toList - -private fun fillInBaseModel( - protocolName: String, - extraServiceAnnotations: String = "", -): String = """ - namespace test - - use aws.protocols#$protocolName - - union TestUnion { - Foo: String, - Bar: Integer, - } - structure TestStruct { - someString: String, - someInt: Integer, - } - - @error("client") - structure SomeError { - Message: String, - } - - structure MessageWithBlob { @eventPayload data: Blob } - structure MessageWithString { @eventPayload data: String } - structure MessageWithStruct { @eventPayload someStruct: TestStruct } - structure MessageWithUnion { @eventPayload someUnion: TestUnion } - structure MessageWithHeaders { - @eventHeader blob: Blob, - @eventHeader boolean: Boolean, - @eventHeader byte: Byte, - @eventHeader int: Integer, - @eventHeader long: Long, - @eventHeader short: Short, - @eventHeader string: String, - @eventHeader timestamp: Timestamp, - } - structure MessageWithHeaderAndPayload { - @eventHeader header: String, - @eventPayload payload: Blob, - } - structure MessageWithNoHeaderPayloadTraits { - someInt: Integer, - someString: String, - } - - @streaming - union TestStream { - MessageWithBlob: MessageWithBlob, - MessageWithString: MessageWithString, - MessageWithStruct: MessageWithStruct, - MessageWithUnion: MessageWithUnion, - MessageWithHeaders: MessageWithHeaders, - MessageWithHeaderAndPayload: MessageWithHeaderAndPayload, - MessageWithNoHeaderPayloadTraits: MessageWithNoHeaderPayloadTraits, - SomeError: SomeError, - } - structure TestStreamInputOutput { @httpPayload @required value: TestStream } - operation TestStreamOp { - input: TestStreamInputOutput, - output: TestStreamInputOutput, - errors: [SomeError], - } - $extraServiceAnnotations - @$protocolName - service TestService { version: "123", operations: [TestStreamOp] } -""" - -object EventStreamTestModels { - private fun restJson1(): Model = fillInBaseModel("restJson1").asSmithyModel() - private fun restXml(): Model = fillInBaseModel("restXml").asSmithyModel() - private fun awsJson11(): Model = fillInBaseModel("awsJson1_1").asSmithyModel() - private fun awsQuery(): Model = - fillInBaseModel("awsQuery", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() - private fun ec2Query(): Model = - fillInBaseModel("ec2Query", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() - - data class TestCase( - val protocolShapeId: String, - val model: Model, - val requestContentType: String, - val responseContentType: String, - val validTestStruct: String, - val validMessageWithNoHeaderPayloadTraits: String, - val validTestUnion: String, - val validSomeError: String, - val validUnmodeledError: String, - val target: CodegenTarget = CodegenTarget.CLIENT, - val protocolBuilder: (CodegenContext) -> Protocol, - ) { - override fun toString(): String = protocolShapeId - } - - private val testCases = listOf( - // - // restJson1 - // - TestCase( - protocolShapeId = "aws.protocols#restJson1", - model = restJson1(), - requestContentType = "application/json", - responseContentType = "application/json", - validTestStruct = """{"someString":"hello","someInt":5}""", - validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", - validTestUnion = """{"Foo":"hello"}""", - validSomeError = """{"Message":"some error"}""", - validUnmodeledError = """{"Message":"unmodeled error"}""", - ) { RestJson(it) }, - - // - // restJson1, server mode - // - TestCase( - protocolShapeId = "aws.protocols#restJson1", - model = restJson1(), - requestContentType = "application/json", - responseContentType = "application/json", - validTestStruct = """{"someString":"hello","someInt":5}""", - validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", - validTestUnion = """{"Foo":"hello"}""", - validSomeError = """{"Message":"some error"}""", - validUnmodeledError = """{"Message":"unmodeled error"}""", - ) { RestJson(it) }, - - // - // awsJson1_1 - // - TestCase( - protocolShapeId = "aws.protocols#awsJson1_1", - model = awsJson11(), - requestContentType = "application/x-amz-json-1.1", - responseContentType = "application/x-amz-json-1.1", - validTestStruct = """{"someString":"hello","someInt":5}""", - validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", - validTestUnion = """{"Foo":"hello"}""", - validSomeError = """{"Message":"some error"}""", - validUnmodeledError = """{"Message":"unmodeled error"}""", - ) { AwsJson(it, AwsJsonVersion.Json11) }, - - // - // restXml - // - TestCase( - protocolShapeId = "aws.protocols#restXml", - model = restXml(), - requestContentType = "application/xml", - responseContentType = "application/xml", - validTestStruct = """ - - hello - 5 - - """.trimIndent(), - validMessageWithNoHeaderPayloadTraits = """ - - hello - 5 - - """.trimIndent(), - validTestUnion = "hello", - validSomeError = """ - - - SomeError - SomeError - some error - - - """.trimIndent(), - validUnmodeledError = """ - - - UnmodeledError - UnmodeledError - unmodeled error - - - """.trimIndent(), - ) { RestXml(it) }, - - // - // awsQuery - // - TestCase( - protocolShapeId = "aws.protocols#awsQuery", - model = awsQuery(), - requestContentType = "application/x-www-form-urlencoded", - responseContentType = "text/xml", - validTestStruct = """ - - hello - 5 - - """.trimIndent(), - validMessageWithNoHeaderPayloadTraits = """ - - hello - 5 - - """.trimIndent(), - validTestUnion = "hello", - validSomeError = """ - - - SomeError - SomeError - some error - - - """.trimIndent(), - validUnmodeledError = """ - - - UnmodeledError - UnmodeledError - unmodeled error - - - """.trimIndent(), - ) { AwsQueryProtocol(it) }, - - // - // ec2Query - // - TestCase( - protocolShapeId = "aws.protocols#ec2Query", - model = ec2Query(), - requestContentType = "application/x-www-form-urlencoded", - responseContentType = "text/xml", - validTestStruct = """ - - hello - 5 - - """.trimIndent(), - validMessageWithNoHeaderPayloadTraits = """ - - hello - 5 - - """.trimIndent(), - validTestUnion = "hello", - validSomeError = """ - - - - SomeError - SomeError - some error - - - - """.trimIndent(), - validUnmodeledError = """ - - - - UnmodeledError - UnmodeledError - unmodeled error - - - - """.trimIndent(), - ) { Ec2QueryProtocol(it) }, - ) - // TODO(https://github.com/awslabs/smithy-rs/issues/1442) Server tests - // should be run from the server subproject using the - // `serverTestSymbolProvider()`. - // .flatMap { listOf(it, it.copy(target = CodegenTarget.SERVER)) } - - class UnmarshallTestCasesProvider : ArgumentsProvider { - override fun provideArguments(context: ExtensionContext?): Stream = - testCases.map { Arguments.of(it) }.stream() - } - - class MarshallTestCasesProvider : ArgumentsProvider { - override fun provideArguments(context: ExtensionContext?): Stream = - // Don't include awsQuery or ec2Query for now since marshall support for them is unimplemented - testCases - .filter { testCase -> !testCase.protocolShapeId.contains("Query") } - .map { Arguments.of(it) }.stream() - } -} - -data class TestEventStreamProject( - val model: Model, - val serviceShape: ServiceShape, - val operationShape: OperationShape, - val streamShape: UnionShape, - val symbolProvider: RustSymbolProvider, - val project: TestWriterDelegator, -) - -object EventStreamTestTools { - fun generateTestProject(testCase: EventStreamTestModels.TestCase): TestEventStreamProject { - val model = EventStreamNormalizer.transform(OperationNormalizer.transform(testCase.model)) - val serviceShape = model.expectShape(ShapeId.from("test#TestService")) as ServiceShape - val operationShape = model.expectShape(ShapeId.from("test#TestStreamOp")) as OperationShape - val unionShape = model.expectShape(ShapeId.from("test#TestStream")) as UnionShape - - val symbolProvider = when (testCase.target) { - CodegenTarget.CLIENT -> testSymbolProvider(model) - CodegenTarget.SERVER -> serverTestSymbolProvider(model) - } - val project = TestWorkspace.testProject(symbolProvider) - val operationSymbol = symbolProvider.toSymbol(operationShape) - project.withModule(ErrorsModule) { - val errors = model.shapes() - .filter { shape -> shape.isStructureShape && shape.hasTrait() } - .map { it.asStructureShape().get() } - .toList() - when (testCase.target) { - CodegenTarget.CLIENT -> CombinedErrorGenerator(model, symbolProvider, operationSymbol, errors).render(this) - CodegenTarget.SERVER -> ServerCombinedErrorGenerator(model, symbolProvider, operationSymbol, errors).render(this) - } - for (shape in model.shapes().filter { shape -> shape.isStructureShape && shape.hasTrait() }) { - StructureGenerator(model, symbolProvider, this, shape as StructureShape).render(testCase.target) - val builderGen = BuilderGenerator(model, symbolProvider, shape) - builderGen.render(this) - implBlock(shape, symbolProvider) { - builderGen.renderConvenienceMethod(this) - } - } - } - project.withModule(ModelsModule) { - val inputOutput = model.lookup("test#TestStreamInputOutput") - recursivelyGenerateModels(model, symbolProvider, inputOutput, this, testCase.target) - } - project.withModule(RustModule.Output) { - operationShape.outputShape(model).renderWithModelBuilder(model, symbolProvider, this) - } - return TestEventStreamProject(model, serviceShape, operationShape, unionShape, symbolProvider, project) - } - - private fun recursivelyGenerateModels( - model: Model, - symbolProvider: RustSymbolProvider, - shape: Shape, - writer: RustWriter, - mode: CodegenTarget, - ) { - for (member in shape.members()) { - val target = model.expectShape(member.target) - if (target is StructureShape || target is UnionShape) { - if (target is StructureShape) { - target.renderWithModelBuilder(model, symbolProvider, writer) - } else if (target is UnionShape) { - UnionGenerator(model, symbolProvider, writer, target, renderUnknownVariant = mode.renderUnknownVariant()).render() - } - recursivelyGenerateModels(model, symbolProvider, target, writer, mode) - } - } - } -} diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt index 5094426d752..a49fc0af800 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt @@ -5,302 +5,45 @@ package software.amazon.smithy.rust.codegen.server.smithy.protocols.parse +import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource import software.amazon.smithy.codegen.core.Symbol -import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.generators.builderSymbol import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.EventStreamUnmarshallerGenerator -import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest -import software.amazon.smithy.rust.codegen.core.testutil.testRustSettings -import software.amazon.smithy.rust.codegen.core.testutil.unitTest -import software.amazon.smithy.rust.codegen.server.smithy.protocols.EventStreamTestModels -import software.amazon.smithy.rust.codegen.server.smithy.protocols.EventStreamTestTools +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools +import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider +import java.util.stream.Stream + +class UnmarshallTestCasesProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream = + EventStreamTestModels.TEST_CASES.map { Arguments.of(it) }.stream() +} class EventStreamUnmarshallerGeneratorTest { @ParameterizedTest - @ArgumentsSource(EventStreamTestModels.UnmarshallTestCasesProvider::class) + @ArgumentsSource(UnmarshallTestCasesProvider::class) fun test(testCase: EventStreamTestModels.TestCase) { - val test = EventStreamTestTools.generateTestProject(testCase) - - val codegenContext = CodegenContext( - test.model, - test.symbolProvider, - test.serviceShape, - ShapeId.from(testCase.protocolShapeId), - testRustSettings(), - target = testCase.target, + EventStreamTestTools.runTestCase( + testCase, + CodegenTarget.SERVER, + { model -> serverTestSymbolProvider(model) }, + { codegenContext, test, protocol -> + fun builderSymbol(shape: StructureShape): Symbol = shape.builderSymbol(codegenContext.symbolProvider) + EventStreamUnmarshallerGenerator( + protocol, + codegenContext, + test.operationShape, + test.streamShape, + ::builderSymbol, + ).render() + }, + marshall = false, ) - val protocol = testCase.protocolBuilder(codegenContext) - fun builderSymbol(shape: StructureShape): Symbol = shape.builderSymbol(codegenContext.symbolProvider) - val generator = EventStreamUnmarshallerGenerator( - protocol, - codegenContext, - test.operationShape, - test.streamShape, - ::builderSymbol, - ) - - test.project.lib { - rust( - """ - use aws_smithy_eventstream::frame::{Header, HeaderValue, Message, UnmarshallMessage, UnmarshalledMessage}; - use aws_smithy_types::{Blob, DateTime}; - use crate::error::*; - use crate::model::*; - - fn msg( - message_type: &'static str, - event_type: &'static str, - content_type: &'static str, - payload: &'static [u8], - ) -> Message { - let message = Message::new(payload) - .add_header(Header::new(":message-type", HeaderValue::String(message_type.into()))) - .add_header(Header::new(":content-type", HeaderValue::String(content_type.into()))); - if message_type == "event" { - message.add_header(Header::new(":event-type", HeaderValue::String(event_type.into()))) - } else { - message.add_header(Header::new(":exception-type", HeaderValue::String(event_type.into()))) - } - } - fn expect_event(unmarshalled: UnmarshalledMessage) -> T { - match unmarshalled { - UnmarshalledMessage::Event(event) => event, - _ => panic!("expected event, got: {:?}", unmarshalled), - } - } - fn expect_error(unmarshalled: UnmarshalledMessage) -> E { - match unmarshalled { - UnmarshalledMessage::Error(error) => error, - _ => panic!("expected error, got: {:?}", unmarshalled), - } - } - """, - ) - - unitTest( - name = "message_with_blob", - test = """ - let message = msg("event", "MessageWithBlob", "application/octet-stream", b"hello, world!"); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithBlob( - MessageWithBlob::builder().data(Blob::new(&b"hello, world!"[..])).build() - ), - expect_event(result.unwrap()) - ); - """, - ) - - if (testCase.target == CodegenTarget.CLIENT) { - unitTest( - "unknown_message", - """ - let message = msg("event", "NewUnmodeledMessageType", "application/octet-stream", b"hello, world!"); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::Unknown, - expect_event(result.unwrap()) - ); - """, - ) - } - - unitTest( - "message_with_string", - """ - let message = msg("event", "MessageWithString", "text/plain", b"hello, world!"); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithString(MessageWithString::builder().data("hello, world!").build()), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_struct", - """ - let message = msg( - "event", - "MessageWithStruct", - "${testCase.responseContentType}", - br#"${testCase.validTestStruct}"# - ); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithStruct(MessageWithStruct::builder().some_struct( - TestStruct::builder() - .some_string("hello") - .some_int(5) - .build() - ).build()), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_union", - """ - let message = msg( - "event", - "MessageWithUnion", - "${testCase.responseContentType}", - br#"${testCase.validTestUnion}"# - ); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithUnion(MessageWithUnion::builder().some_union( - TestUnion::Foo("hello".into()) - ).build()), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_headers", - """ - let message = msg("event", "MessageWithHeaders", "application/octet-stream", b"") - .add_header(Header::new("blob", HeaderValue::ByteArray((&b"test"[..]).into()))) - .add_header(Header::new("boolean", HeaderValue::Bool(true))) - .add_header(Header::new("byte", HeaderValue::Byte(55i8))) - .add_header(Header::new("int", HeaderValue::Int32(100_000i32))) - .add_header(Header::new("long", HeaderValue::Int64(9_000_000_000i64))) - .add_header(Header::new("short", HeaderValue::Int16(16_000i16))) - .add_header(Header::new("string", HeaderValue::String("test".into()))) - .add_header(Header::new("timestamp", HeaderValue::Timestamp(DateTime::from_secs(5)))); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithHeaders(MessageWithHeaders::builder() - .blob(Blob::new(&b"test"[..])) - .boolean(true) - .byte(55i8) - .int(100_000i32) - .long(9_000_000_000i64) - .short(16_000i16) - .string("test") - .timestamp(DateTime::from_secs(5)) - .build() - ), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_header_and_payload", - """ - let message = msg("event", "MessageWithHeaderAndPayload", "application/octet-stream", b"payload") - .add_header(Header::new("header", HeaderValue::String("header".into()))); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithHeaderAndPayload(MessageWithHeaderAndPayload::builder() - .header("header") - .payload(Blob::new(&b"payload"[..])) - .build() - ), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_no_header_payload_traits", - """ - let message = msg( - "event", - "MessageWithNoHeaderPayloadTraits", - "${testCase.responseContentType}", - br#"${testCase.validMessageWithNoHeaderPayloadTraits}"# - ); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithNoHeaderPayloadTraits(MessageWithNoHeaderPayloadTraits::builder() - .some_int(5) - .some_string("hello") - .build() - ), - expect_event(result.unwrap()) - ); - """, - ) - - val (someError, kindSuffix) = when (testCase.target) { - CodegenTarget.CLIENT -> listOf("TestStreamErrorKind::SomeError", ".kind") - CodegenTarget.SERVER -> listOf("TestStreamError::SomeError", "") - } - unitTest( - "some_error", - """ - let message = msg( - "exception", - "SomeError", - "${testCase.responseContentType}", - br#"${testCase.validSomeError}"# - ); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - match expect_error(result.unwrap())$kindSuffix { - $someError(err) => assert_eq!(Some("some error"), err.message()), - kind => panic!("expected SomeError, but got {:?}", kind), - } - """, - ) - - if (testCase.target == CodegenTarget.CLIENT) { - unitTest( - "generic_error", - """ - let message = msg( - "exception", - "UnmodeledError", - "${testCase.responseContentType}", - br#"${testCase.validUnmodeledError}"# - ); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - match expect_error(result.unwrap())$kindSuffix { - TestStreamErrorKind::Unhandled(err) => { - let message = format!("{}", aws_smithy_types::error::display::DisplayErrorContext(&err)); - let expected = "message: \"unmodeled error\""; - assert!(message.contains(expected), "Expected '{message}' to contain '{expected}'"); - } - kind => panic!("expected generic error, but got {:?}", kind), - } - """, - ) - } - - unitTest( - "bad_content_type", - """ - let message = msg( - "event", - "MessageWithBlob", - "wrong-content-type", - br#"${testCase.validTestStruct}"# - ); - let result = ${format(generator.render())}().unmarshall(&message); - assert!(result.is_err(), "expected error, got: {:?}", result); - assert!(format!("{}", result.err().unwrap()).contains("expected :content-type to be")); - """, - ) - } - test.project.compileAndTest() } } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt index 213318b027d..25d6dfadfd0 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt @@ -5,236 +5,47 @@ package software.amazon.smithy.rust.codegen.server.smithy.protocols.serialize +import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource -import software.amazon.smithy.model.shapes.ShapeId -import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency -import software.amazon.smithy.rust.codegen.core.rustlang.DependencyScope -import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext +import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.EventStreamMarshallerGenerator +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig -import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest -import software.amazon.smithy.rust.codegen.core.testutil.testRustSettings -import software.amazon.smithy.rust.codegen.core.testutil.unitTest -import software.amazon.smithy.rust.codegen.core.util.dq -import software.amazon.smithy.rust.codegen.server.smithy.protocols.EventStreamTestModels -import software.amazon.smithy.rust.codegen.server.smithy.protocols.EventStreamTestTools +import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider +import java.util.stream.Stream + +class MarshallTestCasesProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream = + // Don't include awsQuery or ec2Query for now since marshall support for them is unimplemented + EventStreamTestModels.TEST_CASES + .filter { testCase -> !testCase.protocolShapeId.contains("Query") } + .map { Arguments.of(it) }.stream() +} class EventStreamMarshallerGeneratorTest { @ParameterizedTest - @ArgumentsSource(EventStreamTestModels.MarshallTestCasesProvider::class) + @ArgumentsSource(MarshallTestCasesProvider::class) fun test(testCase: EventStreamTestModels.TestCase) { - val test = EventStreamTestTools.generateTestProject(testCase) - - val codegenContext = CodegenContext( - test.model, - test.symbolProvider, - test.serviceShape, - ShapeId.from(testCase.protocolShapeId), - testRustSettings(), - target = testCase.target, - ) - val protocol = testCase.protocolBuilder(codegenContext) - val generator = EventStreamMarshallerGenerator( - test.model, - testCase.target, - TestRuntimeConfig, - test.symbolProvider, - test.streamShape, - protocol.structuredDataSerializer(test.operationShape), - testCase.requestContentType, + EventStreamTestTools.runTestCase( + testCase, + CodegenTarget.SERVER, + { model -> serverTestSymbolProvider(model) }, + { _, test, protocol -> + EventStreamMarshallerGenerator( + test.model, + CodegenTarget.SERVER, + TestRuntimeConfig, + test.symbolProvider, + test.streamShape, + protocol.structuredDataSerializer(test.operationShape), + testCase.requestContentType, + ).render() + }, + marshall = true, ) - - test.project.lib { - val protocolTestHelpers = CargoDependency.smithyProtocolTestHelpers(TestRuntimeConfig) - .copy(scope = DependencyScope.Compile) - rustTemplate( - """ - use aws_smithy_eventstream::frame::{Message, Header, HeaderValue, MarshallMessage}; - use std::collections::HashMap; - use aws_smithy_types::{Blob, DateTime}; - use crate::error::*; - use crate::model::*; - - use #{validate_body}; - use #{MediaType}; - - fn headers_to_map<'a>(headers: &'a [Header]) -> HashMap { - let mut map = HashMap::new(); - for header in headers { - map.insert(header.name().as_str().to_string(), header.value()); - } - map - } - - fn str_header(value: &'static str) -> HeaderValue { - HeaderValue::String(value.into()) - } - """, - "validate_body" to protocolTestHelpers.toType().resolve("validate_body"), - "MediaType" to protocolTestHelpers.toType().resolve("MediaType"), - ) - - unitTest( - "message_with_blob", - """ - let event = TestStream::MessageWithBlob( - MessageWithBlob::builder().data(Blob::new(&b"hello, world!"[..])).build() - ); - let result = ${format(generator.render())}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithBlob"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header("application/octet-stream"), *headers.get(":content-type").unwrap()); - assert_eq!(&b"hello, world!"[..], message.payload()); - """, - ) - - unitTest( - "message_with_string", - """ - let event = TestStream::MessageWithString( - MessageWithString::builder().data("hello, world!").build() - ); - let result = ${format(generator.render())}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithString"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header("text/plain"), *headers.get(":content-type").unwrap()); - assert_eq!(&b"hello, world!"[..], message.payload()); - """, - ) - - unitTest( - "message_with_struct", - """ - let event = TestStream::MessageWithStruct( - MessageWithStruct::builder().some_struct( - TestStruct::builder() - .some_string("hello") - .some_int(5) - .build() - ).build() - ); - let result = ${format(generator.render())}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithStruct"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); - - validate_body( - message.payload(), - ${testCase.validTestStruct.dq()}, - MediaType::from(${testCase.requestContentType.dq()}) - ).unwrap(); - """, - ) - - unitTest( - "message_with_union", - """ - let event = TestStream::MessageWithUnion(MessageWithUnion::builder().some_union( - TestUnion::Foo("hello".into()) - ).build()); - let result = ${format(generator.render())}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithUnion"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); - - validate_body( - message.payload(), - ${testCase.validTestUnion.dq()}, - MediaType::from(${testCase.requestContentType.dq()}) - ).unwrap(); - """, - ) - - unitTest( - "message_with_headers", - """ - let event = TestStream::MessageWithHeaders(MessageWithHeaders::builder() - .blob(Blob::new(&b"test"[..])) - .boolean(true) - .byte(55i8) - .int(100_000i32) - .long(9_000_000_000i64) - .short(16_000i16) - .string("test") - .timestamp(DateTime::from_secs(5)) - .build() - ); - let result = ${format(generator.render())}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let actual_message = result.unwrap(); - let expected_message = Message::new(&b""[..]) - .add_header(Header::new(":message-type", HeaderValue::String("event".into()))) - .add_header(Header::new(":event-type", HeaderValue::String("MessageWithHeaders".into()))) - .add_header(Header::new("blob", HeaderValue::ByteArray((&b"test"[..]).into()))) - .add_header(Header::new("boolean", HeaderValue::Bool(true))) - .add_header(Header::new("byte", HeaderValue::Byte(55i8))) - .add_header(Header::new("int", HeaderValue::Int32(100_000i32))) - .add_header(Header::new("long", HeaderValue::Int64(9_000_000_000i64))) - .add_header(Header::new("short", HeaderValue::Int16(16_000i16))) - .add_header(Header::new("string", HeaderValue::String("test".into()))) - .add_header(Header::new("timestamp", HeaderValue::Timestamp(DateTime::from_secs(5)))); - assert_eq!(expected_message, actual_message); - """, - ) - - unitTest( - "message_with_header_and_payload", - """ - let event = TestStream::MessageWithHeaderAndPayload(MessageWithHeaderAndPayload::builder() - .header("header") - .payload(Blob::new(&b"payload"[..])) - .build() - ); - let result = ${format(generator.render())}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let actual_message = result.unwrap(); - let expected_message = Message::new(&b"payload"[..]) - .add_header(Header::new(":message-type", HeaderValue::String("event".into()))) - .add_header(Header::new(":event-type", HeaderValue::String("MessageWithHeaderAndPayload".into()))) - .add_header(Header::new("header", HeaderValue::String("header".into()))) - .add_header(Header::new(":content-type", HeaderValue::String("application/octet-stream".into()))); - assert_eq!(expected_message, actual_message); - """, - ) - - unitTest( - "message_with_no_header_payload_traits", - """ - let event = TestStream::MessageWithNoHeaderPayloadTraits(MessageWithNoHeaderPayloadTraits::builder() - .some_int(5) - .some_string("hello") - .build() - ); - let result = ${format(generator.render())}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithNoHeaderPayloadTraits"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); - - validate_body( - message.payload(), - ${testCase.validMessageWithNoHeaderPayloadTraits.dq()}, - MediaType::from(${testCase.requestContentType.dq()}) - ).unwrap(); - """, - ) - } - test.project.compileAndTest() } } From 69cdfc865d203314eece3137174c542c0d015ea2 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 14 Dec 2022 18:00:39 -0800 Subject: [PATCH 07/19] Break `codegen-server` dependency on `codegen-client` --- codegen-server/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/codegen-server/build.gradle.kts b/codegen-server/build.gradle.kts index d9cea785193..caecf55676d 100644 --- a/codegen-server/build.gradle.kts +++ b/codegen-server/build.gradle.kts @@ -25,7 +25,6 @@ val kotestVersion: String by project dependencies { implementation(project(":codegen-core")) - implementation(project(":codegen-client")) implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion") implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion") testImplementation("org.junit.jupiter:junit-jupiter:5.6.1") From b8b6ed5a1a20bfb80ae159fc067cfea6bfbf1d6c Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Fri, 16 Dec 2022 16:55:53 -0800 Subject: [PATCH 08/19] Split up `EventStreamTestTools` --- .../testutil/EventStreamMarshallTestCases.kt | 208 +++++ .../core/testutil/EventStreamTestModels.kt | 267 +++++++ .../core/testutil/EventStreamTestTools.kt | 718 +----------------- .../EventStreamUnmarshallTestCases.kt | 274 +++++++ 4 files changed, 751 insertions(+), 716 deletions(-) create mode 100644 codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamMarshallTestCases.kt create mode 100644 codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt create mode 100644 codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamMarshallTestCases.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamMarshallTestCases.kt new file mode 100644 index 00000000000..6e82fc1b2ca --- /dev/null +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamMarshallTestCases.kt @@ -0,0 +1,208 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.core.testutil + +import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.core.rustlang.DependencyScope +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.util.dq + +internal object EventStreamMarshallTestCases { + internal fun RustWriter.writeMarshallTestCases( + testCase: EventStreamTestModels.TestCase, + generator: RuntimeType, + ) { + val protocolTestHelpers = CargoDependency.smithyProtocolTestHelpers(TestRuntimeConfig) + .copy(scope = DependencyScope.Compile) + rustTemplate( + """ + use aws_smithy_eventstream::frame::{Message, Header, HeaderValue, MarshallMessage}; + use std::collections::HashMap; + use aws_smithy_types::{Blob, DateTime}; + use crate::error::*; + use crate::model::*; + + use #{validate_body}; + use #{MediaType}; + + fn headers_to_map<'a>(headers: &'a [Header]) -> HashMap { + let mut map = HashMap::new(); + for header in headers { + map.insert(header.name().as_str().to_string(), header.value()); + } + map + } + + fn str_header(value: &'static str) -> HeaderValue { + HeaderValue::String(value.into()) + } + """, + "validate_body" to protocolTestHelpers.toType().resolve("validate_body"), + "MediaType" to protocolTestHelpers.toType().resolve("MediaType"), + ) + + unitTest( + "message_with_blob", + """ + let event = TestStream::MessageWithBlob( + MessageWithBlob::builder().data(Blob::new(&b"hello, world!"[..])).build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithBlob"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header("application/octet-stream"), *headers.get(":content-type").unwrap()); + assert_eq!(&b"hello, world!"[..], message.payload()); + """, + ) + + unitTest( + "message_with_string", + """ + let event = TestStream::MessageWithString( + MessageWithString::builder().data("hello, world!").build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithString"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header("text/plain"), *headers.get(":content-type").unwrap()); + assert_eq!(&b"hello, world!"[..], message.payload()); + """, + ) + + unitTest( + "message_with_struct", + """ + let event = TestStream::MessageWithStruct( + MessageWithStruct::builder().some_struct( + TestStruct::builder() + .some_string("hello") + .some_int(5) + .build() + ).build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithStruct"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); + + validate_body( + message.payload(), + ${testCase.validTestStruct.dq()}, + MediaType::from(${testCase.requestContentType.dq()}) + ).unwrap(); + """, + ) + + unitTest( + "message_with_union", + """ + let event = TestStream::MessageWithUnion(MessageWithUnion::builder().some_union( + TestUnion::Foo("hello".into()) + ).build()); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithUnion"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); + + validate_body( + message.payload(), + ${testCase.validTestUnion.dq()}, + MediaType::from(${testCase.requestContentType.dq()}) + ).unwrap(); + """, + ) + + unitTest( + "message_with_headers", + """ + let event = TestStream::MessageWithHeaders(MessageWithHeaders::builder() + .blob(Blob::new(&b"test"[..])) + .boolean(true) + .byte(55i8) + .int(100_000i32) + .long(9_000_000_000i64) + .short(16_000i16) + .string("test") + .timestamp(DateTime::from_secs(5)) + .build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let actual_message = result.unwrap(); + let expected_message = Message::new(&b""[..]) + .add_header(Header::new(":message-type", HeaderValue::String("event".into()))) + .add_header(Header::new(":event-type", HeaderValue::String("MessageWithHeaders".into()))) + .add_header(Header::new("blob", HeaderValue::ByteArray((&b"test"[..]).into()))) + .add_header(Header::new("boolean", HeaderValue::Bool(true))) + .add_header(Header::new("byte", HeaderValue::Byte(55i8))) + .add_header(Header::new("int", HeaderValue::Int32(100_000i32))) + .add_header(Header::new("long", HeaderValue::Int64(9_000_000_000i64))) + .add_header(Header::new("short", HeaderValue::Int16(16_000i16))) + .add_header(Header::new("string", HeaderValue::String("test".into()))) + .add_header(Header::new("timestamp", HeaderValue::Timestamp(DateTime::from_secs(5)))); + assert_eq!(expected_message, actual_message); + """, + ) + + unitTest( + "message_with_header_and_payload", + """ + let event = TestStream::MessageWithHeaderAndPayload(MessageWithHeaderAndPayload::builder() + .header("header") + .payload(Blob::new(&b"payload"[..])) + .build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let actual_message = result.unwrap(); + let expected_message = Message::new(&b"payload"[..]) + .add_header(Header::new(":message-type", HeaderValue::String("event".into()))) + .add_header(Header::new(":event-type", HeaderValue::String("MessageWithHeaderAndPayload".into()))) + .add_header(Header::new("header", HeaderValue::String("header".into()))) + .add_header(Header::new(":content-type", HeaderValue::String("application/octet-stream".into()))); + assert_eq!(expected_message, actual_message); + """, + ) + + unitTest( + "message_with_no_header_payload_traits", + """ + let event = TestStream::MessageWithNoHeaderPayloadTraits(MessageWithNoHeaderPayloadTraits::builder() + .some_int(5) + .some_string("hello") + .build() + ); + let result = ${format(generator)}().marshall(event); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + let message = result.unwrap(); + let headers = headers_to_map(message.headers()); + assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); + assert_eq!(&str_header("MessageWithNoHeaderPayloadTraits"), *headers.get(":event-type").unwrap()); + assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); + + validate_body( + message.payload(), + ${testCase.validMessageWithNoHeaderPayloadTraits.dq()}, + MediaType::from(${testCase.requestContentType.dq()}) + ).unwrap(); + """, + ) + } +} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt new file mode 100644 index 00000000000..00fdf08998a --- /dev/null +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt @@ -0,0 +1,267 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.core.testutil + +import software.amazon.smithy.model.Model +import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext +import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJson +import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJsonVersion +import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsQueryProtocol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.Ec2QueryProtocol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestJson +import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestXml + +private fun fillInBaseModel( + protocolName: String, + extraServiceAnnotations: String = "", +): String = """ + namespace test + + use aws.protocols#$protocolName + + union TestUnion { + Foo: String, + Bar: Integer, + } + structure TestStruct { + someString: String, + someInt: Integer, + } + + @error("client") + structure SomeError { + Message: String, + } + + structure MessageWithBlob { @eventPayload data: Blob } + structure MessageWithString { @eventPayload data: String } + structure MessageWithStruct { @eventPayload someStruct: TestStruct } + structure MessageWithUnion { @eventPayload someUnion: TestUnion } + structure MessageWithHeaders { + @eventHeader blob: Blob, + @eventHeader boolean: Boolean, + @eventHeader byte: Byte, + @eventHeader int: Integer, + @eventHeader long: Long, + @eventHeader short: Short, + @eventHeader string: String, + @eventHeader timestamp: Timestamp, + } + structure MessageWithHeaderAndPayload { + @eventHeader header: String, + @eventPayload payload: Blob, + } + structure MessageWithNoHeaderPayloadTraits { + someInt: Integer, + someString: String, + } + + @streaming + union TestStream { + MessageWithBlob: MessageWithBlob, + MessageWithString: MessageWithString, + MessageWithStruct: MessageWithStruct, + MessageWithUnion: MessageWithUnion, + MessageWithHeaders: MessageWithHeaders, + MessageWithHeaderAndPayload: MessageWithHeaderAndPayload, + MessageWithNoHeaderPayloadTraits: MessageWithNoHeaderPayloadTraits, + SomeError: SomeError, + } + structure TestStreamInputOutput { @httpPayload @required value: TestStream } + operation TestStreamOp { + input: TestStreamInputOutput, + output: TestStreamInputOutput, + errors: [SomeError], + } + $extraServiceAnnotations + @$protocolName + service TestService { version: "123", operations: [TestStreamOp] } +""" + +object EventStreamTestModels { + private fun restJson1(): Model = fillInBaseModel("restJson1").asSmithyModel() + private fun restXml(): Model = fillInBaseModel("restXml").asSmithyModel() + private fun awsJson11(): Model = fillInBaseModel("awsJson1_1").asSmithyModel() + private fun awsQuery(): Model = + fillInBaseModel("awsQuery", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() + private fun ec2Query(): Model = + fillInBaseModel("ec2Query", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() + + data class TestCase( + val protocolShapeId: String, + val model: Model, + val requestContentType: String, + val responseContentType: String, + val validTestStruct: String, + val validMessageWithNoHeaderPayloadTraits: String, + val validTestUnion: String, + val validSomeError: String, + val validUnmodeledError: String, + val protocolBuilder: (CodegenContext) -> Protocol, + ) { + override fun toString(): String = protocolShapeId + } + + val TEST_CASES = listOf( + // + // restJson1 + // + TestCase( + protocolShapeId = "aws.protocols#restJson1", + model = restJson1(), + requestContentType = "application/json", + responseContentType = "application/json", + validTestStruct = """{"someString":"hello","someInt":5}""", + validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", + validTestUnion = """{"Foo":"hello"}""", + validSomeError = """{"Message":"some error"}""", + validUnmodeledError = """{"Message":"unmodeled error"}""", + ) { RestJson(it) }, + + // + // awsJson1_1 + // + TestCase( + protocolShapeId = "aws.protocols#awsJson1_1", + model = awsJson11(), + requestContentType = "application/x-amz-json-1.1", + responseContentType = "application/x-amz-json-1.1", + validTestStruct = """{"someString":"hello","someInt":5}""", + validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", + validTestUnion = """{"Foo":"hello"}""", + validSomeError = """{"Message":"some error"}""", + validUnmodeledError = """{"Message":"unmodeled error"}""", + ) { AwsJson(it, AwsJsonVersion.Json11) }, + + // + // restXml + // + TestCase( + protocolShapeId = "aws.protocols#restXml", + model = restXml(), + requestContentType = "application/xml", + responseContentType = "application/xml", + validTestStruct = """ + + hello + 5 + + """.trimIndent(), + validMessageWithNoHeaderPayloadTraits = """ + + hello + 5 + + """.trimIndent(), + validTestUnion = "hello", + validSomeError = """ + + + SomeError + SomeError + some error + + + """.trimIndent(), + validUnmodeledError = """ + + + UnmodeledError + UnmodeledError + unmodeled error + + + """.trimIndent(), + ) { RestXml(it) }, + + // + // awsQuery + // + TestCase( + protocolShapeId = "aws.protocols#awsQuery", + model = awsQuery(), + requestContentType = "application/x-www-form-urlencoded", + responseContentType = "text/xml", + validTestStruct = """ + + hello + 5 + + """.trimIndent(), + validMessageWithNoHeaderPayloadTraits = """ + + hello + 5 + + """.trimIndent(), + validTestUnion = "hello", + validSomeError = """ + + + SomeError + SomeError + some error + + + """.trimIndent(), + validUnmodeledError = """ + + + UnmodeledError + UnmodeledError + unmodeled error + + + """.trimIndent(), + ) { AwsQueryProtocol(it) }, + + // + // ec2Query + // + TestCase( + protocolShapeId = "aws.protocols#ec2Query", + model = ec2Query(), + requestContentType = "application/x-www-form-urlencoded", + responseContentType = "text/xml", + validTestStruct = """ + + hello + 5 + + """.trimIndent(), + validMessageWithNoHeaderPayloadTraits = """ + + hello + 5 + + """.trimIndent(), + validTestUnion = "hello", + validSomeError = """ + + + + SomeError + SomeError + some error + + + + """.trimIndent(), + validUnmodeledError = """ + + + + UnmodeledError + UnmodeledError + unmodeled error + + + + """.trimIndent(), + ) { Ec2QueryProtocol(it) }, + ) +} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt index 73bd622b3ae..9fabf9d2bd3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt @@ -13,12 +13,8 @@ import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.ErrorTrait -import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency -import software.amazon.smithy.rust.codegen.core.rustlang.DependencyScope import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.ErrorsModule @@ -32,272 +28,16 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.error.Combined import software.amazon.smithy.rust.codegen.core.smithy.generators.error.ServerCombinedErrorGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock import software.amazon.smithy.rust.codegen.core.smithy.generators.renderUnknownVariant -import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJson -import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJsonVersion -import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsQueryProtocol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.Ec2QueryProtocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestJson -import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestXml import software.amazon.smithy.rust.codegen.core.smithy.transformers.EventStreamNormalizer import software.amazon.smithy.rust.codegen.core.smithy.transformers.OperationNormalizer -import software.amazon.smithy.rust.codegen.core.util.dq +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamMarshallTestCases.writeMarshallTestCases +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamUnmarshallTestCases.writeUnmarshallTestCases import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.outputShape import kotlin.streams.toList -private fun fillInBaseModel( - protocolName: String, - extraServiceAnnotations: String = "", -): String = """ - namespace test - - use aws.protocols#$protocolName - - union TestUnion { - Foo: String, - Bar: Integer, - } - structure TestStruct { - someString: String, - someInt: Integer, - } - - @error("client") - structure SomeError { - Message: String, - } - - structure MessageWithBlob { @eventPayload data: Blob } - structure MessageWithString { @eventPayload data: String } - structure MessageWithStruct { @eventPayload someStruct: TestStruct } - structure MessageWithUnion { @eventPayload someUnion: TestUnion } - structure MessageWithHeaders { - @eventHeader blob: Blob, - @eventHeader boolean: Boolean, - @eventHeader byte: Byte, - @eventHeader int: Integer, - @eventHeader long: Long, - @eventHeader short: Short, - @eventHeader string: String, - @eventHeader timestamp: Timestamp, - } - structure MessageWithHeaderAndPayload { - @eventHeader header: String, - @eventPayload payload: Blob, - } - structure MessageWithNoHeaderPayloadTraits { - someInt: Integer, - someString: String, - } - - @streaming - union TestStream { - MessageWithBlob: MessageWithBlob, - MessageWithString: MessageWithString, - MessageWithStruct: MessageWithStruct, - MessageWithUnion: MessageWithUnion, - MessageWithHeaders: MessageWithHeaders, - MessageWithHeaderAndPayload: MessageWithHeaderAndPayload, - MessageWithNoHeaderPayloadTraits: MessageWithNoHeaderPayloadTraits, - SomeError: SomeError, - } - structure TestStreamInputOutput { @httpPayload @required value: TestStream } - operation TestStreamOp { - input: TestStreamInputOutput, - output: TestStreamInputOutput, - errors: [SomeError], - } - $extraServiceAnnotations - @$protocolName - service TestService { version: "123", operations: [TestStreamOp] } -""" - -object EventStreamTestModels { - private fun restJson1(): Model = fillInBaseModel("restJson1").asSmithyModel() - private fun restXml(): Model = fillInBaseModel("restXml").asSmithyModel() - private fun awsJson11(): Model = fillInBaseModel("awsJson1_1").asSmithyModel() - private fun awsQuery(): Model = - fillInBaseModel("awsQuery", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() - private fun ec2Query(): Model = - fillInBaseModel("ec2Query", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() - - data class TestCase( - val protocolShapeId: String, - val model: Model, - val requestContentType: String, - val responseContentType: String, - val validTestStruct: String, - val validMessageWithNoHeaderPayloadTraits: String, - val validTestUnion: String, - val validSomeError: String, - val validUnmodeledError: String, - val protocolBuilder: (CodegenContext) -> Protocol, - ) { - override fun toString(): String = protocolShapeId - } - - val TEST_CASES = listOf( - // - // restJson1 - // - TestCase( - protocolShapeId = "aws.protocols#restJson1", - model = restJson1(), - requestContentType = "application/json", - responseContentType = "application/json", - validTestStruct = """{"someString":"hello","someInt":5}""", - validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", - validTestUnion = """{"Foo":"hello"}""", - validSomeError = """{"Message":"some error"}""", - validUnmodeledError = """{"Message":"unmodeled error"}""", - ) { RestJson(it) }, - - // - // awsJson1_1 - // - TestCase( - protocolShapeId = "aws.protocols#awsJson1_1", - model = awsJson11(), - requestContentType = "application/x-amz-json-1.1", - responseContentType = "application/x-amz-json-1.1", - validTestStruct = """{"someString":"hello","someInt":5}""", - validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", - validTestUnion = """{"Foo":"hello"}""", - validSomeError = """{"Message":"some error"}""", - validUnmodeledError = """{"Message":"unmodeled error"}""", - ) { AwsJson(it, AwsJsonVersion.Json11) }, - - // - // restXml - // - TestCase( - protocolShapeId = "aws.protocols#restXml", - model = restXml(), - requestContentType = "application/xml", - responseContentType = "application/xml", - validTestStruct = """ - - hello - 5 - - """.trimIndent(), - validMessageWithNoHeaderPayloadTraits = """ - - hello - 5 - - """.trimIndent(), - validTestUnion = "hello", - validSomeError = """ - - - SomeError - SomeError - some error - - - """.trimIndent(), - validUnmodeledError = """ - - - UnmodeledError - UnmodeledError - unmodeled error - - - """.trimIndent(), - ) { RestXml(it) }, - - // - // awsQuery - // - TestCase( - protocolShapeId = "aws.protocols#awsQuery", - model = awsQuery(), - requestContentType = "application/x-www-form-urlencoded", - responseContentType = "text/xml", - validTestStruct = """ - - hello - 5 - - """.trimIndent(), - validMessageWithNoHeaderPayloadTraits = """ - - hello - 5 - - """.trimIndent(), - validTestUnion = "hello", - validSomeError = """ - - - SomeError - SomeError - some error - - - """.trimIndent(), - validUnmodeledError = """ - - - UnmodeledError - UnmodeledError - unmodeled error - - - """.trimIndent(), - ) { AwsQueryProtocol(it) }, - - // - // ec2Query - // - TestCase( - protocolShapeId = "aws.protocols#ec2Query", - model = ec2Query(), - requestContentType = "application/x-www-form-urlencoded", - responseContentType = "text/xml", - validTestStruct = """ - - hello - 5 - - """.trimIndent(), - validMessageWithNoHeaderPayloadTraits = """ - - hello - 5 - - """.trimIndent(), - validTestUnion = "hello", - validSomeError = """ - - - - SomeError - SomeError - some error - - - - """.trimIndent(), - validUnmodeledError = """ - - - - UnmodeledError - UnmodeledError - unmodeled error - - - - """.trimIndent(), - ) { Ec2QueryProtocol(it) }, - ) -} - data class TestEventStreamProject( val model: Model, val serviceShape: ServiceShape, @@ -398,458 +138,4 @@ object EventStreamTestTools { } } } - - private fun RustWriter.writeUnmarshallTestCases( - testCase: EventStreamTestModels.TestCase, - codegenTarget: CodegenTarget, - generator: RuntimeType, - ) { - rust( - """ - use aws_smithy_eventstream::frame::{Header, HeaderValue, Message, UnmarshallMessage, UnmarshalledMessage}; - use aws_smithy_types::{Blob, DateTime}; - use crate::error::*; - use crate::model::*; - - fn msg( - message_type: &'static str, - event_type: &'static str, - content_type: &'static str, - payload: &'static [u8], - ) -> Message { - let message = Message::new(payload) - .add_header(Header::new(":message-type", HeaderValue::String(message_type.into()))) - .add_header(Header::new(":content-type", HeaderValue::String(content_type.into()))); - if message_type == "event" { - message.add_header(Header::new(":event-type", HeaderValue::String(event_type.into()))) - } else { - message.add_header(Header::new(":exception-type", HeaderValue::String(event_type.into()))) - } - } - fn expect_event(unmarshalled: UnmarshalledMessage) -> T { - match unmarshalled { - UnmarshalledMessage::Event(event) => event, - _ => panic!("expected event, got: {:?}", unmarshalled), - } - } - fn expect_error(unmarshalled: UnmarshalledMessage) -> E { - match unmarshalled { - UnmarshalledMessage::Error(error) => error, - _ => panic!("expected error, got: {:?}", unmarshalled), - } - } - """, - ) - - unitTest( - name = "message_with_blob", - test = """ - let message = msg("event", "MessageWithBlob", "application/octet-stream", b"hello, world!"); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithBlob( - MessageWithBlob::builder().data(Blob::new(&b"hello, world!"[..])).build() - ), - expect_event(result.unwrap()) - ); - """, - ) - - if (codegenTarget == CodegenTarget.CLIENT) { - unitTest( - "unknown_message", - """ - let message = msg("event", "NewUnmodeledMessageType", "application/octet-stream", b"hello, world!"); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::Unknown, - expect_event(result.unwrap()) - ); - """, - ) - } - - unitTest( - "message_with_string", - """ - let message = msg("event", "MessageWithString", "text/plain", b"hello, world!"); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithString(MessageWithString::builder().data("hello, world!").build()), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_struct", - """ - let message = msg( - "event", - "MessageWithStruct", - "${testCase.responseContentType}", - br#"${testCase.validTestStruct}"# - ); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithStruct(MessageWithStruct::builder().some_struct( - TestStruct::builder() - .some_string("hello") - .some_int(5) - .build() - ).build()), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_union", - """ - let message = msg( - "event", - "MessageWithUnion", - "${testCase.responseContentType}", - br#"${testCase.validTestUnion}"# - ); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithUnion(MessageWithUnion::builder().some_union( - TestUnion::Foo("hello".into()) - ).build()), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_headers", - """ - let message = msg("event", "MessageWithHeaders", "application/octet-stream", b"") - .add_header(Header::new("blob", HeaderValue::ByteArray((&b"test"[..]).into()))) - .add_header(Header::new("boolean", HeaderValue::Bool(true))) - .add_header(Header::new("byte", HeaderValue::Byte(55i8))) - .add_header(Header::new("int", HeaderValue::Int32(100_000i32))) - .add_header(Header::new("long", HeaderValue::Int64(9_000_000_000i64))) - .add_header(Header::new("short", HeaderValue::Int16(16_000i16))) - .add_header(Header::new("string", HeaderValue::String("test".into()))) - .add_header(Header::new("timestamp", HeaderValue::Timestamp(DateTime::from_secs(5)))); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithHeaders(MessageWithHeaders::builder() - .blob(Blob::new(&b"test"[..])) - .boolean(true) - .byte(55i8) - .int(100_000i32) - .long(9_000_000_000i64) - .short(16_000i16) - .string("test") - .timestamp(DateTime::from_secs(5)) - .build() - ), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_header_and_payload", - """ - let message = msg("event", "MessageWithHeaderAndPayload", "application/octet-stream", b"payload") - .add_header(Header::new("header", HeaderValue::String("header".into()))); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithHeaderAndPayload(MessageWithHeaderAndPayload::builder() - .header("header") - .payload(Blob::new(&b"payload"[..])) - .build() - ), - expect_event(result.unwrap()) - ); - """, - ) - - unitTest( - "message_with_no_header_payload_traits", - """ - let message = msg( - "event", - "MessageWithNoHeaderPayloadTraits", - "${testCase.responseContentType}", - br#"${testCase.validMessageWithNoHeaderPayloadTraits}"# - ); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - assert_eq!( - TestStream::MessageWithNoHeaderPayloadTraits(MessageWithNoHeaderPayloadTraits::builder() - .some_int(5) - .some_string("hello") - .build() - ), - expect_event(result.unwrap()) - ); - """, - ) - - val (someError, kindSuffix) = when (codegenTarget) { - CodegenTarget.CLIENT -> listOf("TestStreamErrorKind::SomeError", ".kind") - CodegenTarget.SERVER -> listOf("TestStreamError::SomeError", "") - } - unitTest( - "some_error", - """ - let message = msg( - "exception", - "SomeError", - "${testCase.responseContentType}", - br#"${testCase.validSomeError}"# - ); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - match expect_error(result.unwrap())$kindSuffix { - $someError(err) => assert_eq!(Some("some error"), err.message()), - kind => panic!("expected SomeError, but got {:?}", kind), - } - """, - ) - - if (codegenTarget == CodegenTarget.CLIENT) { - unitTest( - "generic_error", - """ - let message = msg( - "exception", - "UnmodeledError", - "${testCase.responseContentType}", - br#"${testCase.validUnmodeledError}"# - ); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - match expect_error(result.unwrap())$kindSuffix { - TestStreamErrorKind::Unhandled(err) => { - let message = format!("{}", aws_smithy_types::error::display::DisplayErrorContext(&err)); - let expected = "message: \"unmodeled error\""; - assert!(message.contains(expected), "Expected '{message}' to contain '{expected}'"); - } - kind => panic!("expected generic error, but got {:?}", kind), - } - """, - ) - } - - unitTest( - "bad_content_type", - """ - let message = msg( - "event", - "MessageWithBlob", - "wrong-content-type", - br#"${testCase.validTestStruct}"# - ); - let result = ${format(generator)}().unmarshall(&message); - assert!(result.is_err(), "expected error, got: {:?}", result); - assert!(format!("{}", result.err().unwrap()).contains("expected :content-type to be")); - """, - ) - } - - private fun RustWriter.writeMarshallTestCases( - testCase: EventStreamTestModels.TestCase, - generator: RuntimeType, - ) { - val protocolTestHelpers = CargoDependency.smithyProtocolTestHelpers(TestRuntimeConfig) - .copy(scope = DependencyScope.Compile) - rustTemplate( - """ - use aws_smithy_eventstream::frame::{Message, Header, HeaderValue, MarshallMessage}; - use std::collections::HashMap; - use aws_smithy_types::{Blob, DateTime}; - use crate::error::*; - use crate::model::*; - - use #{validate_body}; - use #{MediaType}; - - fn headers_to_map<'a>(headers: &'a [Header]) -> HashMap { - let mut map = HashMap::new(); - for header in headers { - map.insert(header.name().as_str().to_string(), header.value()); - } - map - } - - fn str_header(value: &'static str) -> HeaderValue { - HeaderValue::String(value.into()) - } - """, - "validate_body" to protocolTestHelpers.toType().resolve("validate_body"), - "MediaType" to protocolTestHelpers.toType().resolve("MediaType"), - ) - - unitTest( - "message_with_blob", - """ - let event = TestStream::MessageWithBlob( - MessageWithBlob::builder().data(Blob::new(&b"hello, world!"[..])).build() - ); - let result = ${format(generator)}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithBlob"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header("application/octet-stream"), *headers.get(":content-type").unwrap()); - assert_eq!(&b"hello, world!"[..], message.payload()); - """, - ) - - unitTest( - "message_with_string", - """ - let event = TestStream::MessageWithString( - MessageWithString::builder().data("hello, world!").build() - ); - let result = ${format(generator)}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithString"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header("text/plain"), *headers.get(":content-type").unwrap()); - assert_eq!(&b"hello, world!"[..], message.payload()); - """, - ) - - unitTest( - "message_with_struct", - """ - let event = TestStream::MessageWithStruct( - MessageWithStruct::builder().some_struct( - TestStruct::builder() - .some_string("hello") - .some_int(5) - .build() - ).build() - ); - let result = ${format(generator)}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithStruct"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); - - validate_body( - message.payload(), - ${testCase.validTestStruct.dq()}, - MediaType::from(${testCase.requestContentType.dq()}) - ).unwrap(); - """, - ) - - unitTest( - "message_with_union", - """ - let event = TestStream::MessageWithUnion(MessageWithUnion::builder().some_union( - TestUnion::Foo("hello".into()) - ).build()); - let result = ${format(generator)}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithUnion"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); - - validate_body( - message.payload(), - ${testCase.validTestUnion.dq()}, - MediaType::from(${testCase.requestContentType.dq()}) - ).unwrap(); - """, - ) - - unitTest( - "message_with_headers", - """ - let event = TestStream::MessageWithHeaders(MessageWithHeaders::builder() - .blob(Blob::new(&b"test"[..])) - .boolean(true) - .byte(55i8) - .int(100_000i32) - .long(9_000_000_000i64) - .short(16_000i16) - .string("test") - .timestamp(DateTime::from_secs(5)) - .build() - ); - let result = ${format(generator)}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let actual_message = result.unwrap(); - let expected_message = Message::new(&b""[..]) - .add_header(Header::new(":message-type", HeaderValue::String("event".into()))) - .add_header(Header::new(":event-type", HeaderValue::String("MessageWithHeaders".into()))) - .add_header(Header::new("blob", HeaderValue::ByteArray((&b"test"[..]).into()))) - .add_header(Header::new("boolean", HeaderValue::Bool(true))) - .add_header(Header::new("byte", HeaderValue::Byte(55i8))) - .add_header(Header::new("int", HeaderValue::Int32(100_000i32))) - .add_header(Header::new("long", HeaderValue::Int64(9_000_000_000i64))) - .add_header(Header::new("short", HeaderValue::Int16(16_000i16))) - .add_header(Header::new("string", HeaderValue::String("test".into()))) - .add_header(Header::new("timestamp", HeaderValue::Timestamp(DateTime::from_secs(5)))); - assert_eq!(expected_message, actual_message); - """, - ) - - unitTest( - "message_with_header_and_payload", - """ - let event = TestStream::MessageWithHeaderAndPayload(MessageWithHeaderAndPayload::builder() - .header("header") - .payload(Blob::new(&b"payload"[..])) - .build() - ); - let result = ${format(generator)}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let actual_message = result.unwrap(); - let expected_message = Message::new(&b"payload"[..]) - .add_header(Header::new(":message-type", HeaderValue::String("event".into()))) - .add_header(Header::new(":event-type", HeaderValue::String("MessageWithHeaderAndPayload".into()))) - .add_header(Header::new("header", HeaderValue::String("header".into()))) - .add_header(Header::new(":content-type", HeaderValue::String("application/octet-stream".into()))); - assert_eq!(expected_message, actual_message); - """, - ) - - unitTest( - "message_with_no_header_payload_traits", - """ - let event = TestStream::MessageWithNoHeaderPayloadTraits(MessageWithNoHeaderPayloadTraits::builder() - .some_int(5) - .some_string("hello") - .build() - ); - let result = ${format(generator)}().marshall(event); - assert!(result.is_ok(), "expected ok, got: {:?}", result); - let message = result.unwrap(); - let headers = headers_to_map(message.headers()); - assert_eq!(&str_header("event"), *headers.get(":message-type").unwrap()); - assert_eq!(&str_header("MessageWithNoHeaderPayloadTraits"), *headers.get(":event-type").unwrap()); - assert_eq!(&str_header(${testCase.requestContentType.dq()}), *headers.get(":content-type").unwrap()); - - validate_body( - message.payload(), - ${testCase.validMessageWithNoHeaderPayloadTraits.dq()}, - MediaType::from(${testCase.requestContentType.dq()}) - ).unwrap(); - """, - ) - } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt new file mode 100644 index 00000000000..04503c97a33 --- /dev/null +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt @@ -0,0 +1,274 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.core.testutil + +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.rustlang.rust +import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType + +internal object EventStreamUnmarshallTestCases { + internal fun RustWriter.writeUnmarshallTestCases( + testCase: EventStreamTestModels.TestCase, + codegenTarget: CodegenTarget, + generator: RuntimeType, + ) { + rust( + """ + use aws_smithy_eventstream::frame::{Header, HeaderValue, Message, UnmarshallMessage, UnmarshalledMessage}; + use aws_smithy_types::{Blob, DateTime}; + use crate::error::*; + use crate::model::*; + + fn msg( + message_type: &'static str, + event_type: &'static str, + content_type: &'static str, + payload: &'static [u8], + ) -> Message { + let message = Message::new(payload) + .add_header(Header::new(":message-type", HeaderValue::String(message_type.into()))) + .add_header(Header::new(":content-type", HeaderValue::String(content_type.into()))); + if message_type == "event" { + message.add_header(Header::new(":event-type", HeaderValue::String(event_type.into()))) + } else { + message.add_header(Header::new(":exception-type", HeaderValue::String(event_type.into()))) + } + } + fn expect_event(unmarshalled: UnmarshalledMessage) -> T { + match unmarshalled { + UnmarshalledMessage::Event(event) => event, + _ => panic!("expected event, got: {:?}", unmarshalled), + } + } + fn expect_error(unmarshalled: UnmarshalledMessage) -> E { + match unmarshalled { + UnmarshalledMessage::Error(error) => error, + _ => panic!("expected error, got: {:?}", unmarshalled), + } + } + """, + ) + + unitTest( + name = "message_with_blob", + test = """ + let message = msg("event", "MessageWithBlob", "application/octet-stream", b"hello, world!"); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithBlob( + MessageWithBlob::builder().data(Blob::new(&b"hello, world!"[..])).build() + ), + expect_event(result.unwrap()) + ); + """, + ) + + if (codegenTarget == CodegenTarget.CLIENT) { + unitTest( + "unknown_message", + """ + let message = msg("event", "NewUnmodeledMessageType", "application/octet-stream", b"hello, world!"); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::Unknown, + expect_event(result.unwrap()) + ); + """, + ) + } + + unitTest( + "message_with_string", + """ + let message = msg("event", "MessageWithString", "text/plain", b"hello, world!"); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithString(MessageWithString::builder().data("hello, world!").build()), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_struct", + """ + let message = msg( + "event", + "MessageWithStruct", + "${testCase.responseContentType}", + br#"${testCase.validTestStruct}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithStruct(MessageWithStruct::builder().some_struct( + TestStruct::builder() + .some_string("hello") + .some_int(5) + .build() + ).build()), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_union", + """ + let message = msg( + "event", + "MessageWithUnion", + "${testCase.responseContentType}", + br#"${testCase.validTestUnion}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithUnion(MessageWithUnion::builder().some_union( + TestUnion::Foo("hello".into()) + ).build()), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_headers", + """ + let message = msg("event", "MessageWithHeaders", "application/octet-stream", b"") + .add_header(Header::new("blob", HeaderValue::ByteArray((&b"test"[..]).into()))) + .add_header(Header::new("boolean", HeaderValue::Bool(true))) + .add_header(Header::new("byte", HeaderValue::Byte(55i8))) + .add_header(Header::new("int", HeaderValue::Int32(100_000i32))) + .add_header(Header::new("long", HeaderValue::Int64(9_000_000_000i64))) + .add_header(Header::new("short", HeaderValue::Int16(16_000i16))) + .add_header(Header::new("string", HeaderValue::String("test".into()))) + .add_header(Header::new("timestamp", HeaderValue::Timestamp(DateTime::from_secs(5)))); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithHeaders(MessageWithHeaders::builder() + .blob(Blob::new(&b"test"[..])) + .boolean(true) + .byte(55i8) + .int(100_000i32) + .long(9_000_000_000i64) + .short(16_000i16) + .string("test") + .timestamp(DateTime::from_secs(5)) + .build() + ), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_header_and_payload", + """ + let message = msg("event", "MessageWithHeaderAndPayload", "application/octet-stream", b"payload") + .add_header(Header::new("header", HeaderValue::String("header".into()))); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithHeaderAndPayload(MessageWithHeaderAndPayload::builder() + .header("header") + .payload(Blob::new(&b"payload"[..])) + .build() + ), + expect_event(result.unwrap()) + ); + """, + ) + + unitTest( + "message_with_no_header_payload_traits", + """ + let message = msg( + "event", + "MessageWithNoHeaderPayloadTraits", + "${testCase.responseContentType}", + br#"${testCase.validMessageWithNoHeaderPayloadTraits}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + assert_eq!( + TestStream::MessageWithNoHeaderPayloadTraits(MessageWithNoHeaderPayloadTraits::builder() + .some_int(5) + .some_string("hello") + .build() + ), + expect_event(result.unwrap()) + ); + """, + ) + + val (someError, kindSuffix) = when (codegenTarget) { + CodegenTarget.CLIENT -> listOf("TestStreamErrorKind::SomeError", ".kind") + CodegenTarget.SERVER -> listOf("TestStreamError::SomeError", "") + } + unitTest( + "some_error", + """ + let message = msg( + "exception", + "SomeError", + "${testCase.responseContentType}", + br#"${testCase.validSomeError}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + match expect_error(result.unwrap())$kindSuffix { + $someError(err) => assert_eq!(Some("some error"), err.message()), + kind => panic!("expected SomeError, but got {:?}", kind), + } + """, + ) + + if (codegenTarget == CodegenTarget.CLIENT) { + unitTest( + "generic_error", + """ + let message = msg( + "exception", + "UnmodeledError", + "${testCase.responseContentType}", + br#"${testCase.validUnmodeledError}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_ok(), "expected ok, got: {:?}", result); + match expect_error(result.unwrap())$kindSuffix { + TestStreamErrorKind::Unhandled(err) => { + let message = format!("{}", aws_smithy_types::error::display::DisplayErrorContext(&err)); + let expected = "message: \"unmodeled error\""; + assert!(message.contains(expected), "Expected '{message}' to contain '{expected}'"); + } + kind => panic!("expected generic error, but got {:?}", kind), + } + """, + ) + } + + unitTest( + "bad_content_type", + """ + let message = msg( + "event", + "MessageWithBlob", + "wrong-content-type", + br#"${testCase.validTestStruct}"# + ); + let result = ${format(generator)}().unmarshall(&message); + assert!(result.is_err(), "expected error, got: {:?}", result); + assert!(format!("{}", result.err().unwrap()).contains("expected :content-type to be")); + """, + ) + } +} From d93346eb526b1304729ee622c51615724c7aa51f Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Fri, 16 Dec 2022 17:19:36 -0800 Subject: [PATCH 09/19] Move codegen context creation in event stream tests --- .../EventStreamUnmarshallerGeneratorTest.kt | 58 +++++++++++--- .../EventStreamMarshallerGeneratorTest.kt | 50 +++++++++--- .../core/testutil/EventStreamTestTools.kt | 49 ++++++++---- .../EventStreamUnmarshallerGeneratorTest.kt | 74 +++++++++++++++--- .../EventStreamMarshallerGeneratorTest.kt | 76 +++++++++++++++---- 5 files changed, 248 insertions(+), 59 deletions(-) diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt index e23dec720d7..208c9c40121 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt @@ -11,13 +11,25 @@ import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource import software.amazon.smithy.codegen.core.Symbol +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.testutil.clientTestRustSettings import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.generators.builderSymbol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.EventStreamUnmarshallerGenerator import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety +import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject import java.util.stream.Stream class UnmarshallTestCasesProvider : ArgumentsProvider { @@ -31,19 +43,41 @@ class EventStreamUnmarshallerGeneratorTest { fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - CodegenTarget.CLIENT, - { model -> testSymbolProvider(model) }, - { codegenContext, test, protocol -> - fun builderSymbol(shape: StructureShape): Symbol = shape.builderSymbol(codegenContext.symbolProvider) - EventStreamUnmarshallerGenerator( - protocol, - codegenContext, - test.operationShape, - test.streamShape, - ::builderSymbol, - ).render() + object : EventStreamTestRequirements { + override fun createCodegenContext( + model: Model, + symbolProvider: RustSymbolProvider, + serviceShape: ServiceShape, + protocolShapeId: ShapeId, + codegenTarget: CodegenTarget, + ): ClientCodegenContext = ClientCodegenContext( + model, + symbolProvider, + serviceShape, + protocolShapeId, + clientTestRustSettings(), + CombinedClientCodegenDecorator(emptyList()), + ) + + override fun createSymbolProvider(model: Model): RustSymbolProvider = testSymbolProvider(model) + + override fun renderGenerator( + codegenContext: ClientCodegenContext, + project: TestEventStreamProject, + protocol: Protocol, + ): RuntimeType { + fun builderSymbol(shape: StructureShape): Symbol = shape.builderSymbol(codegenContext.symbolProvider) + return EventStreamUnmarshallerGenerator( + protocol, + codegenContext, + project.operationShape, + project.streamShape, + ::builderSymbol, + ).render() + } }, - marshall = false, + CodegenTarget.CLIENT, + EventStreamTestVariety.Unmarshall, ) } } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt index aedf0a68a8f..aeee19be200 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt @@ -10,11 +10,23 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.testutil.clientTestRustSettings import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.EventStreamMarshallerGenerator import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety +import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig import java.util.stream.Stream @@ -32,20 +44,40 @@ class EventStreamMarshallerGeneratorTest { fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - CodegenTarget.CLIENT, - { model -> testSymbolProvider(model) }, - { _, test, protocol -> - EventStreamMarshallerGenerator( - test.model, + object : EventStreamTestRequirements { + override fun createCodegenContext( + model: Model, + symbolProvider: RustSymbolProvider, + serviceShape: ServiceShape, + protocolShapeId: ShapeId, + codegenTarget: CodegenTarget, + ): ClientCodegenContext = ClientCodegenContext( + model, + symbolProvider, + serviceShape, + protocolShapeId, + clientTestRustSettings(), + CombinedClientCodegenDecorator(emptyList()), + ) + + override fun createSymbolProvider(model: Model): RustSymbolProvider = testSymbolProvider(model) + + override fun renderGenerator( + codegenContext: ClientCodegenContext, + project: TestEventStreamProject, + protocol: Protocol, + ): RuntimeType = EventStreamMarshallerGenerator( + project.model, CodegenTarget.CLIENT, TestRuntimeConfig, - test.symbolProvider, - test.streamShape, - protocol.structuredDataSerializer(test.operationShape), + project.symbolProvider, + project.streamShape, + protocol.structuredDataSerializer(project.operationShape), testCase.requestContentType, ).render() }, - marshall = true, + CodegenTarget.CLIENT, + EventStreamTestVariety.Marshall, ) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt index 9fabf9d2bd3..da5dfc176bd 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt @@ -47,32 +47,55 @@ data class TestEventStreamProject( val project: TestWriterDelegator, ) +enum class EventStreamTestVariety { + Marshall, + Unmarshall +} + +interface EventStreamTestRequirements { + /** Create a codegen context for the tests */ + fun createCodegenContext( + model: Model, + symbolProvider: RustSymbolProvider, + serviceShape: ServiceShape, + protocolShapeId: ShapeId, + codegenTarget: CodegenTarget, + ): C + + /** Create a symbol provider for the tests */ + fun createSymbolProvider(model: Model): RustSymbolProvider + + /** Render the event stream marshall/unmarshall code generator */ + fun renderGenerator( + codegenContext: C, + project: TestEventStreamProject, + protocol: Protocol, + ): RuntimeType +} + object EventStreamTestTools { - fun runTestCase( + fun runTestCase( testCase: EventStreamTestModels.TestCase, + requirements: EventStreamTestRequirements, codegenTarget: CodegenTarget, - createSymbolProvider: (Model) -> RustSymbolProvider, - renderGenerator: (CodegenContext, TestEventStreamProject, Protocol) -> RuntimeType, - marshall: Boolean, + variety: EventStreamTestVariety, ) { - val test = generateTestProject(testCase, codegenTarget, createSymbolProvider) + val test = generateTestProject(testCase, codegenTarget, requirements::createSymbolProvider) - val codegenContext = CodegenContext( + val codegenContext = requirements.createCodegenContext( test.model, test.symbolProvider, test.serviceShape, ShapeId.from(testCase.protocolShapeId), - testRustSettings(), - target = codegenTarget, + codegenTarget, ) val protocol = testCase.protocolBuilder(codegenContext) - val generator = renderGenerator(codegenContext, test, protocol) + val generator = requirements.renderGenerator(codegenContext, test, protocol) test.project.lib { - if (marshall) { - writeMarshallTestCases(testCase, generator) - } else { - writeUnmarshallTestCases(testCase, codegenTarget, generator) + when (variety) { + EventStreamTestVariety.Marshall -> writeMarshallTestCases(testCase, generator) + EventStreamTestVariety.Unmarshall -> writeUnmarshallTestCases(testCase, codegenTarget, generator) } } test.project.compileAndTest() diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt index a49fc0af800..d08eac3c704 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt @@ -11,12 +11,26 @@ import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource import software.amazon.smithy.codegen.core.Symbol +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.generators.builderSymbol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.EventStreamUnmarshallerGenerator import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety +import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject +import software.amazon.smithy.rust.codegen.server.smithy.RustCodegenServerPlugin +import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext +import software.amazon.smithy.rust.codegen.server.smithy.ServerSymbolProviders +import software.amazon.smithy.rust.codegen.server.smithy.testutil.ServerTestSymbolVisitorConfig +import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider import java.util.stream.Stream @@ -31,19 +45,55 @@ class EventStreamUnmarshallerGeneratorTest { fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - CodegenTarget.SERVER, - { model -> serverTestSymbolProvider(model) }, - { codegenContext, test, protocol -> - fun builderSymbol(shape: StructureShape): Symbol = shape.builderSymbol(codegenContext.symbolProvider) - EventStreamUnmarshallerGenerator( - protocol, - codegenContext, - test.operationShape, - test.streamShape, - ::builderSymbol, - ).render() + object : EventStreamTestRequirements { + override fun createCodegenContext( + model: Model, + symbolProvider: RustSymbolProvider, + serviceShape: ServiceShape, + protocolShapeId: ShapeId, + codegenTarget: CodegenTarget, + ): ServerCodegenContext { + val settings = serverTestRustSettings() + val serverSymbolProviders = ServerSymbolProviders.from( + model, + serviceShape, + ServerTestSymbolVisitorConfig, + settings.codegenConfig.publicConstrainedTypes, + RustCodegenServerPlugin::baseSymbolProvider, + ) + return ServerCodegenContext( + model, + symbolProvider, + serviceShape, + protocolShapeId, + settings, + serverSymbolProviders.unconstrainedShapeSymbolProvider, + serverSymbolProviders.constrainedShapeSymbolProvider, + serverSymbolProviders.constraintViolationSymbolProvider, + serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, + ) + } + + override fun createSymbolProvider(model: Model): RustSymbolProvider = + serverTestSymbolProvider(model) + + override fun renderGenerator( + codegenContext: ServerCodegenContext, + project: TestEventStreamProject, + protocol: Protocol, + ): RuntimeType { + fun builderSymbol(shape: StructureShape): Symbol = shape.builderSymbol(codegenContext.symbolProvider) + return EventStreamUnmarshallerGenerator( + protocol, + codegenContext, + project.operationShape, + project.streamShape, + ::builderSymbol, + ).render() + } }, - marshall = false, + CodegenTarget.SERVER, + EventStreamTestVariety.Unmarshall, ) } } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt index 25d6dfadfd0..329370cbce3 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt @@ -10,11 +10,25 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.EventStreamMarshallerGenerator import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety +import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig +import software.amazon.smithy.rust.codegen.server.smithy.RustCodegenServerPlugin +import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext +import software.amazon.smithy.rust.codegen.server.smithy.ServerSymbolProviders +import software.amazon.smithy.rust.codegen.server.smithy.testutil.ServerTestSymbolVisitorConfig +import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider import java.util.stream.Stream @@ -32,20 +46,56 @@ class EventStreamMarshallerGeneratorTest { fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - CodegenTarget.SERVER, - { model -> serverTestSymbolProvider(model) }, - { _, test, protocol -> - EventStreamMarshallerGenerator( - test.model, - CodegenTarget.SERVER, - TestRuntimeConfig, - test.symbolProvider, - test.streamShape, - protocol.structuredDataSerializer(test.operationShape), - testCase.requestContentType, - ).render() + object : EventStreamTestRequirements { + override fun createCodegenContext( + model: Model, + symbolProvider: RustSymbolProvider, + serviceShape: ServiceShape, + protocolShapeId: ShapeId, + codegenTarget: CodegenTarget, + ): ServerCodegenContext { + val settings = serverTestRustSettings() + val serverSymbolProviders = ServerSymbolProviders.from( + model, + serviceShape, + ServerTestSymbolVisitorConfig, + settings.codegenConfig.publicConstrainedTypes, + RustCodegenServerPlugin::baseSymbolProvider, + ) + return ServerCodegenContext( + model, + symbolProvider, + serviceShape, + protocolShapeId, + settings, + serverSymbolProviders.unconstrainedShapeSymbolProvider, + serverSymbolProviders.constrainedShapeSymbolProvider, + serverSymbolProviders.constraintViolationSymbolProvider, + serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, + ) + } + + override fun createSymbolProvider(model: Model): RustSymbolProvider = + serverTestSymbolProvider(model) + + override fun renderGenerator( + codegenContext: ServerCodegenContext, + project: TestEventStreamProject, + protocol: Protocol, + ): RuntimeType { + return EventStreamMarshallerGenerator( + project.model, + CodegenTarget.SERVER, + TestRuntimeConfig, + project.symbolProvider, + project.streamShape, + protocol.structuredDataSerializer(project.operationShape), + testCase.requestContentType, + ).render() + } }, - marshall = true, + CodegenTarget.SERVER, + EventStreamTestVariety.Marshall, ) } } From 52899f90fbf7e43e96231a730257724323d7dd2d Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Fri, 16 Dec 2022 17:53:24 -0800 Subject: [PATCH 10/19] Restructure tests so that #1442 is easier to resolve in the future --- .../EventStreamBaseRequirements.kt | 53 ++++++++++ .../EventStreamMarshallerGeneratorTest.kt | 29 +----- .../EventStreamUnmarshallerGeneratorTest.kt | 29 +----- .../core/testutil/EventStreamTestTools.kt | 47 +++++---- .../EventStreamBaseRequirements.kt | 52 ++++++++++ .../EventStreamMarshallerGeneratorTest.kt | 62 ++++-------- .../EventStreamUnmarshallerGeneratorTest.kt | 94 ++++++++++++++++++ .../EventStreamUnmarshallerGeneratorTest.kt | 99 ------------------- 8 files changed, 250 insertions(+), 215 deletions(-) create mode 100644 codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt rename codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/{serialize => eventstream}/EventStreamMarshallerGeneratorTest.kt (65%) rename codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/{parse => eventstream}/EventStreamUnmarshallerGeneratorTest.kt (65%) create mode 100644 codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt rename codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/{serialize => eventstream}/EventStreamMarshallerGeneratorTest.kt (54%) create mode 100644 codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt delete mode 100644 codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt new file mode 100644 index 00000000000..73ccb79350a --- /dev/null +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt @@ -0,0 +1,53 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.client.smithy.protocols.eventstream + +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.testutil.clientTestRustSettings +import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerator +import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements + +abstract class EventStreamBaseRequirements : EventStreamTestRequirements { + override fun createCodegenContext( + model: Model, + symbolProvider: RustSymbolProvider, + serviceShape: ServiceShape, + protocolShapeId: ShapeId, + codegenTarget: CodegenTarget, + ): ClientCodegenContext = ClientCodegenContext( + model, + symbolProvider, + serviceShape, + protocolShapeId, + clientTestRustSettings(), + CombinedClientCodegenDecorator(emptyList()), + ) + + override fun createSymbolProvider(model: Model): RustSymbolProvider = testSymbolProvider(model) + + override fun renderBuilderForShape( + writer: RustWriter, + codegenContext: ClientCodegenContext, + shape: StructureShape, + ) { + BuilderGenerator(codegenContext.model, codegenContext.symbolProvider, shape).apply { + render(writer) + writer.implBlock(shape, codegenContext.symbolProvider) { + renderConvenienceMethod(writer) + } + } + } +} diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt similarity index 65% rename from codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt rename to codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt index aeee19be200..129e241fb92 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt @@ -3,27 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.client.smithy.protocols.serialize +package software.amazon.smithy.rust.codegen.client.smithy.protocols.eventstream import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource -import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.testutil.clientTestRustSettings -import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.EventStreamMarshallerGenerator import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels -import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject @@ -44,24 +36,7 @@ class EventStreamMarshallerGeneratorTest { fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - object : EventStreamTestRequirements { - override fun createCodegenContext( - model: Model, - symbolProvider: RustSymbolProvider, - serviceShape: ServiceShape, - protocolShapeId: ShapeId, - codegenTarget: CodegenTarget, - ): ClientCodegenContext = ClientCodegenContext( - model, - symbolProvider, - serviceShape, - protocolShapeId, - clientTestRustSettings(), - CombinedClientCodegenDecorator(emptyList()), - ) - - override fun createSymbolProvider(model: Model): RustSymbolProvider = testSymbolProvider(model) - + object : EventStreamBaseRequirements() { override fun renderGenerator( codegenContext: ClientCodegenContext, project: TestEventStreamProject, diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt similarity index 65% rename from codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt rename to codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt index 208c9c40121..8ec1f27bbee 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.client.smithy.protocols.parse +package software.amazon.smithy.rust.codegen.client.smithy.protocols.eventstream import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.ParameterizedTest @@ -11,22 +11,14 @@ import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource import software.amazon.smithy.codegen.core.Symbol -import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.testutil.clientTestRustSettings -import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.generators.builderSymbol import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.EventStreamUnmarshallerGenerator import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels -import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject @@ -43,24 +35,7 @@ class EventStreamUnmarshallerGeneratorTest { fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - object : EventStreamTestRequirements { - override fun createCodegenContext( - model: Model, - symbolProvider: RustSymbolProvider, - serviceShape: ServiceShape, - protocolShapeId: ShapeId, - codegenTarget: CodegenTarget, - ): ClientCodegenContext = ClientCodegenContext( - model, - symbolProvider, - serviceShape, - protocolShapeId, - clientTestRustSettings(), - CombinedClientCodegenDecorator(emptyList()), - ) - - override fun createSymbolProvider(model: Model): RustSymbolProvider = testSymbolProvider(model) - + object : EventStreamBaseRequirements() { override fun renderGenerator( codegenContext: ClientCodegenContext, project: TestEventStreamProject, diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt index da5dfc176bd..33e3989bc5c 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt @@ -21,12 +21,10 @@ import software.amazon.smithy.rust.codegen.core.smithy.ErrorsModule import software.amazon.smithy.rust.codegen.core.smithy.ModelsModule import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.error.CombinedErrorGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.error.ServerCombinedErrorGenerator -import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock import software.amazon.smithy.rust.codegen.core.smithy.generators.renderUnknownVariant import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.transformers.EventStreamNormalizer @@ -71,6 +69,13 @@ interface EventStreamTestRequirements { project: TestEventStreamProject, protocol: Protocol, ): RuntimeType + + /** Render a builder for the given shape */ + fun renderBuilderForShape( + writer: RustWriter, + codegenContext: C, + shape: StructureShape, + ) } object EventStreamTestTools { @@ -80,15 +85,17 @@ object EventStreamTestTools { codegenTarget: CodegenTarget, variety: EventStreamTestVariety, ) { - val test = generateTestProject(testCase, codegenTarget, requirements::createSymbolProvider) - + val model = EventStreamNormalizer.transform(OperationNormalizer.transform(testCase.model)) + val symbolProvider = requirements.createSymbolProvider(model) + val serviceShape = model.expectShape(ShapeId.from("test#TestService")) as ServiceShape val codegenContext = requirements.createCodegenContext( - test.model, - test.symbolProvider, - test.serviceShape, + model, + symbolProvider, + serviceShape, ShapeId.from(testCase.protocolShapeId), codegenTarget, ) + val test = generateTestProject(requirements, codegenContext, codegenTarget) val protocol = testCase.protocolBuilder(codegenContext) val generator = requirements.renderGenerator(codegenContext, test, protocol) @@ -101,17 +108,16 @@ object EventStreamTestTools { test.project.compileAndTest() } - private fun generateTestProject( - testCase: EventStreamTestModels.TestCase, + private fun generateTestProject( + requirements: EventStreamTestRequirements, + codegenContext: C, codegenTarget: CodegenTarget, - createSymbolProvider: (Model) -> RustSymbolProvider, ): TestEventStreamProject { - val model = EventStreamNormalizer.transform(OperationNormalizer.transform(testCase.model)) - val serviceShape = model.expectShape(ShapeId.from("test#TestService")) as ServiceShape + val model = codegenContext.model + val symbolProvider = codegenContext.symbolProvider val operationShape = model.expectShape(ShapeId.from("test#TestStreamOp")) as OperationShape val unionShape = model.expectShape(ShapeId.from("test#TestStream")) as UnionShape - val symbolProvider = createSymbolProvider(model) val project = TestWorkspace.testProject(symbolProvider) val operationSymbol = symbolProvider.toSymbol(operationShape) project.withModule(ErrorsModule) { @@ -125,11 +131,7 @@ object EventStreamTestTools { } for (shape in model.shapes().filter { shape -> shape.isStructureShape && shape.hasTrait() }) { StructureGenerator(model, symbolProvider, this, shape as StructureShape).render(codegenTarget) - val builderGen = BuilderGenerator(model, symbolProvider, shape) - builderGen.render(this) - implBlock(shape, symbolProvider) { - builderGen.renderConvenienceMethod(this) - } + requirements.renderBuilderForShape(this, codegenContext, shape) } } project.withModule(ModelsModule) { @@ -139,7 +141,14 @@ object EventStreamTestTools { project.withModule(RustModule.Output) { operationShape.outputShape(model).renderWithModelBuilder(model, symbolProvider, this) } - return TestEventStreamProject(model, serviceShape, operationShape, unionShape, symbolProvider, project) + return TestEventStreamProject( + model, + codegenContext.serviceShape, + operationShape, + unionShape, + symbolProvider, + project, + ) } private fun recursivelyGenerateModels( diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt new file mode 100644 index 00000000000..4e8bf3da7cb --- /dev/null +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt @@ -0,0 +1,52 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.server.smithy.protocols.eventstream + +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements +import software.amazon.smithy.rust.codegen.server.smithy.RustCodegenServerPlugin +import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext +import software.amazon.smithy.rust.codegen.server.smithy.ServerSymbolProviders +import software.amazon.smithy.rust.codegen.server.smithy.testutil.ServerTestSymbolVisitorConfig +import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings +import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider + +abstract class EventStreamBaseRequirements : EventStreamTestRequirements { + override fun createCodegenContext( + model: Model, + symbolProvider: RustSymbolProvider, + serviceShape: ServiceShape, + protocolShapeId: ShapeId, + codegenTarget: CodegenTarget, + ): ServerCodegenContext { + val settings = serverTestRustSettings() + val serverSymbolProviders = ServerSymbolProviders.from( + model, + serviceShape, + ServerTestSymbolVisitorConfig, + settings.codegenConfig.publicConstrainedTypes, + RustCodegenServerPlugin::baseSymbolProvider, + ) + return ServerCodegenContext( + model, + symbolProvider, + serviceShape, + protocolShapeId, + settings, + serverSymbolProviders.unconstrainedShapeSymbolProvider, + serverSymbolProviders.constrainedShapeSymbolProvider, + serverSymbolProviders.constraintViolationSymbolProvider, + serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, + ) + } + + override fun createSymbolProvider(model: Model): RustSymbolProvider = + serverTestSymbolProvider(model) +} diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt similarity index 54% rename from codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt rename to codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt index 329370cbce3..f575aeeb117 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt @@ -3,33 +3,27 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.server.smithy.protocols.serialize +package software.amazon.smithy.rust.codegen.server.smithy.protocols.eventstream import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource -import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.EventStreamMarshallerGenerator import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels -import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig -import software.amazon.smithy.rust.codegen.server.smithy.RustCodegenServerPlugin import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext -import software.amazon.smithy.rust.codegen.server.smithy.ServerSymbolProviders -import software.amazon.smithy.rust.codegen.server.smithy.testutil.ServerTestSymbolVisitorConfig -import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings -import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider +import software.amazon.smithy.rust.codegen.server.smithy.generators.ServerBuilderGenerator import java.util.stream.Stream class MarshallTestCasesProvider : ArgumentsProvider { @@ -46,38 +40,7 @@ class EventStreamMarshallerGeneratorTest { fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - object : EventStreamTestRequirements { - override fun createCodegenContext( - model: Model, - symbolProvider: RustSymbolProvider, - serviceShape: ServiceShape, - protocolShapeId: ShapeId, - codegenTarget: CodegenTarget, - ): ServerCodegenContext { - val settings = serverTestRustSettings() - val serverSymbolProviders = ServerSymbolProviders.from( - model, - serviceShape, - ServerTestSymbolVisitorConfig, - settings.codegenConfig.publicConstrainedTypes, - RustCodegenServerPlugin::baseSymbolProvider, - ) - return ServerCodegenContext( - model, - symbolProvider, - serviceShape, - protocolShapeId, - settings, - serverSymbolProviders.unconstrainedShapeSymbolProvider, - serverSymbolProviders.constrainedShapeSymbolProvider, - serverSymbolProviders.constraintViolationSymbolProvider, - serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, - ) - } - - override fun createSymbolProvider(model: Model): RustSymbolProvider = - serverTestSymbolProvider(model) - + object : EventStreamBaseRequirements() { override fun renderGenerator( codegenContext: ServerCodegenContext, project: TestEventStreamProject, @@ -93,6 +56,19 @@ class EventStreamMarshallerGeneratorTest { testCase.requestContentType, ).render() } + + override fun renderBuilderForShape( + writer: RustWriter, + codegenContext: ServerCodegenContext, + shape: StructureShape, + ) { + ServerBuilderGenerator(codegenContext, shape).apply { + render(writer) + writer.implBlock(shape, codegenContext.symbolProvider) { + renderConvenienceMethod(writer) + } + } + } }, CodegenTarget.SERVER, EventStreamTestVariety.Marshall, diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt new file mode 100644 index 00000000000..f1dc3c022b5 --- /dev/null +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt @@ -0,0 +1,94 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.server.smithy.protocols.eventstream + +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import org.junit.jupiter.params.provider.ArgumentsSource +import software.amazon.smithy.codegen.core.Symbol +import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerator +import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock +import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.EventStreamUnmarshallerGenerator +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety +import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject +import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext +import software.amazon.smithy.rust.codegen.server.smithy.generators.serverBuilderSymbol +import java.util.stream.Stream + +data class TestCase( + val eventStreamTestCase: EventStreamTestModels.TestCase, + val publicConstrainedTypes: Boolean, +) { + override fun toString(): String = "$eventStreamTestCase, publicConstrainedTypes = $publicConstrainedTypes" +} + +class UnmarshallTestCasesProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream = + EventStreamTestModels.TEST_CASES.flatMap { testCase -> + listOf( + // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Enable tests for `publicConstrainedTypes = false` + // TestCase(testCase, false), + TestCase(testCase, true), + ) + }.map { Arguments.of(it) }.stream() +} + +class EventStreamUnmarshallerGeneratorTest { + @ParameterizedTest + @ArgumentsSource(UnmarshallTestCasesProvider::class) + fun test(testCase: TestCase) { + EventStreamTestTools.runTestCase( + testCase.eventStreamTestCase, + object : EventStreamBaseRequirements() { + override fun renderGenerator( + codegenContext: ServerCodegenContext, + project: TestEventStreamProject, + protocol: Protocol, + ): RuntimeType { + fun builderSymbol(shape: StructureShape): Symbol = shape.serverBuilderSymbol(codegenContext) + return EventStreamUnmarshallerGenerator( + protocol, + codegenContext, + project.operationShape, + project.streamShape, + ::builderSymbol, + ).render() + } + + override fun renderBuilderForShape( + writer: RustWriter, + codegenContext: ServerCodegenContext, + shape: StructureShape, + ) { + // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Use the correct builder: + // ServerBuilderGenerator(codegenContext, shape).apply { + // render(writer) + // writer.implBlock(shape, codegenContext.symbolProvider) { + // renderConvenienceMethod(writer) + // } + // } + BuilderGenerator(codegenContext.model, codegenContext.symbolProvider, shape).apply { + render(writer) + writer.implBlock(shape, codegenContext.symbolProvider) { + renderConvenienceMethod(writer) + } + } + } + }, + CodegenTarget.SERVER, + EventStreamTestVariety.Unmarshall, + ) + } +} diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt deleted file mode 100644 index d08eac3c704..00000000000 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rust.codegen.server.smithy.protocols.parse - -import org.junit.jupiter.api.extension.ExtensionContext -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.ArgumentsProvider -import org.junit.jupiter.params.provider.ArgumentsSource -import software.amazon.smithy.codegen.core.Symbol -import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.model.shapes.ShapeId -import software.amazon.smithy.model.shapes.StructureShape -import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.generators.builderSymbol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.EventStreamUnmarshallerGenerator -import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels -import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements -import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools -import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety -import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject -import software.amazon.smithy.rust.codegen.server.smithy.RustCodegenServerPlugin -import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext -import software.amazon.smithy.rust.codegen.server.smithy.ServerSymbolProviders -import software.amazon.smithy.rust.codegen.server.smithy.testutil.ServerTestSymbolVisitorConfig -import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings -import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider -import java.util.stream.Stream - -class UnmarshallTestCasesProvider : ArgumentsProvider { - override fun provideArguments(context: ExtensionContext?): Stream = - EventStreamTestModels.TEST_CASES.map { Arguments.of(it) }.stream() -} - -class EventStreamUnmarshallerGeneratorTest { - @ParameterizedTest - @ArgumentsSource(UnmarshallTestCasesProvider::class) - fun test(testCase: EventStreamTestModels.TestCase) { - EventStreamTestTools.runTestCase( - testCase, - object : EventStreamTestRequirements { - override fun createCodegenContext( - model: Model, - symbolProvider: RustSymbolProvider, - serviceShape: ServiceShape, - protocolShapeId: ShapeId, - codegenTarget: CodegenTarget, - ): ServerCodegenContext { - val settings = serverTestRustSettings() - val serverSymbolProviders = ServerSymbolProviders.from( - model, - serviceShape, - ServerTestSymbolVisitorConfig, - settings.codegenConfig.publicConstrainedTypes, - RustCodegenServerPlugin::baseSymbolProvider, - ) - return ServerCodegenContext( - model, - symbolProvider, - serviceShape, - protocolShapeId, - settings, - serverSymbolProviders.unconstrainedShapeSymbolProvider, - serverSymbolProviders.constrainedShapeSymbolProvider, - serverSymbolProviders.constraintViolationSymbolProvider, - serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, - ) - } - - override fun createSymbolProvider(model: Model): RustSymbolProvider = - serverTestSymbolProvider(model) - - override fun renderGenerator( - codegenContext: ServerCodegenContext, - project: TestEventStreamProject, - protocol: Protocol, - ): RuntimeType { - fun builderSymbol(shape: StructureShape): Symbol = shape.builderSymbol(codegenContext.symbolProvider) - return EventStreamUnmarshallerGenerator( - protocol, - codegenContext, - project.operationShape, - project.streamShape, - ::builderSymbol, - ).render() - } - }, - CodegenTarget.SERVER, - EventStreamTestVariety.Unmarshall, - ) - } -} From 5f7bc7eb6a29d1f9835e706111ec73c319996a43 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Fri, 16 Dec 2022 18:09:46 -0800 Subject: [PATCH 11/19] Fix comments in `SmithyTypesPubUseExtra` --- .../core/smithy/customizations/SmithyTypesPubUseExtra.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt index 3a37fa0a9be..02a8843c19c 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt @@ -31,6 +31,7 @@ private fun hasStreamingOperations(model: Model): Boolean { } } +// TODO(https://github.com/awslabs/smithy-rs/issues/2111): Fix this logic to consider collection/map shapes private fun structUnionMembersMatchPredicate(model: Model, predicate: (Shape) -> Boolean): Boolean = model.structureShapes.any { structure -> structure.members().any { member -> predicate(model.expectShape(member.target)) } @@ -38,10 +39,10 @@ private fun structUnionMembersMatchPredicate(model: Model, predicate: (Shape) -> union.members().any { member -> predicate(model.expectShape(member.target)) } } -/** Returns true if the model has any blob shapes or members */ +/** Returns true if the model uses any blob shapes */ private fun hasBlobs(model: Model): Boolean = structUnionMembersMatchPredicate(model, Shape::isBlobShape) -/** Returns true if the model has any timestamp shapes or members */ +/** Returns true if the model uses any timestamp shapes */ private fun hasDateTimes(model: Model): Boolean = structUnionMembersMatchPredicate(model, Shape::isTimestampShape) /** Returns a list of types that should be re-exported for the given model */ From 2dd9881b0a72fdee7d985cf4beb36c8d77429da3 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Fri, 16 Dec 2022 18:12:09 -0800 Subject: [PATCH 12/19] Use pair instead of list --- .../codegen/core/testutil/EventStreamUnmarshallTestCases.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt index 04503c97a33..bb27c724e00 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt @@ -211,8 +211,8 @@ internal object EventStreamUnmarshallTestCases { ) val (someError, kindSuffix) = when (codegenTarget) { - CodegenTarget.CLIENT -> listOf("TestStreamErrorKind::SomeError", ".kind") - CodegenTarget.SERVER -> listOf("TestStreamError::SomeError", "") + CodegenTarget.CLIENT -> "TestStreamErrorKind::SomeError" to ".kind" + CodegenTarget.SERVER -> "TestStreamError::SomeError" to "" } unitTest( "some_error", From be77fa0df3888633117973eed62a7784ed4df258 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Tue, 20 Dec 2022 09:35:55 -0800 Subject: [PATCH 13/19] Simplify base event stream test requirements --- .../EventStreamBaseRequirements.kt | 6 +-- .../core/testutil/EventStreamTestTools.kt | 6 --- .../smithy/testutil/ServerTestHelpers.kt | 12 +++++- .../EventStreamBaseRequirements.kt | 41 +++++-------------- .../EventStreamMarshallerGeneratorTest.kt | 2 + .../EventStreamUnmarshallerGeneratorTest.kt | 2 + 6 files changed, 26 insertions(+), 43 deletions(-) diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt index 73ccb79350a..2192fd64b5f 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt @@ -15,7 +15,6 @@ import software.amazon.smithy.rust.codegen.client.testutil.clientTestRustSetting import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements @@ -23,21 +22,18 @@ import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirem abstract class EventStreamBaseRequirements : EventStreamTestRequirements { override fun createCodegenContext( model: Model, - symbolProvider: RustSymbolProvider, serviceShape: ServiceShape, protocolShapeId: ShapeId, codegenTarget: CodegenTarget, ): ClientCodegenContext = ClientCodegenContext( model, - symbolProvider, + testSymbolProvider(model), serviceShape, protocolShapeId, clientTestRustSettings(), CombinedClientCodegenDecorator(emptyList()), ) - override fun createSymbolProvider(model: Model): RustSymbolProvider = testSymbolProvider(model) - override fun renderBuilderForShape( writer: RustWriter, codegenContext: ClientCodegenContext, diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt index 33e3989bc5c..4fb17db3010 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt @@ -54,15 +54,11 @@ interface EventStreamTestRequirements { /** Create a codegen context for the tests */ fun createCodegenContext( model: Model, - symbolProvider: RustSymbolProvider, serviceShape: ServiceShape, protocolShapeId: ShapeId, codegenTarget: CodegenTarget, ): C - /** Create a symbol provider for the tests */ - fun createSymbolProvider(model: Model): RustSymbolProvider - /** Render the event stream marshall/unmarshall code generator */ fun renderGenerator( codegenContext: C, @@ -86,11 +82,9 @@ object EventStreamTestTools { variety: EventStreamTestVariety, ) { val model = EventStreamNormalizer.transform(OperationNormalizer.transform(testCase.model)) - val symbolProvider = requirements.createSymbolProvider(model) val serviceShape = model.expectShape(ShapeId.from("test#TestService")) as ServiceShape val codegenContext = requirements.createCodegenContext( model, - symbolProvider, serviceShape, ShapeId.from(testCase.protocolShapeId), codegenTarget, diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt index 86bb4439bcd..9d49dfb9fea 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt @@ -39,12 +39,20 @@ private fun testServiceShapeFor(model: Model) = fun serverTestSymbolProvider(model: Model, serviceShape: ServiceShape? = null) = serverTestSymbolProviders(model, serviceShape).symbolProvider -fun serverTestSymbolProviders(model: Model, serviceShape: ServiceShape? = null) = +fun serverTestSymbolProviders( + model: Model, + serviceShape: ServiceShape? = null, + settings: ServerRustSettings? = null, +) = ServerSymbolProviders.from( model, serviceShape ?: testServiceShapeFor(model), ServerTestSymbolVisitorConfig, - serverTestRustSettings((serviceShape ?: testServiceShapeFor(model)).id).codegenConfig.publicConstrainedTypes, + ( + settings ?: serverTestRustSettings( + (serviceShape ?: testServiceShapeFor(model)).id, + ) + ).codegenConfig.publicConstrainedTypes, RustCodegenServerPlugin::baseSymbolProvider, ) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt index 4e8bf3da7cb..55caf7f5972 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt @@ -9,44 +9,25 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements -import software.amazon.smithy.rust.codegen.server.smithy.RustCodegenServerPlugin +import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenConfig import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext -import software.amazon.smithy.rust.codegen.server.smithy.ServerSymbolProviders -import software.amazon.smithy.rust.codegen.server.smithy.testutil.ServerTestSymbolVisitorConfig +import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings -import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider abstract class EventStreamBaseRequirements : EventStreamTestRequirements { + abstract val publicConstrainedTypes: Boolean + override fun createCodegenContext( model: Model, - symbolProvider: RustSymbolProvider, serviceShape: ServiceShape, protocolShapeId: ShapeId, codegenTarget: CodegenTarget, - ): ServerCodegenContext { - val settings = serverTestRustSettings() - val serverSymbolProviders = ServerSymbolProviders.from( - model, - serviceShape, - ServerTestSymbolVisitorConfig, - settings.codegenConfig.publicConstrainedTypes, - RustCodegenServerPlugin::baseSymbolProvider, - ) - return ServerCodegenContext( - model, - symbolProvider, - serviceShape, - protocolShapeId, - settings, - serverSymbolProviders.unconstrainedShapeSymbolProvider, - serverSymbolProviders.constrainedShapeSymbolProvider, - serverSymbolProviders.constraintViolationSymbolProvider, - serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, - ) - } - - override fun createSymbolProvider(model: Model): RustSymbolProvider = - serverTestSymbolProvider(model) + ): ServerCodegenContext = serverTestCodegenContext( + model, serviceShape, + serverTestRustSettings( + codegenConfig = ServerCodegenConfig(publicConstrainedTypes = publicConstrainedTypes), + ), + protocolShapeId, + ) } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt index f575aeeb117..bc483c1bf0c 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt @@ -41,6 +41,8 @@ class EventStreamMarshallerGeneratorTest { EventStreamTestTools.runTestCase( testCase, object : EventStreamBaseRequirements() { + override val publicConstrainedTypes: Boolean get() = true + override fun renderGenerator( codegenContext: ServerCodegenContext, project: TestEventStreamProject, diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt index f1dc3c022b5..f7f3f5dedae 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt @@ -52,6 +52,8 @@ class EventStreamUnmarshallerGeneratorTest { EventStreamTestTools.runTestCase( testCase.eventStreamTestCase, object : EventStreamBaseRequirements() { + override val publicConstrainedTypes: Boolean get() = testCase.publicConstrainedTypes + override fun renderGenerator( codegenContext: ServerCodegenContext, project: TestEventStreamProject, From c608a775bf02ce33b73f6827bb12b6a8b94ad6ed Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Tue, 20 Dec 2022 09:39:10 -0800 Subject: [PATCH 14/19] Explode on unrecognized shape types in event stream test tools --- .../core/testutil/EventStreamTestTools.kt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt index 4fb17db3010..b179663cded 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt @@ -123,7 +123,7 @@ object EventStreamTestTools { CodegenTarget.CLIENT -> CombinedErrorGenerator(model, symbolProvider, operationSymbol, errors).render(this) CodegenTarget.SERVER -> ServerCombinedErrorGenerator(model, symbolProvider, operationSymbol, errors).render(this) } - for (shape in model.shapes().filter { shape -> shape.isStructureShape && shape.hasTrait() }) { + for (shape in model.shapes().filter { shape -> shape is StructureShape && shape.hasTrait() }) { StructureGenerator(model, symbolProvider, this, shape as StructureShape).render(codegenTarget) requirements.renderBuilderForShape(this, codegenContext, shape) } @@ -155,10 +155,16 @@ object EventStreamTestTools { for (member in shape.members()) { val target = model.expectShape(member.target) if (target is StructureShape || target is UnionShape) { - if (target is StructureShape) { - target.renderWithModelBuilder(model, symbolProvider, writer) - } else if (target is UnionShape) { - UnionGenerator(model, symbolProvider, writer, target, renderUnknownVariant = mode.renderUnknownVariant()).render() + when (target) { + is StructureShape -> target.renderWithModelBuilder(model, symbolProvider, writer) + is UnionShape -> UnionGenerator( + model, + symbolProvider, + writer, + target, + renderUnknownVariant = mode.renderUnknownVariant(), + ).render() + else -> TODO("EventStreamTestTools doesn't support rendering $target") } recursivelyGenerateModels(model, symbolProvider, target, writer, mode) } From 5c73370f087e40863b0960118bfb49e07325d926 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Tue, 20 Dec 2022 09:45:11 -0800 Subject: [PATCH 15/19] Add client/server prefixes to test classes --- ...seRequirements.kt => ClientEventStreamBaseRequirements.kt} | 2 +- ...torTest.kt => ClientEventStreamMarshallerGeneratorTest.kt} | 4 ++-- ...rTest.kt => ClientEventStreamUnmarshallerGeneratorTest.kt} | 4 ++-- ...seRequirements.kt => ServerEventStreamBaseRequirements.kt} | 2 +- ...torTest.kt => ServerEventStreamMarshallerGeneratorTest.kt} | 4 ++-- ...rTest.kt => ServerEventStreamUnmarshallerGeneratorTest.kt} | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) rename codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/{EventStreamBaseRequirements.kt => ClientEventStreamBaseRequirements.kt} (95%) rename codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/{EventStreamMarshallerGeneratorTest.kt => ClientEventStreamMarshallerGeneratorTest.kt} (96%) rename codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/{EventStreamUnmarshallerGeneratorTest.kt => ClientEventStreamUnmarshallerGeneratorTest.kt} (95%) rename codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/{EventStreamBaseRequirements.kt => ServerEventStreamBaseRequirements.kt} (92%) rename codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/{EventStreamMarshallerGeneratorTest.kt => ServerEventStreamMarshallerGeneratorTest.kt} (97%) rename codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/{EventStreamUnmarshallerGeneratorTest.kt => ServerEventStreamUnmarshallerGeneratorTest.kt} (97%) diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamBaseRequirements.kt similarity index 95% rename from codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt rename to codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamBaseRequirements.kt index 2192fd64b5f..989645db124 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamBaseRequirements.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamBaseRequirements.kt @@ -19,7 +19,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerat import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements -abstract class EventStreamBaseRequirements : EventStreamTestRequirements { +abstract class ClientEventStreamBaseRequirements : EventStreamTestRequirements { override fun createCodegenContext( model: Model, serviceShape: ServiceShape, diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamMarshallerGeneratorTest.kt similarity index 96% rename from codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt rename to codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamMarshallerGeneratorTest.kt index 129e241fb92..1ba97ddb62f 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamMarshallerGeneratorTest.kt @@ -30,13 +30,13 @@ class MarshallTestCasesProvider : ArgumentsProvider { .map { Arguments.of(it) }.stream() } -class EventStreamMarshallerGeneratorTest { +class ClientEventStreamMarshallerGeneratorTest { @ParameterizedTest @ArgumentsSource(MarshallTestCasesProvider::class) fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - object : EventStreamBaseRequirements() { + object : ClientEventStreamBaseRequirements() { override fun renderGenerator( codegenContext: ClientCodegenContext, project: TestEventStreamProject, diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamUnmarshallerGeneratorTest.kt similarity index 95% rename from codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt rename to codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamUnmarshallerGeneratorTest.kt index 8ec1f27bbee..147e791ee13 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamUnmarshallerGeneratorTest.kt @@ -29,13 +29,13 @@ class UnmarshallTestCasesProvider : ArgumentsProvider { EventStreamTestModels.TEST_CASES.map { Arguments.of(it) }.stream() } -class EventStreamUnmarshallerGeneratorTest { +class ClientEventStreamUnmarshallerGeneratorTest { @ParameterizedTest @ArgumentsSource(UnmarshallTestCasesProvider::class) fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - object : EventStreamBaseRequirements() { + object : ClientEventStreamBaseRequirements() { override fun renderGenerator( codegenContext: ClientCodegenContext, project: TestEventStreamProject, diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt similarity index 92% rename from codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt rename to codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt index 55caf7f5972..ca45fe81f51 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamBaseRequirements.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt @@ -15,7 +15,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings -abstract class EventStreamBaseRequirements : EventStreamTestRequirements { +abstract class ServerEventStreamBaseRequirements : EventStreamTestRequirements { abstract val publicConstrainedTypes: Boolean override fun createCodegenContext( diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamMarshallerGeneratorTest.kt similarity index 97% rename from codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt rename to codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamMarshallerGeneratorTest.kt index bc483c1bf0c..d19865d2074 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamMarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamMarshallerGeneratorTest.kt @@ -34,13 +34,13 @@ class MarshallTestCasesProvider : ArgumentsProvider { .map { Arguments.of(it) }.stream() } -class EventStreamMarshallerGeneratorTest { +class ServerEventStreamMarshallerGeneratorTest { @ParameterizedTest @ArgumentsSource(MarshallTestCasesProvider::class) fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, - object : EventStreamBaseRequirements() { + object : ServerEventStreamBaseRequirements() { override val publicConstrainedTypes: Boolean get() = true override fun renderGenerator( diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt similarity index 97% rename from codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt rename to codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt index f7f3f5dedae..65030562243 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/EventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt @@ -45,13 +45,13 @@ class UnmarshallTestCasesProvider : ArgumentsProvider { }.map { Arguments.of(it) }.stream() } -class EventStreamUnmarshallerGeneratorTest { +class ServerEventStreamUnmarshallerGeneratorTest { @ParameterizedTest @ArgumentsSource(UnmarshallTestCasesProvider::class) fun test(testCase: TestCase) { EventStreamTestTools.runTestCase( testCase.eventStreamTestCase, - object : EventStreamBaseRequirements() { + object : ServerEventStreamBaseRequirements() { override val publicConstrainedTypes: Boolean get() = testCase.publicConstrainedTypes override fun renderGenerator( From a47597fccc413b489e6c9d3f93dc3c2149a2036c Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Tue, 20 Dec 2022 09:50:05 -0800 Subject: [PATCH 16/19] Improve TODO comments in server event stream tests --- ...verEventStreamUnmarshallerGeneratorTest.kt | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt index 65030562243..42f69728861 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt @@ -74,17 +74,33 @@ class ServerEventStreamUnmarshallerGeneratorTest { codegenContext: ServerCodegenContext, shape: StructureShape, ) { - // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Use the correct builder: - // ServerBuilderGenerator(codegenContext, shape).apply { - // render(writer) - // writer.implBlock(shape, codegenContext.symbolProvider) { - // renderConvenienceMethod(writer) - // } - // } - BuilderGenerator(codegenContext.model, codegenContext.symbolProvider, shape).apply { - render(writer) - writer.implBlock(shape, codegenContext.symbolProvider) { - renderConvenienceMethod(writer) + if (testCase.publicConstrainedTypes) { + // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Use the ServerBuilderGenerator: + // ServerBuilderGenerator(codegenContext, shape).apply { + // render(writer) + // writer.implBlock(shape, codegenContext.symbolProvider) { + // renderConvenienceMethod(writer) + // } + // } + BuilderGenerator(codegenContext.model, codegenContext.symbolProvider, shape).apply { + render(writer) + writer.implBlock(shape, codegenContext.symbolProvider) { + renderConvenienceMethod(writer) + } + } + } else { + // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Use the ServerBuilderGeneratorWithoutPublicConstraintedTypes: + // ServerBuilderGeneratorWithoutPublicConstrainedTypes(codegenContext, shape).apply { + // render(writer) + // writer.implBlock(shape, codegenContext.symbolProvider) { + // renderConvenienceMethod(writer) + // } + // } + BuilderGenerator(codegenContext.model, codegenContext.symbolProvider, shape).apply { + render(writer) + writer.implBlock(shape, codegenContext.symbolProvider) { + renderConvenienceMethod(writer) + } } } } From 0b77d8ffe7380d07a0ff648ae4e526ecc28616d7 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Tue, 20 Dec 2022 10:00:57 -0800 Subject: [PATCH 17/19] Use correct builders for `ServerEventStreamMarshallerGeneratorTest` --- .../ServerEventStreamBaseRequirements.kt | 35 +++++++++++++++ ...erverEventStreamMarshallerGeneratorTest.kt | 32 +++++--------- ...verEventStreamUnmarshallerGeneratorTest.kt | 43 +++---------------- 3 files changed, 52 insertions(+), 58 deletions(-) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt index ca45fe81f51..65029697583 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt @@ -8,13 +8,26 @@ package software.amazon.smithy.rust.codegen.server.smithy.protocols.eventstream import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenConfig import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext +import software.amazon.smithy.rust.codegen.server.smithy.generators.ServerBuilderGenerator +import software.amazon.smithy.rust.codegen.server.smithy.generators.ServerBuilderGeneratorWithoutPublicConstrainedTypes import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings +data class TestCase( + val eventStreamTestCase: EventStreamTestModels.TestCase, + val publicConstrainedTypes: Boolean, +) { + override fun toString(): String = "$eventStreamTestCase, publicConstrainedTypes = $publicConstrainedTypes" +} + abstract class ServerEventStreamBaseRequirements : EventStreamTestRequirements { abstract val publicConstrainedTypes: Boolean @@ -30,4 +43,26 @@ abstract class ServerEventStreamBaseRequirements : EventStreamTestRequirements !testCase.protocolShapeId.contains("Query") } - .map { Arguments.of(it) }.stream() + .flatMap { testCase -> + listOf( + TestCase(testCase, publicConstrainedTypes = false), + TestCase(testCase, publicConstrainedTypes = true), + ) + }.map { Arguments.of(it) }.stream() } class ServerEventStreamMarshallerGeneratorTest { @ParameterizedTest @ArgumentsSource(MarshallTestCasesProvider::class) - fun test(testCase: EventStreamTestModels.TestCase) { + fun test(testCase: TestCase) { EventStreamTestTools.runTestCase( - testCase, + testCase.eventStreamTestCase, object : ServerEventStreamBaseRequirements() { - override val publicConstrainedTypes: Boolean get() = true + override val publicConstrainedTypes: Boolean get() = testCase.publicConstrainedTypes override fun renderGenerator( codegenContext: ServerCodegenContext, @@ -55,22 +56,9 @@ class ServerEventStreamMarshallerGeneratorTest { project.symbolProvider, project.streamShape, protocol.structuredDataSerializer(project.operationShape), - testCase.requestContentType, + testCase.eventStreamTestCase.requestContentType, ).render() } - - override fun renderBuilderForShape( - writer: RustWriter, - codegenContext: ServerCodegenContext, - shape: StructureShape, - ) { - ServerBuilderGenerator(codegenContext, shape).apply { - render(writer) - writer.implBlock(shape, codegenContext.symbolProvider) { - renderConvenienceMethod(writer) - } - } - } }, CodegenTarget.SERVER, EventStreamTestVariety.Marshall, diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt index 42f69728861..9d6a031b82f 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt @@ -27,20 +27,13 @@ import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.generators.serverBuilderSymbol import java.util.stream.Stream -data class TestCase( - val eventStreamTestCase: EventStreamTestModels.TestCase, - val publicConstrainedTypes: Boolean, -) { - override fun toString(): String = "$eventStreamTestCase, publicConstrainedTypes = $publicConstrainedTypes" -} - class UnmarshallTestCasesProvider : ArgumentsProvider { override fun provideArguments(context: ExtensionContext?): Stream = EventStreamTestModels.TEST_CASES.flatMap { testCase -> listOf( // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Enable tests for `publicConstrainedTypes = false` - // TestCase(testCase, false), - TestCase(testCase, true), + // TestCase(testCase, publicConstrainedTypes = false), + TestCase(testCase, publicConstrainedTypes = true), ) }.map { Arguments.of(it) }.stream() } @@ -69,38 +62,16 @@ class ServerEventStreamUnmarshallerGeneratorTest { ).render() } + // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Delete this function override to use the correct builder from the parent class override fun renderBuilderForShape( writer: RustWriter, codegenContext: ServerCodegenContext, shape: StructureShape, ) { - if (testCase.publicConstrainedTypes) { - // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Use the ServerBuilderGenerator: - // ServerBuilderGenerator(codegenContext, shape).apply { - // render(writer) - // writer.implBlock(shape, codegenContext.symbolProvider) { - // renderConvenienceMethod(writer) - // } - // } - BuilderGenerator(codegenContext.model, codegenContext.symbolProvider, shape).apply { - render(writer) - writer.implBlock(shape, codegenContext.symbolProvider) { - renderConvenienceMethod(writer) - } - } - } else { - // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Use the ServerBuilderGeneratorWithoutPublicConstraintedTypes: - // ServerBuilderGeneratorWithoutPublicConstrainedTypes(codegenContext, shape).apply { - // render(writer) - // writer.implBlock(shape, codegenContext.symbolProvider) { - // renderConvenienceMethod(writer) - // } - // } - BuilderGenerator(codegenContext.model, codegenContext.symbolProvider, shape).apply { - render(writer) - writer.implBlock(shape, codegenContext.symbolProvider) { - renderConvenienceMethod(writer) - } + BuilderGenerator(codegenContext.model, codegenContext.symbolProvider, shape).apply { + render(writer) + writer.implBlock(shape, codegenContext.symbolProvider) { + renderConvenienceMethod(writer) } } } From 38598f2e318b201d78a81d8e2c1185587f962c4e Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Tue, 20 Dec 2022 10:10:28 -0800 Subject: [PATCH 18/19] Fix shape check in event stream test tools --- .../core/testutil/EventStreamTestTools.kt | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt index b179663cded..8340ff3ee3d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestTools.kt @@ -153,21 +153,22 @@ object EventStreamTestTools { mode: CodegenTarget, ) { for (member in shape.members()) { + if (member.target.namespace == "smithy.api") { + continue + } val target = model.expectShape(member.target) - if (target is StructureShape || target is UnionShape) { - when (target) { - is StructureShape -> target.renderWithModelBuilder(model, symbolProvider, writer) - is UnionShape -> UnionGenerator( - model, - symbolProvider, - writer, - target, - renderUnknownVariant = mode.renderUnknownVariant(), - ).render() - else -> TODO("EventStreamTestTools doesn't support rendering $target") - } - recursivelyGenerateModels(model, symbolProvider, target, writer, mode) + when (target) { + is StructureShape -> target.renderWithModelBuilder(model, symbolProvider, writer) + is UnionShape -> UnionGenerator( + model, + symbolProvider, + writer, + target, + renderUnknownVariant = mode.renderUnknownVariant(), + ).render() + else -> TODO("EventStreamTestTools doesn't support rendering $target") } + recursivelyGenerateModels(model, symbolProvider, target, writer, mode) } } } From 80ed7a9510c43a6cbb030c047694b326de53c15a Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Tue, 20 Dec 2022 10:22:46 -0800 Subject: [PATCH 19/19] Remove test cases for protocols that don't support event streams --- .../ClientEventStreamBaseRequirements.kt | 10 +++ ...lientEventStreamMarshallerGeneratorTest.kt | 14 +-- ...entEventStreamUnmarshallerGeneratorTest.kt | 11 +-- .../core/testutil/EventStreamTestModels.kt | 88 ------------------- .../ServerEventStreamBaseRequirements.kt | 15 ++++ ...erverEventStreamMarshallerGeneratorTest.kt | 20 +---- ...verEventStreamUnmarshallerGeneratorTest.kt | 24 ++--- 7 files changed, 35 insertions(+), 147 deletions(-) diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamBaseRequirements.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamBaseRequirements.kt index 989645db124..3f6a7a8c564 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamBaseRequirements.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamBaseRequirements.kt @@ -5,6 +5,9 @@ package software.amazon.smithy.rust.codegen.client.smithy.protocols.eventstream +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId @@ -17,7 +20,14 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock +import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements +import java.util.stream.Stream + +class TestCasesProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream = + EventStreamTestModels.TEST_CASES.map { Arguments.of(it) }.stream() +} abstract class ClientEventStreamBaseRequirements : EventStreamTestRequirements { override fun createCodegenContext( diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamMarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamMarshallerGeneratorTest.kt index 1ba97ddb62f..936d3b63243 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamMarshallerGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamMarshallerGeneratorTest.kt @@ -5,10 +5,7 @@ package software.amazon.smithy.rust.codegen.client.smithy.protocols.eventstream -import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget @@ -20,19 +17,10 @@ import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig -import java.util.stream.Stream - -class MarshallTestCasesProvider : ArgumentsProvider { - override fun provideArguments(context: ExtensionContext?): Stream = - // Don't include awsQuery or ec2Query for now since marshall support for them is unimplemented - EventStreamTestModels.TEST_CASES - .filter { testCase -> !testCase.protocolShapeId.contains("Query") } - .map { Arguments.of(it) }.stream() -} class ClientEventStreamMarshallerGeneratorTest { @ParameterizedTest - @ArgumentsSource(MarshallTestCasesProvider::class) + @ArgumentsSource(TestCasesProvider::class) fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamUnmarshallerGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamUnmarshallerGeneratorTest.kt index 147e791ee13..f9be7b3bf4c 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/eventstream/ClientEventStreamUnmarshallerGeneratorTest.kt @@ -5,10 +5,7 @@ package software.amazon.smithy.rust.codegen.client.smithy.protocols.eventstream -import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.shapes.StructureShape @@ -22,16 +19,10 @@ import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject -import java.util.stream.Stream - -class UnmarshallTestCasesProvider : ArgumentsProvider { - override fun provideArguments(context: ExtensionContext?): Stream = - EventStreamTestModels.TEST_CASES.map { Arguments.of(it) }.stream() -} class ClientEventStreamUnmarshallerGeneratorTest { @ParameterizedTest - @ArgumentsSource(UnmarshallTestCasesProvider::class) + @ArgumentsSource(TestCasesProvider::class) fun test(testCase: EventStreamTestModels.TestCase) { EventStreamTestTools.runTestCase( testCase, diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt index 00fdf08998a..58ab85eec60 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt @@ -9,8 +9,6 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJson import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsJsonVersion -import software.amazon.smithy.rust.codegen.core.smithy.protocols.AwsQueryProtocol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.Ec2QueryProtocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestJson import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestXml @@ -177,91 +175,5 @@ object EventStreamTestModels { """.trimIndent(), ) { RestXml(it) }, - - // - // awsQuery - // - TestCase( - protocolShapeId = "aws.protocols#awsQuery", - model = awsQuery(), - requestContentType = "application/x-www-form-urlencoded", - responseContentType = "text/xml", - validTestStruct = """ - - hello - 5 - - """.trimIndent(), - validMessageWithNoHeaderPayloadTraits = """ - - hello - 5 - - """.trimIndent(), - validTestUnion = "hello", - validSomeError = """ - - - SomeError - SomeError - some error - - - """.trimIndent(), - validUnmodeledError = """ - - - UnmodeledError - UnmodeledError - unmodeled error - - - """.trimIndent(), - ) { AwsQueryProtocol(it) }, - - // - // ec2Query - // - TestCase( - protocolShapeId = "aws.protocols#ec2Query", - model = ec2Query(), - requestContentType = "application/x-www-form-urlencoded", - responseContentType = "text/xml", - validTestStruct = """ - - hello - 5 - - """.trimIndent(), - validMessageWithNoHeaderPayloadTraits = """ - - hello - 5 - - """.trimIndent(), - validTestUnion = "hello", - validSomeError = """ - - - - SomeError - SomeError - some error - - - - """.trimIndent(), - validUnmodeledError = """ - - - - UnmodeledError - UnmodeledError - unmodeled error - - - - """.trimIndent(), - ) { Ec2QueryProtocol(it) }, ) } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt index 65029697583..1e2cdef43f2 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamBaseRequirements.kt @@ -5,6 +5,9 @@ package software.amazon.smithy.rust.codegen.server.smithy.protocols.eventstream +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId @@ -20,6 +23,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.generators.ServerBuilde import software.amazon.smithy.rust.codegen.server.smithy.generators.ServerBuilderGeneratorWithoutPublicConstrainedTypes import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings +import java.util.stream.Stream data class TestCase( val eventStreamTestCase: EventStreamTestModels.TestCase, @@ -28,6 +32,17 @@ data class TestCase( override fun toString(): String = "$eventStreamTestCase, publicConstrainedTypes = $publicConstrainedTypes" } +class TestCasesProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream = + EventStreamTestModels.TEST_CASES + .flatMap { testCase -> + listOf( + TestCase(testCase, publicConstrainedTypes = false), + TestCase(testCase, publicConstrainedTypes = true), + ) + }.map { Arguments.of(it) }.stream() +} + abstract class ServerEventStreamBaseRequirements : EventStreamTestRequirements { abstract val publicConstrainedTypes: Boolean diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamMarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamMarshallerGeneratorTest.kt index 39f188f3d06..860b451ee85 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamMarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamMarshallerGeneratorTest.kt @@ -5,39 +5,21 @@ package software.amazon.smithy.rust.codegen.server.smithy.protocols.eventstream -import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.EventStreamMarshallerGenerator -import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext -import java.util.stream.Stream - -class MarshallTestCasesProvider : ArgumentsProvider { - override fun provideArguments(context: ExtensionContext?): Stream = - // Don't include awsQuery or ec2Query for now since marshall support for them is unimplemented - EventStreamTestModels.TEST_CASES - .filter { testCase -> !testCase.protocolShapeId.contains("Query") } - .flatMap { testCase -> - listOf( - TestCase(testCase, publicConstrainedTypes = false), - TestCase(testCase, publicConstrainedTypes = true), - ) - }.map { Arguments.of(it) }.stream() -} class ServerEventStreamMarshallerGeneratorTest { @ParameterizedTest - @ArgumentsSource(MarshallTestCasesProvider::class) + @ArgumentsSource(TestCasesProvider::class) fun test(testCase: TestCase) { EventStreamTestTools.runTestCase( testCase.eventStreamTestCase, diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt index 9d6a031b82f..08a5ef5f588 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/eventstream/ServerEventStreamUnmarshallerGeneratorTest.kt @@ -5,10 +5,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.protocols.eventstream -import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.provider.ArgumentsSource import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.shapes.StructureShape @@ -19,29 +16,22 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerat import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.EventStreamUnmarshallerGenerator -import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestModels import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestTools import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestVariety import software.amazon.smithy.rust.codegen.core.testutil.TestEventStreamProject import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.generators.serverBuilderSymbol -import java.util.stream.Stream - -class UnmarshallTestCasesProvider : ArgumentsProvider { - override fun provideArguments(context: ExtensionContext?): Stream = - EventStreamTestModels.TEST_CASES.flatMap { testCase -> - listOf( - // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Enable tests for `publicConstrainedTypes = false` - // TestCase(testCase, publicConstrainedTypes = false), - TestCase(testCase, publicConstrainedTypes = true), - ) - }.map { Arguments.of(it) }.stream() -} class ServerEventStreamUnmarshallerGeneratorTest { @ParameterizedTest - @ArgumentsSource(UnmarshallTestCasesProvider::class) + @ArgumentsSource(TestCasesProvider::class) fun test(testCase: TestCase) { + // TODO(https://github.com/awslabs/smithy-rs/issues/1442): Enable tests for `publicConstrainedTypes = false` + // by deleting this if/return + if (!testCase.publicConstrainedTypes) { + return + } + EventStreamTestTools.runTestCase( testCase.eventStreamTestCase, object : ServerEventStreamBaseRequirements() {