From 36d121f8fcae212b8a1f5814d9e055abfc44bf9f Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Wed, 30 Nov 2022 11:17:32 -0600 Subject: [PATCH 01/19] Use acceptors branch of smithy-swift --- Package.swift | 2 +- packageDependencies.plist | 2 +- scripts/regen.sh | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100755 scripts/regen.sh diff --git a/Package.swift b/Package.swift index 2270e057886..f04c5d5f511 100644 --- a/Package.swift +++ b/Package.swift @@ -340,7 +340,7 @@ let package = Package( .library(name: "AWSXRay", targets: ["AWSXRay"]), ], dependencies: [ - .package(url: "https://github.com/awslabs/smithy-swift", branch: "main"), + .package(url: "https://github.com/awslabs/smithy-swift", branch: "jbe/acceptors"), .package(url: "https://github.com/awslabs/aws-crt-swift", branch: "main") ], targets: [ diff --git a/packageDependencies.plist b/packageDependencies.plist index e2a9bc727a3..dc2df5e2fa2 100644 --- a/packageDependencies.plist +++ b/packageDependencies.plist @@ -7,7 +7,7 @@ awsCRTSwiftVersion 0.3.1 clientRuntimeBranch - main + jbe/acceptors awsCRTSwiftBranch main diff --git a/scripts/regen.sh b/scripts/regen.sh new file mode 100755 index 00000000000..4753052c71d --- /dev/null +++ b/scripts/regen.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +osascript -e 'quit app "Xcode"' +rm -rf release/ +./gradlew -p codegen/sdk-codegen build +./gradlew -p codegen/sdk-codegen stageSdks +./scripts/mergeModels.sh release +./scripts/generatePackageSwift.swift > Package.swift +open -a Xcode From 76d819181f96322a071a93299d1f6d5d1f0e77b0 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Wed, 30 Nov 2022 17:33:32 -0600 Subject: [PATCH 02/19] Code-generate a waiter and run tests against its acceptors --- codegen/Package.swift | 2 + .../waitersTests/WaitersTests.swift | 63 +++++++++++++++++++ .../build.gradle.kts | 4 ++ .../model/main.smithy | 53 +++++++++++++++- 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift diff --git a/codegen/Package.swift b/codegen/Package.swift index 1de338ef4d4..8ae79ecf3ab 100644 --- a/codegen/Package.swift +++ b/codegen/Package.swift @@ -59,6 +59,8 @@ appendLibTarget(name: "aws_restjson", path: "\(baseDirLocal)/aws-restjson") appendTstTarget(name: "aws_restjsonTests", path: "\(baseDirLocal)/aws-restjson", dependency: "aws_restjson") appendLibTarget(name: "rest_json_extras", path: "\(baseDirLocal)/rest_json_extras") appendTstTarget(name: "rest_json_extrasTests", path: "\(baseDirLocal)/rest_json_extras", dependency: "rest_json_extras") +appendLibTarget(name: "waiters", path: "\(baseDirLocal)/waiters") +appendTstTarget(name: "waitersTests", path: "./protocol-test-codegen-local/Tests", dependency: "waiters") func appendLibTarget(name: String, path: String) { package.targets.append( diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift new file mode 100644 index 00000000000..ad934f40417 --- /dev/null +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift @@ -0,0 +1,63 @@ +import XCTest +@testable import waiters +@testable import ClientRuntime + +class WaitersTests: XCTestCase { + + func test_existsWaiter_hasSuccessWaiterAtPosition0() async throws { + let waiterConfig = try WaitersClient.existsWaiterConfig() + let subject = waiterConfig.acceptors[0] + XCTAssertEqual(subject.state, .success) + } + + func test_existsWaiter_waiterAtPosition0MatchesOnOutput() async throws { + let input = GetWidgetInput(payload: "abc") + let output = GetWidgetOutputResponse(payload: "def") + let waiterConfig = try WaitersClient.existsWaiterConfig() + let subject = waiterConfig.acceptors[0] + let match = subject.evaluate(input: input, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_existsWaiter_waiterAtPosition0FailsToMatchOnError() async throws { + let input = GetWidgetInput(payload: "abc") + let waiterConfig = try WaitersClient.existsWaiterConfig() + let subject = waiterConfig.acceptors[0] + let match = subject.evaluate(input: input, result: .failure("boom")) + XCTAssertNil(match) + } +} + +extension WaiterConfiguration.Acceptor.Match: Equatable where Input: Equatable, Output: Equatable { + + public static func == ( + lhs: ClientRuntime.WaiterConfiguration.Acceptor.Match, + rhs: ClientRuntime.WaiterConfiguration.Acceptor.Match + ) -> Bool { + switch (lhs, rhs) { + case (.success(let left), .success(let right)): + return compare(left, right) + case (.failure(let left), .failure(let right)): + return compare(left, right) + case (.retry, .retry): + return true + default: + return false + } + } + + private static func compare(_ lhs: Result, _ rhs: Result) -> Bool { + switch (lhs, rhs) { + case (.success(let left), .success(let right)): + return left == right + case (.failure(let left), .failure(let right)): + return left.localizedDescription == right.localizedDescription + default: + return false + } + } +} + +extension String: Error { + var localizedString: String? { self } +} diff --git a/codegen/protocol-test-codegen-local/build.gradle.kts b/codegen/protocol-test-codegen-local/build.gradle.kts index 5bf69d95f3c..e7c72349fd2 100644 --- a/codegen/protocol-test-codegen-local/build.gradle.kts +++ b/codegen/protocol-test-codegen-local/build.gradle.kts @@ -35,6 +35,10 @@ val codegenTests = listOf( CodegenTest( "aws.protocoltests.restjson#RestJsonExtras", "rest_json_extras" + ), + CodegenTest( + "aws.protocoltests.restjson#Waiters", + "waiters" ) ) diff --git a/codegen/protocol-test-codegen-local/model/main.smithy b/codegen/protocol-test-codegen-local/model/main.smithy index ce883cec184..54752f5587e 100644 --- a/codegen/protocol-test-codegen-local/model/main.smithy +++ b/codegen/protocol-test-codegen-local/model/main.smithy @@ -2,6 +2,7 @@ $version: "1.0" namespace aws.protocoltests.restjson +use smithy.waiters#waitable use aws.protocols#restJson1 use aws.api#service use smithy.test#httpRequestTests @@ -138,4 +139,54 @@ structure EnumQueryInput { @httpLabel @required enum: StringEnum -} \ No newline at end of file +} + + +/// A REST JSON service that sends JSON requests and responses. +@service(sdkId: "Waiters Protocol") +@restJson1 +service Waiters { + version: "2022-11-30", + operations: [GetWidget] +} + +@http(uri: "/widget", method: "GET") +@readonly +@httpRequestTests([ + { + id: "Widget", + uri: "/widget", + method: "GET", + queryParams: ["payload=queryInput"] + protocol: "aws.protocols#restJson1" + } +]) +@waitable( + Exists: { + documentation: "Waits until the widget exists" + acceptors: [ + // Acceptor 0 matches on success, and transitions waiting to the success state. + { + state: "success" + matcher: { + success: true + } + } + ] + } +) +operation GetWidget { + input: WidgetInput, + output: WidgetOutput +} + +structure WidgetInput { + @httpQuery("payload") + payload: String +} + +structure WidgetOutput { + @httpPayload + payload: String +} + From 48c2ef744799823137c4387a4c5bb17e74945cf5 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Wed, 30 Nov 2022 17:58:51 -0600 Subject: [PATCH 03/19] Cleanup --- .../Tests/swift-codegen/waitersTests/WaitersTests.swift | 8 +++++--- codegen/protocol-test-codegen-local/model/main.smithy | 8 ++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift index ad934f40417..fd0250284de 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift @@ -4,13 +4,13 @@ import XCTest class WaitersTests: XCTestCase { - func test_existsWaiter_hasSuccessWaiterAtPosition0() async throws { + func test_existsWaiterConfig_hasSuccessWaiterAtPosition0() async throws { let waiterConfig = try WaitersClient.existsWaiterConfig() let subject = waiterConfig.acceptors[0] XCTAssertEqual(subject.state, .success) } - func test_existsWaiter_waiterAtPosition0MatchesOnOutput() async throws { + func test_existsWaiterConfig_acceptorAtPosition0MatchesOnOutput() async throws { let input = GetWidgetInput(payload: "abc") let output = GetWidgetOutputResponse(payload: "def") let waiterConfig = try WaitersClient.existsWaiterConfig() @@ -19,7 +19,7 @@ class WaitersTests: XCTestCase { XCTAssertEqual(match, .success(.success(output))) } - func test_existsWaiter_waiterAtPosition0FailsToMatchOnError() async throws { + func test_existsWaiterConfig_acceptorAtPosition0FailsToMatchOnError() async throws { let input = GetWidgetInput(payload: "abc") let waiterConfig = try WaitersClient.existsWaiterConfig() let subject = waiterConfig.acceptors[0] @@ -28,6 +28,8 @@ class WaitersTests: XCTestCase { } } +// Convenience test-helper methods for testing acceptor matches + extension WaiterConfiguration.Acceptor.Match: Equatable where Input: Equatable, Output: Equatable { public static func == ( diff --git a/codegen/protocol-test-codegen-local/model/main.smithy b/codegen/protocol-test-codegen-local/model/main.smithy index 54752f5587e..75832615dfd 100644 --- a/codegen/protocol-test-codegen-local/model/main.smithy +++ b/codegen/protocol-test-codegen-local/model/main.smithy @@ -141,8 +141,12 @@ structure EnumQueryInput { enum: StringEnum } - -/// A REST JSON service that sends JSON requests and responses. +// A service which has a GET operation with a waiter defined upon it. +// The acceptors in the waiter serve as subjects for unit testing, +// to ensure that the logic in code-generated acceptors works as +// expected. +// The service also has a protocol test defined on it but that test +// is unused.` @service(sdkId: "Waiters Protocol") @restJson1 service Waiters { From f1ff3f9bfe619f1f99e1a0a096fc4482ec5365de Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Thu, 1 Dec 2022 13:12:23 -0600 Subject: [PATCH 04/19] Add more test waiters & unit tests --- codegen/Package.swift | 8 +- .../waitersTests/WaitersTests.swift | 85 ++++++++++++++++--- .../build.gradle.kts | 2 +- .../model/main.smithy | 73 +++++++++++----- scripts/protogen.sh | 9 ++ 5 files changed, 135 insertions(+), 42 deletions(-) create mode 100755 scripts/protogen.sh diff --git a/codegen/Package.swift b/codegen/Package.swift index 8ae79ecf3ab..a161c71ab46 100644 --- a/codegen/Package.swift +++ b/codegen/Package.swift @@ -59,8 +59,8 @@ appendLibTarget(name: "aws_restjson", path: "\(baseDirLocal)/aws-restjson") appendTstTarget(name: "aws_restjsonTests", path: "\(baseDirLocal)/aws-restjson", dependency: "aws_restjson") appendLibTarget(name: "rest_json_extras", path: "\(baseDirLocal)/rest_json_extras") appendTstTarget(name: "rest_json_extrasTests", path: "\(baseDirLocal)/rest_json_extras", dependency: "rest_json_extras") -appendLibTarget(name: "waiters", path: "\(baseDirLocal)/waiters") -appendTstTarget(name: "waitersTests", path: "./protocol-test-codegen-local/Tests", dependency: "waiters") +appendLibTarget(name: "Waiters", path: "\(baseDirLocal)/Waiters") +appendTstTarget(name: "WaitersTests", path: "./protocol-test-codegen-local/Tests", dependency: "Waiters") func appendLibTarget(name: String, path: String) { package.targets.append( @@ -105,7 +105,7 @@ if let smithySwiftDir = ProcessInfo.processInfo.environment["SMITHY_SWIFT_CI_DIR ] } else { package.dependencies += [ - .package(path: "~/Projects/Amplify/SwiftSDK/smithy-swift"), - .package(path: "~/Projects/Amplify/SwiftSDK/aws-sdk-swift"), + .package(path: "../../smithy-swift"), + .package(path: "../../aws-sdk-swift"), ] } diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift index fd0250284de..1a4ef56ea40 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift @@ -1,31 +1,87 @@ import XCTest -@testable import waiters +@testable import Waiters @testable import ClientRuntime class WaitersTests: XCTestCase { - func test_existsWaiterConfig_hasSuccessWaiterAtPosition0() async throws { - let waiterConfig = try WaitersClient.existsWaiterConfig() + func test_successTrue_hasSuccessStateWaiter() async throws { + let waiterConfig = try WaitersClient.successTrueMatcherWaiterConfig() let subject = waiterConfig.acceptors[0] XCTAssertEqual(subject.state, .success) } - func test_existsWaiterConfig_acceptorAtPosition0MatchesOnOutput() async throws { - let input = GetWidgetInput(payload: "abc") - let output = GetWidgetOutputResponse(payload: "def") - let waiterConfig = try WaitersClient.existsWaiterConfig() - let subject = waiterConfig.acceptors[0] - let match = subject.evaluate(input: input, result: .success(output)) + func test_successTrue_acceptorMatchesOnOutput() async throws { + let output = GetWidgetOutputResponse(stringProperty: "def") + let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) XCTAssertEqual(match, .success(.success(output))) } - func test_existsWaiterConfig_acceptorAtPosition0FailsToMatchOnError() async throws { - let input = GetWidgetInput(payload: "abc") - let waiterConfig = try WaitersClient.existsWaiterConfig() - let subject = waiterConfig.acceptors[0] - let match = subject.evaluate(input: input, result: .failure("boom")) + func test_successTrue_acceptorFailsToMatchOnError() async throws { + let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .failure("boom")) + XCTAssertNil(match) + } + + func test_successFalse_acceptorFailsToMatchOnOutput() async throws { + let output = GetWidgetOutputResponse(stringProperty: "def") + let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_successFalse_acceptorMatchesOnError() async throws { + let error = "boom" + let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .failure(error)) + XCTAssertEqual(match, .success(.failure(error))) + } + + func test_outputStringProperty_acceptorMatchesOnPropertyMatch() async throws { + let output = GetWidgetOutputResponse(stringProperty: "payload property contents") + let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_outputStringProperty_acceptorFailsToMatchOnPropertyMismatch() async throws { + let output = GetWidgetOutputResponse(stringProperty: "not the payload property contents") + let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) XCTAssertNil(match) } + + func test_outputStringProperty_acceptorFailsToMatchOnNullProperty() async throws { + let output = GetWidgetOutputResponse(stringProperty: nil) + let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_outputBooleanProperty_acceptorMatchesOnPropertyMatch() async throws { + let output = GetWidgetOutputResponse(booleanProperty: false) + let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_outputBooleanProperty_acceptorFailsToMatchOnPropertyMismatch() async throws { + let output = GetWidgetOutputResponse(booleanProperty: true) + let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_outputBooleanProperty_acceptorFailsToMatchOnNullProperty() async throws { + let output = GetWidgetOutputResponse(booleanProperty: nil) + let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + // MARK: - Helper methods + + private var anInput: GetWidgetInput { GetWidgetInput() } } // Convenience test-helper methods for testing acceptor matches @@ -60,6 +116,7 @@ extension WaiterConfiguration.Acceptor.Match: Equatable where Input: Equatable, } } +// Allows for the use of a string as an Error, for easy test validation & easy-to-read tests. extension String: Error { var localizedString: String? { self } } diff --git a/codegen/protocol-test-codegen-local/build.gradle.kts b/codegen/protocol-test-codegen-local/build.gradle.kts index e7c72349fd2..adb3cee029d 100644 --- a/codegen/protocol-test-codegen-local/build.gradle.kts +++ b/codegen/protocol-test-codegen-local/build.gradle.kts @@ -38,7 +38,7 @@ val codegenTests = listOf( ), CodegenTest( "aws.protocoltests.restjson#Waiters", - "waiters" + "Waiters" ) ) diff --git a/codegen/protocol-test-codegen-local/model/main.smithy b/codegen/protocol-test-codegen-local/model/main.smithy index 75832615dfd..0e4d85512c4 100644 --- a/codegen/protocol-test-codegen-local/model/main.smithy +++ b/codegen/protocol-test-codegen-local/model/main.smithy @@ -141,35 +141,22 @@ structure EnumQueryInput { enum: StringEnum } -// A service which has a GET operation with a waiter defined upon it. -// The acceptors in the waiter serve as subjects for unit testing, +// A service which has a GET operation with waiters defined upon it. +// The acceptor in each waiter serves as subject for unit testing, // to ensure that the logic in code-generated acceptors works as // expected. -// The service also has a protocol test defined on it but that test -// is unused.` -@service(sdkId: "Waiters Protocol") +@service(sdkId: "Waiters") @restJson1 service Waiters { version: "2022-11-30", operations: [GetWidget] } -@http(uri: "/widget", method: "GET") -@readonly -@httpRequestTests([ - { - id: "Widget", - uri: "/widget", - method: "GET", - queryParams: ["payload=queryInput"] - protocol: "aws.protocols#restJson1" - } -]) +@http(uri: "/widget", method: "POST") @waitable( - Exists: { - documentation: "Waits until the widget exists" + SuccessTrueMatcher: { + documentation: "Acceptor matches on successful request" acceptors: [ - // Acceptor 0 matches on success, and transitions waiting to the success state. { state: "success" matcher: { @@ -178,6 +165,47 @@ service Waiters { } ] } + SuccessFalseMatcher: { + documentation: "Acceptor matches on unsuccessful request" + acceptors: [ + { + state: "success" + matcher: { + success: false + } + } + ] + } + OutputStringPropertyMatcher: { + documentation: "Acceptor matches on output payload property" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "stringProperty" + expected: "payload property contents" + comparator: "stringEquals" + } + } + } + ] + } + OutputBooleanPropertyMatcher: { + documentation: "Acceptor matches on output payload property" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "booleanProperty" + expected: "false" + comparator: "booleanEquals" + } + } + } + ] + } ) operation GetWidget { input: WidgetInput, @@ -185,12 +213,11 @@ operation GetWidget { } structure WidgetInput { - @httpQuery("payload") - payload: String + stringProperty: String } structure WidgetOutput { - @httpPayload - payload: String + stringProperty: String + booleanProperty: Boolean } diff --git a/scripts/protogen.sh b/scripts/protogen.sh new file mode 100755 index 00000000000..a8b997ae9ae --- /dev/null +++ b/scripts/protogen.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +osascript -e 'quit app "Xcode"' +rm -rf codegen/protocol-test-codegen/build +rm -rf codegen/protocol-test-codegen-local/build +./gradlew -p codegen/protocol-test-codegen build +./gradlew -p codegen/protocol-test-codegen-local build +rm codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test-codegen-local/Waiters/swift-codegen/Package.swift +open -a Xcode From 917d6221f9f2c40b4fc8a6260da74383dd5c2cf5 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Thu, 1 Dec 2022 15:35:25 -0600 Subject: [PATCH 05/19] Added all/any comparator tests, input/output matcher --- .../WaitersTests/WaiterTestUtils.swift | 45 +++++ .../WaitersTests/WaitersTests.swift | 179 ++++++++++++++++++ .../waitersTests/WaitersTests.swift | 122 ------------ .../model/main.smithy | 54 ++++++ 4 files changed, 278 insertions(+), 122 deletions(-) create mode 100644 codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaiterTestUtils.swift create mode 100644 codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift delete mode 100644 codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaiterTestUtils.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaiterTestUtils.swift new file mode 100644 index 00000000000..80e43b0f73a --- /dev/null +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaiterTestUtils.swift @@ -0,0 +1,45 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import ClientRuntime + +// Convenience test-helper methods for testing acceptor matches + +extension WaiterConfiguration.Acceptor.Match: Equatable where Input: Equatable, Output: Equatable { + + public static func == ( + lhs: ClientRuntime.WaiterConfiguration.Acceptor.Match, + rhs: ClientRuntime.WaiterConfiguration.Acceptor.Match + ) -> Bool { + switch (lhs, rhs) { + case (.success(let left), .success(let right)): + return compare(left, right) + case (.failure(let left), .failure(let right)): + return compare(left, right) + case (.retry, .retry): + return true + default: + return false + } + } + + private static func compare(_ lhs: Result, _ rhs: Result) -> Bool { + switch (lhs, rhs) { + case (.success(let left), .success(let right)): + return left == right + case (.failure(let left), .failure(let right)): + return left.localizedDescription == right.localizedDescription + default: + return false + } + } +} + +// Allows for the use of a string as an Error, for easy test validation & easy-to-read tests. +extension String: Error { + var localizedString: String? { self } +} diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift new file mode 100644 index 00000000000..d2bdc6726b8 --- /dev/null +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift @@ -0,0 +1,179 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +@testable import Waiters +@testable import ClientRuntime + +class WaitersTests: XCTestCase { + + // MARK: - success matcher + + func test_successTrue_hasSuccessStateWaiter() async throws { + let waiterConfig = try WaitersClient.successTrueMatcherWaiterConfig() + let subject = waiterConfig.acceptors[0] + XCTAssertEqual(subject.state, .success) + } + + func test_successTrue_acceptorMatchesOnOutput() async throws { + let output = GetWidgetOutputResponse() + let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_successTrue_acceptorFailsToMatchOnError() async throws { + let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .failure("boom")) + XCTAssertNil(match) + } + + func test_successFalse_acceptorFailsToMatchOnOutput() async throws { + let output = GetWidgetOutputResponse() + let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_successFalse_acceptorMatchesOnError() async throws { + let error = "boom" + let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .failure(error)) + XCTAssertEqual(match, .success(.failure(error))) + } + + // MARK: - errorType matcher + + // none yet, will fill this when errorType is properly implemented + + // MARK: - output matcher + + func test_outputStringProperty_acceptorMatchesOnPropertyMatch() async throws { + let output = GetWidgetOutputResponse(stringProperty: "payload property contents") + let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_outputStringProperty_acceptorFailsToMatchOnPropertyMismatch() async throws { + let output = GetWidgetOutputResponse(stringProperty: "not the payload property contents") + let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_outputStringProperty_acceptorFailsToMatchOnNullProperty() async throws { + let output = GetWidgetOutputResponse(stringProperty: nil) + let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_outputBooleanProperty_acceptorMatchesOnPropertyMatch() async throws { + let output = GetWidgetOutputResponse(booleanProperty: false) + let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_outputBooleanProperty_acceptorFailsToMatchOnPropertyMismatch() async throws { + let output = GetWidgetOutputResponse(booleanProperty: true) + let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_outputBooleanProperty_acceptorFailsToMatchOnNullProperty() async throws { + let output = GetWidgetOutputResponse(booleanProperty: nil) + let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_arrayPropertyAll_acceptorMatchesWhenArrayElementsAllMatch() async throws { + let expected = "payload property contents" + let output = GetWidgetOutputResponse(stringArrayProperty: [expected, expected, expected]) + let subject = try WaitersClient.outputStringArrayAllPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_arrayPropertyAll_acceptorFailsToMatchWhenArrayElementsDontMatch() async throws { + let expected = "payload property contents" + let output = GetWidgetOutputResponse(stringArrayProperty: [expected, expected, "unexpected"]) + let subject = try WaitersClient.outputStringArrayAllPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_arrayPropertyAll_acceptorFailsToMatchWhenArrayIsEmpty() async throws { + let output = GetWidgetOutputResponse(stringArrayProperty: []) + let subject = try WaitersClient.outputStringArrayAllPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_arrayPropertyAll_acceptorFailsToMatchWhenArrayIsNull() async throws { + let output = GetWidgetOutputResponse(stringArrayProperty: nil) + let subject = try WaitersClient.outputStringArrayAllPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_arrayPropertyAny_acceptorMatchesWhenArrayElementsAllMatch() async throws { + let expected = "payload property contents" + let output = GetWidgetOutputResponse(stringArrayProperty: [expected, expected, expected]) + let subject = try WaitersClient.outputStringArrayAnyPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_arrayPropertyAny_acceptorMatchesWhenAllButOneElementMismatches() async throws { + let expected = "payload property contents" + let output = GetWidgetOutputResponse(stringArrayProperty: [expected, expected, "unexpected"]) + let subject = try WaitersClient.outputStringArrayAnyPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_arrayPropertyAny_acceptorFailsToMatchWhenAllElementsMismatch() async throws { + let unexpected = "unexpected" + let output = GetWidgetOutputResponse(stringArrayProperty: [unexpected, unexpected, unexpected]) + let subject = try WaitersClient.outputStringArrayAnyPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_arrayPropertyAny_acceptorFailsToMatchWhenArrayIsEmpty() async throws { + let output = GetWidgetOutputResponse(stringArrayProperty: []) + let subject = try WaitersClient.outputStringArrayAnyPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_arrayPropertyAny_acceptorFailsToMatchWhenArrayIsNull() async throws { + let output = GetWidgetOutputResponse(stringArrayProperty: nil) + let subject = try WaitersClient.outputStringArrayAnyPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + // MARK: - inputOutput matcher + + func test_inputOutput_acceptorMatchesWhenInputAndOutputPropertiesMatch() async throws { + let value = UUID().uuidString + let input = GetWidgetInput(stringProperty: value) + let output = GetWidgetOutputResponse(stringProperty: value) + let subject = try WaitersClient.inputOutputPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: input, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + // MARK: - Helper methods + + private var anInput: GetWidgetInput { GetWidgetInput() } +} diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift deleted file mode 100644 index 1a4ef56ea40..00000000000 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/waitersTests/WaitersTests.swift +++ /dev/null @@ -1,122 +0,0 @@ -import XCTest -@testable import Waiters -@testable import ClientRuntime - -class WaitersTests: XCTestCase { - - func test_successTrue_hasSuccessStateWaiter() async throws { - let waiterConfig = try WaitersClient.successTrueMatcherWaiterConfig() - let subject = waiterConfig.acceptors[0] - XCTAssertEqual(subject.state, .success) - } - - func test_successTrue_acceptorMatchesOnOutput() async throws { - let output = GetWidgetOutputResponse(stringProperty: "def") - let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertEqual(match, .success(.success(output))) - } - - func test_successTrue_acceptorFailsToMatchOnError() async throws { - let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .failure("boom")) - XCTAssertNil(match) - } - - func test_successFalse_acceptorFailsToMatchOnOutput() async throws { - let output = GetWidgetOutputResponse(stringProperty: "def") - let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertNil(match) - } - - func test_successFalse_acceptorMatchesOnError() async throws { - let error = "boom" - let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .failure(error)) - XCTAssertEqual(match, .success(.failure(error))) - } - - func test_outputStringProperty_acceptorMatchesOnPropertyMatch() async throws { - let output = GetWidgetOutputResponse(stringProperty: "payload property contents") - let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertEqual(match, .success(.success(output))) - } - - func test_outputStringProperty_acceptorFailsToMatchOnPropertyMismatch() async throws { - let output = GetWidgetOutputResponse(stringProperty: "not the payload property contents") - let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertNil(match) - } - - func test_outputStringProperty_acceptorFailsToMatchOnNullProperty() async throws { - let output = GetWidgetOutputResponse(stringProperty: nil) - let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertNil(match) - } - - func test_outputBooleanProperty_acceptorMatchesOnPropertyMatch() async throws { - let output = GetWidgetOutputResponse(booleanProperty: false) - let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertEqual(match, .success(.success(output))) - } - - func test_outputBooleanProperty_acceptorFailsToMatchOnPropertyMismatch() async throws { - let output = GetWidgetOutputResponse(booleanProperty: true) - let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertNil(match) - } - - func test_outputBooleanProperty_acceptorFailsToMatchOnNullProperty() async throws { - let output = GetWidgetOutputResponse(booleanProperty: nil) - let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertNil(match) - } - - // MARK: - Helper methods - - private var anInput: GetWidgetInput { GetWidgetInput() } -} - -// Convenience test-helper methods for testing acceptor matches - -extension WaiterConfiguration.Acceptor.Match: Equatable where Input: Equatable, Output: Equatable { - - public static func == ( - lhs: ClientRuntime.WaiterConfiguration.Acceptor.Match, - rhs: ClientRuntime.WaiterConfiguration.Acceptor.Match - ) -> Bool { - switch (lhs, rhs) { - case (.success(let left), .success(let right)): - return compare(left, right) - case (.failure(let left), .failure(let right)): - return compare(left, right) - case (.retry, .retry): - return true - default: - return false - } - } - - private static func compare(_ lhs: Result, _ rhs: Result) -> Bool { - switch (lhs, rhs) { - case (.success(let left), .success(let right)): - return left == right - case (.failure(let left), .failure(let right)): - return left.localizedDescription == right.localizedDescription - default: - return false - } - } -} - -// Allows for the use of a string as an Error, for easy test validation & easy-to-read tests. -extension String: Error { - var localizedString: String? { self } -} diff --git a/codegen/protocol-test-codegen-local/model/main.smithy b/codegen/protocol-test-codegen-local/model/main.smithy index 0e4d85512c4..032e943b245 100644 --- a/codegen/protocol-test-codegen-local/model/main.smithy +++ b/codegen/protocol-test-codegen-local/model/main.smithy @@ -191,6 +191,36 @@ service Waiters { } ] } + OutputStringArrayAllPropertyMatcher: { + documentation: "Acceptor matches on output payload property" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "stringArrayProperty" + expected: "payload property contents" + comparator: "allStringEquals" + } + } + } + ] + } + OutputStringArrayAnyPropertyMatcher: { + documentation: "Acceptor matches on output payload property" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "stringArrayProperty" + expected: "payload property contents" + comparator: "anyStringEquals" + } + } + } + ] + } OutputBooleanPropertyMatcher: { documentation: "Acceptor matches on output payload property" acceptors: [ @@ -206,6 +236,21 @@ service Waiters { } ] } + InputOutputPropertyMatcher: { + documentation: "Acceptor matches on input property equaling output property" + acceptors: [ + { + state: "success" + matcher: { + inputOutput: { + path: "input.stringProperty == output.stringProperty" + expected: "true" + comparator: "booleanEquals" + } + } + } + ] + } ) operation GetWidget { input: WidgetInput, @@ -218,6 +263,15 @@ structure WidgetInput { structure WidgetOutput { stringProperty: String + stringArrayProperty: StringArrayProperty booleanProperty: Boolean + booleanArrayProperty: BooleanArrayProperty +} + +list StringArrayProperty { + member: String } +list BooleanArrayProperty { + member: Boolean +} From a1fd875e47c3e5995f678ac5589c2f2ca0ba1f35 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Thu, 1 Dec 2022 20:06:50 -0600 Subject: [PATCH 06/19] Add tree structure to output --- .../WaitersTests/WaitersTests.swift | 51 ++++++++++++++ .../model/main.smithy | 70 +++++++++++++++++-- 2 files changed, 117 insertions(+), 4 deletions(-) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift index d2bdc6726b8..2cb95a0e877 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift @@ -173,7 +173,58 @@ class WaitersTests: XCTestCase { XCTAssertEqual(match, .success(.success(output))) } + // MARK: - Flatten operator + + func test_flatten_acceptorMatchesWhenFlattenedValueMatches() async throws { + let expected = "expected name" + let output = outputTree(embeddedName: expected) + let subject = try WaitersClient.flattenMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_flatten_acceptorDoesNotMatchWhenNoFlattenedValueMatches() async throws { + let unexpected = "not the expected name" + let output = outputTree(embeddedName: unexpected) + let subject = try WaitersClient.flattenMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_flattenLength1_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { + let unexpected = "not the expected name" + let output = outputTree(embeddedName: unexpected) + let subject = try WaitersClient.flattenLengthMatcher1WaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_flattenLength2_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { + let unexpected = "not the expected name" + let output = outputTree(embeddedName: unexpected) + let subject = try WaitersClient.flattenLengthMatcher2WaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + // MARK: - Helper methods private var anInput: GetWidgetInput { GetWidgetInput() } + + private func outputTree(globalName: String? = nil, embeddedName: String? = "c") -> GetWidgetOutputResponse { + GetWidgetOutputResponse(children: [ + .init(grandchildren: [ + .init(name: globalName ?? "a"), + .init(name: globalName ?? "b") + ]), + .init(grandchildren: [ + .init(name: embeddedName ?? globalName), + .init(name: globalName ?? "d") + ]), + .init(grandchildren: [ + .init(name: globalName ?? "e"), + .init(name: globalName ?? "f") + ]) + ]) + } } diff --git a/codegen/protocol-test-codegen-local/model/main.smithy b/codegen/protocol-test-codegen-local/model/main.smithy index 032e943b245..9bf71fe45dd 100644 --- a/codegen/protocol-test-codegen-local/model/main.smithy +++ b/codegen/protocol-test-codegen-local/model/main.smithy @@ -251,6 +251,51 @@ service Waiters { } ] } + FlattenMatcher: { + documentation: "Acceptor matches on flattened output property" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "children[*].grandchildren[*].name" + expected: "expected name" + comparator: "anyStringEquals" + } + } + } + ] + } + FlattenLengthMatcher1: { + documentation: "Acceptor matches on flattened output property" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "length(children[].grandchildren[]) == `6`" + expected: "true" + comparator: "booleanEquals" + } + } + } + ] + } + FlattenLengthMatcher2: { + documentation: "Acceptor matches on flattened output property" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "length(children[*].grandchildren[*]) == `3`" + expected: "true" + comparator: "booleanEquals" + } + } + } + ] + } ) operation GetWidget { input: WidgetInput, @@ -263,15 +308,32 @@ structure WidgetInput { structure WidgetOutput { stringProperty: String - stringArrayProperty: StringArrayProperty + stringArrayProperty: StringArray booleanProperty: Boolean - booleanArrayProperty: BooleanArrayProperty + booleanArrayProperty: BooleanArray + children: ChildArray +} + +structure Child { + grandchildren: GrandchildArray +} + +structure Grandchild { + name: String } -list StringArrayProperty { +list StringArray{ member: String } -list BooleanArrayProperty { +list BooleanArray{ member: Boolean } + +list ChildArray { + member: Child +} + +list GrandchildArray { + member: Grandchild +} From d8a1335b89e0d6aa1958b249096b3cd1b04dd606 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Thu, 1 Dec 2022 20:52:03 -0600 Subject: [PATCH 07/19] Fix JMESPath in flatten tests --- .../WaitersTests/WaitersTests.swift | 35 +++++++++++-------- .../model/main.smithy | 10 +++--- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift index 2cb95a0e877..8e1b0725b9a 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift @@ -191,36 +191,43 @@ class WaitersTests: XCTestCase { XCTAssertNil(match) } - func test_flattenLength1_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { + func test_flattenLength_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { let unexpected = "not the expected name" let output = outputTree(embeddedName: unexpected) - let subject = try WaitersClient.flattenLengthMatcher1WaiterConfig().acceptors[0] + let subject = try WaitersClient.flattenLengthMatcherWaiterConfig().acceptors[0] let match = subject.evaluate(input: anInput, result: .success(output)) XCTAssertEqual(match, .success(.success(output))) } - func test_flattenLength2_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { - let unexpected = "not the expected name" - let output = outputTree(embeddedName: unexpected) - let subject = try WaitersClient.flattenLengthMatcher2WaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertEqual(match, .success(.success(output))) + // MARK: - Projections + + func test_projectedLength_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { + let output1 = outputTree() + let subject = try WaitersClient.projectedLengthMatcherWaiterConfig().acceptors[0] + let match1 = subject.evaluate(input: anInput, result: .success(output1)) + XCTAssertNil(match1) + let output2 = outputTree(appendBonusKid: true) + let match2 = subject.evaluate(input: anInput, result: .success(output2)) + XCTAssertEqual(match2, .success(.success(output2))) + } // MARK: - Helper methods private var anInput: GetWidgetInput { GetWidgetInput() } - private func outputTree(globalName: String? = nil, embeddedName: String? = "c") -> GetWidgetOutputResponse { - GetWidgetOutputResponse(children: [ + private func outputTree(globalName: String? = nil, embeddedName: String? = "c", appendBonusKid: Bool = false) -> GetWidgetOutputResponse { + var grandchildren2: [WaitersClientTypes.Grandchild] = [ + .init(name: embeddedName ?? globalName), + .init(name: globalName ?? "d") + ] + if appendBonusKid { grandchildren2.append(.init(name: "bonus kid"))} + return GetWidgetOutputResponse(children: [ .init(grandchildren: [ .init(name: globalName ?? "a"), .init(name: globalName ?? "b") ]), - .init(grandchildren: [ - .init(name: embeddedName ?? globalName), - .init(name: globalName ?? "d") - ]), + .init(grandchildren: grandchildren2), .init(grandchildren: [ .init(name: globalName ?? "e"), .init(name: globalName ?? "f") diff --git a/codegen/protocol-test-codegen-local/model/main.smithy b/codegen/protocol-test-codegen-local/model/main.smithy index 9bf71fe45dd..08441ee7b7a 100644 --- a/codegen/protocol-test-codegen-local/model/main.smithy +++ b/codegen/protocol-test-codegen-local/model/main.smithy @@ -258,7 +258,7 @@ service Waiters { state: "success" matcher: { output: { - path: "children[*].grandchildren[*].name" + path: "children[].grandchildren[].name" expected: "expected name" comparator: "anyStringEquals" } @@ -266,7 +266,7 @@ service Waiters { } ] } - FlattenLengthMatcher1: { + FlattenLengthMatcher: { documentation: "Acceptor matches on flattened output property" acceptors: [ { @@ -281,14 +281,14 @@ service Waiters { } ] } - FlattenLengthMatcher2: { - documentation: "Acceptor matches on flattened output property" + ProjectedLengthMatcher: { + documentation: "Acceptor matches on exactly one child with 3 grandchildren" acceptors: [ { state: "success" matcher: { output: { - path: "length(children[*].grandchildren[*]) == `3`" + path: "length(children[?length(grandchildren) == `3`]) == `1`" expected: "true" comparator: "booleanEquals" } From 0e8eb50c72c14a4a2455a52815e84b0d410750e0 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Thu, 1 Dec 2022 23:31:31 -0600 Subject: [PATCH 08/19] Reorganized tests, added filter test --- .../WaitersTests/ErrorTypeMatcherTests.swift | 22 +++++ .../InputOutputMatcherTests.swift | 31 +++++++ ...rsTests.swift => OutputMatcherTests.swift} | 89 ++++++------------- .../WaitersTests/SuccessMatcherTests.swift | 48 ++++++++++ .../WaitersTests/WaiterTestUtils.swift | 3 + .../model/main.smithy | 39 +++++++- 6 files changed, 167 insertions(+), 65 deletions(-) create mode 100644 codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift create mode 100644 codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift rename codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/{WaitersTests.swift => OutputMatcherTests.swift} (77%) create mode 100644 codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift new file mode 100644 index 00000000000..81809d5f38e --- /dev/null +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift @@ -0,0 +1,22 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +@testable import Waiters +@testable import ClientRuntime + +class ErrorTypeMatcherTests: XCTestCase { + + // MARK: - errorType matcher + + func test_errorType_neverMatchesUntilImplemented() async throws { + let subject = try WaitersClient.errorTypeMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .failure("MyError")) + XCTAssertNil(match) + } + +} diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift new file mode 100644 index 00000000000..de8726b3c93 --- /dev/null +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift @@ -0,0 +1,31 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +@testable import Waiters +@testable import ClientRuntime + +class InputOutputMatcherTests: XCTestCase { + + func test_inputOutput_acceptorMatchesWhenInputAndOutputPropertiesMatch() async throws { + let value = UUID().uuidString + let input = GetWidgetInput(stringProperty: value) + let output = GetWidgetOutputResponse(stringProperty: value) + let subject = try WaitersClient.inputOutputPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: input, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_inputOutput_acceptorFailsToMatchWhenInputAndOutputPropertiesDontMatch() async throws { + let value = UUID().uuidString + let input = GetWidgetInput(stringProperty: value) + let output = GetWidgetOutputResponse(stringProperty: value + "xxx") + let subject = try WaitersClient.inputOutputPropertyMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: input, result: .success(output)) + XCTAssertNil(match) + } +} diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift similarity index 77% rename from codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift rename to codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift index 8e1b0725b9a..3cfa1669dbb 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaitersTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift @@ -9,48 +9,9 @@ import XCTest @testable import Waiters @testable import ClientRuntime -class WaitersTests: XCTestCase { +class OutputMatcherTests: XCTestCase { - // MARK: - success matcher - - func test_successTrue_hasSuccessStateWaiter() async throws { - let waiterConfig = try WaitersClient.successTrueMatcherWaiterConfig() - let subject = waiterConfig.acceptors[0] - XCTAssertEqual(subject.state, .success) - } - - func test_successTrue_acceptorMatchesOnOutput() async throws { - let output = GetWidgetOutputResponse() - let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertEqual(match, .success(.success(output))) - } - - func test_successTrue_acceptorFailsToMatchOnError() async throws { - let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .failure("boom")) - XCTAssertNil(match) - } - - func test_successFalse_acceptorFailsToMatchOnOutput() async throws { - let output = GetWidgetOutputResponse() - let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .success(output)) - XCTAssertNil(match) - } - - func test_successFalse_acceptorMatchesOnError() async throws { - let error = "boom" - let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .failure(error)) - XCTAssertEqual(match, .success(.failure(error))) - } - - // MARK: - errorType matcher - - // none yet, will fill this when errorType is properly implemented - - // MARK: - output matcher + // MARK: properties & stringEquals comparator func test_outputStringProperty_acceptorMatchesOnPropertyMatch() async throws { let output = GetWidgetOutputResponse(stringProperty: "payload property contents") @@ -73,6 +34,8 @@ class WaitersTests: XCTestCase { XCTAssertNil(match) } + // MARK: properties & booleanEquals comparator + func test_outputBooleanProperty_acceptorMatchesOnPropertyMatch() async throws { let output = GetWidgetOutputResponse(booleanProperty: false) let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] @@ -94,6 +57,8 @@ class WaitersTests: XCTestCase { XCTAssertNil(match) } + // MARK: properties & allStringEquals comparator + func test_arrayPropertyAll_acceptorMatchesWhenArrayElementsAllMatch() async throws { let expected = "payload property contents" let output = GetWidgetOutputResponse(stringArrayProperty: [expected, expected, expected]) @@ -124,6 +89,8 @@ class WaitersTests: XCTestCase { XCTAssertNil(match) } + // MARK: properties & anyStringEquals comparator + func test_arrayPropertyAny_acceptorMatchesWhenArrayElementsAllMatch() async throws { let expected = "payload property contents" let output = GetWidgetOutputResponse(stringArrayProperty: [expected, expected, expected]) @@ -162,17 +129,6 @@ class WaitersTests: XCTestCase { XCTAssertNil(match) } - // MARK: - inputOutput matcher - - func test_inputOutput_acceptorMatchesWhenInputAndOutputPropertiesMatch() async throws { - let value = UUID().uuidString - let input = GetWidgetInput(stringProperty: value) - let output = GetWidgetOutputResponse(stringProperty: value) - let subject = try WaitersClient.inputOutputPropertyMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: input, result: .success(output)) - XCTAssertEqual(match, .success(.success(output))) - } - // MARK: - Flatten operator func test_flatten_acceptorMatchesWhenFlattenedValueMatches() async throws { @@ -199,6 +155,18 @@ class WaitersTests: XCTestCase { XCTAssertEqual(match, .success(.success(output))) } + // MARK: - Filter + + func test_filter_acceptorMatchesWhenFilterMatches() async throws { + let output1 = outputTree() + let subject = try WaitersClient.filterMatcherWaiterConfig().acceptors[0] + let match1 = subject.evaluate(input: anInput, result: .success(output1)) + XCTAssertNil(match1) + let output2 = outputTree(appendBonusKid: true) + let match2 = subject.evaluate(input: anInput, result: .success(output2)) + XCTAssertEqual(match2, .success(.success(output2))) + } + // MARK: - Projections func test_projectedLength_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { @@ -209,28 +177,25 @@ class WaitersTests: XCTestCase { let output2 = outputTree(appendBonusKid: true) let match2 = subject.evaluate(input: anInput, result: .success(output2)) XCTAssertEqual(match2, .success(.success(output2))) - } // MARK: - Helper methods - private var anInput: GetWidgetInput { GetWidgetInput() } - private func outputTree(globalName: String? = nil, embeddedName: String? = "c", appendBonusKid: Bool = false) -> GetWidgetOutputResponse { var grandchildren2: [WaitersClientTypes.Grandchild] = [ - .init(name: embeddedName ?? globalName), - .init(name: globalName ?? "d") + .init(name: embeddedName ?? globalName, number: 1), + .init(name: globalName ?? "d", number: 2) ] - if appendBonusKid { grandchildren2.append(.init(name: "bonus kid"))} + if appendBonusKid { grandchildren2.append(.init(name: "bonus kid", number: 7))} return GetWidgetOutputResponse(children: [ .init(grandchildren: [ - .init(name: globalName ?? "a"), - .init(name: globalName ?? "b") + .init(name: globalName ?? "a", number: 3), + .init(name: globalName ?? "b", number: 4) ]), .init(grandchildren: grandchildren2), .init(grandchildren: [ - .init(name: globalName ?? "e"), - .init(name: globalName ?? "f") + .init(name: globalName ?? "e", number: 5), + .init(name: globalName ?? "f", number: 6) ]) ]) } diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift new file mode 100644 index 00000000000..9950a2e9e80 --- /dev/null +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift @@ -0,0 +1,48 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +@testable import Waiters +@testable import ClientRuntime + +class SuccessMatcherTests: XCTestCase { + + // MARK: - success matcher + + func test_successTrue_hasSuccessStateWaiter() async throws { + let waiterConfig = try WaitersClient.successTrueMatcherWaiterConfig() + let subject = waiterConfig.acceptors[0] + XCTAssertEqual(subject.state, .success) + } + + func test_successTrue_acceptorMatchesOnOutput() async throws { + let output = GetWidgetOutputResponse() + let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_successTrue_acceptorFailsToMatchOnError() async throws { + let subject = try WaitersClient.successTrueMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .failure("boom")) + XCTAssertNil(match) + } + + func test_successFalse_acceptorFailsToMatchOnOutput() async throws { + let output = GetWidgetOutputResponse() + let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + func test_successFalse_acceptorMatchesOnError() async throws { + let error = "boom" + let subject = try WaitersClient.successFalseMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .failure(error)) + XCTAssertEqual(match, .success(.failure(error))) + } +} diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaiterTestUtils.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaiterTestUtils.swift index 80e43b0f73a..1a67c91cacc 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaiterTestUtils.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/WaiterTestUtils.swift @@ -6,6 +6,7 @@ // import ClientRuntime +import Waiters // Convenience test-helper methods for testing acceptor matches @@ -43,3 +44,5 @@ extension WaiterConfiguration.Acceptor.Match: Equatable where Input: Equatable, extension String: Error { var localizedString: String? { self } } + +var anInput = GetWidgetInput() diff --git a/codegen/protocol-test-codegen-local/model/main.smithy b/codegen/protocol-test-codegen-local/model/main.smithy index 08441ee7b7a..2903c623283 100644 --- a/codegen/protocol-test-codegen-local/model/main.smithy +++ b/codegen/protocol-test-codegen-local/model/main.smithy @@ -176,6 +176,17 @@ service Waiters { } ] } + ErrorTypeMatcher: { + documentation: "Acceptor matches on receipt of specified error" + acceptors: [ + { + state: "success" + matcher: { + errorType: "MyError" + } + } + ] + } OutputStringPropertyMatcher: { documentation: "Acceptor matches on output payload property" acceptors: [ @@ -252,7 +263,7 @@ service Waiters { ] } FlattenMatcher: { - documentation: "Acceptor matches on flattened output property" + documentation: "Matches when any grandchild has name 'expected name'" acceptors: [ { state: "success" @@ -267,7 +278,7 @@ service Waiters { ] } FlattenLengthMatcher: { - documentation: "Acceptor matches on flattened output property" + documentation: "Matches when there are 6 grandchildren total" acceptors: [ { state: "success" @@ -282,7 +293,7 @@ service Waiters { ] } ProjectedLengthMatcher: { - documentation: "Acceptor matches on exactly one child with 3 grandchildren" + documentation: "Matches when exactly one child has 3 grandchildren" acceptors: [ { state: "success" @@ -296,10 +307,26 @@ service Waiters { } ] } + FilterMatcher: { + documentation: "Matches when exactly 3 grandchildren have numbers above 4" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "length((children[].grandchildren[])[?number > `4`]) == `3`" + expected: "true" + comparator: "booleanEquals" + } + } + } + ] + } ) operation GetWidget { input: WidgetInput, output: WidgetOutput + errors: [MyError] } structure WidgetInput { @@ -320,6 +347,7 @@ structure Child { structure Grandchild { name: String + number: Integer } list StringArray{ @@ -337,3 +365,8 @@ list ChildArray { list GrandchildArray { member: Grandchild } + +@error("client") +structure MyError { + message: String +} From 992f06c14a0fa7e262d67d6b41976b8719f8f0e5 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Fri, 2 Dec 2022 09:26:43 -0600 Subject: [PATCH 09/19] Empty commit From 2dd64c15a86b0ae196f297b00e8e1ddbce815b1c Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Fri, 2 Dec 2022 13:21:55 -0600 Subject: [PATCH 10/19] Disable waiter tests below Swift 5.7 --- .../swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift | 2 ++ .../swift-codegen/WaitersTests/InputOutputMatcherTests.swift | 2 ++ .../Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift | 2 ++ .../Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift | 2 ++ 4 files changed, 8 insertions(+) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift index 81809d5f38e..68bd8be10f7 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift @@ -9,6 +9,7 @@ import XCTest @testable import Waiters @testable import ClientRuntime +#if swift(>=5.7) class ErrorTypeMatcherTests: XCTestCase { // MARK: - errorType matcher @@ -20,3 +21,4 @@ class ErrorTypeMatcherTests: XCTestCase { } } +#endif diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift index de8726b3c93..30fbd5433d6 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift @@ -9,6 +9,7 @@ import XCTest @testable import Waiters @testable import ClientRuntime +#if swift(>=5.7) class InputOutputMatcherTests: XCTestCase { func test_inputOutput_acceptorMatchesWhenInputAndOutputPropertiesMatch() async throws { @@ -29,3 +30,4 @@ class InputOutputMatcherTests: XCTestCase { XCTAssertNil(match) } } +#endif diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift index 3cfa1669dbb..7f61883782b 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift @@ -9,6 +9,7 @@ import XCTest @testable import Waiters @testable import ClientRuntime +#if swift(>=5.7) class OutputMatcherTests: XCTestCase { // MARK: properties & stringEquals comparator @@ -200,3 +201,4 @@ class OutputMatcherTests: XCTestCase { ]) } } +#endif diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift index 9950a2e9e80..f5c61c504c8 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift @@ -9,6 +9,7 @@ import XCTest @testable import Waiters @testable import ClientRuntime +#if swift(>=5.7) class SuccessMatcherTests: XCTestCase { // MARK: - success matcher @@ -46,3 +47,4 @@ class SuccessMatcherTests: XCTestCase { XCTAssertEqual(match, .success(.failure(error))) } } +#endif From 0ad3041f97a0a67a080d64be84d76cf02af5371c Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Fri, 2 Dec 2022 14:29:17 -0600 Subject: [PATCH 11/19] Fix lint error --- AWSClientRuntime/Sources/Protocols/RestJSON/RestJSONError.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AWSClientRuntime/Sources/Protocols/RestJSON/RestJSONError.swift b/AWSClientRuntime/Sources/Protocols/RestJSON/RestJSONError.swift index ce3b6b11b3d..a88e6102394 100644 --- a/AWSClientRuntime/Sources/Protocols/RestJSON/RestJSONError.swift +++ b/AWSClientRuntime/Sources/Protocols/RestJSON/RestJSONError.swift @@ -50,7 +50,7 @@ public struct RestJSONError { } /// Filter additional information from error name and sanitize it - // Reference: https://awslabs.github.io/smithy/1.0/spec/aws/aws-restjson1-protocol.html#operation-error-serialization + /// Reference: https://awslabs.github.io/smithy/1.0/spec/aws/aws-restjson1-protocol.html#operation-error-serialization static func sanitizeErrorType(_ type: String?) -> String? { guard let errorType = type else { return type From dc47e295c1fcaaa879a41162626807c50d3d54e6 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Fri, 2 Dec 2022 14:49:20 -0600 Subject: [PATCH 12/19] Comment up scripts --- scripts/protogen.sh | 27 +++++++++++++++++++++++++++ scripts/regen.sh | 14 ++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/scripts/protogen.sh b/scripts/protogen.sh index a8b997ae9ae..2c9274de18c 100755 --- a/scripts/protogen.sh +++ b/scripts/protogen.sh @@ -1,9 +1,36 @@ #!/bin/bash +# This script may be used to regenerate protocol tests during development. +# Run this script from the SDK project's root dir. + +# Quit Xcode since it tends to get hung up when files are being changed for a local project. osascript -e 'quit app "Xcode"' + +# Delete the build products from any previous run of protocol tests. rm -rf codegen/protocol-test-codegen/build rm -rf codegen/protocol-test-codegen-local/build + +# Regenerate protocol tests ./gradlew -p codegen/protocol-test-codegen build ./gradlew -p codegen/protocol-test-codegen-local build + +# Delete the generated Package.swift for protocol test packages so they may be seen in Xcode +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/aws-restjson/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/aws-json-10/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/aws-json-11/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/rest-xml/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/rest-xml-xmlns/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/ec2-query/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/aws-query/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/apigateway/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/glacier/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/machinelearning/swift-codegen/Package.swift +rm codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen/s3/swift-codegen/Package.swift + +# Now do the same for local protocol tests +rm codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test-codegen-local/aws-restjson/swift-codegen/Package.swift +rm codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test-codegen-local/rest_json_extras/swift-codegen/Package.swift rm codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test-codegen-local/Waiters/swift-codegen/Package.swift + +# Work's done, reopen Xcode to the refreshed tests open -a Xcode diff --git a/scripts/regen.sh b/scripts/regen.sh index 4753052c71d..7a2c5b6ba54 100755 --- a/scripts/regen.sh +++ b/scripts/regen.sh @@ -1,9 +1,23 @@ #!/bin/bash +# Regenerates the SDK. For use during development only. +# Run this script from the SDK project root directory. + +# Quit Xcode so it doesn't get overwhelmed by source file changes. osascript -e 'quit app "Xcode"' + +# Delete the current autogenerated SDK code rm -rf release/ + +# Regenerate code ./gradlew -p codegen/sdk-codegen build ./gradlew -p codegen/sdk-codegen stageSdks + +# Merge the newly built models ./scripts/mergeModels.sh release + +# Regenerate the package manifest ./scripts/generatePackageSwift.swift > Package.swift + +# Open Xcode to the newly refreshed SDK open -a Xcode From 896d39dfc8f3ca006dbf7ce7e31583058ed54b64 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Fri, 2 Dec 2022 17:19:17 -0600 Subject: [PATCH 13/19] Add comments with JMESPaths to acceptor tests --- .../InputOutputMatcherTests.swift | 7 ++++ .../WaitersTests/OutputMatcherTests.swift | 32 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift index 30fbd5433d6..d9ceffd89ee 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift @@ -12,6 +12,13 @@ import XCTest #if swift(>=5.7) class InputOutputMatcherTests: XCTestCase { + // JMESPath expression: input.stringProperty == output.stringProperty + // JMESPath comparator: booleanEquals + // JMESPath expected value: true + + // inputOutput tests are just on the input & output properties, because all the other logic + // in them is shared with output matchers, which are tested more comprehensively. + func test_inputOutput_acceptorMatchesWhenInputAndOutputPropertiesMatch() async throws { let value = UUID().uuidString let input = GetWidgetInput(stringProperty: value) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift index 7f61883782b..2924b6e9d52 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift @@ -14,6 +14,10 @@ class OutputMatcherTests: XCTestCase { // MARK: properties & stringEquals comparator + // JMESPath expression: stringProperty + // JMESPath comparator: stringEquals + // JMESPath expected value: payload property contents + func test_outputStringProperty_acceptorMatchesOnPropertyMatch() async throws { let output = GetWidgetOutputResponse(stringProperty: "payload property contents") let subject = try WaitersClient.outputStringPropertyMatcherWaiterConfig().acceptors[0] @@ -37,6 +41,10 @@ class OutputMatcherTests: XCTestCase { // MARK: properties & booleanEquals comparator + // JMESPath expression: booleanProperty + // JMESPath comparator: booleanEquals + // JMESPath expected value: false + func test_outputBooleanProperty_acceptorMatchesOnPropertyMatch() async throws { let output = GetWidgetOutputResponse(booleanProperty: false) let subject = try WaitersClient.outputBooleanPropertyMatcherWaiterConfig().acceptors[0] @@ -60,6 +68,10 @@ class OutputMatcherTests: XCTestCase { // MARK: properties & allStringEquals comparator + // JMESPath expression: stringArrayProperty + // JMESPath comparator: allStringEquals + // JMESPath expected value: payload property contents + func test_arrayPropertyAll_acceptorMatchesWhenArrayElementsAllMatch() async throws { let expected = "payload property contents" let output = GetWidgetOutputResponse(stringArrayProperty: [expected, expected, expected]) @@ -92,6 +104,10 @@ class OutputMatcherTests: XCTestCase { // MARK: properties & anyStringEquals comparator + // JMESPath expression: stringArrayProperty + // JMESPath comparator: anyStringEquals + // JMESPath expected value: payload property contents + func test_arrayPropertyAny_acceptorMatchesWhenArrayElementsAllMatch() async throws { let expected = "payload property contents" let output = GetWidgetOutputResponse(stringArrayProperty: [expected, expected, expected]) @@ -132,6 +148,10 @@ class OutputMatcherTests: XCTestCase { // MARK: - Flatten operator + // JMESPath expression: children[].grandchildren[].name + // JMESPath comparator: anyStringEquals + // JMESPath expected value: expected name + func test_flatten_acceptorMatchesWhenFlattenedValueMatches() async throws { let expected = "expected name" let output = outputTree(embeddedName: expected) @@ -148,6 +168,10 @@ class OutputMatcherTests: XCTestCase { XCTAssertNil(match) } + // JMESPath expression: length(children[].grandchildren[]) == `6` + // JMESPath comparator: booleanEquals + // JMESPath expected value: true + func test_flattenLength_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { let unexpected = "not the expected name" let output = outputTree(embeddedName: unexpected) @@ -158,6 +182,10 @@ class OutputMatcherTests: XCTestCase { // MARK: - Filter + // JMESPath expression: length((children[].grandchildren[])[?number > `4`]) == `3` + // JMESPath comparator: booleanEquals + // JMESPath expected value: true + func test_filter_acceptorMatchesWhenFilterMatches() async throws { let output1 = outputTree() let subject = try WaitersClient.filterMatcherWaiterConfig().acceptors[0] @@ -170,6 +198,10 @@ class OutputMatcherTests: XCTestCase { // MARK: - Projections + // JMESPath expression: length(children[?length(grandchildren) == `3`]) == `1` + // JMESPath comparator: booleanEquals + // JMESPath expected value: true + func test_projectedLength_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { let output1 = outputTree() let subject = try WaitersClient.projectedLengthMatcherWaiterConfig().acceptors[0] From b4f89be28c04459970dfa132a34b8563af52c044 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Fri, 9 Dec 2022 15:58:48 -0600 Subject: [PATCH 14/19] Add real tests for error matchers --- .../WaitersTests/ErrorTypeMatcherTests.swift | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift index 68bd8be10f7..d8a2077b161 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift @@ -10,15 +10,57 @@ import XCTest @testable import ClientRuntime #if swift(>=5.7) + class ErrorTypeMatcherTests: XCTestCase { + // expected errorType for these tests: "MyError" + // MARK: - errorType matcher - func test_errorType_neverMatchesUntilImplemented() async throws { + func test_errorType_matchesWhenErrorTypeMatchesAndErrorIsAWaiterTypedError() async throws { + let error = WaiterTypedErrorImpl() + let subject = try WaitersClient.errorTypeMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .failure(error)) + XCTAssertEqual(match, .success(.failure(error))) + } + + func test_errorType_doesNotMatchWhenErrorTypeDoesNotMatchAndErrorIsAWaiterTypedError() async throws { + let error = WaiterTypedErrorNoMatchImpl() + let subject = try WaitersClient.errorTypeMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .failure(error)) + XCTAssertNil(match) + } + + func test_errorType_doesNotMatchWhenErrorTypeMatchesButErrorIsNotAWaiterTypedError() async throws { + let error = WaiterTypedErrorNoMatchImpl() let subject = try WaitersClient.errorTypeMatcherWaiterConfig().acceptors[0] - let match = subject.evaluate(input: anInput, result: .failure("MyError")) + let match = subject.evaluate(input: anInput, result: .failure(error)) XCTAssertNil(match) } + func test_errorType_doesNotMatchWhenResultIsSuccess() async throws { + let response = GetWidgetOutputResponse() + let subject = try WaitersClient.errorTypeMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(response)) + XCTAssertNil(match) + } } + +// Error types used in tests above + +private struct WaiterTypedErrorImpl: WaiterTypedError, Equatable { + + var waiterErrorType: String? { "MyError" } +} + +private struct WaiterTypedErrorNoMatchImpl: WaiterTypedError, Equatable { + + var waiterErrorType: String? { "OtherError" } +} + +private struct NotAWaiterTypedErrorImpl: Error, Equatable { // An error but not a WaiterTypedError + + var waiterErrorType: String? { "MyError" } +} + #endif From 014c41d6dedfecc22902a2fe24647c95a33b1708 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Fri, 9 Dec 2022 17:20:49 -0600 Subject: [PATCH 15/19] Improved error names for error type matcher tests --- .../WaitersTests/ErrorTypeMatcherTests.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift index d8a2077b161..2c887b32342 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift @@ -18,21 +18,21 @@ class ErrorTypeMatcherTests: XCTestCase { // MARK: - errorType matcher func test_errorType_matchesWhenErrorTypeMatchesAndErrorIsAWaiterTypedError() async throws { - let error = WaiterTypedErrorImpl() + let error = WaiterTypedErrorThatMatches() let subject = try WaitersClient.errorTypeMatcherWaiterConfig().acceptors[0] let match = subject.evaluate(input: anInput, result: .failure(error)) XCTAssertEqual(match, .success(.failure(error))) } func test_errorType_doesNotMatchWhenErrorTypeDoesNotMatchAndErrorIsAWaiterTypedError() async throws { - let error = WaiterTypedErrorNoMatchImpl() + let error = WaiterTypedErrorThatDoesntMatch() let subject = try WaitersClient.errorTypeMatcherWaiterConfig().acceptors[0] let match = subject.evaluate(input: anInput, result: .failure(error)) XCTAssertNil(match) } func test_errorType_doesNotMatchWhenErrorTypeMatchesButErrorIsNotAWaiterTypedError() async throws { - let error = WaiterTypedErrorNoMatchImpl() + let error = NotAWaiterTypedError() let subject = try WaitersClient.errorTypeMatcherWaiterConfig().acceptors[0] let match = subject.evaluate(input: anInput, result: .failure(error)) XCTAssertNil(match) @@ -48,17 +48,17 @@ class ErrorTypeMatcherTests: XCTestCase { // Error types used in tests above -private struct WaiterTypedErrorImpl: WaiterTypedError, Equatable { +private struct WaiterTypedErrorThatMatches: WaiterTypedError, Equatable { var waiterErrorType: String? { "MyError" } } -private struct WaiterTypedErrorNoMatchImpl: WaiterTypedError, Equatable { +private struct WaiterTypedErrorThatDoesntMatch: WaiterTypedError, Equatable { var waiterErrorType: String? { "OtherError" } } -private struct NotAWaiterTypedErrorImpl: Error, Equatable { // An error but not a WaiterTypedError +private struct NotAWaiterTypedError: Error, Equatable { // An error but not a WaiterTypedError var waiterErrorType: String? { "MyError" } } From e875551fb10cf979da90587654852fff615dc70b Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Wed, 14 Dec 2022 23:38:32 -0600 Subject: [PATCH 16/19] Allow waiters tests to run on Swift below 5.7 --- .../swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift | 3 --- .../swift-codegen/WaitersTests/InputOutputMatcherTests.swift | 3 +-- .../Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift | 3 +-- .../Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift | 3 +-- scripts/protogen.sh | 2 +- scripts/regen.sh | 2 +- 6 files changed, 5 insertions(+), 11 deletions(-) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift index 2c887b32342..1dab86ac804 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/ErrorTypeMatcherTests.swift @@ -9,8 +9,6 @@ import XCTest @testable import Waiters @testable import ClientRuntime -#if swift(>=5.7) - class ErrorTypeMatcherTests: XCTestCase { // expected errorType for these tests: "MyError" @@ -63,4 +61,3 @@ private struct NotAWaiterTypedError: Error, Equatable { // An error but not a W var waiterErrorType: String? { "MyError" } } -#endif diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift index d9ceffd89ee..3d6ce83a2e5 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/InputOutputMatcherTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import Waiters @testable import ClientRuntime -#if swift(>=5.7) class InputOutputMatcherTests: XCTestCase { // JMESPath expression: input.stringProperty == output.stringProperty @@ -37,4 +36,4 @@ class InputOutputMatcherTests: XCTestCase { XCTAssertNil(match) } } -#endif + diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift index 2924b6e9d52..41663a62721 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import Waiters @testable import ClientRuntime -#if swift(>=5.7) class OutputMatcherTests: XCTestCase { // MARK: properties & stringEquals comparator @@ -233,4 +232,4 @@ class OutputMatcherTests: XCTestCase { ]) } } -#endif + diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift index f5c61c504c8..22b01a7bcc4 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/SuccessMatcherTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import Waiters @testable import ClientRuntime -#if swift(>=5.7) class SuccessMatcherTests: XCTestCase { // MARK: - success matcher @@ -47,4 +46,4 @@ class SuccessMatcherTests: XCTestCase { XCTAssertEqual(match, .success(.failure(error))) } } -#endif + diff --git a/scripts/protogen.sh b/scripts/protogen.sh index 2c9274de18c..34794aedeb9 100755 --- a/scripts/protogen.sh +++ b/scripts/protogen.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash -eo pipefail # This script may be used to regenerate protocol tests during development. # Run this script from the SDK project's root dir. diff --git a/scripts/regen.sh b/scripts/regen.sh index 7a2c5b6ba54..f10f3c78dc6 100755 --- a/scripts/regen.sh +++ b/scripts/regen.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash -eo pipefail # Regenerates the SDK. For use during development only. # Run this script from the SDK project root directory. From 3315e772e0af6d2829504c7ad3385d33b235336b Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Thu, 15 Dec 2022 11:21:39 -0600 Subject: [PATCH 17/19] Add projection tests for Waiters --- .../WaitersTests/OutputMatcherTests.swift | 64 +++++++++++++------ .../model/main.smithy | 25 +++++++- scripts/{regen.sh => codegen.sh} | 0 3 files changed, 69 insertions(+), 20 deletions(-) rename scripts/{regen.sh => codegen.sh} (100%) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift index 41663a62721..c9ce7d80940 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift @@ -179,36 +179,64 @@ class OutputMatcherTests: XCTestCase { XCTAssertEqual(match, .success(.success(output))) } - // MARK: - Filter + // MARK: - Length - Flatten - Filter // JMESPath expression: length((children[].grandchildren[])[?number > `4`]) == `3` // JMESPath comparator: booleanEquals // JMESPath expected value: true - func test_filter_acceptorMatchesWhenFilterMatches() async throws { - let output1 = outputTree() - let subject = try WaitersClient.filterMatcherWaiterConfig().acceptors[0] - let match1 = subject.evaluate(input: anInput, result: .success(output1)) - XCTAssertNil(match1) - let output2 = outputTree(appendBonusKid: true) - let match2 = subject.evaluate(input: anInput, result: .success(output2)) - XCTAssertEqual(match2, .success(.success(output2))) + func test_lengthFlattenFilter_acceptorMatchesWhenFilterMatches() async throws { + let output = outputTree(appendBonusKid: true) + let subject = try WaitersClient.lengthFlattenFilterMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_lengthFlattenFilter_acceptorDoesNotMatchWhenFilterDoesNotMatch() async throws { + let output = outputTree() + let subject = try WaitersClient.lengthFlattenFilterMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) } - // MARK: - Projections + // MARK: - Flatten - Filter // JMESPath expression: length(children[?length(grandchildren) == `3`]) == `1` // JMESPath comparator: booleanEquals // JMESPath expected value: true - func test_projectedLength_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { - let output1 = outputTree() - let subject = try WaitersClient.projectedLengthMatcherWaiterConfig().acceptors[0] - let match1 = subject.evaluate(input: anInput, result: .success(output1)) - XCTAssertNil(match1) - let output2 = outputTree(appendBonusKid: true) - let match2 = subject.evaluate(input: anInput, result: .success(output2)) - XCTAssertEqual(match2, .success(.success(output2))) + func test_flattenFilter_acceptorMatchesWhenFlattenedValueMatchesCount() async throws { + let output = outputTree(appendBonusKid: true) + let subject = try WaitersClient.flattenFilterMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_flattenFilter_acceptorDoesNotMatchWhenFlattenedValueDoesntMatchCount() async throws { + let output = outputTree() + let subject = try WaitersClient.flattenFilterMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + + // MARK: - Projection + + // JMESPath expression: "dataMap.*" + // JMESPath comparator: "allStringEquals" + // JMESPath expected value: "abc" + + func test_projection_acceptorMatchesWhenProjectedValuesMatchExpectation() async throws { + let output = GetWidgetOutputResponse(dataMap: ["x": "abc", "y": "abc", "z": "abc"]) + let subject = try WaitersClient.projectionMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_projection_acceptorDoesNotMatchWhenProjectedValuesDontMatchExpectation() async throws { + let output = GetWidgetOutputResponse(dataMap: ["x": "abc", "y": "abc", "z": "def"]) + let subject = try WaitersClient.projectionMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) } // MARK: - Helper methods diff --git a/codegen/protocol-test-codegen-local/model/main.smithy b/codegen/protocol-test-codegen-local/model/main.smithy index 2903c623283..b3175a74c99 100644 --- a/codegen/protocol-test-codegen-local/model/main.smithy +++ b/codegen/protocol-test-codegen-local/model/main.smithy @@ -292,7 +292,7 @@ service Waiters { } ] } - ProjectedLengthMatcher: { + FlattenFilterMatcher: { documentation: "Matches when exactly one child has 3 grandchildren" acceptors: [ { @@ -307,7 +307,7 @@ service Waiters { } ] } - FilterMatcher: { + LengthFlattenFilterMatcher: { documentation: "Matches when exactly 3 grandchildren have numbers above 4" acceptors: [ { @@ -322,6 +322,21 @@ service Waiters { } ] } + ProjectionMatcher: { + documentation: "Matches when dataMap values are all `abc`" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "dataMap.*" + expected: "abc" + comparator: "allStringEquals" + } + } + } + ] + } ) operation GetWidget { input: WidgetInput, @@ -339,6 +354,7 @@ structure WidgetOutput { booleanProperty: Boolean booleanArrayProperty: BooleanArray children: ChildArray + dataMap: DataMap } structure Child { @@ -366,6 +382,11 @@ list GrandchildArray { member: Grandchild } +map DataMap { + key: String + value: String +} + @error("client") structure MyError { message: String diff --git a/scripts/regen.sh b/scripts/codegen.sh similarity index 100% rename from scripts/regen.sh rename to scripts/codegen.sh From 82b5b3b0f259cb05a3e8c376bb5f65ceb5fd45db Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Fri, 16 Dec 2022 13:39:50 -0600 Subject: [PATCH 18/19] Add tests for JMES contain() function with optional search param --- .../WaitersTests/OutputMatcherTests.swift | 20 +++++++++++++++++++ .../model/main.smithy | 15 ++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift index c9ce7d80940..7f461baf5f8 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/WaitersTests/OutputMatcherTests.swift @@ -239,6 +239,26 @@ class OutputMatcherTests: XCTestCase { XCTAssertNil(match) } + // MARK: - Contains with non-literal, optional search param + + // JMESPath expression: "contains(dataMap.*, stringProperty)" + // JMESPath comparator: "booleanEquals" + // JMESPath expected value: "true" + + func test_containsNonLiteral_acceptorMatchesWhenStringPropertyIsFound() async throws { + let output = GetWidgetOutputResponse(dataMap: ["a": "abc", "b": "xyz"], stringProperty: "xyz") + let subject = try WaitersClient.containsFieldMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertEqual(match, .success(.success(output))) + } + + func test_containsNonLiteral_acceptorDoesNotMatchWhenStringPropertyIsNotFound() async throws { + let output = GetWidgetOutputResponse(dataMap: ["a": "abc", "b": "xyz"], stringProperty: "def") + let subject = try WaitersClient.containsFieldMatcherWaiterConfig().acceptors[0] + let match = subject.evaluate(input: anInput, result: .success(output)) + XCTAssertNil(match) + } + // MARK: - Helper methods private func outputTree(globalName: String? = nil, embeddedName: String? = "c", appendBonusKid: Bool = false) -> GetWidgetOutputResponse { diff --git a/codegen/protocol-test-codegen-local/model/main.smithy b/codegen/protocol-test-codegen-local/model/main.smithy index b3175a74c99..32a11a78bd0 100644 --- a/codegen/protocol-test-codegen-local/model/main.smithy +++ b/codegen/protocol-test-codegen-local/model/main.smithy @@ -337,6 +337,21 @@ service Waiters { } ] } + ContainsFieldMatcher: { + documentation: "Matches when any value of dataMap is the same as stringProperty" + acceptors: [ + { + state: "success" + matcher: { + output: { + path: "contains(dataMap.*, stringProperty)" + expected: "true" + comparator: "booleanEquals" + } + } + } + ] + } ) operation GetWidget { input: WidgetInput, From 35d9316742b8aa9bbd640df47264be51b5eb608c Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Fri, 16 Dec 2022 14:18:37 -0600 Subject: [PATCH 19/19] Point smithy-swift to waiters feature branch --- packageDependencies.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packageDependencies.plist b/packageDependencies.plist index 5b24f3d6467..0fe3cc01648 100644 --- a/packageDependencies.plist +++ b/packageDependencies.plist @@ -7,7 +7,7 @@ awsCRTSwiftVersion 0.4.0 clientRuntimeBranch - jbe/acceptors + feat/waiters awsCRTSwiftBranch main