diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2e086d1301c..b0713cf239f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,8 +11,8 @@ coroutines-version = "1.9.0" atomicfu-version = "0.25.0" # smithy-kotlin codegen and runtime are versioned separately -smithy-kotlin-runtime-version = "1.3.29" -smithy-kotlin-codegen-version = "0.33.29" +smithy-kotlin-runtime-version = "1.3.30" +smithy-kotlin-codegen-version = "0.33.30" # codegen smithy-version = "1.51.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index fa43e4d2789..7f35e266c03 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -53,6 +53,7 @@ include(":hll:hll-mapping-core") include(":services") include(":tests") include(":tests:codegen:event-stream") +include(":tests:codegen:rules-engine") include(":tests:e2e-test-util") include(":tests:codegen:smoke-tests") include(":tests:codegen:smoke-tests:services") diff --git a/tests/codegen/rules-engine/build.gradle.kts b/tests/codegen/rules-engine/build.gradle.kts new file mode 100644 index 00000000000..ef35526b380 --- /dev/null +++ b/tests/codegen/rules-engine/build.gradle.kts @@ -0,0 +1,158 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import aws.sdk.kotlin.gradle.codegen.dsl.generateSmithyProjections +import aws.sdk.kotlin.gradle.codegen.dsl.smithyKotlinPlugin +import aws.sdk.kotlin.gradle.codegen.smithyKotlinProjectionSrcDir + +plugins { + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.aws.kotlin.repo.tools.smithybuild) +} + +description = "Smithy rules engine codegen integration test suite" + +data class Test( + val projectionName: String, + val protocolName: String, + val modelTemplate: File, +) { + val model: File + get() = layout.buildDirectory.file("$projectionName/model.smithy").get().asFile +} + +val tests = listOf( + Test("operationContextParams", "operationContextParams", file("operation-context-params.smithy")), +) + +fun fillInModel(output: File, protocolName: String, template: File) { + val input = template.readText() + val opTraits = when (protocolName) { + "restJson1", "restXml" -> """@http(method: "POST", uri: "/test-eventstream", code: 200)""" + else -> "" + } + val replaced = input + .replace("{protocol-name}", protocolName) + .replace("{op-traits}", opTraits) + + output.parentFile.mkdirs() + output.writeText(replaced) +} + +val testServiceShapeId = "aws.sdk.kotlin.test#TestService" +smithyBuild { + tests.forEach { test -> + + projections.register(test.projectionName) { + imports = listOf(test.model.absolutePath) + transforms = listOf( + """ + { + "name": "includeServices", + "args": { + "services": ["$testServiceShapeId"] + } + } + """, + ) + + smithyKotlinPlugin { + serviceShapeId = testServiceShapeId + packageName = "aws.sdk.kotlin.test.${test.projectionName.lowercase()}" + packageVersion = "1.0" + buildSettings { + generateFullProject = false + generateDefaultBuildFiles = false + optInAnnotations = listOf( + "aws.smithy.kotlin.runtime.InternalApi", + "aws.sdk.kotlin.runtime.InternalSdkApi", + ) + } + } + } + } +} + +val codegen by configurations.getting +dependencies { + codegen(project(":codegen:aws-sdk-codegen")) + codegen(libs.smithy.cli) + codegen(libs.smithy.model) +} + +tasks.generateSmithyBuild { + doFirst { + tests.forEach { test -> fillInModel(test.model, test.protocolName, test.modelTemplate) } + } +} + +tasks.generateSmithyProjections { + doFirst { + // ensure the generated tests use the same version of the runtime as the aws aws-runtime + val smithyKotlinRuntimeVersion = libs.versions.smithy.kotlin.runtime.version.get() + System.setProperty("smithy.kotlin.codegen.clientRuntimeVersion", smithyKotlinRuntimeVersion) + } +} + +val optinAnnotations = listOf( + "kotlin.RequiresOptIn", + "aws.smithy.kotlin.runtime.InternalApi", + "aws.sdk.kotlin.runtime.InternalSdkApi", +) + +kotlin.sourceSets.all { + optinAnnotations.forEach { languageSettings.optIn(it) } +} + +kotlin.sourceSets.getByName("test") { + smithyBuild.projections.forEach { + kotlin.srcDir(smithyBuild.smithyKotlinProjectionSrcDir(it.name)) + } +} + +tasks.withType { + dependsOn(tasks.generateSmithyProjections) + // generated clients have quite a few warnings + kotlinOptions.allWarningsAsErrors = false +} + +tasks.test { + useJUnitPlatform() + testLogging { + events("passed", "skipped", "failed") + showStandardStreams = true + showStackTraces = true + showExceptions = true + exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL + } +} + +dependencies { + + implementation(libs.kotlinx.coroutines.core) + + testImplementation(libs.kotlin.test) + testImplementation(libs.kotlin.test.junit5) + testImplementation(libs.kotlinx.coroutines.test) + + testImplementation(libs.smithy.kotlin.smithy.test) + testImplementation(libs.smithy.kotlin.aws.signing.default) + testImplementation(libs.smithy.kotlin.telemetry.api) + + // have to manually add all the dependencies of the generated client(s) + // doing it this way (as opposed to doing what we do for protocol-tests) allows + // the tests to work without a publish to maven-local step at the cost of maintaining + // this set of dependencies manually + // <-- BEGIN GENERATED DEPENDENCY LIST --> + implementation(libs.bundles.smithy.kotlin.service.client) + implementation(libs.smithy.kotlin.aws.event.stream) + implementation(project(":aws-runtime:aws-http")) + implementation(libs.smithy.kotlin.aws.json.protocols) + implementation(libs.smithy.kotlin.serde.json) + api(project(":aws-runtime:aws-config")) + api(project(":aws-runtime:aws-core")) + api(project(":aws-runtime:aws-endpoint")) + // <-- END GENERATED DEPENDENCY LIST --> +} diff --git a/tests/codegen/rules-engine/operation-context-params.smithy b/tests/codegen/rules-engine/operation-context-params.smithy new file mode 100644 index 00000000000..c63a2756e39 --- /dev/null +++ b/tests/codegen/rules-engine/operation-context-params.smithy @@ -0,0 +1,58 @@ +$version: "2.0" +namespace aws.sdk.kotlin.test + +use aws.protocols#awsJson1_0 +use smithy.rules#operationContextParams +use smithy.rules#endpointRuleSet +use aws.api#service + +@awsJson1_0 +@service(sdkId: "OperationContextParamsTest") +@endpointRuleSet( + version: "1.0", + parameters: { + "ObjectKeys": { + "type": "stringArray", + "documentation": "A string array.", + "required": true + } + }, + rules: [ + { + "type": "endpoint", + "conditions": [], + "endpoint": { + "url": "https://static.endpoint" + } + } + ] +) +service TestService { + operations: [DeleteObjects], + version: "1" +} + +@operationContextParams( + ObjectKeys: { + path: "Delete.Objects[*].[Key][]" + } +) +operation DeleteObjects { + input: DeleteObjectsRequest +} + +structure DeleteObjectsRequest { + Delete: Delete +} + +structure Delete { + Objects: ObjectIdentifierList +} + +list ObjectIdentifierList { + member: ObjectIdentifier +} + +structure ObjectIdentifier { + Key: String +}