Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

misc: add rules engine codegen tests #1459

Merged
merged 10 commits into from
Dec 16, 2024
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
158 changes: 158 additions & 0 deletions tests/codegen/rules-engine/build.gradle.kts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed most of this file is copy-pasted from elsewhere, is there any reason this needs to be a new module rather than in the existing codegen tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Organization mostly, it didn't feel right to have this under tests/codegen/event-stream

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather see the codegen build scripts abstracted to cover both event streams and endpoint rules than copy-pasting the entire file, is that possible?

Original file line number Diff line number Diff line change
@@ -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<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
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 -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this dependency list generated by?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's just manually written. I couldn't find anything that suggests it's code generated

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 -->
}
58 changes: 58 additions & 0 deletions tests/codegen/rules-engine/operation-context-params.smithy
Original file line number Diff line number Diff line change
@@ -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
}
Loading