Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: Test code-generated Waiters components #732

Merged
merged 23 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
36d121f
Use acceptors branch of smithy-swift
jbelkins Nov 30, 2022
76d8191
Code-generate a waiter and run tests against its acceptors
jbelkins Nov 30, 2022
48c2ef7
Cleanup
jbelkins Nov 30, 2022
f1ff3f9
Add more test waiters & unit tests
jbelkins Dec 1, 2022
917d622
Added all/any comparator tests, input/output matcher
jbelkins Dec 1, 2022
a1fd875
Add tree structure to output
jbelkins Dec 2, 2022
d8a1335
Fix JMESPath in flatten tests
jbelkins Dec 2, 2022
0e8eb50
Reorganized tests, added filter test
jbelkins Dec 2, 2022
992f06c
Empty commit
jbelkins Dec 2, 2022
2dd64c1
Disable waiter tests below Swift 5.7
jbelkins Dec 2, 2022
0ad3041
Fix lint error
jbelkins Dec 2, 2022
dc47e29
Comment up scripts
jbelkins Dec 2, 2022
651cb29
Merge branch 'main' into jbe/acceptors
jbelkins Dec 2, 2022
896d39d
Add comments with JMESPaths to acceptor tests
jbelkins Dec 2, 2022
a3543f2
Merge branch 'main' of github.com:awslabs/aws-sdk-swift into jbe/acce…
jbelkins Dec 2, 2022
4d1fb3c
Merge branch 'jbe/acceptors' of github.com:awslabs/aws-sdk-swift into…
jbelkins Dec 2, 2022
1ea0625
Merge branch 'feat/waiters' into jbe/acceptors
jbelkins Dec 8, 2022
b4f89be
Add real tests for error matchers
jbelkins Dec 9, 2022
014c41d
Improved error names for error type matcher tests
jbelkins Dec 9, 2022
e875551
Allow waiters tests to run on Swift below 5.7
jbelkins Dec 15, 2022
3315e77
Add projection tests for Waiters
jbelkins Dec 15, 2022
82b5b3b
Add tests for JMES contain() function with optional search param
jbelkins Dec 16, 2022
35d9316
Point smithy-swift to waiters feature branch
jbelkins Dec 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions codegen/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -103,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"),
jbelkins marked this conversation as resolved.
Show resolved Hide resolved
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import XCTest
@testable import Waiters
@testable import ClientRuntime

#if swift(>=5.7)

class ErrorTypeMatcherTests: XCTestCase {

// expected errorType for these tests: "MyError"

// MARK: - errorType matcher

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(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 {
jbelkins marked this conversation as resolved.
Show resolved Hide resolved

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
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import XCTest
@testable import Waiters
@testable import ClientRuntime

#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)
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)
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import XCTest
@testable import Waiters
@testable import ClientRuntime

#if swift(>=5.7)
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]
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)
}

// 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]
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: 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])
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)
}

// 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])
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: - 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)
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)
}

// 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)
let subject = try WaitersClient.flattenLengthMatcherWaiterConfig().acceptors[0]
let match = subject.evaluate(input: anInput, result: .success(output))
XCTAssertEqual(match, .success(.success(output)))
}

// 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]
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

// 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)))
}

// MARK: - Helper methods

private func outputTree(globalName: String? = nil, embeddedName: String? = "c", appendBonusKid: Bool = false) -> GetWidgetOutputResponse {
var grandchildren2: [WaitersClientTypes.Grandchild] = [
.init(name: embeddedName ?? globalName, number: 1),
.init(name: globalName ?? "d", number: 2)
]
if appendBonusKid { grandchildren2.append(.init(name: "bonus kid", number: 7))}
return GetWidgetOutputResponse(children: [
.init(grandchildren: [
.init(name: globalName ?? "a", number: 3),
.init(name: globalName ?? "b", number: 4)
]),
.init(grandchildren: grandchildren2),
.init(grandchildren: [
.init(name: globalName ?? "e", number: 5),
.init(name: globalName ?? "f", number: 6)
])
])
}
}
#endif
Loading