Unverified Commit eb482614 authored by david-perez's avatar david-perez Committed by GitHub
Browse files

`codegen-serde`: traverse operations of resources (#3882)

The current implementation doesn't traverse a resource's operations if
the serialization root is a service shape; the added test fails without
this fix.

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
parent ef07c887
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
package software.amazon.smithy.rust.codegen.serde

import software.amazon.smithy.codegen.core.Symbol
import software.amazon.smithy.model.knowledge.TopDownIndex
import software.amazon.smithy.model.shapes.BlobShape
import software.amazon.smithy.model.shapes.BooleanShape
import software.amazon.smithy.model.shapes.CollectionShape
@@ -61,6 +62,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.hasConstraintTrait

class SerializeImplGenerator(private val codegenContext: CodegenContext) {
    private val model = codegenContext.model
    private val topIndex = TopDownIndex.of(model)

    fun generateRootSerializerForShape(shape: Shape): Writable = serializerFn(shape, null)

@@ -78,7 +80,9 @@ class SerializeImplGenerator(private val codegenContext: CodegenContext) {
        applyTo: Writable?,
    ): Writable {
        if (shape is ServiceShape) {
            return shape.operations.map { serializerFn(model.expectShape(it), null) }.join("\n")
            return topIndex.getContainedOperations(shape).map {
                serializerFn(it, null)
            }.join("\n")
        } else if (shape is OperationShape) {
            if (shape.isEventStream(model)) {
                // Don't generate serializers for event streams
+52 −0
Original line number Diff line number Diff line
@@ -179,6 +179,58 @@ class SerdeDecoratorTest {
        structure NotSerde {}
        """.asSmithyModel(smithyVersion = "2")

    @Test
    fun `decorator should traverse resources`() {
        val model =
            """
            namespace com.example
            use smithy.rust#serde
            use aws.protocols#awsJson1_0
            
            @awsJson1_0
            @serde
            service MyResourceService {
                resources: [MyResource]
            }
            
            resource MyResource {
                read: ReadMyResource
            }
            
            @readonly
            operation ReadMyResource {
                input := { }
            }
        """.asSmithyModel(smithyVersion = "2")

        val params =
            IntegrationTestParams(cargoCommand = "cargo test --all-features", service = "com.example#MyResourceService")
        serverIntegrationTest(model, params = params) { ctx, crate ->
            val codegenScope =
                arrayOf(
                    "crate" to RustType.Opaque(ctx.moduleUseName()),
                    "serde_json" to CargoDependency("serde_json", CratesIo("1")).toDevDependency().toType(),
                    // we need the derive feature
                    "serde" to CargoDependency.Serde.toDevDependency().toType(),
                )

            crate.integrationTest("test_serde") {
                unitTest("input_serialized") {
                    rustTemplate(
                        """
                        use #{crate}::input::ReadMyResourceInput;
                        use #{crate}::serde::*;
                        let input = ReadMyResourceInput { };
                        let settings = SerializationSettings::default();
                        let _serialized = #{serde_json}::to_string(&input.serialize_ref(&settings)).expect("failed to serialize");
                        """,
                        *codegenScope,
                    )
                }
            }
        }
    }

    @Test
    fun generateSerializersThatWorkServer() {
        serverIntegrationTest(simpleModel, params = params) { ctx, crate ->