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

feat: smoke tests #1427

Merged
merged 34 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
602bac1
feat: smoke tests
0marperez Aug 23, 2024
989d8ec
Merge branch 'main' of https://github.com/awslabs/aws-sdk-kotlin into…
0marperez Aug 23, 2024
9ca8f2e
Sending verified commit to trigger CI
0marperez Aug 23, 2024
b00ec1f
Actually sign commit message[B
0marperez Aug 23, 2024
35708df
PR feedback
0marperez Aug 28, 2024
2399355
Remove error log commited by accident
0marperez Aug 28, 2024
2d98a99
Add TODO
0marperez Aug 28, 2024
d7a4877
Added E2E tests
0marperez Sep 13, 2024
f390f6a
Remove dangerous gradle task, move sdk denylist check to codegen inst…
0marperez Sep 17, 2024
90a93ac
Fix kotlin native builds failing
0marperez Sep 18, 2024
6b288ed
Temp print statement to debug
0marperez Sep 18, 2024
c6701cb
Change debugging print to exception
0marperez Sep 18, 2024
95b553d
chmod gradlew before tests
0marperez Sep 18, 2024
5ac3db2
Use gradlew.bat
0marperez Sep 19, 2024
ca30211
ls sdk root dir
0marperez Sep 19, 2024
08356db
Use gradle connector instead of process builder
0marperez Sep 20, 2024
e7fdeff
build before testing
0marperez Sep 20, 2024
8f0dec1
increase gradle connection timeout
0marperez Sep 20, 2024
431e63e
run from sdk root dir, better logging, use explicit gradle distributi…
0marperez Sep 20, 2024
1706764
Enable gradle daemon with an idle timeout, increment internal timeout
0marperez Sep 21, 2024
bb53c3d
use gradle runner instead of connector
0marperez Sep 22, 2024
e13e9fc
Specify smokeTests to run & better test failure logging
0marperez Sep 22, 2024
afc5168
fix parallel task execution issues
0marperez Sep 22, 2024
c39f3fe
move task dependency from ci tests to code
0marperez Sep 23, 2024
5dfd004
easy to fix PR feedback and decoupling SmokeTestRunnerGenerator from SDK
0marperez Sep 23, 2024
87fa6bb
Merge branch 'main' of https://github.com/awslabs/aws-sdk-kotlin into…
0marperez Sep 23, 2024
c1e0edf
Remove accidental changes to AWS model
0marperez Sep 24, 2024
dfcffbb
Run smoke tests in common
0marperez Sep 24, 2024
25b8e8e
Self nits
0marperez Sep 24, 2024
8aae6e4
Use new runtime function for env vars
0marperez Sep 24, 2024
5687f7e
Cleanup, Clarity changes to test code in src
0marperez Sep 25, 2024
1e35fc7
Merge from main
0marperez Oct 2, 2024
d465c50
Disable native for smoke test e2e tests
0marperez Oct 3, 2024
73f694a
Use vararg instead of list & add FIXME to enable native builds later
0marperez Oct 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ build/
.idea/
__pycache__/
local.properties

# ignore generated files
services/*/generated-src
services/*/build.gradle.kts
.kotest/
*.klib
*.klib
tests/codegen/smoke-tests/services/*/generated-src
tests/codegen/smoke-tests/services/*/build.gradle.kts
1 change: 1 addition & 0 deletions codegen/aws-sdk-codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies {
api(libs.smithy.aws.cloudformation.traits)
api(libs.smithy.protocol.test.traits)
implementation(libs.smithy.aws.endpoints)
implementation(libs.smithy.smoke.test.traits)

testImplementation(libs.junit.jupiter)
testImplementation(libs.junit.jupiter.params)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@
*/
package aws.sdk.kotlin.codegen

import aws.sdk.kotlin.codegen.model.traits.testing.TestFailedResponseTrait
import aws.sdk.kotlin.codegen.model.traits.testing.TestSuccessResponseTrait
import aws.sdk.kotlin.codegen.smoketests.smokeTestDenyList
import software.amazon.smithy.kotlin.codegen.core.*
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.model.expectShape
import software.amazon.smithy.kotlin.codegen.model.hasTrait
import software.amazon.smithy.kotlin.codegen.rendering.GradleWriter
import software.amazon.smithy.kotlin.codegen.utils.topDownOperations
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.smoketests.traits.SmokeTestsTrait

// TODO - would be nice to allow integrations to define custom settings in the plugin
// e.g. we could then more consistently apply this integration if we could define a property like: `build.isAwsSdk: true`
Expand Down Expand Up @@ -64,9 +72,72 @@ class GradleGenerator : KotlinIntegration {
}
}
}
if (ctx.model.topDownOperations(ctx.settings.service).any { it.hasTrait<SmokeTestsTrait>() } && ctx.settings.sdkId !in smokeTestDenyList) {
write("")
generateSmokeTestConfig(writer, ctx)
}
}

