Skip to content

Commit c8ba2d5

Browse files
authored
Fix auth failures in codegen-client-tests in orchestrator mode (#2812)
## Motivation and Context In orchestrator mode, most `codegen-client-test` tests were failing due to being unable to find a matching auth scheme, or due to some of the test models referencing the `@sigv4` trait. This PR fixes all of those failures, and adds the `smithy.runtime.mode` flag to `codegen-client-test` as well. ---- _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 5eb885c commit c8ba2d5

File tree

13 files changed

+144
-146
lines changed

13 files changed

+144
-146
lines changed

buildSrc/src/main/kotlin/CodegenTestCommon.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ data class CodegenTest(
1818
val service: String,
1919
val module: String,
2020
val extraConfig: String? = null,
21+
val extraCodegenConfig: String? = null,
2122
val imports: List<String> = emptyList(),
2223
)
2324

@@ -38,6 +39,7 @@ private fun generateSmithyBuild(projectDir: String, pluginName: String, tests: L
3839
"relativePath": "$projectDir/rust-runtime"
3940
},
4041
"codegen": {
42+
${it.extraCodegenConfig ?: ""}
4143
},
4244
"service": "${it.service}",
4345
"module": "${it.module}",

codegen-client-test/build.gradle.kts

Lines changed: 74 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ plugins {
1515
val smithyVersion: String by project
1616
val defaultRustDocFlags: String by project
1717
val properties = PropertyRetriever(rootProject, project)
18+
fun getSmithyRuntimeMode(): String = properties.get("smithy.runtime.mode") ?: "middleware"
1819

1920
val pluginName = "rust-client-codegen"
2021
val workingDirUnderBuildDir = "smithyprojections/codegen-client-test/"
@@ -33,71 +34,82 @@ dependencies {
3334
implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion")
3435
}
3536

36-
val allCodegenTests = "../codegen-core/common-test-models".let { commonModels ->
37-
listOf(
38-
CodegenTest("com.amazonaws.simple#SimpleService", "simple", imports = listOf("$commonModels/simple.smithy")),
39-
CodegenTest("com.amazonaws.dynamodb#DynamoDB_20120810", "dynamo"),
40-
CodegenTest("com.amazonaws.ebs#Ebs", "ebs", imports = listOf("$commonModels/ebs.json")),
41-
CodegenTest("aws.protocoltests.json10#JsonRpc10", "json_rpc10"),
42-
CodegenTest("aws.protocoltests.json#JsonProtocol", "json_rpc11"),
43-
CodegenTest("aws.protocoltests.restjson#RestJson", "rest_json"),
44-
CodegenTest("aws.protocoltests.restjson#RestJsonExtras", "rest_json_extras", imports = listOf("$commonModels/rest-json-extras.smithy")),
45-
CodegenTest("aws.protocoltests.misc#MiscService", "misc", imports = listOf("$commonModels/misc.smithy")),
46-
CodegenTest(
47-
"aws.protocoltests.restxml#RestXml", "rest_xml",
48-
extraConfig = """, "codegen": { "addMessageToErrors": false } """,
49-
),
50-
51-
CodegenTest(
52-
"aws.protocoltests.query#AwsQuery", "aws_query",
53-
extraConfig = """, "codegen": { "addMessageToErrors": false } """,
54-
),
55-
CodegenTest(
56-
"aws.protocoltests.ec2#AwsEc2", "ec2_query",
57-
extraConfig = """, "codegen": { "addMessageToErrors": false } """,
58-
),
59-
CodegenTest(
60-
"aws.protocoltests.restxml.xmlns#RestXmlWithNamespace",
61-
"rest_xml_namespace",
62-
extraConfig = """, "codegen": { "addMessageToErrors": false } """,
63-
),
64-
CodegenTest(
65-
"aws.protocoltests.restxml#RestXmlExtras",
66-
"rest_xml_extras",
67-
extraConfig = """, "codegen": { "addMessageToErrors": false } """,
68-
),
69-
CodegenTest(
70-
"aws.protocoltests.restxmlunwrapped#RestXmlExtrasUnwrappedErrors",
71-
"rest_xml_extras_unwrapped",
72-
extraConfig = """, "codegen": { "addMessageToErrors": false } """,
73-
),
74-
CodegenTest(
75-
"crate#Config",
76-
"naming_test_ops",
77-
"""
78-
, "codegen": { "renameErrors": false }
79-
""".trimIndent(),
80-
imports = listOf("$commonModels/naming-obstacle-course-ops.smithy"),
81-
),
82-
CodegenTest(
83-
"casing#ACRONYMInside_Service",
84-
"naming_test_casing",
85-
imports = listOf("$commonModels/naming-obstacle-course-casing.smithy"),
86-
),
87-
CodegenTest(
88-
"naming_obs_structs#NamingObstacleCourseStructs",
89-
"naming_test_structs",
90-
"""
91-
, "codegen": { "renameErrors": false }
92-
""".trimIndent(),
93-
imports = listOf("$commonModels/naming-obstacle-course-structs.smithy"),
94-
),
95-
CodegenTest("aws.protocoltests.json#TestService", "endpoint-rules"),
96-
CodegenTest("com.aws.example#PokemonService", "pokemon-service-client", imports = listOf("$commonModels/pokemon.smithy", "$commonModels/pokemon-common.smithy")),
97-
CodegenTest("com.aws.example#PokemonService", "pokemon-service-awsjson-client", imports = listOf("$commonModels/pokemon-awsjson.smithy", "$commonModels/pokemon-common.smithy")),
37+
data class ClientTest(
38+
val serviceShapeName: String,
39+
val moduleName: String,
40+
val dependsOn: List<String> = emptyList(),
41+
val addMessageToErrors: Boolean = true,
42+
val renameErrors: Boolean = true,
43+
) {
44+
fun toCodegenTest(): CodegenTest = CodegenTest(
45+
serviceShapeName,
46+
moduleName,
47+
extraCodegenConfig = extraCodegenConfig(),
48+
imports = imports(),
9849
)
50+
51+
private fun extraCodegenConfig(): String = StringBuilder().apply {
52+
append("\"addMessageToErrors\": $addMessageToErrors,\n")
53+
append("\"renameErrors\": $renameErrors\n,")
54+
append("\"enableNewSmithyRuntime\": \"${getSmithyRuntimeMode()}\"")
55+
}.toString()
56+
57+
private fun imports(): List<String> = dependsOn.map { "../codegen-core/common-test-models/$it" }
9958
}
10059

60+
val allCodegenTests = listOf(
61+
ClientTest("com.amazonaws.simple#SimpleService", "simple", dependsOn = listOf("simple.smithy")),
62+
ClientTest("com.amazonaws.dynamodb#DynamoDB_20120810", "dynamo"),
63+
ClientTest("com.amazonaws.ebs#Ebs", "ebs", dependsOn = listOf("ebs.json")),
64+
ClientTest("aws.protocoltests.json10#JsonRpc10", "json_rpc10"),
65+
ClientTest("aws.protocoltests.json#JsonProtocol", "json_rpc11"),
66+
ClientTest("aws.protocoltests.restjson#RestJson", "rest_json"),
67+
ClientTest(
68+
"aws.protocoltests.restjson#RestJsonExtras",
69+
"rest_json_extras",
70+
dependsOn = listOf("rest-json-extras.smithy"),
71+
),
72+
ClientTest("aws.protocoltests.misc#MiscService", "misc", dependsOn = listOf("misc.smithy")),
73+
ClientTest("aws.protocoltests.restxml#RestXml", "rest_xml", addMessageToErrors = false),
74+
ClientTest("aws.protocoltests.query#AwsQuery", "aws_query", addMessageToErrors = false),
75+
ClientTest("aws.protocoltests.ec2#AwsEc2", "ec2_query", addMessageToErrors = false),
76+
ClientTest("aws.protocoltests.restxml.xmlns#RestXmlWithNamespace", "rest_xml_namespace", addMessageToErrors = false),
77+
ClientTest("aws.protocoltests.restxml#RestXmlExtras", "rest_xml_extras", addMessageToErrors = false),
78+
ClientTest(
79+
"aws.protocoltests.restxmlunwrapped#RestXmlExtrasUnwrappedErrors",
80+
"rest_xml_extras_unwrapped",
81+
addMessageToErrors = false,
82+
),
83+
ClientTest(
84+
"crate#Config",
85+
"naming_test_ops",
86+
dependsOn = listOf("naming-obstacle-course-ops.smithy"),
87+
renameErrors = false,
88+
),
89+
ClientTest(
90+
"casing#ACRONYMInside_Service",
91+
"naming_test_casing",
92+
dependsOn = listOf("naming-obstacle-course-casing.smithy"),
93+
),
94+
ClientTest(
95+
"naming_obs_structs#NamingObstacleCourseStructs",
96+
"naming_test_structs",
97+
dependsOn = listOf("naming-obstacle-course-structs.smithy"),
98+
renameErrors = false,
99+
),
100+
ClientTest("aws.protocoltests.json#TestService", "endpoint-rules"),
101+
ClientTest(
102+
"com.aws.example#PokemonService",
103+
"pokemon-service-client",
104+
dependsOn = listOf("pokemon.smithy", "pokemon-common.smithy"),
105+
),
106+
ClientTest(
107+
"com.aws.example#PokemonService",
108+
"pokemon-service-awsjson-client",
109+
dependsOn = listOf("pokemon-awsjson.smithy", "pokemon-common.smithy"),
110+
),
111+
).map(ClientTest::toCodegenTest)
112+
101113
project.registerGenerateSmithyBuildTask(rootProject, pluginName, allCodegenTests)
102114
project.registerGenerateCargoWorkspaceTask(rootProject, pluginName, allCodegenTests, workingDirUnderBuildDir)
103115
project.registerGenerateCargoConfigTomlTask(buildDir.resolve(workingDirUnderBuildDir))

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/NoAuthDecorator.kt

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,17 @@ package software.amazon.smithy.rust.codegen.client.smithy.customizations
77

88
import software.amazon.smithy.model.shapes.OperationShape
99
import software.amazon.smithy.model.shapes.ShapeId
10-
import software.amazon.smithy.model.traits.OptionalAuthTrait
1110
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
1211
import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthOption
1312
import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator
14-
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization
15-
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection
1613
import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency
17-
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
1814
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
19-
import software.amazon.smithy.rust.codegen.core.rustlang.writable
2015
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
21-
import software.amazon.smithy.rust.codegen.core.util.hasTrait
22-
import software.amazon.smithy.rust.codegen.core.util.letIf
2316

2417
val noAuthSchemeShapeId: ShapeId = ShapeId.from("aws.smithy.rs#NoAuth")
2518

2619
private fun noAuthModule(codegenContext: ClientCodegenContext): RuntimeType =
2720
CargoDependency.smithyRuntime(codegenContext.runtimeConfig)
28-
.withFeature("no-auth")
2921
.toType()
3022
.resolve("client::auth::no_auth")
3123

@@ -37,38 +29,11 @@ class NoAuthDecorator : ClientCodegenDecorator {
3729
codegenContext: ClientCodegenContext,
3830
operationShape: OperationShape,
3931
baseAuthOptions: List<AuthOption>,
40-
): List<AuthOption> = baseAuthOptions.letIf(operationShape.hasTrait<OptionalAuthTrait>()) {
41-
it + AuthOption.StaticAuthOption(noAuthSchemeShapeId) {
32+
): List<AuthOption> = baseAuthOptions +
33+
AuthOption.StaticAuthOption(noAuthSchemeShapeId) {
4234
rustTemplate(
4335
"#{NO_AUTH_SCHEME_ID},",
4436
"NO_AUTH_SCHEME_ID" to noAuthModule(codegenContext).resolve("NO_AUTH_SCHEME_ID"),
4537
)
4638
}
47-
}
48-
49-
override fun operationCustomizations(
50-
codegenContext: ClientCodegenContext,
51-
operation: OperationShape,
52-
baseCustomizations: List<OperationCustomization>,
53-
): List<OperationCustomization> = baseCustomizations + AnonymousAuthCustomization(codegenContext, operation)
54-
}
55-
56-
class AnonymousAuthCustomization(
57-
private val codegenContext: ClientCodegenContext,
58-
private val operationShape: OperationShape,
59-
) : OperationCustomization() {
60-
override fun section(section: OperationSection): Writable = writable {
61-
if (
62-
codegenContext.smithyRuntimeMode.generateOrchestrator &&
63-
section is OperationSection.AdditionalRuntimePlugins &&
64-
operationShape.hasTrait<OptionalAuthTrait>()
65-
) {
66-
section.addOperationRuntimePlugin(this) {
67-
rustTemplate(
68-
"#{NoAuthRuntimePlugin}::new()",
69-
"NoAuthRuntimePlugin" to noAuthModule(codegenContext).resolve("NoAuthRuntimePlugin"),
70-
)
71-
}
72-
}
73-
}
7439
}

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
2828
import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter
2929
import software.amazon.smithy.rust.codegen.core.rustlang.writable
3030
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
31+
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
3132
import software.amazon.smithy.rust.codegen.core.smithy.isOptional
3233
import software.amazon.smithy.rust.codegen.core.smithy.makeOptional
3334
import software.amazon.smithy.rust.codegen.core.smithy.mapRustType
@@ -232,7 +233,8 @@ internal class EndpointParamsGenerator(private val parameters: Parameters) {
232233
rustWriter.rustBlock("impl ParamsBuilder") {
233234
docs("Consume this builder, creating [`Params`].")
234235
rustBlockTemplate(
235-
"pub fn build(self) -> Result<#{Params}, #{ParamsError}>",
236+
"pub fn build(self) -> #{Result}<#{Params}, #{ParamsError}>",
237+
*preludeScope,
236238
"Params" to paramsStruct(),
237239
"ParamsError" to paramsError(),
238240
) {

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsInterceptorGenerator.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
2727
import software.amazon.smithy.rust.codegen.core.rustlang.withBlockTemplate
2828
import software.amazon.smithy.rust.codegen.core.rustlang.writable
2929
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
30+
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
3031
import software.amazon.smithy.rust.codegen.core.util.PANIC
3132
import software.amazon.smithy.rust.codegen.core.util.dq
3233
import software.amazon.smithy.rust.codegen.core.util.inputShape
@@ -45,6 +46,7 @@ class EndpointParamsInterceptorGenerator(
4546
val orchestrator = runtimeApi.resolve("client::orchestrator")
4647
val smithyTypes = CargoDependency.smithyTypes(rc).toType()
4748
arrayOf(
49+
*preludeScope,
4850
"BoxError" to RuntimeType.boxError(rc),
4951
"ConfigBag" to RuntimeType.configBag(rc),
5052
"ConfigBagAccessors" to RuntimeType.smithyRuntimeApi(rc)
@@ -78,7 +80,7 @@ class EndpointParamsInterceptorGenerator(
7880
&self,
7981
context: &#{BeforeSerializationInterceptorContextRef}<'_, #{Input}, #{Output}, #{Error}>,
8082
cfg: &mut #{ConfigBag},
81-
) -> Result<(), #{BoxError}> {
83+
) -> #{Result}<(), #{BoxError}> {
8284
use #{ConfigBagAccessors};
8385
let _input = context.input()
8486
.downcast_ref::<${operationInput.name}>()
@@ -91,7 +93,7 @@ class EndpointParamsInterceptorGenerator(
9193
.build()
9294
.map_err(|err| #{ContextAttachedError}::new("endpoint params could not be built", err))?;
9395
cfg.interceptor_state().set_endpoint_resolver_params(#{EndpointResolverParams}::new(params));
94-
Ok(())
96+
#{Ok}(())
9597
}
9698
}
9799
""",

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ open class OperationGenerator(
5959
let mut runtime_plugins = runtime_plugins
6060
.with_client_plugin(handle.conf.clone())
6161
.with_client_plugin(crate::config::ServiceRuntimePlugin::new(handle))
62+
.with_client_plugin(#{NoAuthRuntimePlugin}::new())
6263
.with_operation_plugin(operation);
6364
if let Some(config_override) = config_override {
6465
runtime_plugins = runtime_plugins.with_operation_plugin(config_override);
@@ -71,6 +72,8 @@ open class OperationGenerator(
7172
"RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig),
7273
"RuntimePlugins" to RuntimeType.smithyRuntimeApi(runtimeConfig)
7374
.resolve("client::runtime_plugin::RuntimePlugins"),
75+
"NoAuthRuntimePlugin" to RuntimeType.smithyRuntime(runtimeConfig)
76+
.resolve("client::auth::no_auth::NoAuthRuntimePlugin"),
7477
)
7578
}
7679
}

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

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.pre
2121
import software.amazon.smithy.rust.codegen.core.smithy.customize.writeCustomizations
2222
import software.amazon.smithy.rust.codegen.core.util.dq
2323
import software.amazon.smithy.rust.codegen.core.util.hasTrait
24+
import java.util.logging.Logger
2425

2526
/**
2627
* Generates operation-level runtime plugins
2728
*/
2829
class OperationRuntimePluginGenerator(
2930
private val codegenContext: ClientCodegenContext,
3031
) {
32+
private val logger: Logger = Logger.getLogger(javaClass.name)
3133
private val codegenScope = codegenContext.runtimeConfig.let { rc ->
3234
val runtimeApi = RuntimeType.smithyRuntimeApi(rc)
3335
val smithyTypes = RuntimeType.smithyTypes(rc)
@@ -136,29 +138,25 @@ class OperationRuntimePluginGenerator(
136138
"])));",
137139
*codegenScope,
138140
) {
141+
var noSupportedAuthSchemes = true
139142
val authSchemes = ServiceIndex.of(codegenContext.model)
140143
.getEffectiveAuthSchemes(codegenContext.serviceShape, operationShape)
141-
var atLeastOneScheme = false
142144
for (schemeShapeId in authSchemes.keys) {
143145
val authOption = authOptionsMap[schemeShapeId]
144-
?: throw IllegalStateException("no auth scheme implementation available for $schemeShapeId")
145-
authOption.constructor(this)
146-
atLeastOneScheme = true
146+
if (authOption != null) {
147+
authOption.constructor(this)
148+
noSupportedAuthSchemes = false
149+
} else {
150+
logger.warning(
151+
"No auth scheme implementation available for $schemeShapeId. " +
152+
"The generated client will not attempt to use this auth scheme.",
153+
)
154+
}
147155
}
148-
if (operationShape.hasTrait<OptionalAuthTrait>()) {
156+
if (operationShape.hasTrait<OptionalAuthTrait>() || noSupportedAuthSchemes) {
149157
val authOption = authOptionsMap[noAuthSchemeShapeId]
150-
?: throw IllegalStateException("missing 'no auth' implementation")
158+
?: throw IllegalStateException("Missing 'no auth' implementation. This is a codegen bug.")
151159
authOption.constructor(this)
152-
atLeastOneScheme = true
153-
}
154-
if (!atLeastOneScheme) {
155-
throw IllegalStateException(
156-
"this client won't have any auth schemes " +
157-
"(not even optional/no-auth auth), which means the generated client " +
158-
"won't work at all for the ${operationShape.id} operation. See " +
159-
"https://smithy.io/2.0/spec/authentication-traits.html for documentation " +
160-
"on Smithy authentication traits.",
161-
)
162160
}
163161
}
164162
}

0 commit comments

Comments
 (0)