Skip to content

Commit 8d8e7ab

Browse files
authored
Bump smithy version to 1.52 (#3887)
## Motivation and Context <!--- Why is this change required? What problem does it solve? --> <!--- If it fixes an open issue, please link to the issue here --> Bumping smithy to 1.52 for an `httpChecksum` trait bugfix A few fixes had to be made to protocol tests for this release: * Update document to initialize as empty `{}` instead of null * Update our header serialization to serialize present but empty headers to `""` (Note that this change does not apply to server header serialization) * Add `accept: application/cbor` header to add rpcV2Cbor requests * Skip two broken tests. These tests were fixed in smithy-lang/smithy#2423 and that change was included in the 1.52 release notes, but the actual change did not make it into the build artifact. The changes should make it into the 1.52.1 release in the next few days: smithy-lang/smithy#2428 _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
1 parent 2e53910 commit 8d8e7ab

File tree

6 files changed

+94
-34
lines changed

6 files changed

+94
-34
lines changed

codegen-client-test/model/error-correction-nullability-test.smithy

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ apply SayHello @httpResponseTests([{
102102
listValue: [],
103103
mapValue: {},
104104
doubleListValue: []
105-
document: null
105+
document: {}
106106
nested: { a: "" }
107107
},
108108
code: 200,

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class RequestBindingGenerator(
9191
*/
9292
fun renderUpdateHttpBuilder(implBlockWriter: RustWriter) {
9393
uriBase(implBlockWriter)
94-
val addHeadersFn = httpBindingGenerator.generateAddHeadersFn(operationShape)
94+
val addHeadersFn = httpBindingGenerator.generateAddHeadersFn(operationShape, serializeEmptyHeaders = true)
9595
val hasQuery = uriQuery(implBlockWriter)
9696
Attribute.AllowClippyUnnecessaryWraps.render(implBlockWriter)
9797
implBlockWriter.rustBlockTemplate(

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ClientProtocolTestGenerator.kt

+42-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
package software.amazon.smithy.rust.codegen.client.smithy.generators.protocol
77

8-
import software.amazon.smithy.model.node.NumberNode
98
import software.amazon.smithy.model.shapes.DoubleShape
109
import software.amazon.smithy.model.shapes.FloatShape
1110
import software.amazon.smithy.model.shapes.OperationShape
@@ -28,6 +27,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.Broke
2827
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.FailingTest
2928
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolSupport
3029
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolTestGenerator
30+
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ServiceShapeId
3131
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ServiceShapeId.AWS_JSON_10
3232
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ServiceShapeId.REST_JSON
3333
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ServiceShapeId.RPC_V2_CBOR
@@ -83,20 +83,54 @@ class ClientProtocolTestGenerator(
8383
)
8484

8585
private val BrokenTests:
86-
Set<BrokenTest> = setOf()
86+
Set<BrokenTest> =
87+
// The two tests below were fixed in "https://github.com/smithy-lang/smithy/pull/2423", but the fixes didn't make
88+
// it into the build artifact for 1.52
89+
setOf(
90+
BrokenTest.ResponseTest(
91+
ServiceShapeId.REST_XML,
92+
"NestedXmlMapWithXmlNameDeserializes",
93+
howToFixItFn = ::fixRestXMLInvalidRootNodeResponse,
94+
inAtLeast = setOf("1.52.0"),
95+
trackedIn =
96+
setOf(
97+
"https://github.com/smithy-lang/smithy/pull/2423",
98+
),
99+
),
100+
BrokenTest.RequestTest(
101+
ServiceShapeId.REST_XML,
102+
"NestedXmlMapWithXmlNameSerializes",
103+
howToFixItFn = ::fixRestXMLInvalidRootNodeRequest,
104+
inAtLeast = setOf("1.52.0"),
105+
trackedIn =
106+
setOf(
107+
"https://github.com/smithy-lang/smithy/pull/2423",
108+
),
109+
),
110+
)
87111

88-
private fun fixRestJsonClientIgnoresDefaultValuesIfMemberValuesArePresentInResponse(
89-
testCase: TestCase.ResponseTest,
90-
): TestCase.ResponseTest {
91-
val fixedParams =
92-
testCase.testCase.params.toBuilder().withMember("defaultTimestamp", NumberNode.from(2)).build()
112+
private fun fixRestXMLInvalidRootNodeResponse(testCase: TestCase.ResponseTest): TestCase.ResponseTest {
113+
val fixedBody =
114+
testCase.testCase.body.get()
115+
.replace("NestedXmlMapWithXmlNameResponse", "NestedXmlMapWithXmlNameInputOutput")
93116
return TestCase.ResponseTest(
94117
testCase.testCase.toBuilder()
95-
.params(fixedParams)
118+
.body(fixedBody)
96119
.build(),
97120
testCase.targetShape,
98121
)
99122
}
123+
124+
private fun fixRestXMLInvalidRootNodeRequest(testCase: TestCase.RequestTest): TestCase.RequestTest {
125+
val fixedBody =
126+
testCase.testCase.body.get()
127+
.replace("NestedXmlMapWithXmlNameRequest", "NestedXmlMapWithXmlNameInputOutput")
128+
return TestCase.RequestTest(
129+
testCase.testCase.toBuilder()
130+
.body(fixedBody)
131+
.build(),
132+
)
133+
}
100134
}
101135

102136
override val appliesTo: AppliesTo

codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/http/HttpBindingGenerator.kt

+47-22
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustType
3030
import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter
3131
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
3232
import software.amazon.smithy.rust.codegen.core.rustlang.asOptional
33+
import software.amazon.smithy.rust.codegen.core.rustlang.conditionalBlock
3334
import software.amazon.smithy.rust.codegen.core.rustlang.qualifiedName
3435
import software.amazon.smithy.rust.codegen.core.rustlang.render
3536
import software.amazon.smithy.rust.codegen.core.rustlang.rust
@@ -491,6 +492,7 @@ class HttpBindingGenerator(
491492
fun generateAddHeadersFn(
492493
shape: Shape,
493494
httpMessageType: HttpMessageType = HttpMessageType.REQUEST,
495+
serializeEmptyHeaders: Boolean = false,
494496
): RuntimeType? {
495497
val (headerBindings, prefixHeaderBinding) =
496498
when (httpMessageType) {
@@ -538,7 +540,7 @@ class HttpBindingGenerator(
538540
""",
539541
*codegenScope,
540542
) {
541-
headerBindings.forEach { httpBinding -> renderHeaders(httpBinding) }
543+
headerBindings.forEach { httpBinding -> renderHeaders(httpBinding, serializeEmptyHeaders) }
542544
if (prefixHeaderBinding != null) {
543545
renderPrefixHeader(prefixHeaderBinding)
544546
}
@@ -547,7 +549,10 @@ class HttpBindingGenerator(
547549
}
548550
}
549551

550-
private fun RustWriter.renderHeaders(httpBinding: HttpBinding) {
552+
private fun RustWriter.renderHeaders(
553+
httpBinding: HttpBinding,
554+
serializeEmptyHeaders: Boolean,
555+
) {
551556
check(httpBinding.location == HttpLocation.HEADER)
552557
val memberShape = httpBinding.member
553558
val targetShape = model.expectShape(memberShape.target)
@@ -585,6 +590,7 @@ class HttpBindingGenerator(
585590
targetShape,
586591
timestampFormat,
587592
renderErrorMessage,
593+
serializeEmptyHeaders,
588594
)
589595
} else {
590596
renderHeaderValue(
@@ -596,6 +602,7 @@ class HttpBindingGenerator(
596602
renderErrorMessage,
597603
serializeIfDefault = memberSymbol.isOptional(),
598604
memberShape,
605+
serializeEmptyHeaders,
599606
)
600607
}
601608
}
@@ -608,6 +615,7 @@ class HttpBindingGenerator(
608615
shape: CollectionShape,
609616
timestampFormat: TimestampFormatTrait.Format,
610617
renderErrorMessage: (String) -> Writable,
618+
serializeEmptyHeaders: Boolean,
611619
) {
612620
val loopVariable = ValueExpression.Reference(safeName("inner"))
613621
val context = HeaderValueSerializationContext(value, shape)
@@ -617,17 +625,29 @@ class HttpBindingGenerator(
617625
)(this)
618626
}
619627

620-
rustBlock("for ${loopVariable.name} in ${context.valueExpression.asRef()}") {
621-
this.renderHeaderValue(
622-
headerName,
623-
loopVariable,
624-
model.expectShape(shape.member.target),
625-
isMultiValuedHeader = true,
626-
timestampFormat,
627-
renderErrorMessage,
628-
serializeIfDefault = true,
629-
shape.member,
630-
)
628+
// Conditionally wrap the header generation in a block that handles empty header values if
629+
// `serializeEmptyHeaders` is true
630+
conditionalBlock(
631+
"""
632+
// Empty vec in header is serialized as an empty string
633+
if ${context.valueExpression.name}.is_empty() {
634+
builder = builder.header("$headerName", "");
635+
} else {""",
636+
"}", conditional = serializeEmptyHeaders,
637+
) {
638+
rustBlock("for ${loopVariable.name} in ${context.valueExpression.asRef()}") {
639+
this.renderHeaderValue(
640+
headerName,
641+
loopVariable,
642+
model.expectShape(shape.member.target),
643+
isMultiValuedHeader = true,
644+
timestampFormat,
645+
renderErrorMessage,
646+
serializeIfDefault = true,
647+
shape.member,
648+
serializeEmptyHeaders,
649+
)
650+
}
631651
}
632652
}
633653

@@ -647,6 +667,7 @@ class HttpBindingGenerator(
647667
renderErrorMessage: (String) -> Writable,
648668
serializeIfDefault: Boolean,
649669
memberShape: MemberShape,
670+
serializeEmptyHeaders: Boolean,
650671
) {
651672
val context = HeaderValueSerializationContext(value, shape)
652673
for (customization in customizations) {
@@ -669,20 +690,24 @@ class HttpBindingGenerator(
669690
isMultiValuedHeader = isMultiValuedHeader,
670691
)
671692
val safeName = safeName("formatted")
672-
rustTemplate(
673-
"""
674-
let $safeName = $formatted;
675-
if !$safeName.is_empty() {
693+
694+
// If `serializeEmptyHeaders` is false we wrap header serialization in a `!foo.is_empty()` check and skip
695+
// serialization if the header value is empty
696+
rust("let $safeName = $formatted;")
697+
conditionalBlock("if !$safeName.is_empty() {", "}", conditional = !serializeEmptyHeaders) {
698+
rustTemplate(
699+
"""
676700
let header_value = $safeName;
677701
let header_value: #{HeaderValue} = header_value.parse().map_err(|err| {
678702
#{invalid_field_error:W}
679703
})?;
680704
builder = builder.header("$headerName", header_value);
681-
}
682-
""",
683-
"HeaderValue" to RuntimeType.Http.resolve("HeaderValue"),
684-
"invalid_field_error" to renderErrorMessage("header_value"),
685-
)
705+
706+
""",
707+
"HeaderValue" to RuntimeType.Http.resolve("HeaderValue"),
708+
"invalid_field_error" to renderErrorMessage("header_value"),
709+
)
710+
}
686711
}
687712
if (serializeIfDefault) {
688713
block(context.valueExpression)

codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/RpcV2Cbor.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ open class RpcV2Cbor(val codegenContext: CodegenContext) : Protocol {
111111
// using floating point seconds from the epoch.
112112
override val defaultTimestampFormat: TimestampFormatTrait.Format = TimestampFormatTrait.Format.EPOCH_SECONDS
113113

114+
// The accept header is required by the spec (and by all of the protocol tests)
114115
override fun additionalRequestHeaders(operationShape: OperationShape): List<Pair<String, String>> =
115-
listOf("smithy-protocol" to "rpc-v2-cbor")
116+
listOf("smithy-protocol" to "rpc-v2-cbor", "accept" to "application/cbor")
116117

117118
override fun additionalResponseHeaders(operationShape: OperationShape): List<Pair<String, String>> =
118119
listOf("smithy-protocol" to "rpc-v2-cbor")

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ smithy.rs.runtime.crate.unstable.version=0.60.6
1515
kotlin.code.style=official
1616
# codegen
1717
smithyGradlePluginVersion=0.9.0
18-
smithyVersion=1.51.0
18+
smithyVersion=1.52.0
1919
allowLocalDeps=false
2020
# kotlin
2121
kotlinVersion=1.9.20

0 commit comments

Comments
 (0)