Skip to content

Commit 3e6adcd

Browse files
authored
Disallow ignoring a constrained shape in an event stream's closure (#2113)
The server SDK will otherwise produce Rust code that cannot be compiled, so it doesn't make sense to prompt users to disregard the warning and opt into `ignoreUnsupportedConstraints`. To continue synthesizing the model, the user must remove any constrained traits from the event stream's closure. This commit also tweaks formatting of errors yielded by `ValidateUnsupportedConstraints`. Prior to this commit, they were a bit off due to carelessness when interpolation occurs. For example: ``` [SEVERE] Operation com.amazonaws.constraints#ConstrainedShapesOperation takes in input that is constrained(https://awslabs.github.io/smithy/2.0/spec/constraint-traits.html), and as such can fail with a validationexception. You must model this behavior in the operation shape in your model file. ```
1 parent 1deb644 commit 3e6adcd

File tree

2 files changed

+75
-39
lines changed

2 files changed

+75
-39
lines changed

codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraints.kt

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,21 @@ private sealed class UnsupportedConstraintMessageKind {
3737
private val constraintTraitsUberIssue = "https://github.com/awslabs/smithy-rs/issues/1401"
3838

3939
fun intoLogMessage(ignoreUnsupportedConstraints: Boolean): LogMessage {
40-
fun buildMessage(intro: String, willSupport: Boolean, trackingIssue: String) =
41-
"""
42-
$intro
43-
This is not supported in the smithy-rs server SDK.
44-
${if (willSupport) "It will be supported in the future." else ""}
45-
See the tracking issue ($trackingIssue).
46-
If you want to go ahead and generate the server SDK ignoring unsupported constraint traits, set the key `ignoreUnsupportedConstraints`
47-
inside the `runtimeConfig.codegenConfig` JSON object in your `smithy-build.json` to `true`.
48-
""".trimIndent().replace("\n", " ")
40+
fun buildMessage(intro: String, willSupport: Boolean, trackingIssue: String, canBeIgnored: Boolean = true): String {
41+
var msg = """
42+
$intro
43+
This is not supported in the smithy-rs server SDK."""
44+
if (willSupport) {
45+
msg += """
46+
It will be supported in the future. See the tracking issue ($trackingIssue)."""
47+
}
48+
if (canBeIgnored) {
49+
msg += """
50+
If you want to go ahead and generate the server SDK ignoring unsupported constraint traits, set the key `ignoreUnsupportedConstraints`
51+
inside the `runtimeConfig.codegenConfig` JSON object in your `smithy-build.json` to `true`."""
52+
}
53+
return msg.trimIndent().replace("\n", " ")
54+
}
4955

5056
fun buildMessageShapeHasUnsupportedConstraintTrait(
5157
shape: Shape,
@@ -67,14 +73,16 @@ private sealed class UnsupportedConstraintMessageKind {
6773
)
6874

6975
is UnsupportedConstraintOnShapeReachableViaAnEventStream -> LogMessage(
70-
level,
76+
Level.SEVERE,
7177
buildMessage(
7278
"""
7379
The ${shape.type} shape `${shape.id}` has the constraint trait `${constraintTrait.toShapeId()}` attached.
7480
This shape is also part of an event stream; it is unclear what the semantics for constrained shapes in event streams are.
81+
Please remove the trait from the shape to synthesize your model.
7582
""".trimIndent().replace("\n", " "),
7683
willSupport = false,
7784
"https://github.com/awslabs/smithy/issues/1388",
85+
canBeIgnored = false,
7886
),
7987
)
8088

@@ -161,9 +169,9 @@ fun validateOperationsWithConstrainedInputHaveValidationExceptionAttached(
161169
LogMessage(
162170
Level.SEVERE,
163171
"""
164-
Operation ${it.shape.id} takes in input that is constrained
165-
(https://awslabs.github.io/smithy/2.0/spec/constraint-traits.html), and as such can fail with a validation
166-
exception. You must model this behavior in the operation shape in your model file.
172+
Operation ${it.shape.id} takes in input that is constrained
173+
(https://awslabs.github.io/smithy/2.0/spec/constraint-traits.html), and as such can fail with a
174+
validation exception. You must model this behavior in the operation shape in your model file.
167175
""".trimIndent().replace("\n", "") +
168176
"""
169177

codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraintsAreNotUsedTest.kt

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import io.kotest.matchers.collections.shouldHaveAtLeastSize
1212
import io.kotest.matchers.collections.shouldHaveSize
1313
import io.kotest.matchers.shouldBe
1414
import io.kotest.matchers.string.shouldContain
15+
import io.kotest.matchers.string.shouldNotContain
1516
import org.junit.jupiter.api.Test
1617
import software.amazon.smithy.model.Model
1718
import software.amazon.smithy.model.shapes.ServiceShape
@@ -56,7 +57,17 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest {
5657
val validationResult = validateOperationsWithConstrainedInputHaveValidationExceptionAttached(model, service)
5758

5859
validationResult.messages shouldHaveSize 1
59-
validationResult.messages[0].message shouldContain "Operation test#TestOperation takes in input that is constrained"
60+
61+
// Asserts the exact message, to ensure the formatting is appropriate.
62+
validationResult.messages[0].message shouldBe """Operation test#TestOperation takes in input that is constrained (https://awslabs.github.io/smithy/2.0/spec/constraint-traits.html), and as such can fail with a validation exception. You must model this behavior in the operation shape in your model file.
63+
```smithy
64+
use smithy.framework#ValidationException
65+
66+
operation TestOperation {
67+
...
68+
errors: [..., ValidationException] // <-- Add this.
69+
}
70+
```"""
6071
}
6172

6273
@Test
@@ -120,53 +131,68 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest {
120131
}
121132
}
122133

123-
@Test
124-
fun `it should detect when constraint traits in event streams are used`() {
125-
val model =
126-
"""
127-
$baseModel
134+
val constrainedShapesInEventStreamModel =
135+
"""
136+
$baseModel
128137
129-
structure TestInputOutput {
130-
eventStream: EventStream
131-
}
138+
structure TestInputOutput {
139+
eventStream: EventStream
140+
}
132141
133-
@streaming
134-
union EventStream {
135-
message: Message,
136-
error: Error
137-
}
142+
@streaming
143+
union EventStream {
144+
message: Message,
145+
error: Error
146+
}
138147
139-
structure Message {
140-
lengthString: LengthString
141-
}
148+
structure Message {
149+
lengthString: LengthString
150+
}
142151
143-
structure Error {
144-
@required
145-
message: String
146-
}
152+
structure Error {
153+
@required
154+
message: String
155+
}
147156
148-
@length(min: 1)
149-
string LengthString
150-
""".asSmithyModel()
151-
val validationResult = validateModel(EventStreamNormalizer.transform(model))
157+
@length(min: 1)
158+
string LengthString
159+
""".asSmithyModel()
160+
161+
@Test
162+
fun `it should detect when constraint traits in event streams are used`() {
163+
val validationResult = validateModel(EventStreamNormalizer.transform(constrainedShapesInEventStreamModel))
152164

153165
validationResult.messages shouldHaveSize 2
154166
validationResult.messages.forOne {
155167
it.message shouldContain
156168
"""
157169
The string shape `test#LengthString` has the constraint trait `smithy.api#length` attached.
158170
This shape is also part of an event stream; it is unclear what the semantics for constrained shapes in event streams are.
171+
Please remove the trait from the shape to synthesize your model.
159172
""".trimIndent().replace("\n", " ")
173+
it.message shouldNotContain "If you want to go ahead and generate the server SDK ignoring unsupported constraint traits"
160174
}
161175
validationResult.messages.forOne {
162176
it.message shouldContain
163177
"""
164178
The member shape `test#Error${"$"}message` has the constraint trait `smithy.api#required` attached.
165179
This shape is also part of an event stream; it is unclear what the semantics for constrained shapes in event streams are.
180+
Please remove the trait from the shape to synthesize your model.
166181
""".trimIndent().replace("\n", " ")
182+
it.message shouldNotContain "If you want to go ahead and generate the server SDK ignoring unsupported constraint traits"
167183
}
168184
}
169185

186+
@Test
187+
fun `it should abort when constraint traits in event streams are used, despite opting into ignoreUnsupportedConstraintTraits`() {
188+
val validationResult = validateModel(
189+
EventStreamNormalizer.transform(constrainedShapesInEventStreamModel),
190+
ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true),
191+
)
192+
193+
validationResult.shouldAbort shouldBe true
194+
}
195+
170196
@Test
171197
fun `it should detect when the length trait on blob shapes is used`() {
172198
val model =
@@ -183,7 +209,9 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest {
183209
val validationResult = validateModel(model)
184210

185211
validationResult.messages shouldHaveSize 1
186-
validationResult.messages[0].message shouldContain "The blob shape `test#LengthBlob` has the constraint trait `smithy.api#length` attached"
212+
213+
// This test additionally asserts the exact message, to ensure the formatting is appropriate.
214+
validationResult.messages[0].message shouldBe "The blob shape `test#LengthBlob` has the constraint trait `smithy.api#length` attached. This is not supported in the smithy-rs server SDK. It will be supported in the future. See the tracking issue (https://github.com/awslabs/smithy-rs/issues/1401). If you want to go ahead and generate the server SDK ignoring unsupported constraint traits, set the key `ignoreUnsupportedConstraints` inside the `runtimeConfig.codegenConfig` JSON object in your `smithy-build.json` to `true`."
187215
}
188216

189217
@Test

0 commit comments

Comments
 (0)