Skip to content

Refactor event stream tests with {client,server}IntegrationTests #2342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
58013c0
Refactor `ClientEventStreamUnmarshallerGeneratorTest` to use `clientI…
jjant Feb 9, 2023
623c592
Refactor `ClientEventStreamUnmarshallerGeneratorTest` with `clientInt…
jjant Feb 10, 2023
82053c2
Refactor `ClientEventStreamUnmarshallerGeneratorTest` to use generic …
jjant Feb 13, 2023
5d53efc
Start refactoring `ServerEventStreamUnmarshallerGeneratorTest`
jjant Feb 13, 2023
c1e4bab
Make `ServerEventStreamUnmarshallerGeneratorTest` tests work
jjant Feb 13, 2023
fcf69bd
Uncomment other test models
jjant Feb 13, 2023
573eea7
Allow unused on `parse_generic_error`
jjant Feb 13, 2023
0a35b85
Rename `ServerEventStreamUnmarshallerGeneratorTest`
jjant Feb 13, 2023
84f27a5
Merge branch 'main' into jjant/replace-event-stream-tests
jjant Feb 14, 2023
5b08533
Make `EventStreamUnmarshallTestCases` codegenTarget-agnostic
jjant Feb 14, 2023
47de13c
Refactor `ClientEventStreamMarshallerGeneratorTest`: Tests run but fail
jjant Feb 14, 2023
66f7741
Refactor `ServerEventStreamMarshallerGeneratorTest`
jjant Feb 14, 2023
e1c5cd2
Move `.into()` calls to `conditionalBuilderInput`
jjant Feb 14, 2023
c1cd042
Add "context" to TODO
jjant Feb 14, 2023
7a60d7c
Fix client unmarshall tests
jjant Feb 14, 2023
45e762a
Fix clippy lint
jjant Feb 14, 2023
1865cee
Fix more clippy lints
jjant Feb 14, 2023
8223a98
Add docs for `event_stream_serde` module
jjant Feb 14, 2023
5cadd33
Fix client tests
jjant Feb 15, 2023
2afb915
Remove `#[allow(missing_docs)]` from event stream module
jjant Feb 15, 2023
5970d74
Remove unused `EventStreamTestTools`
jjant Feb 24, 2023
2bc6b3f
Add `smithy-validation-model` test dep to `codegen-client`
jjant Feb 24, 2023
449d4bb
Temporarily add docs to make tests compile
jjant Feb 24, 2023
6f8a5ef
Undo change in model
jjant Feb 24, 2023
4b57f01
Make event stream unmarshaller tests a unit test
jjant Feb 24, 2023
8c5aa82
Remove unused code
jjant Feb 25, 2023
2086bd4
Merge branch 'main' into jjant/replace-event-stream-tests
jjant Feb 25, 2023
fefdb1a
Make `ServerEventStreamUnmarshallerGeneratorTest` a unit test
jjant Feb 25, 2023
fb15f43
Make `ServerEventStreamMarshallerGeneratorTest` a unit test
jjant Feb 26, 2023
c7887c9
Make `ServerEventStreamMarshallerGeneratorTest` pass
jjant Feb 26, 2023
489a9ab
Make remaining tests non-integration tests
jjant Feb 26, 2023
897c0ab
Make event stream serde module private again
jjant Feb 26, 2023
2f92227
Remove unnecessary clippy allowances
jjant Feb 26, 2023
8f70237
Remove clippy allowance
jjant Feb 27, 2023
64d23c8
Remove docs for `event_stream_serde` module
jjant Feb 27, 2023
ee389ae
Remove docs for `$unmarshallerTypeName::new`
jjant Feb 27, 2023
eae2701
Remove more unnecessary docs
jjant Feb 27, 2023
3aac2e0
Merge branch 'main' into jjant/replace-event-stream-tests
jjant Feb 27, 2023
43c8040
Remove more superfluous docs
jjant Feb 27, 2023
108fc18
Undo unnecessary diffs
jjant Feb 28, 2023
a14463a
Uncomment last test
jjant Feb 28, 2023
4567ff2
Merge branch 'main' into jjant/replace-event-stream-tests
jjant Feb 28, 2023
e952961
Make `conditionalBuilderInput` internal
jjant Feb 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +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.codegen.core.Symbol
import software.amazon.smithy.model.shapes.StructureShape
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest
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.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.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.EventStreamUnmarshallTestCases.writeUnmarshallTestCases
import software.amazon.smithy.rust.codegen.core.testutil.IntegrationTestParams
import software.amazon.smithy.rust.codegen.core.testutil.integrationTest
import software.amazon.smithy.rust.codegen.core.testutil.unitTest

