diff --git a/.gitignore b/.gitignore index e1f7d79c4e2..300d9787a0a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ Package.resolved build/ codegen/protocol-test-codegen-local/smithy-build.json codegen/protocol-test-codegen/smithy-build.json +SmokeTests/ # vim temporary files *.swp diff --git a/AWSSDKSwiftCLI/Package.swift b/AWSSDKSwiftCLI/Package.swift index 8d9ac136740..584fd7a0454 100644 --- a/AWSSDKSwiftCLI/Package.swift +++ b/AWSSDKSwiftCLI/Package.swift @@ -26,6 +26,7 @@ let package = Package( resources: [ .process("Resources/Package.Prefix.txt"), .process("Resources/Package.Base.txt"), + .process("Resources/SmokeTestsPackage.Base.txt"), .process("Resources/DocIndex.Base.md") ] ), diff --git a/AWSSDKSwiftCLI/Sources/AWSCLIUtils/FileManager+Utils.swift b/AWSSDKSwiftCLI/Sources/AWSCLIUtils/FileManager+Utils.swift index 8dcce837d6a..e689c5250ed 100644 --- a/AWSSDKSwiftCLI/Sources/AWSCLIUtils/FileManager+Utils.swift +++ b/AWSSDKSwiftCLI/Sources/AWSCLIUtils/FileManager+Utils.swift @@ -36,6 +36,19 @@ public extension FileManager { .filter { !$0.hasPrefix(".") } } + /// Returns the list of services that have smoke tests and test runner generated for them. + /// Service names are extracted from service name prefix of directory names under `SmokeTests/`. + /// E.g., extract `AWSS3` from `SmokeTests/AWSS3SmokeTestRunner/`. + /// + /// - Returns: The list of services with generated smoke tests. + func servicesWithSmokeTests() throws -> [String] { + try FileManager.default + .contentsOfDirectory(atPath: "SmokeTests") + .sorted() + .filter { !$0.hasPrefix(".") && $0.hasSuffix("SmokeTestRunner") } + .map { $0.replacingOccurrences(of: "SmokeTestRunner", with: "") } + } + /// Returns the list of Smithy runtime modules within `../smithy-swift/Sources/Core` /// /// - Returns: The list of Smithy runtime modules. diff --git a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/AWSSDKSwiftCLI/AWSSDKSwiftCLI.swift b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/AWSSDKSwiftCLI/AWSSDKSwiftCLI.swift index 6858269b5ab..af3d28df8dc 100644 --- a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/AWSSDKSwiftCLI/AWSSDKSwiftCLI.swift +++ b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/AWSSDKSwiftCLI/AWSSDKSwiftCLI.swift @@ -17,7 +17,8 @@ struct AWSSDKSwiftCLI: ParsableCommand { PrepareReleaseCommand.self, SyncClientRuntimeVersionCommand.self, TestAWSSDKCommand.self, - GenerateDocIndexCommand.self + GenerateDocIndexCommand.self, + GenerateSmokeTestsPackageManifestCommand.self ] ) } diff --git a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/AWSSDKSwiftCLI/Subcommands/GenerateSmokeTestsPackageManifest.swift b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/AWSSDKSwiftCLI/Subcommands/GenerateSmokeTestsPackageManifest.swift new file mode 100644 index 00000000000..15ec0c73390 --- /dev/null +++ b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/AWSSDKSwiftCLI/Subcommands/GenerateSmokeTestsPackageManifest.swift @@ -0,0 +1,72 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import ArgumentParser +import Foundation +import AWSCLIUtils + +struct GenerateSmokeTestsPackageManifestCommand: ParsableCommand { + static var configuration = CommandConfiguration( + commandName: "generate-smoke-tests-package-manifest", + abstract: "Generates the Package.swift manifest for the aws-sdk-swift/SmokeTests package." + ) + + @Argument(help: "The path to the aws-sdk-swift repository") + var repoPath: String + + func run() throws { + let generateSmokeTestsPackageManifest = GenerateSmokeTestsPackageManifest( + repoPath: repoPath + ) + try generateSmokeTestsPackageManifest.run() + } +} + +struct GenerateSmokeTestsPackageManifest { + /// The path to the package repository + let repoPath: String + + func run() throws { + try FileManager.default.changeWorkingDirectory(repoPath) + // Generate package manifest for smoke tests and save it as aws-sdk-swift/SmokeTests/Package.swift + let smokeTestsContents = try generateSmokeTestsPackageManifestContents() + try savePackageManifest(smokeTestsContents) + } + + // MARK: - Helpers + + func generateSmokeTestsPackageManifestContents() throws -> String { + return [ + // SmokeTests package manifest uses same prefix as one for aws-sdk-swift. + try PackageManifestBuilder.contentReader(filename: "Package.Prefix")(), + try generateServiceNamesArray(), + try PackageManifestBuilder.contentReader(filename: "SmokeTestsPackage.Base")() + ].joined(separator: .newline) + } + + func generateServiceNamesArray() throws -> String { + let servicesWithSmokeTests = try FileManager.default.servicesWithSmokeTests() + let formatedServiceList = servicesWithSmokeTests.map { "\t\"\($0)\"," }.joined(separator: .newline) + return [ + "// All services that have smoke tests generated for them.", + "let serviceNames: [String] = [", + formatedServiceList, + "]" + ].joined(separator: .newline) + } + + func savePackageManifest(_ contents: String) throws { + let packageFilePath = "SmokeTests/Package.swift" + log("Saving package manifest to \(packageFilePath)...") + try contents.write( + toFile: packageFilePath, + atomically: true, + encoding: .utf8 + ) + log("Successfully saved package manifest to \(packageFilePath)") + } +} diff --git a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Resources/SmokeTestsPackage.Base.txt b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Resources/SmokeTestsPackage.Base.txt new file mode 100644 index 00000000000..537ffc87374 --- /dev/null +++ b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Resources/SmokeTestsPackage.Base.txt @@ -0,0 +1,39 @@ +// MARK: - Static Content + +extension Target.Dependency { + // AWS runtime module + static var awsClientRuntime: Self { .product(name: "AWSClientRuntime", package: "aws-sdk-swift") } + // Smithy runtime module + static var clientRuntime: Self { .product(name: "ClientRuntime", package: "smithy-swift") } +} + +let package = Package( + name: "SmokeTests", + platforms: [ + .macOS(.v10_15) + ], + products: serviceNames.map(productForRunner(_:)), + dependencies: [ + .package(path: "../../smithy-swift"), + .package(path: "../../aws-sdk-swift") + ], + targets: serviceNames.map(targetForRunner(_:)) +) + +// MARK: - Helper functions + +private func productForRunner(_ serviceName: String) -> Product { + .executable(name: "\(serviceName)SmokeTestRunner", targets: ["\(serviceName)SmokeTestRunner"]) +} + +private func targetForRunner(_ serviceName: String) -> Target { + .executableTarget( + name: "\(serviceName)SmokeTestRunner", + dependencies: [ + .clientRuntime, + .awsClientRuntime, + .product(name: "\(serviceName)", package: "aws-sdk-swift") + ], + path: "\(serviceName)SmokeTestRunner" + ) +} diff --git a/SmokeTests/.gitkeep b/SmokeTests/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/codegen/sdk-codegen/build.gradle.kts b/codegen/sdk-codegen/build.gradle.kts index ed342d159bb..34e88492b94 100644 --- a/codegen/sdk-codegen/build.gradle.kts +++ b/codegen/sdk-codegen/build.gradle.kts @@ -203,13 +203,23 @@ val AwsService.modelExtrasDir: String task("stageSdks") { group = "codegen" - description = "relocate generated SDK(s) from build directory to Sources and Tests directories" + description = "relocate generated SDK artifacts from build directory to correct locations" doLast { discoveredServices.forEach { logger.info("copying ${it.outputDir} source to ${it.sourcesDir}") copy { - from("${it.outputDir}") - into("${it.sourcesDir}") + from(it.outputDir) + into(it.sourcesDir) + exclude { details -> + // Exclude `SmokeTests` directory + details.file.name.endsWith("SmokeTests") + } + } + + logger.info("copying ${it.outputDir}/SmokeTests to SmokeTests") + copy { + from("${it.outputDir}/SmokeTests") + into(rootProject.file("SmokeTests").absolutePath) } } } diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSHTTPBindingProtocolGenerator.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSHTTPBindingProtocolGenerator.kt index 32dcbdc56cf..73764d6ca54 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSHTTPBindingProtocolGenerator.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSHTTPBindingProtocolGenerator.kt @@ -36,8 +36,8 @@ abstract class AWSHTTPBindingProtocolGenerator( val requestTestBuilder = HttpProtocolUnitTestRequestGenerator.Builder() val responseTestBuilder = HttpProtocolUnitTestResponseGenerator.Builder() val errorTestBuilder = HttpProtocolUnitTestErrorGenerator.Builder() - open val testsToIgnore: Set = setOf() - open val tagsToIgnore: Set = setOf() + open val protocolTestsToIgnore: Set = setOf() + open val protocolTestTagsToIgnore: Set = setOf() override val shouldRenderEncodableConformance = false override fun generateProtocolUnitTests(ctx: ProtocolGenerator.GenerationContext): Int { @@ -48,11 +48,15 @@ abstract class AWSHTTPBindingProtocolGenerator( errorTestBuilder, customizations, getProtocolHttpBindingResolver(ctx, defaultContentType), - testsToIgnore, - tagsToIgnore, + protocolTestsToIgnore, + protocolTestTagsToIgnore, ).generateProtocolTests() + renderEndpointsTests(ctx) } + override fun generateSmokeTests(ctx: ProtocolGenerator.GenerationContext) { + return AWSSmokeTestGenerator(ctx).generateSmokeTests() + } + fun renderEndpointsTests(ctx: ProtocolGenerator.GenerationContext): Int { val ruleSetNode = ctx.service.getTrait()?.ruleSet val ruleSet = if (ruleSetNode != null) EndpointRuleSet.fromNode(ruleSetNode) else null diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSSmokeTestGenerator.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSSmokeTestGenerator.kt new file mode 100644 index 00000000000..aeb317c8557 --- /dev/null +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSSmokeTestGenerator.kt @@ -0,0 +1,77 @@ +package software.amazon.smithy.aws.swift.codegen + +import software.amazon.smithy.aws.traits.ServiceTrait +import software.amazon.smithy.model.node.ObjectNode +import software.amazon.smithy.swift.codegen.SwiftWriter +import software.amazon.smithy.swift.codegen.integration.ProtocolGenerator +import software.amazon.smithy.swift.codegen.integration.SmokeTestGenerator +import software.amazon.smithy.swift.codegen.utils.toUpperCamelCase + +class AWSSmokeTestGenerator( + private val ctx: ProtocolGenerator.GenerationContext +) : SmokeTestGenerator(ctx) { + // Filter out tests by name or tag at codegen time. + // Each element must have the prefix ":" before the test name or tag name. + // E.g., "AWSS3:GetObjectTest" or "AWSS3:BucketTests" + override val smokeTestIdsToIgnore = setOf( + // Add smoke test name to ignore here: + // E.g., "AWSACM:GetCertificateFailure", + ) + override val smokeTestTagsToIgnore = setOf( + // Add smoke test tag to ignore here: + // E.g., "AWSACM:TagToIgnore", + ) + + override fun getServiceName(): String { + return "AWS" + ctx.service.getTrait(ServiceTrait::class.java).get().sdkId.toUpperCamelCase() + } + + override fun getClientName(): String { + return ctx.service.getTrait(ServiceTrait::class.java).get().sdkId.toUpperCamelCase().removeSuffix("Service") + "Client" + } + + override fun renderCustomFilePrivateVariables(writer: SwiftWriter) { + writer.write("fileprivate let regionFromEnv = ProcessInfo.processInfo.environment[\"AWS_SMOKE_TEST_REGION\"]") + writer.write("fileprivate let tagsToSkip = (ProcessInfo.processInfo.environment[\"AWS_SMOKE_TEST_SKIP_TAGS\"] ?? \"\").components(separatedBy: \",\")") + } + + override fun handleVendorParams(vendorParams: ObjectNode, writer: SwiftWriter) { + val nameToValueMappings = getFormattedVendorParams(vendorParams) + nameToValueMappings.forEach { mapping -> + writer.write("config.${mapping.key} = ${mapping.value}") + } + } + + // Converts trait definition vendor param key:value pairs to Swift SDK config field:value pairs. + private fun getFormattedVendorParams(vendorParams: ObjectNode): Map { + val formattedMapping = mutableMapOf() + vendorParams.members.forEach { originalMapping -> + when (originalMapping.key.value) { + /* BaseAwsVendorParams members */ + "region" -> { + // Take region value retrieved from environment variable if present; otherwise, take from trait definition. + val regionValue = "regionFromEnv ?? \"${originalMapping.value.expectStringNode().value}\"" + formattedMapping.put("region", regionValue) + formattedMapping.put("signingRegion", regionValue) + } + "sigv4aRegionSet" -> { /* no-op; setting multiple signing regions in config is unsupported atm. */ } + "uri" -> { formattedMapping.put("endpoint", "\"${originalMapping.value.expectStringNode().value}\"") } + "useFips" -> { formattedMapping.put("useFIPS", originalMapping.value.expectBooleanNode().value.toString()) } + "useDualstack" -> { formattedMapping.put("useDualStack", originalMapping.value.expectBooleanNode().value.toString()) } + "useAccountIdRouting" -> { /* no-op; setting account ID routing in config is unsupported atm. */ } + + /* S3VendorParams members */ + "useAccelerate" -> { formattedMapping.put("accelerate", originalMapping.value.expectBooleanNode().value.toString()) } + "useMultiRegionAccessPoints" -> { + // Name for corresponding config in Swift SDK is: `disableMultiRegionAccessPoints`; value needs to be flipped. + formattedMapping.put("disableMultiRegionAccessPoints", (!(originalMapping.value.expectBooleanNode().value)).toString()) + } + "useGlobalEndpoint", "forcePathStyle", "useArnRegion" -> { + // No change needed for these + formattedMapping.put(originalMapping.key.value, originalMapping.value.expectBooleanNode().value.toString()) + } + } + } + return formattedMapping + } +} diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsjson/AWSJSON1_0ProtocolGenerator.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsjson/AWSJSON1_0ProtocolGenerator.kt index e1506fd9dc4..5ff59ae248f 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsjson/AWSJSON1_0ProtocolGenerator.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsjson/AWSJSON1_0ProtocolGenerator.kt @@ -19,7 +19,7 @@ class AWSJSON1_0ProtocolGenerator : AWSHTTPBindingProtocolGenerator(AWSJSONCusto override val defaultContentType = "application/x-amz-json-1.0" override val protocol: ShapeId = AwsJson1_0Trait.ID override val shouldRenderEncodableConformance: Boolean = true - override val testsToIgnore = setOf( + override val protocolTestsToIgnore = setOf( "SDKAppliedContentEncoding_awsJson1_0", "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_0", ) diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsjson/AWSJSON1_1ProtocolGenerator.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsjson/AWSJSON1_1ProtocolGenerator.kt index fa4cf34548b..0b583f4c998 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsjson/AWSJSON1_1ProtocolGenerator.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsjson/AWSJSON1_1ProtocolGenerator.kt @@ -19,7 +19,7 @@ class AWSJSON1_1ProtocolGenerator : AWSHTTPBindingProtocolGenerator(AWSJSONCusto override val defaultContentType = "application/x-amz-json-1.1" override val protocol: ShapeId = AwsJson1_1Trait.ID override val shouldRenderEncodableConformance: Boolean = true - override val testsToIgnore = setOf( + override val protocolTestsToIgnore = setOf( "SDKAppliedContentEncoding_awsJson1_1", "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_1", ) diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsquery/AWSQueryProtocolGenerator.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsquery/AWSQueryProtocolGenerator.kt index 6b90e716075..e9a7c58b075 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsquery/AWSQueryProtocolGenerator.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/awsquery/AWSQueryProtocolGenerator.kt @@ -23,7 +23,7 @@ open class AWSQueryProtocolGenerator : AWSHTTPBindingProtocolGenerator(AWSQueryC HttpBindingResolver = FormURLHttpBindingResolver(ctx, defaultContentType) override val shouldRenderEncodableConformance = true - override val testsToIgnore = setOf( + override val protocolTestsToIgnore = setOf( "SDKAppliedContentEncoding_awsQuery", "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsQuery", ) diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/ec2query/EC2QueryProtocolGenerator.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/ec2query/EC2QueryProtocolGenerator.kt index 449ad111070..53b12cabbc8 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/ec2query/EC2QueryProtocolGenerator.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/ec2query/EC2QueryProtocolGenerator.kt @@ -23,7 +23,7 @@ class EC2QueryProtocolGenerator : AWSHTTPBindingProtocolGenerator(EC2QueryCustom HttpBindingResolver = FormURLHttpBindingResolver(ctx, contentType) override val shouldRenderEncodableConformance = true - override val testsToIgnore = setOf( + override val protocolTestsToIgnore = setOf( "SDKAppliedContentEncoding_ec2Query", "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_ec2Query" ) diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/restjson/AWSRestJson1ProtocolGenerator.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/restjson/AWSRestJson1ProtocolGenerator.kt index b745bebbc28..4fff69196fd 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/restjson/AWSRestJson1ProtocolGenerator.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/restjson/AWSRestJson1ProtocolGenerator.kt @@ -11,7 +11,7 @@ import software.amazon.smithy.model.shapes.ShapeId class AWSRestJson1ProtocolGenerator : AWSHTTPBindingProtocolGenerator(RestJSONCustomizations()) { override val defaultContentType = "application/json" override val protocol: ShapeId = RestJson1Trait.ID - override val testsToIgnore = setOf( + override val protocolTestsToIgnore = setOf( "SDKAppliedContentEncoding_restJson1", "SDKAppendedGzipAfterProvidedEncoding_restJson1", ) diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/restxml/RestXMLProtocolGenerator.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/restxml/RestXMLProtocolGenerator.kt index 360f3ff15e4..fd9e9a152f4 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/restxml/RestXMLProtocolGenerator.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/protocols/restxml/RestXMLProtocolGenerator.kt @@ -13,7 +13,7 @@ import software.amazon.smithy.swift.codegen.integration.ProtocolGenerator class RestXMLProtocolGenerator : AWSHTTPBindingProtocolGenerator(RestXMLCustomizations()) { override val defaultContentType: String = "application/xml" override val protocol: ShapeId = RestXmlTrait.ID - override val testsToIgnore: Set = setOf( + override val protocolTestsToIgnore: Set = setOf( "S3DefaultAddressing", // can leave disabled, pre-endpoints 2.0 "S3VirtualHostAddressing", // can leave disabled, pre-endpoints 2.0 "S3VirtualHostDualstackAddressing", // can leave disabled, pre-endpoints 2.0 diff --git a/scripts/codegen.sh b/scripts/codegen.sh index e04596ab867..53e38550e87 100755 --- a/scripts/codegen.sh +++ b/scripts/codegen.sh @@ -23,6 +23,7 @@ rm -rf codegen/sdk-codegen/build/smithyprojections/sdk-codegen/* rm -rf ServiceClients/* rm -rf Sources/Services/* rm -rf Tests/Services/* +rm -rf SmokeTests/* # Regenerate code ./gradlew -p codegen/sdk-codegen build diff --git a/scripts/run-every-smoke-test.sh b/scripts/run-every-smoke-test.sh new file mode 100755 index 00000000000..3cb3dd77f99 --- /dev/null +++ b/scripts/run-every-smoke-test.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# This is a convenience script for developers for running every smoke test under SmokeTests/. +# The script must be run from aws-sdk-swift/, the directory containing SmokeTests/. + +# cd into test module dir +cd SmokeTests/ || { echo "ERROR: Failed to change directory to SmokeTests."; exit 1; } + +# Build and discard output for clean log +echo "INFO: Building SmokeTests module..." +swift build > /dev/null 2>&1 + +# Header print helpers +print_header() { + print_spacer + local header=$1 + echo "##### $header #####" + print_spacer +} + +print_spacer() { + echo "" +} + +# Build and run each and every test runner; save result to results array +print_header "TEST RUNS" +results=() +for runnerName in ./*; do + if [ -d "$runnerName" ]; then + swift run "${runnerName#./}" + if [ $? -eq 0 ]; then + # Record success + results+=("SUCCESS: ${runnerName#./}") + else + # record failure + results+=("FAILURE: ${runnerName#./}") + fi + print_spacer + fi +done + +# Print result summary +print_header "TEST RESULT SUMMARY" +for result in "${results[@]}"; do + echo "$result" +done diff --git a/scripts/run-smoke-tests.sh b/scripts/run-smoke-tests.sh new file mode 100755 index 00000000000..227cce92af1 --- /dev/null +++ b/scripts/run-smoke-tests.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# This script must be run from the directory containing aws-sdk-swift. +SMOKE_TESTS_DIR="aws-sdk-swift/SmokeTests/" +cd "$SMOKE_TESTS_DIR" || { echo "ERROR: Failed to change directory to $SMOKE_TESTS_DIR"; exit 1; } + +print_header() { + local header=$1 + print_empty_line + echo "##### $header #####" + print_empty_line +} + +print_empty_line() { + echo "" +} + +print_header "SETUP SMOKE TESTS" + +# Clean build +swift package clean > /dev/null 2>&1 + +# Expect comma-separated service names from AWS_SMOKE_TEST_SERVICE_IDS environment variable. +# The service names in environment variable must be in the format "AWSName", e.g., "AWSS3". +# The resulting array will be in the format "AWSNameSmokeTestRunner", e.g., "AWSS3SmokeTestRunner". +if [ -z "$AWS_SMOKE_TEST_SERVICE_IDS" ]; then + echo "INFO: The environment variable AWS_SMOKE_TEST_SERVICE_IDS is not set or is empty." + echo "INFO: It must set to a comma-separated string of service names for which you want to run smoke test for." + echo "INFO: Exiting run-smoke-tests.sh with exit code 0." + exit 0 +else + IFS=',' read -r -a testRunnerNames <<< "$AWS_SMOKE_TEST_SERVICE_IDS" + for i in "${!testRunnerNames[@]}"; do + testRunnerNames[$i]="${testRunnerNames[$i]}SmokeTestRunner" + done + echo "INFO: Retrieved the value of AWS_SMOKE_TEST_SERVICE_IDS: $AWS_SMOKE_TEST_SERVICE_IDS." + echo "INFO: Constructed test runner names: ${testRunnerNames[@]}" +fi + +# Array of test failure logs. +testFailureLogs=() + +print_header "RUN SMOKE TESTS" + +for testRunnerName in "${testRunnerNames[@]}"; do + # If test runner was generated under SmokeTests/ + if [ -d "$testRunnerName" ]; then + echo "INFO: Found smoke tests for the service ${testRunnerName%SmokeTestRunner}." + echo "INFO: Building smoke test(s) for the service ${testRunnerName%SmokeTestRunner}..." + # Build the test runner executable (discard output for clean log) + swift build --target "$testRunnerName" > /dev/null 2>&1 + echo "INFO: Running smoke test(s) for the service ${testRunnerName%SmokeTestRunner}..." + # Run executable and save output to `testRunOutput` + testRunOutput=$(swift run --quiet "$testRunnerName") + # Get test runner exit code + testRunExitCode=$? + # If exit code was 1, one or more tests failed. Save its output to array. + if [ "$testRunExitCode" -eq 1 ]; then + testFailureLogs+=("$testRunOutput") + fi + print_empty_line + # If no smoke tests were generated, no-op + else + echo "INFO: No smoke tests found for the service ${testRunnerName%SmokeTestRunner}. Skipping..." + print_empty_line + fi +done + +print_header "SMOKE TEST RESULTS" + +# Log any failure outputs if present and exit with 1 +if [ ${#testFailureLogs[@]} -gt 0 ]; then + echo "# One or more smoke test(s) failed. See the log(s) for failed test runner(s) below:" + print_empty_line + for failureLog in "${testFailureLogs[@]}"; do + echo "${failureLog}" + print_empty_line + done + exit 1 +else + echo "INFO: Every smoke test for every service passed!" + exit 0 +fi