Unverified Commit c3ae6f7e authored by Julian Antonielli's avatar Julian Antonielli Committed by GitHub
Browse files

Refactor event stream tests with `{client,server}IntegrationTest`s (#2342)

* Refactor `ClientEventStreamUnmarshallerGeneratorTest` to use `clientIntegrationTest` (WIP)

* Refactor `ClientEventStreamUnmarshallerGeneratorTest` with `clientIntegrationTest`

* Refactor `ClientEventStreamUnmarshallerGeneratorTest` to use generic test cases

* Start refactoring `ServerEventStreamUnmarshallerGeneratorTest`

* Make `ServerEventStreamUnmarshallerGeneratorTest` tests work

* Uncomment other test models

* Allow unused on `parse_generic_error`

* Rename `ServerEventStreamUnmarshallerGeneratorTest`

* Make `EventStreamUnmarshallTestCases` codegenTarget-agnostic

* Refactor `ClientEventStreamMarshallerGeneratorTest`: Tests run but fail

* Refactor `ServerEventStreamMarshallerGeneratorTest`

* Move `.into()` calls to `conditionalBuilderInput`

* Add "context" to TODO

* Fix client unmarshall tests

* Fix clippy lint

* Fix more clippy lints

* Add docs for `event_stream_serde` module

* Fix client tests

* Remove `#[allow(missing_docs)]` from event stream module

* Remove unused `EventStreamTestTools`

* Add `smithy-validation-model` test dep to `codegen-client`

* Temporarily add docs to make tests compile

* Undo change in model

* Make event stream unmarshaller tests a unit test

* Remove unused code

* Make `ServerEventStreamUnmarshallerGeneratorTest` a unit test

* Make `ServerEventStreamMarshallerGeneratorTest` a unit test

* Make `ServerEventStreamMarshallerGeneratorTest` pass

* Make remaining tests non-integration tests

* Make event stream serde module private again

* Remove unnecessary clippy allowances

* Remove clippy allowance

* Remove docs for `event_stream_serde` module

* Remove docs for `$unmarshallerTypeName::new`

* Remove more unnecessary docs

* Remove more superfluous docs

* Undo unnecessary diffs

* Uncomment last test

* Make `conditionalBuilderInput` internal
parent 72df8440
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -28,6 +28,10 @@ dependencies {
    implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion")
    implementation("software.amazon.smithy:smithy-waiters:$smithyVersion")
    implementation("software.amazon.smithy:smithy-rules-engine:$smithyVersion")

    // `smithy.framework#ValidationException` is defined here, which is used in event stream
// marshalling/unmarshalling tests.
    testImplementation("software.amazon.smithy:smithy-validation-model:$smithyVersion")
}

tasks.compileKotlin {
+0 −98
Original line number Diff line number Diff line
/*
 * 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 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.Shape
import software.amazon.smithy.model.shapes.ShapeId
import software.amazon.smithy.model.shapes.StructureShape
import software.amazon.smithy.model.traits.ErrorTrait
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.smithy.generators.error.ErrorGenerator
import software.amazon.smithy.rust.codegen.client.smithy.generators.error.OperationErrorGenerator
import software.amazon.smithy.rust.codegen.client.testutil.testClientRustSettings
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.rustlang.implBlock
import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
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.testutil.EventStreamTestModels
import software.amazon.smithy.rust.codegen.core.testutil.EventStreamTestRequirements
import software.amazon.smithy.rust.codegen.core.util.expectTrait
import java.util.stream.Stream

class TestCasesProvider : ArgumentsProvider {
    override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> =
        EventStreamTestModels.TEST_CASES.map { Arguments.of(it) }.stream()
}

abstract class ClientEventStreamBaseRequirements : EventStreamTestRequirements<ClientCodegenContext> {
    override fun createCodegenContext(
        model: Model,
        serviceShape: ServiceShape,
        protocolShapeId: ShapeId,
        codegenTarget: CodegenTarget,
    ): ClientCodegenContext = ClientCodegenContext(
        model,
        testSymbolProvider(model),
        serviceShape,
        protocolShapeId,
        testClientRustSettings(),
        CombinedClientCodegenDecorator(emptyList()),
    )

    override fun renderBuilderForShape(
        rustCrate: RustCrate,
        writer: RustWriter,
        codegenContext: ClientCodegenContext,
        shape: StructureShape,
    ) {
        BuilderGenerator(codegenContext.model, codegenContext.symbolProvider, shape, emptyList()).apply {
            render(writer)
        }
        writer.implBlock(codegenContext.symbolProvider.toSymbol(shape)) {
            BuilderGenerator.renderConvenienceMethod(writer, codegenContext.symbolProvider, shape)
        }
    }

    override fun renderOperationError(
        writer: RustWriter,
        model: Model,
        symbolProvider: RustSymbolProvider,
        operationOrEventStream: Shape,
    ) {
        OperationErrorGenerator(model, symbolProvider, operationOrEventStream, emptyList()).render(writer)
    }

    override fun renderError(
        rustCrate: RustCrate,
        writer: RustWriter,
        codegenContext: ClientCodegenContext,
        shape: StructureShape,
    ) {
        val errorTrait = shape.expectTrait<ErrorTrait>()
        val errorGenerator = ErrorGenerator(
            codegenContext.model,
            codegenContext.symbolProvider,
            shape,
            errorTrait,
            emptyList(),
        )
        rustCrate.useShapeWriter(shape) {
            errorGenerator.renderStruct(this)
        }
        rustCrate.withModule(codegenContext.symbolProvider.moduleForBuilder(shape)) {
            errorGenerator.renderBuilder(this)
        }
    }
}
+17 −30
Original line number Diff line number Diff line
@@ -5,43 +5,30 @@

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
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.client.testutil.clientIntegrationTest
import software.amazon.smithy.rust.codegen.core.testutil.EventStreamMarshallTestCases.writeMarshallTestCases
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.core.testutil.compileAndTest
import software.amazon.smithy.rust.codegen.core.testutil.testModule
import java.util.stream.Stream

class ClientEventStreamMarshallerGeneratorTest {
    @ParameterizedTest
    @ArgumentsSource(TestCasesProvider::class)
    fun test(testCase: EventStreamTestModels.TestCase) {
        EventStreamTestTools.setupTestCase(
            testCase,
            object : ClientEventStreamBaseRequirements() {
                override fun renderGenerator(
                    codegenContext: ClientCodegenContext,
                    project: TestEventStreamProject,
                    protocol: Protocol,
                ): RuntimeType = EventStreamMarshallerGenerator(
                    project.model,
                    CodegenTarget.CLIENT,
                    TestRuntimeConfig,
                    project.symbolProvider,
                    project.streamShape,
                    protocol.structuredDataSerializer(project.operationShape),
                    testCase.requestContentType,
                ).render()
            },
            CodegenTarget.CLIENT,
            EventStreamTestVariety.Marshall,
        ).compileAndTest()
        clientIntegrationTest(testCase.model) { _, rustCrate ->
            rustCrate.testModule {
                writeMarshallTestCases(testCase, optionalBuilderInputs = false)
            }
        }
    }
}

class TestCasesProvider : ArgumentsProvider {
    override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> =
        EventStreamTestModels.TEST_CASES.map { Arguments.of(it) }.stream()
}
+49 −28
Original line number Diff line number Diff line
@@ -7,39 +7,60 @@ package software.amazon.smithy.rust.codegen.client.smithy.protocols.eventstream

import org.junit.jupiter.params.ParameterizedTest
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
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.parse.EventStreamUnmarshallerGenerator
import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest
import software.amazon.smithy.rust.codegen.core.rustlang.rust
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.compileAndTest
import software.amazon.smithy.rust.codegen.core.testutil.EventStreamUnmarshallTestCases.writeUnmarshallTestCases
import software.amazon.smithy.rust.codegen.core.testutil.IntegrationTestParams
import software.amazon.smithy.rust.codegen.core.testutil.testModule
import software.amazon.smithy.rust.codegen.core.testutil.unitTest

class ClientEventStreamUnmarshallerGeneratorTest {
    @ParameterizedTest
    @ArgumentsSource(TestCasesProvider::class)
    fun test(testCase: EventStreamTestModels.TestCase) {
        EventStreamTestTools.setupTestCase(
            testCase,
            object : ClientEventStreamBaseRequirements() {
                override fun renderGenerator(
                    codegenContext: ClientCodegenContext,
                    project: TestEventStreamProject,
                    protocol: Protocol,
                ): RuntimeType {
                    return EventStreamUnmarshallerGenerator(
                        protocol,
                        codegenContext,
                        project.operationShape,
                        project.streamShape,
                    ).render()
        clientIntegrationTest(
            testCase.model,
            IntegrationTestParams(service = "test#TestService", addModuleToEventStreamAllowList = true),
        ) { _, rustCrate ->
            val generator = "crate::event_stream_serde::TestStreamUnmarshaller"

            rustCrate.testModule {
                rust("##![allow(unused_imports, dead_code)]")
                writeUnmarshallTestCases(testCase, optionalBuilderInputs = false)

                unitTest(
                    "unknown_message",
                    """
                    let message = msg("event", "NewUnmodeledMessageType", "application/octet-stream", b"hello, world!");
                    let result = $generator::new().unmarshall(&message);
                    assert!(result.is_ok(), "expected ok, got: {:?}", result);
                    assert!(expect_event(result.unwrap()).is_unknown());
                    """,
                )

                unitTest(
                    "generic_error",
                    """
                    let message = msg(
                        "exception",
                        "UnmodeledError",
                        "${testCase.responseContentType}",
                        br#"${testCase.validUnmodeledError}"#
                    );
                    let result = $generator::new().unmarshall(&message);
                    assert!(result.is_ok(), "expected ok, got: {:?}", result);
                    match expect_error(result.unwrap()) {
                        TestStreamError::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),
                    }
                    """,
                )
            }
        }
            },
            CodegenTarget.CLIENT,
            EventStreamTestVariety.Unmarshall,
        ).compileAndTest()
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -470,9 +470,11 @@ class Attribute(val inner: Writable) {
        val AllowDeprecated = Attribute(allow("deprecated"))
        val AllowIrrefutableLetPatterns = Attribute(allow("irrefutable_let_patterns"))
        val AllowUnreachableCode = Attribute(allow("unreachable_code"))
        val AllowUnreachablePatterns = Attribute(allow("unreachable_patterns"))
        val AllowUnusedImports = Attribute(allow("unused_imports"))
        val AllowUnusedMut = Attribute(allow("unused_mut"))
        val AllowUnusedVariables = Attribute(allow("unused_variables"))
        val AllowMissingDocs = Attribute(allow("missing_docs"))
        val CfgTest = Attribute(cfg("test"))
        val DenyMissingDocs = Attribute(deny("missing_docs"))
        val DocHidden = Attribute(doc("hidden"))
Loading