Skip to content

Commit

Permalink
Refactor event stream tests with {client,server}IntegrationTests (s…
Browse files Browse the repository at this point in the history
…mithy-lang#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
  • Loading branch information
jjant committed Feb 28, 2023
1 parent 72df844 commit c3ae6f7
Show file tree
Hide file tree
Showing 17 changed files with 541 additions and 898 deletions.
4 changes: 4 additions & 0 deletions codegen-client/build.gradle.kts
Expand Up @@ -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 {
Expand Down

This file was deleted.

Expand Up @@ -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()
}
Expand Up @@ -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()
}
},
CodegenTarget.CLIENT,
EventStreamTestVariety.Unmarshall,
).compileAndTest()
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),
}
""",
)
}
}
}
}
Expand Up @@ -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"))
Expand Down
Expand Up @@ -116,7 +116,7 @@ private fun <T : AbstractCodeWriter<T>, U> T.withTemplate(
* This enables conditionally wrapping a block in a prefix/suffix, e.g.
*
* ```
* writer.withBlock("Some(", ")", conditional = symbol.isOptional()) {
* writer.conditionalBlock("Some(", ")", conditional = symbol.isOptional()) {
* write("symbolValue")
* }
* ```
Expand Down
Expand Up @@ -43,6 +43,9 @@ import software.amazon.smithy.rust.codegen.core.util.expectTrait
import software.amazon.smithy.rust.codegen.core.util.hasTrait
import software.amazon.smithy.rust.codegen.core.util.toPascalCase

fun RustModule.Companion.eventStreamSerdeModule(): RustModule.LeafModule =
private("event_stream_serde")

class EventStreamUnmarshallerGenerator(
private val protocol: Protocol,
codegenContext: CodegenContext,
Expand All @@ -60,7 +63,7 @@ class EventStreamUnmarshallerGenerator(
symbolProvider.symbolForEventStreamError(unionShape)
}
private val smithyEventStream = RuntimeType.smithyEventStream(runtimeConfig)
private val eventStreamSerdeModule = RustModule.private("event_stream_serde")
private val eventStreamSerdeModule = RustModule.eventStreamSerdeModule()
private val codegenScope = arrayOf(
"Blob" to RuntimeType.blob(runtimeConfig),
"expect_fns" to smithyEventStream.resolve("smithy"),
Expand All @@ -84,15 +87,16 @@ class EventStreamUnmarshallerGenerator(
}

private fun RustWriter.renderUnmarshaller(unmarshallerType: RuntimeType, unionSymbol: Symbol) {
val unmarshallerTypeName = unmarshallerType.name
rust(
"""
##[non_exhaustive]
##[derive(Debug)]
pub struct ${unmarshallerType.name};
pub struct $unmarshallerTypeName;
impl ${unmarshallerType.name} {
impl $unmarshallerTypeName {
pub fn new() -> Self {
${unmarshallerType.name}
$unmarshallerTypeName
}
}
""",
Expand Down Expand Up @@ -154,6 +158,7 @@ class EventStreamUnmarshallerGenerator(
"Output" to unionSymbol,
*codegenScope,
)

false -> rustTemplate(
"return Err(#{Error}::unmarshalling(format!(\"unrecognized :event-type: {}\", _unknown_variant)));",
*codegenScope,
Expand All @@ -179,6 +184,7 @@ class EventStreamUnmarshallerGenerator(
*codegenScope,
)
}

payloadOnly -> {
withBlock("let parsed = ", ";") {
renderParseProtocolPayload(unionMember)
Expand All @@ -189,6 +195,7 @@ class EventStreamUnmarshallerGenerator(
*codegenScope,
)
}

else -> {
rust("let mut builder = #T::default();", symbolProvider.symbolForBuilder(unionStruct))
val payloadMember = unionStruct.members().firstOrNull { it.hasTrait<EventPayloadTrait>() }
Expand Down Expand Up @@ -265,6 +272,7 @@ class EventStreamUnmarshallerGenerator(
is BlobShape -> {
rustTemplate("#{Blob}::new(message.payload().as_ref())", *codegenScope)
}

is StringShape -> {
rustTemplate(
"""
Expand All @@ -275,6 +283,7 @@ class EventStreamUnmarshallerGenerator(
*codegenScope,
)
}

is UnionShape, is StructureShape -> {
renderParseProtocolPayload(member)
}
Expand Down Expand Up @@ -312,6 +321,7 @@ class EventStreamUnmarshallerGenerator(
*codegenScope,
)
}

CodegenTarget.SERVER -> {}
}

Expand Down Expand Up @@ -350,6 +360,7 @@ class EventStreamUnmarshallerGenerator(
)
}
}

CodegenTarget.SERVER -> {
val target = model.expectShape(member.target, StructureShape::class.java)
val parser = protocol.structuredDataParser(operationShape).errorParser(target)
Expand Down Expand Up @@ -391,6 +402,7 @@ class EventStreamUnmarshallerGenerator(
CodegenTarget.CLIENT -> {
rustTemplate("Ok(#{UnmarshalledMessage}::Error(#{OpError}::generic(generic)))", *codegenScope)
}

CodegenTarget.SERVER -> {
rustTemplate(
"""
Expand Down

0 comments on commit c3ae6f7

Please sign in to comment.