diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt new file mode 100644 index 0000000000000000000000000000000000000000..d76284792cc22212e567e54ce5e0c8c515730015 --- /dev/null +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -0,0 +1,104 @@ +import java.lang.IllegalArgumentException + +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +/** + * This file contains common functionality shared across the buildscripts for the `codegen-test` and `codegen-server-test` + * modules. + */ + +data class CodegenTest(val service: String, val module: String, val extraConfig: String? = null) + +fun generateSmithyBuild(projectDir: String, pluginName: String, tests: List): String { + val projections = tests.joinToString(",\n") { + """ + "${it.module}": { + "plugins": { + "$pluginName": { + "runtimeConfig": { + "relativePath": "$projectDir/rust-runtime" + }, + "service": "${it.service}", + "module": "${it.module}", + "moduleVersion": "0.0.1", + "moduleDescription": "test", + "moduleAuthors": ["protocoltest@example.com"] + ${it.extraConfig ?: ""} + } + } + } + """.trimIndent() + } + return """ + { + "version": "1.0", + "projections": { + $projections + } + } + """.trimIndent() +} + +enum class Cargo(val toString: String) { + CHECK("cargoCheck"), + TEST("cargoTest"), + DOCS("cargoDocs"), + CLIPPY("cargoClippy"); +} + +fun generateCargoWorkspace(pluginName: String, tests: List) = + """ + [workspace] + members = [ + ${tests.joinToString(",") { "\"${it.module}/$pluginName\"" }} + ] + """.trimIndent() + +/** + * Filter the service integration tests for which to generate Rust crates in [allTests] using the given [properties]. + */ +fun codegenTests(properties: PropertyRetriever, allTests: List): List { + val modulesOverride = properties.get("modules")?.split(",")?.map { it.trim() } + + val ret = if (modulesOverride != null) { + println("modulesOverride: $modulesOverride") + allTests.filter { modulesOverride.contains(it.module) } + } else { + allTests + } + require(ret.isNotEmpty()) { + "None of the provided module overrides (`$modulesOverride`) are valid test services (`${allTests.map { it.module }}`)" + } + return ret +} + +val AllCargoCommands = listOf(Cargo.CHECK, Cargo.TEST, Cargo.CLIPPY, Cargo.DOCS) +/** + * Filter the Cargo commands to be run on the generated Rust crates using the given [properties]. + * The list of Cargo commands that is run by default is defined in [AllCargoCommands]. + */ +fun cargoCommands(properties: PropertyRetriever): List { + val cargoCommandsOverride = properties.get("cargoCommands")?.split(",")?.map { it.trim() }?.map { + when(it) { + "check" -> Cargo.CHECK + "test" -> Cargo.TEST + "docs" -> Cargo.DOCS + "clippy" -> Cargo.CLIPPY + else -> throw IllegalArgumentException("Unexpected Cargo command `$it` (valid commands are `check`, `test`, `docs`, `clippy`)") + } + } + + val ret = if (cargoCommandsOverride != null) { + println("cargoCommandsOverride: $cargoCommandsOverride") + AllCargoCommands.filter { cargoCommandsOverride.contains(it) } + } else { + AllCargoCommands + } + require(ret.isNotEmpty()) { + "None of the provided cargo commands (`$cargoCommandsOverride`) are valid cargo commands (`${AllCargoCommands.map { it.toString }}`)" + } + return ret +} diff --git a/codegen-server-test/README.md b/codegen-server-test/README.md index a91b9adebd4d2e96a35c914030f50504f391c159..c7ceedb4a8e3ba35806082a08388156cf72388d6 100644 --- a/codegen-server-test/README.md +++ b/codegen-server-test/README.md @@ -1,8 +1,6 @@ -# Codegen Integration Test -This module defines an integration test of the code generation machinery. `.build.gradle.kts` will generate a `smithy-build.json` file as part of the build. The Smithy build plugin then invokes our codegen machinery and generates Rust crates. +# Server Codegen Integration Tests -The `test` task will run `cargo check` and `cargo clippy` to validate that the generated Rust compiles and is idiomatic. -## Usage -``` -../gradlew test -``` +Refer to `../codegen-test/README.md` for documentation on how to use this +module. This module is analogous to the `codegen-test` one, but it's named +`codegen-server-test` and it runs the `rust-server-codegen` Smithy build +plugin instead. diff --git a/codegen-server-test/build.gradle.kts b/codegen-server-test/build.gradle.kts index e323b1182d83be05a1cd4bbfaf655464ab22a63c..5cd3e0833262638e584652fe88ec8656fb18bdda 100644 --- a/codegen-server-test/build.gradle.kts +++ b/codegen-server-test/build.gradle.kts @@ -4,7 +4,6 @@ */ extra["displayName"] = "Smithy :: Rust :: Codegen :: Server :: Test" - extra["moduleName"] = "software.amazon.smithy.rust.kotlin.codegen.server.test" tasks["jar"].enabled = false @@ -14,6 +13,10 @@ plugins { id("software.amazon.smithy").version("0.5.3") } val smithyVersion: String by project val defaultRustFlags: String by project val defaultRustDocFlags: String by project +val properties = PropertyRetriever(rootProject, project) + +val pluginName = "rust-server-codegen" +val workingDirUnderBuildDir = "smithyprojections/codegen-server-test/" buildscript { val smithyVersion: String by project @@ -29,104 +32,64 @@ dependencies { implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion") } -data class CodegenTest(val service: String, val module: String, val extraConfig: String? = null) - -val CodegenTests = listOf( +val allCodegenTests = listOf( CodegenTest("com.amazonaws.simple#SimpleService", "simple"), CodegenTest("aws.protocoltests.restjson#RestJson", "rest_json"), CodegenTest("com.amazonaws.ebs#Ebs", "ebs"), CodegenTest("com.amazonaws.s3#AmazonS3", "s3") ) -/** - * `includeFluentClient` must be set to `false` as we are not generating all the supporting - * code for it. - * TODO: Review how can we make this a default in the server so that customers don't - * have to specify it. - */ -fun generateSmithyBuild(tests: List): String { - val projections = - tests.joinToString(",\n") { - """ - "${it.module}": { - "plugins": { - "rust-server-codegen": { - "runtimeConfig": { - "relativePath": "${rootProject.projectDir.absolutePath}/rust-runtime" - }, - "service": "${it.service}", - "module": "${it.module}", - "moduleVersion": "0.0.1", - "moduleDescription": "test", - "moduleAuthors": ["protocoltest@example.com"] - ${it.extraConfig ?: ""} - } - } - } - """.trimIndent() - } - return """ - { - "version": "1.0", - "projections": { $projections } - } - """ -} - task("generateSmithyBuild") { description = "generate smithy-build.json" - doFirst { projectDir.resolve("smithy-build.json").writeText(generateSmithyBuild(CodegenTests)) } -} - -fun generateCargoWorkspace(tests: List): String { - return """ - [workspace] - members = [ - ${tests.joinToString(",") { "\"${it.module}/rust-server-codegen\"" }} - ] - """.trimIndent() + doFirst { + projectDir.resolve("smithy-build.json") + .writeText(generateSmithyBuild( + rootProject.projectDir.absolutePath, + pluginName, + codegenTests(properties, allCodegenTests)) + ) + } } task("generateCargoWorkspace") { description = "generate Cargo.toml workspace file" doFirst { - buildDir.resolve("smithyprojections/codegen-server-test/Cargo.toml") - .writeText(generateCargoWorkspace(CodegenTests)) + buildDir.resolve("$workingDirUnderBuildDir/Cargo.toml") + .writeText(generateCargoWorkspace(pluginName, codegenTests(properties, allCodegenTests))) } } tasks["smithyBuildJar"].dependsOn("generateSmithyBuild") -tasks["assemble"].dependsOn("smithyBuildJar") tasks["assemble"].finalizedBy("generateCargoWorkspace") -tasks.register("cargoCheck") { - workingDir("build/smithyprojections/codegen-server-test/") +tasks.register(Cargo.CHECK.toString) { + workingDir("$buildDir/$workingDirUnderBuildDir") environment("RUSTFLAGS", defaultRustFlags) commandLine("cargo", "check") dependsOn("assemble") } -tasks.register("cargoTest") { - workingDir("build/smithyprojections/codegen-server-test/") +tasks.register(Cargo.TEST.toString) { + workingDir("$buildDir/$workingDirUnderBuildDir") environment("RUSTFLAGS", defaultRustFlags) commandLine("cargo", "test") dependsOn("assemble") } -tasks.register("cargoDocs") { - workingDir("build/smithyprojections/codegen-server-test/") +tasks.register(Cargo.DOCS.toString) { + workingDir("$buildDir/$workingDirUnderBuildDir") environment("RUSTDOCFLAGS", defaultRustDocFlags) commandLine("cargo", "doc", "--no-deps") dependsOn("assemble") } -tasks.register("cargoClippy") { - workingDir("build/smithyprojections/codegen-server-test/") +tasks.register(Cargo.CLIPPY.toString) { + workingDir("$buildDir/$workingDirUnderBuildDir") environment("RUSTFLAGS", defaultRustFlags) commandLine("cargo", "clippy") dependsOn("assemble") } -tasks["test"].finalizedBy("cargoCheck", "cargoClippy", "cargoTest", "cargoDocs") +tasks["test"].finalizedBy(cargoCommands(properties).map { it.toString }) tasks["clean"].doFirst { delete("smithy-build.json") } diff --git a/codegen-test/README.md b/codegen-test/README.md index a91b9adebd4d2e96a35c914030f50504f391c159..65800b9248fa7db5c2fc8a635516e28851a634fe 100644 --- a/codegen-test/README.md +++ b/codegen-test/README.md @@ -1,8 +1,42 @@ -# Codegen Integration Test -This module defines an integration test of the code generation machinery. `.build.gradle.kts` will generate a `smithy-build.json` file as part of the build. The Smithy build plugin then invokes our codegen machinery and generates Rust crates. +# Codegen Integration Tests + +This module defines integration tests of the code generation machinery. +`./build.gradle.kts` will generate a `smithy-build.json` file as part of the +build. The `rust-codegen` Smithy build plugin then invokes our codegen +machinery and generates Rust crates, one for each of the integration test +services defined under `model/`. -The `test` task will run `cargo check` and `cargo clippy` to validate that the generated Rust compiles and is idiomatic. ## Usage + +These commands are all meant to be run from the repository root. + +To run all protocol tests of all the integration test services: + +```sh +./gradlew codegen-test:build +``` + +To run only a _subset_ of the integration test services (refer to +`./build.gradle.kts` for a full list): + +```sh +./gradlew codegen-test:build -P modules='simple,rest_json' +``` + +The Gradle task will run `cargo check`, `cargo test`, `cargo docs` and `cargo +clippy` by default on all the generated Rust crates. You can also specify a +subset of these commands. For instance, if you're working on documentation and +want to check that the crates also compile, you can run: + +```sh +./gradlew codegen-test:build -P cargoCommands='check,docs' ``` -../gradlew test + +For fast development iteration cycles on protocol tests, we recommend you write +a codegen _unit_ test with a minimal service definition and only run that unit +test. Alternatively, you can write a minimal integration test service +definition in `model/simple.smithy` and run: + +```sh +./gradlew codegen-test:build -P cargoCommands='test' -P modules='simple' ``` diff --git a/codegen-test/build.gradle.kts b/codegen-test/build.gradle.kts index 74944ebf9718260d5ae2bcb9109272d5717d1bf5..07a96d4559c480cb996e34f47f0c996b656d2a97 100644 --- a/codegen-test/build.gradle.kts +++ b/codegen-test/build.gradle.kts @@ -15,6 +15,10 @@ plugins { val smithyVersion: String by project val defaultRustFlags: String by project val defaultRustDocFlags: String by project +val properties = PropertyRetriever(rootProject, project) + +val pluginName = "rust-codegen" +val workingDirUnderBuildDir = "smithyprojections/codegen-test/" buildscript { val smithyVersion: String by project @@ -30,9 +34,7 @@ dependencies { implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion") } -data class CodegenTest(val service: String, val module: String, val extraConfig: String? = null) - -val CodegenTests = listOf( +val allCodegenTests = listOf( CodegenTest("com.amazonaws.simple#SimpleService", "simple"), CodegenTest("com.amazonaws.dynamodb#DynamoDB_20120810", "dynamo"), CodegenTest("com.amazonaws.ebs#Ebs", "ebs"), @@ -84,88 +86,58 @@ val CodegenTests = listOf( ) ) -fun generateSmithyBuild(tests: List): String { - val projections = tests.joinToString(",\n") { - """ - "${it.module}": { - "plugins": { - "rust-codegen": { - "runtimeConfig": { - "relativePath": "${rootProject.projectDir.absolutePath}/rust-runtime" - }, - "service": "${it.service}", - "module": "${it.module}", - "moduleVersion": "0.0.1", - "moduleDescription": "test", - "moduleAuthors": ["protocoltest@example.com"] - ${it.extraConfig ?: ""} - } - } - } - """.trimIndent() - } - return """ - { - "version": "1.0", - "projections": { $projections } - } - """ -} - task("generateSmithyBuild") { description = "generate smithy-build.json" doFirst { - projectDir.resolve("smithy-build.json").writeText(generateSmithyBuild(CodegenTests)) + projectDir.resolve("smithy-build.json") + .writeText(generateSmithyBuild( + rootProject.projectDir.absolutePath, + pluginName, + codegenTests(properties, allCodegenTests)) + ) } } -fun generateCargoWorkspace(tests: List): String { - return """ - [workspace] - members = [ - ${tests.joinToString(",") { "\"${it.module}/rust-codegen\"" }} - ] - """.trimIndent() -} task("generateCargoWorkspace") { description = "generate Cargo.toml workspace file" doFirst { - buildDir.resolve("smithyprojections/codegen-test/Cargo.toml").writeText(generateCargoWorkspace(CodegenTests)) + buildDir.resolve("$workingDirUnderBuildDir/Cargo.toml") + .writeText(generateCargoWorkspace(pluginName, codegenTests(properties, allCodegenTests))) } } tasks["smithyBuildJar"].dependsOn("generateSmithyBuild") tasks["assemble"].finalizedBy("generateCargoWorkspace") -tasks.register("cargoCheck") { - workingDir("build/smithyprojections/codegen-test/") +tasks.register(Cargo.CHECK.toString) { + workingDir("$buildDir/$workingDirUnderBuildDir") environment("RUSTFLAGS", defaultRustFlags) commandLine("cargo", "check") dependsOn("assemble") } -tasks.register("cargoTest") { - workingDir("build/smithyprojections/codegen-test/") +tasks.register(Cargo.TEST.toString) { + workingDir("$buildDir/$workingDirUnderBuildDir") environment("RUSTFLAGS", defaultRustFlags) commandLine("cargo", "test") dependsOn("assemble") } -tasks.register("cargoDocs") { - workingDir("build/smithyprojections/codegen-test/") +tasks.register(Cargo.DOCS.toString) { + workingDir("$buildDir/$workingDirUnderBuildDir") environment("RUSTDOCFLAGS", defaultRustDocFlags) commandLine("cargo", "doc", "--no-deps") dependsOn("assemble") } -tasks.register("cargoClippy") { - workingDir("build/smithyprojections/codegen-test/") +tasks.register(Cargo.CLIPPY.toString) { + workingDir("$buildDir/$workingDirUnderBuildDir") environment("RUSTFLAGS", defaultRustFlags) commandLine("cargo", "clippy") dependsOn("assemble") } -tasks["test"].finalizedBy("cargoCheck", "cargoClippy", "cargoTest", "cargoDocs") +tasks["test"].finalizedBy(cargoCommands(properties).map { it.toString }) tasks["clean"].doFirst { delete("smithy-build.json")