val contents = writer.toString()
delegator.fileManifest.writeFile("build.gradle.kts", contents)
}

private fun generateSmokeTestConfig(writer: GradleWriter, ctx: CodegenContext) {
generateSmokeTestJarTask(writer, ctx)
writer.write("")
generateSmokeTestTask(writer, ctx)
}

/**
* Generates a gradle task to create smoke test runner JARs
*/
private fun generateSmokeTestJarTask(writer: GradleWriter, ctx: CodegenContext) {
writer.withBlock("jvm {", "}") {
withBlock("compilations {", "}") {
write("val mainPath = getByName(#S).output.classesDirs", "main")
write("val testPath = getByName(#S).output.classesDirs", "test")
withBlock("tasks {", "}") {
withBlock("register<Jar>(#S) {", "}", "smokeTestJar") {
write("description = #S", "Creates smoke tests jar")
write("group = #S", "application")
write("dependsOn(build)")
write("mustRunAfter(build)")
withBlock("manifest {", "}") {
write("attributes[#S] = #S", "Main-Class", "${ctx.settings.pkg.name}.smoketests.SmokeTestsKt")
}
write("val runtimePath = configurations.getByName(#S).map { if (it.isDirectory) it else zipTree(it) }", "jvmRuntimeClasspath")
write("duplicatesStrategy = DuplicatesStrategy.EXCLUDE")
write("from(runtimePath, mainPath, testPath)")
write("archiveBaseName.set(#S)", "\${project.name}-smoketests")
}
}
}
}
}

