Skip to content

Commit

Permalink
feat: test-suite (#651)
Browse files Browse the repository at this point in the history
* chore: Require Swift 5.7, fix deprecation warnings (#600)

* feat: support initial-response in RPC based event streams (#597)

* chore: Updates version to 0.32.0

* chore: Add newline to README.md (#602)

* feat: add limited support in smithy-swift for visionOS (#606)

* feat: add support for requiresLength trait and Transfer-Encoding: Chunked (#604)

* chore: Update to aws-crt-swift 0.15.0 (#607)

* fix: content-length middleware should not error on event streams (#608)

* chore: Updates version to 0.33.0

* chore: Improved downstream task (#568)

* chore: Convert idempotency token middleware from closure to reusable type (#610)

* fix: Update aws-crt-swift dependency to 0.17.0 (#612)

* chore: Updates version to 0.34.0

* fix: Endpoint url should be nil if host or scheme is missing (#614)

* fix: Pool HTTP connections based on scheme, host, and port (#615)

* add default log level to initialize method (#616)

* feat: add utility method for converting SdkHttpRequest to URLRequest. (#613)

* Add extension constructor to URLRequest to convert SDKHttpRequest

* Add preprocessor conditional import functionality to SwiftWriter.

---------

Co-authored-by: Sichan Yoo <[email protected]>

* chore: Updates version to 0.35.0

* Add customizations to auth resolve process.

Add internal modeled layer for services (S3, EventBridge) that use rules-based auth scheme resolver.

Rules-based auth scheme resolver work wrap-up.

Wrap-up presign / presign-url refactor.

Wrap-up refactor for fitting in rules-based auth scheme resolver.

Update test cases to include new middlewares.

Move requestSignature getter / setter/ key from aws middleware context extension to here. Also, add saving requestSignature to SignerMiddleware for consumption by event stream signing.

* Add signEvent API to Signer protocol, and rename sign to signRequest.

* Add mock auth scheme resolver, mock auth schemes, mock identity, mock identity resolver, and mock signer to use for middleware unit tests.

* Add unit tests for AuthSchemeMiddleware and SignerMiddleware.

* Update MockSigner to conform to modified Signer API with signEvent.

* Rename directory containing mocks for auth tests from AuthTest to AuthTestUtil.

* fix: Add a header to operation doc comments (#621)

* remove unnecessary TODOs (#622)

* fix: Codegen issues re: recursion, Swift keywords in unions (#623)

* feat!: Replace the XML encoder with a custom Smithy implementation (#619)

* feat!: Use closures for processing HTTP response (#624)

* feat: add custom trait PaginationTruncationMember (#625)

* allow isTruncated to be optional bool (#626)

* chore: Updates version to 0.36.0

* chore: Run tvOS old & new in CI (#628)

* fix: Fix Package.swift warning on Mac (#629)

* chore: refactor HttpBody and ByteStream to be a single class ByteStream (#627)

* chore: remove sync read in unused data extension (#630)

* update smithy to 1.42.0 (#631)

* chore: Updates version to 0.37.0

* chore: Update to aws-crt-swift 0.20.0 (#633)

* fix: add back from method with fileHandle (#635)

* fix!: Add no-op behavior for initialize methods of logging system. (#637)

* Add no-op behavior for initialize methods if it isn't the first time being called.

* Make LockingSystem threadsafe.

* Make initialize methods async.

---------

Co-authored-by: Sichan Yoo <[email protected]>

* feat!: URLSession-based HTTP Client (#636)

* bump up CRT version to 0.22.0 (#639)

* chore: Update version to 0.38.0 (#641)

* chore: Empty commit (#643)

* feat: add wrapper for checksums + unit tests (#642)

* Update to reflect midleware generics change.

* Delete unnessary line from test case.

* Add CloudFront KeyValueStore as one of the services that use rules based auth scheme resolver customization.

* feat: Use the Foundation HTTP client by default on Mac (#646)

* chore: Updates version to 0.39.0

* Fix auth scheme middleware to save the selected auth scheme to middleware context by modifying the original context. Fixes transcribe streaming integration test where streaming signing flow was only accessing the original context and not the newly built one with selected auth scheme that was being passed to next middleware in line.

* chore: Change MyURLQueryItem to SDKURLQueryItem (#652)

* feat!: Provide HTTP request components by closure instead of protocol (#654)

* fix: Don't retry modeled errors by default (#653)

* Address Josh's PR comments.

* Merge updated CRT version from main into feat/test-suite.

---------

Co-authored-by: Josh Elkins <[email protected]>
Co-authored-by: David Yaffe <[email protected]>
Co-authored-by: AWS SDK Swift Automation <[email protected]>
Co-authored-by: Cyprien Ricque <[email protected]>
Co-authored-by: Sichan Yoo <[email protected]>
  • Loading branch information
6 people authored Feb 8, 2024
1 parent c695be9 commit ec8f4ea
Show file tree
Hide file tree
Showing 11 changed files with 420 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ let package = Package(
.library(name: "SmithyTestUtil", targets: ["SmithyTestUtil"]),
],
dependencies: [
.package(url: "https://github.com/awslabs/aws-crt-swift.git", exact: "0.22.0"),
.package(url: "https://github.com/awslabs/aws-crt-swift.git", exact: "0.26.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
.package(url: "https://github.com/MaxDesiatov/XMLCoder.git", exact: "0.17.0")
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ public struct AuthSchemeMiddleware<OperationStackOutput: HttpResponseBinding,
}

// Set the selected auth scheme in context for subsequent middleware access, then pass to next middleware in chain
return try await next.handle(
context: context.toBuilder().withSelectedAuthScheme(value: selectedAuthScheme).build(), input: input
)
context.attributes.set(key: AttributeKeys.selectedAuthScheme, value: selectedAuthScheme)
return try await next.handle(context: context, input: input)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public struct ContentMD5Middleware<OperationStackOutput>: Middleware {

switch input.body {
case .data(let data):
guard let data = data else {
guard let data else {
return try await next.handle(context: context, input: input)
}
let md5Hash = try data.computeMD5()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
import ClientRuntime

public struct MockAuthSchemeResolverParameters: ClientRuntime.AuthSchemeResolverParameters {
public let operation: String
}

public protocol MockAuthSchemeResolver: ClientRuntime.AuthSchemeResolver {
// Intentionally empty.
// This is the parent protocol that all auth scheme resolver implementations of
// the service Mock must conform to.
}

public struct DefaultMockAuthSchemeResolver: MockAuthSchemeResolver {
public init () {}

public func resolveAuthScheme(params: ClientRuntime.AuthSchemeResolverParameters) throws -> [AuthOption] {
var validAuthOptions = Array<AuthOption>()
guard let serviceParams = params as? MockAuthSchemeResolverParameters else {
throw ClientError.authError("Service specific auth scheme parameters type must be passed to auth scheme resolver.")
}
switch serviceParams.operation {
case "authA":
validAuthOptions.append(AuthOption(schemeID: "MockAuthSchemeA"))
case "authAB":
validAuthOptions.append(AuthOption(schemeID: "MockAuthSchemeA"))
validAuthOptions.append(AuthOption(schemeID: "MockAuthSchemeB"))
case "authABC":
validAuthOptions.append(AuthOption(schemeID: "MockAuthSchemeA"))
validAuthOptions.append(AuthOption(schemeID: "MockAuthSchemeB"))
validAuthOptions.append(AuthOption(schemeID: "MockAuthSchemeC"))
case "authABCNoAuth":
validAuthOptions.append(AuthOption(schemeID: "MockAuthSchemeA"))
validAuthOptions.append(AuthOption(schemeID: "MockAuthSchemeB"))
validAuthOptions.append(AuthOption(schemeID: "MockAuthSchemeC"))
validAuthOptions.append(AuthOption(schemeID: "smithy.api#noAuth"))
default:
validAuthOptions.append(AuthOption(schemeID: "fillerAuth"))
}
return validAuthOptions
}

public func constructParameters(context: HttpContext) throws -> ClientRuntime.AuthSchemeResolverParameters {
guard let opName = context.getOperation() else {
throw ClientError.dataNotFound("Operation name not configured in middleware context for auth scheme resolver params construction.")
}
return MockAuthSchemeResolverParameters(operation: opName)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import ClientRuntime

public struct MockAuthSchemeA: ClientRuntime.AuthScheme {
public let schemeID: String = "MockAuthSchemeA"
public let signer: ClientRuntime.Signer = MockSigner()
public let idKind: ClientRuntime.IdentityKind = .aws

public init() {}

public func customizeSigningProperties(signingProperties: ClientRuntime.Attributes, context: ClientRuntime.HttpContext) -> ClientRuntime.Attributes {
return signingProperties
}
}

public struct MockAuthSchemeB: ClientRuntime.AuthScheme {
public let schemeID: String = "MockAuthSchemeB"
public let signer: ClientRuntime.Signer = MockSigner()
public let idKind: ClientRuntime.IdentityKind = .aws

public init() {}

public func customizeSigningProperties(signingProperties: ClientRuntime.Attributes, context: ClientRuntime.HttpContext) -> ClientRuntime.Attributes {
return signingProperties
}
}

public struct MockAuthSchemeC: ClientRuntime.AuthScheme {
public let schemeID: String = "MockAuthSchemeC"
public let signer: ClientRuntime.Signer = MockSigner()
public let idKind: ClientRuntime.IdentityKind = .aws

public init() {}

public func customizeSigningProperties(signingProperties: ClientRuntime.Attributes, context: ClientRuntime.HttpContext) -> ClientRuntime.Attributes {
return signingProperties
}
}

public struct MockNoAuth: ClientRuntime.AuthScheme {
public let schemeID: String = "smithy.api#noAuth"
public let signer: ClientRuntime.Signer = MockSigner()
public let idKind: ClientRuntime.IdentityKind = .aws

public init() {}

public func customizeSigningProperties(signingProperties: ClientRuntime.Attributes, context: ClientRuntime.HttpContext) -> ClientRuntime.Attributes {
return signingProperties
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import ClientRuntime

public struct MockIdentity: Identity {
public init() {}
public var expiration: ClientRuntime.Date? = nil
}

public struct MockIdentityResolver: IdentityResolver {
public typealias IdentityT = MockIdentity
public init() {}
public func getIdentity(identityProperties: ClientRuntime.Attributes?) async throws -> MockIdentity {
return MockIdentity()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import ClientRuntime
import Foundation

public struct MockSigner: ClientRuntime.Signer {
public init() {}

public func signRequest<IdentityT: Identity>(
requestBuilder: ClientRuntime.SdkHttpRequestBuilder,
identity: IdentityT,
signingProperties: ClientRuntime.Attributes
) async throws -> ClientRuntime.SdkHttpRequestBuilder {
requestBuilder.withHeader(name: "Mock-Authorization", value: "Mock-Signed")
return requestBuilder
}

public func signEvent(
payload: Data,
previousSignature: String,
signingProperties: Attributes
) async throws -> SigningResult<EventStream.Message> {
return SigningResult(output: EventStream.Message(), signature: "")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import XCTest
import SmithyTestUtil
@testable import ClientRuntime

class AuthSchemeMiddlewareTests: XCTestCase {
private var contextBuilder: HttpContextBuilder!
private var operationStack: OperationStack<MockInput, MockOutput>!

override func setUp() async throws {
try await super.setUp()
contextBuilder = HttpContextBuilder()
.withAuthSchemeResolver(value: DefaultMockAuthSchemeResolver())
.withAuthScheme(value: MockNoAuth())
.withIdentityResolver(value: MockIdentityResolver(), type: .aws)
operationStack = OperationStack<MockInput, MockOutput>(id: "auth scheme middleware test stack")
}

// Test exception cases
func testNoAuthSchemeResolverConfigured() async throws {
contextBuilder.attributes.remove(key: AttributeKeys.authSchemeResolver)
contextBuilder.withOperation(value: "fillerOp")
do {
try await AssertSelectedAuthSchemeMatches(builtContext: contextBuilder.build(), expectedAuthScheme: "")
} catch ClientError.authError(let message) {
let expected = "No auth scheme resolver has been configured on the service."
XCTAssertEqual(message, expected)
} catch {
XCTFail("Unexpected error thrown: \(error.localizedDescription)")
}
}

func testNoIdentityResolverConfigured() async throws {
contextBuilder.attributes.remove(key: AttributeKeys.identityResolvers)
contextBuilder.withOperation(value: "fillerOp")
do {
try await AssertSelectedAuthSchemeMatches(builtContext: contextBuilder.build(), expectedAuthScheme: "")
} catch ClientError.authError(let message) {
let expected = "No identity resolver has been configured on the service."
XCTAssertEqual(message, expected)
} catch {
XCTFail("Unexpected error thrown: \(error.localizedDescription)")
}
}

func testNoAuthSchemeCouldBeLoaded() async throws {
contextBuilder.withOperation(value: "fillerOp")
do {
try await AssertSelectedAuthSchemeMatches(builtContext: contextBuilder.build(), expectedAuthScheme: "")
} catch ClientError.authError(let message) {
let expected = "Could not resolve auth scheme for the operation call. Log: Auth scheme fillerAuth was not enabled for this request."
XCTAssertEqual(message, expected)
} catch {
XCTFail("Unexpected error thrown: \(error.localizedDescription)")
}
}

// Test success cases
func testOnlyAuthSchemeA() async throws {
let context = contextBuilder
.withOperation(value: "authA")
.withAuthScheme(value: MockAuthSchemeA())
.build()
try await AssertSelectedAuthSchemeMatches(builtContext: context, expectedAuthScheme: "MockAuthSchemeA")
}

func testAuthOrderABSelectA() async throws {
let context = contextBuilder
.withOperation(value: "authAB")
.withAuthScheme(value: MockAuthSchemeA())
.withAuthScheme(value: MockAuthSchemeB())
.build()
try await AssertSelectedAuthSchemeMatches(builtContext: context, expectedAuthScheme: "MockAuthSchemeA")
}

func testAuthOrderABSelectB() async throws {
let context = contextBuilder
.withOperation(value: "authAB")
.withAuthScheme(value: MockAuthSchemeB())
.build()
try await AssertSelectedAuthSchemeMatches(builtContext: context, expectedAuthScheme: "MockAuthSchemeB")
}

func testAuthOrderABCSelectA() async throws {
let context = contextBuilder
.withOperation(value: "authABC")
.withAuthScheme(value: MockAuthSchemeA())
.withAuthScheme(value: MockAuthSchemeB())
.withAuthScheme(value: MockAuthSchemeC())
.build()
try await AssertSelectedAuthSchemeMatches(builtContext: context, expectedAuthScheme: "MockAuthSchemeA")
}

func testAuthOrderABCSelectB() async throws {
let context = contextBuilder
.withOperation(value: "authABC")
.withAuthScheme(value: MockAuthSchemeB())
.withAuthScheme(value: MockAuthSchemeC())
.build()
try await AssertSelectedAuthSchemeMatches(builtContext: context, expectedAuthScheme: "MockAuthSchemeB")
}

func testAuthOrderABCSelectC() async throws {
let context = contextBuilder
.withOperation(value: "authABC")
.withAuthScheme(value: MockAuthSchemeC())
.build()
try await AssertSelectedAuthSchemeMatches(builtContext: context, expectedAuthScheme: "MockAuthSchemeC")
}

func testAuthOderABCNoAuthSelectNoAuth() async throws {
let context = contextBuilder
.withOperation(value: "authABCNoAuth")
.build()
try await AssertSelectedAuthSchemeMatches(builtContext: context, expectedAuthScheme: "smithy.api#noAuth")
}

private func AssertSelectedAuthSchemeMatches(builtContext: HttpContext, expectedAuthScheme: String) async throws {
operationStack.buildStep.intercept(position: .before, middleware: AuthSchemeMiddleware<MockOutput, MockMiddlewareError>())

let mockHandler = MockHandler(handleCallback: { (context, input) in
let selectedAuthScheme = context.getSelectedAuthScheme()
XCTAssertEqual(expectedAuthScheme, selectedAuthScheme?.schemeID)
let httpResponse = HttpResponse(body: .noStream, statusCode: HttpStatusCode.ok)
let mockOutput = try! MockOutput(httpResponse: httpResponse, decoder: nil)
let output = OperationOutput<MockOutput>(httpResponse: httpResponse, output: mockOutput)
return output
})

_ = try await operationStack.handleMiddleware(context: builtContext, input: MockInput(), next: mockHandler)
}
}
Loading

0 comments on commit ec8f4ea

Please sign in to comment.