class ClientEventStreamUnmarshallerGeneratorTest {
@ParameterizedTest
@ArgumentsSource(TestCasesProvider::class)
fun test(testCase: EventStreamTestModels.TestCase) {
EventStreamTestTools.runTestCase(
testCase,
object : ClientEventStreamBaseRequirements() {
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()
}
},
CodegenTarget.CLIENT,
EventStreamTestVariety.Unmarshall,
)
fun `test event stream unmarshaller generator`(testCase: EventStreamTestModels.TestCase) {
clientIntegrationTest(
testCase.model,
IntegrationTestParams(service = "test#TestService", addModuleToEventStreamAllowList = true),
) { codegenContext, rustCrate ->
val crateName = codegenContext.moduleUseName()
val generator = "$crateName::event_stream_serde::TestStreamUnmarshaller"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably not good

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might break with @drganjoo 's PR, #2256

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It didn't 🤔


rustCrate.integrationTest("unmarshall") {
writeUnmarshallTestCases(testCase, codegenTarget = CodegenTarget.CLIENT, generator, codegenContext)

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()).kind {
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),
}
""",
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -458,9 +458,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
Original file line number Diff line number Diff line change
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()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs were wrong.

* write("symbolValue")
* }
* ```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import software.amazon.smithy.model.shapes.TimestampShape
import software.amazon.smithy.model.shapes.UnionShape
import software.amazon.smithy.model.traits.EventHeaderTrait
import software.amazon.smithy.model.traits.EventPayloadTrait
import software.amazon.smithy.rust.codegen.core.rustlang.Attribute
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.Visibility
import software.amazon.smithy.rust.codegen.core.rustlang.conditionalBlock
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock
Expand All @@ -44,6 +46,16 @@ 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 =
RustModule.new(
"event_stream_serde",
visibility = Visibility.PUBLIC,
documentation = "TODO",
inline = false,
parent = RustModule.LibRs,
additionalAttributes = listOf(Attribute.AllowMissingDocs),
)

class EventStreamUnmarshallerGenerator(
private val protocol: Protocol,
codegenContext: CodegenContext,
Expand All @@ -52,6 +64,7 @@ class EventStreamUnmarshallerGenerator(
/** Function that maps a StructureShape into its builder symbol */
private val builderSymbol: (StructureShape) -> Symbol,
) {
private val crateName = codegenContext.moduleUseName()
private val model = codegenContext.model
private val symbolProvider = codegenContext.symbolProvider
private val codegenTarget = codegenContext.target
Expand All @@ -63,7 +76,7 @@ class EventStreamUnmarshallerGenerator(
unionShape.eventStreamErrorSymbol(symbolProvider).toSymbol()
}
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 @@ -87,15 +100,17 @@ 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 {
/// Creates a new $unmarshallerTypeName
pub fn new() -> Self {
${unmarshallerType.name}
$unmarshallerTypeName
}
}
""",
Expand Down Expand Up @@ -157,6 +172,7 @@ class EventStreamUnmarshallerGenerator(
"Output" to unionSymbol,
*codegenScope,
)

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

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

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

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

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

CodegenTarget.SERVER -> {}
}

Expand Down Expand Up @@ -355,10 +376,15 @@ class EventStreamUnmarshallerGenerator(
)
}
}