/**
* Generates a gradle task to run smoke tests
*/
private fun generateSmokeTestTask(writer: GradleWriter, ctx: CodegenContext) {
val hasSuccessResponseTrait = ctx.model.expectShape<ServiceShape>(ctx.settings.service).hasTrait(TestSuccessResponseTrait.ID)
val hasFailedResponseTrait = ctx.model.expectShape<ServiceShape>(ctx.settings.service).hasTrait(TestFailedResponseTrait.ID)
val inTestingEnvironment = hasFailedResponseTrait || hasSuccessResponseTrait

/**
* E2E tests don't have sdkVersion in jar names. They're added later for publishing.
* @see SmokeTestE2ETest
*/
val jarName = if (inTestingEnvironment) "\${project.name}-smoketests.jar" else "\${project.name}-smoketests-\$sdkVersion.jar"

writer.withBlock("tasks.register<JavaExec>(#S) {", "}", "smokeTest") {
write("description = #S", "Runs smoke tests jar")
write("group = #S", "verification")
write("dependsOn(tasks.getByName(#S))", "smokeTestJar")
write("mustRunAfter(tasks.getByName(#S))", "smokeTestJar")
write("")
write("val sdkVersion: String by project")
write("val jarFile = file(#S)", "build/libs/$jarName")
write("classpath = files(jarFile)")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package aws.sdk.kotlin.codegen.model.traits.testing

import software.amazon.smithy.model.node.ObjectNode
import software.amazon.smithy.model.shapes.ShapeId
import software.amazon.smithy.model.traits.AnnotationTrait

/**
* Indicates the annotated service should always return a failed response.
* IMPORTANT: This trait is intended for use in integration or E2E tests only, not in real-life smoke tests that run
* against a service endpoint.
*/
class TestFailedResponseTrait(node: ObjectNode) : AnnotationTrait(ID, node) {
companion object {
val ID: ShapeId = ShapeId.from("smithy.kotlin.traits#failedResponseTrait")
}
}

/**
* Indicates the annotated service should always return a success response.
* IMPORTANT: This trait is intended for use in integration or E2E tests only, not in real-life smoke tests that run
* against a service endpoint.
*/
class TestSuccessResponseTrait(node: ObjectNode) : AnnotationTrait(ID, node) {
companion object {
val ID: ShapeId = ShapeId.from("smithy.kotlin.traits#successResponseTrait")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package aws.sdk.kotlin.codegen.smoketests

import software.amazon.smithy.kotlin.codegen.KotlinSettings
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.integration.SectionWriter
import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding
import software.amazon.smithy.kotlin.codegen.model.hasTrait
import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestAdditionalEnvVars
import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestDefaultConfig
import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestRegionDefault
import software.amazon.smithy.kotlin.codegen.utils.topDownOperations
import software.amazon.smithy.model.Model
import software.amazon.smithy.smoketests.traits.SmokeTestsTrait

/**
* Adds AWS region support to smoke tests
*/
class SmokeTestsCodegenRegionIntegration : KotlinIntegration {
override fun enabledForService(model: Model, settings: KotlinSettings): Boolean =
model.topDownOperations(settings.service).any { it.hasTrait<SmokeTestsTrait>() }

override val sectionWriters: List<SectionWriterBinding>
get() = listOf(
SectionWriterBinding(SmokeTestAdditionalEnvVars, envVars),
SectionWriterBinding(SmokeTestDefaultConfig, region),
SectionWriterBinding(SmokeTestRegionDefault, regionDefault),
)

private val envVars = SectionWriter { writer, _ ->
writer.write(
"private val regionOverride = #T.System.getenv(#S)",
RuntimeTypes.Core.Utils.PlatformProvider,
"AWS_SMOKE_TEST_REGION",
)
}

private val region = SectionWriter { writer, _ ->
writer.write("region = regionOverride")
}

private val regionDefault = SectionWriter { writer, _ ->
writer.write("regionOverride ?:")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package aws.sdk.kotlin.codegen.smoketests.testing

import aws.sdk.kotlin.codegen.model.traits.testing.TestFailedResponseTrait
import aws.sdk.kotlin.codegen.model.traits.testing.TestSuccessResponseTrait
import software.amazon.smithy.kotlin.codegen.KotlinSettings
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes
import software.amazon.smithy.kotlin.codegen.core.withBlock
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.integration.SectionWriter
import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding
import software.amazon.smithy.kotlin.codegen.model.expectShape
import software.amazon.smithy.kotlin.codegen.model.hasTrait
import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestHttpEngineOverride
import software.amazon.smithy.kotlin.codegen.utils.topDownOperations
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.smoketests.traits.SmokeTestsTrait

/**
* Adds [TestFailedResponseTrait] support to smoke tests
* IMPORTANT: This integration is intended for use in integration or E2E tests only, not in real-life smoke tests that run
* against a service endpoint.
*/
class SmokeTestFailHttpEngineIntegration : KotlinIntegration {
override fun enabledForService(model: Model, settings: KotlinSettings): Boolean =
model.topDownOperations(settings.service).any { it.hasTrait<SmokeTestsTrait>() } &&
!model.expectShape<ServiceShape>(settings.service).hasTrait(TestSuccessResponseTrait.ID) &&
model.expectShape<ServiceShape>(settings.service).hasTrait(TestFailedResponseTrait.ID)

override val sectionWriters: List<SectionWriterBinding>
get() = listOf(
SectionWriterBinding(SmokeTestHttpEngineOverride, httpClientOverride),
)

private val httpClientOverride = SectionWriter { writer, _ ->
writer.withBlock("httpClient = #T(", ")", RuntimeTypes.HttpTest.TestEngine) {
withBlock("roundTripImpl = { _, request ->", "}") {
write(
"val resp = #T(#T.BadRequest, #T.Empty, #T.Empty)",
RuntimeTypes.Http.Response.HttpResponse,
RuntimeTypes.Http.StatusCode,
RuntimeTypes.Http.Headers,
RuntimeTypes.Http.HttpBody,
)
write("val now = #T.now()", RuntimeTypes.Core.Instant)
write("#T(request, resp, now, now)", RuntimeTypes.Http.HttpCall)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package aws.sdk.kotlin.codegen.smoketests.testing

import aws.sdk.kotlin.codegen.model.traits.testing.TestFailedResponseTrait
import aws.sdk.kotlin.codegen.model.traits.testing.TestSuccessResponseTrait
import software.amazon.smithy.kotlin.codegen.KotlinSettings
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.integration.SectionWriter
import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding
import software.amazon.smithy.kotlin.codegen.model.expectShape
import software.amazon.smithy.kotlin.codegen.model.hasTrait
import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestHttpEngineOverride
import software.amazon.smithy.kotlin.codegen.utils.topDownOperations
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.smoketests.traits.SmokeTestsTrait

/**
* Adds [TestSuccessResponseTrait] support to smoke tests
* IMPORTANT: This integration is intended for use in integration or E2E tests only, not in real-life smoke tests that run
* against a service endpoint.
*/
class SmokeTestSuccessHttpEngineIntegration : KotlinIntegration {
override fun enabledForService(model: Model, settings: KotlinSettings): Boolean =
model.topDownOperations(settings.service).any { it.hasTrait<SmokeTestsTrait>() } &&
model.expectShape<ServiceShape>(settings.service).hasTrait(TestSuccessResponseTrait.ID) &&
!model.expectShape<ServiceShape>(settings.service).hasTrait(TestFailedResponseTrait.ID)

override val sectionWriters: List<SectionWriterBinding>
get() = listOf(
SectionWriterBinding(SmokeTestHttpEngineOverride, httpClientOverride),
)

private val httpClientOverride = SectionWriter { writer, _ ->
writer.write("httpClient = #T()", RuntimeTypes.HttpTest.TestEngine)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ aws.sdk.kotlin.codegen.customization.s3.express.S3ExpressIntegration
aws.sdk.kotlin.codegen.customization.s3.S3ExpiresIntegration
aws.sdk.kotlin.codegen.BusinessMetricsIntegration
aws.sdk.kotlin.codegen.smoketests.SmokeTestsDenyListIntegration
aws.sdk.kotlin.codegen.smoketests.SmokeTestsCodegenRegionIntegration
aws.sdk.kotlin.codegen.smoketests.testing.SmokeTestSuccessHttpEngineIntegration
aws.sdk.kotlin.codegen.smoketests.testing.SmokeTestFailHttpEngineIntegration
9 changes: 9 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ include(":services")
include(":tests")
include(":tests:codegen:event-stream")
include(":tests:e2e-test-util")
include(":tests:codegen:smoke-tests")
include(":tests:codegen:smoke-tests:services")

// generated services
val File.isServiceDir: Boolean
Expand All @@ -57,6 +59,13 @@ file("services").listFiles().forEach {
}
}

// generated services by smoke tests test suite
file("tests/codegen/smoke-tests/services").listFiles().forEach {
if (it.isServiceDir) {
include(":tests:codegen:smoke-tests:services:${it.name}")
}
}

// Service benchmarks project
val benchmarkServices = listOf(
// keep this list in sync with tests/benchmarks/service-benchmarks/build.gradle.kts
Expand Down
Loading
Loading