CodegenTarget.SERVER -> {
val target = model.expectShape(member.target, StructureShape::class.java)
val parser = protocol.structuredDataParser(operationShape).errorParser(target)
val mut = if (parser != null) { " mut" } else { "" }
val mut = if (parser != null) {
" mut"
} else {
""
}
rust("let$mut builder = #T::default();", builderSymbol(target))
if (parser != null) {
rustTemplate(
Expand Down Expand Up @@ -396,6 +422,7 @@ class EventStreamUnmarshallerGenerator(
CodegenTarget.CLIENT -> {
rustTemplate("Ok(#{UnmarshalledMessage}::Error(#{OpError}::generic(generic)))", *codegenScope)
}

CodegenTarget.SERVER -> {
rustTemplate(
"""
Expand All @@ -411,6 +438,6 @@ class EventStreamUnmarshallerGenerator(

private fun UnionShape.eventStreamUnmarshallerType(): RuntimeType {
val symbol = symbolProvider.toSymbol(this)
return RuntimeType("crate::event_stream_serde::${symbol.name.toPascalCase()}Unmarshaller")
return RuntimeType("$crateName::event_stream_serde::${symbol.name.toPascalCase()}Unmarshaller")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider
import software.amazon.smithy.rust.codegen.core.smithy.generators.error.eventStreamErrorSymbol
import software.amazon.smithy.rust.codegen.core.smithy.generators.renderUnknownVariant
import software.amazon.smithy.rust.codegen.core.smithy.generators.unknownVariantError
import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.eventStreamSerdeModule
import software.amazon.smithy.rust.codegen.core.smithy.rustType
import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticEventStreamUnionTrait
import software.amazon.smithy.rust.codegen.core.smithy.transformers.eventStreamErrors
Expand All @@ -50,7 +51,7 @@ class EventStreamErrorMarshallerGenerator(
} else {
unionShape.eventStreamErrorSymbol(symbolProvider).toSymbol()
}
private val eventStreamSerdeModule = RustModule.private("event_stream_serde")
private val eventStreamSerdeModule = RustModule.eventStreamSerdeModule()
private val errorsShape = unionShape.expectTrait<SyntheticEventStreamUnionTrait>()
private val codegenScope = arrayOf(
"MarshallMessage" to smithyEventStream.resolve("frame::MarshallMessage"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator
import software.amazon.smithy.rust.codegen.core.smithy.generators.renderUnknownVariant
import software.amazon.smithy.rust.codegen.core.smithy.generators.unknownVariantError
import software.amazon.smithy.rust.codegen.core.smithy.isOptional
import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.eventStreamSerdeModule
import software.amazon.smithy.rust.codegen.core.smithy.rustType
import software.amazon.smithy.rust.codegen.core.util.dq
import software.amazon.smithy.rust.codegen.core.util.hasTrait
Expand All @@ -53,7 +54,7 @@ open class EventStreamMarshallerGenerator(
private val payloadContentType: String,
) {
private val smithyEventStream = RuntimeType.smithyEventStream(runtimeConfig)
private val eventStreamSerdeModule = RustModule.private("event_stream_serde")
private val eventStreamSerdeModule = RustModule.eventStreamSerdeModule()
private val codegenScope = arrayOf(
"MarshallMessage" to smithyEventStream.resolve("frame::MarshallMessage"),
"Message" to smithyEventStream.resolve("frame::Message"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ private fun fillInBaseModel(
): String = """
namespace test

use smithy.framework#ValidationException
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Prefer making this conditional rather than adding the test dependency to codegen-client.

Copy link
Contributor Author

@jjant jjant Feb 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Why is the ValidationException not needed in the client?
  • I would rather keep the models the same for client/server tests. In a real scenario customers would use the same model for both

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the ValidationException not needed in the client?

Clients don't validate since the server should be the authority on what is valid.

use aws.protocols#$protocolName

union TestUnion {
Expand Down Expand Up @@ -69,12 +70,28 @@ private fun fillInBaseModel(
MessageWithNoHeaderPayloadTraits: MessageWithNoHeaderPayloadTraits,
SomeError: SomeError,
}
structure TestStreamInputOutput { @httpPayload @required value: TestStream }

structure TestStreamInput {
@httpLabel
@required
id: String,

@httpPayload
value: TestStream,
}

structure TestStreamOutput {
@httpPayload
value: TestStream
}

@http(method: "POST", uri: "/test/{id}")
operation TestStreamOp {
input: TestStreamInputOutput,
output: TestStreamInputOutput,
errors: [SomeError],
input: TestStreamInput,
output: TestStreamOutput,
errors: [SomeError, ValidationException],
}

$extraServiceAnnotations
@$protocolName
service TestService { version: "123", operations: [TestStreamOp] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol
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.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
Expand Down Expand Up @@ -104,7 +103,7 @@ object EventStreamTestTools {
test.project.lib {
when (variety) {
EventStreamTestVariety.Marshall -> writeMarshallTestCases(testCase, generator)
EventStreamTestVariety.Unmarshall -> writeUnmarshallTestCases(testCase, codegenTarget, generator)
EventStreamTestVariety.Unmarshall -> Unit // writeUnmarshallTestCases(testCase, codegenTarget, generator)
}
}
test.project.compileAndTest()
Expand Down
Loading