├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── codeql.yml │ └── swift.yml ├── .gitignore ├── .swiftlint.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── Package.resolved ├── Package.swift ├── README.md ├── Sources ├── SmokeAsync │ ├── OperationHandler+futureWithContextInputNoOutput.swift │ ├── OperationHandler+futureWithContextInputWithOutput.swift │ ├── OperationHandler+futureWithInputNoOutput.swift │ └── OperationHandler+futureWithInputWithOutput.swift ├── SmokeAsyncHTTP1 │ ├── SmokeHTTP1HandlerSelector+futureFromProviderWithInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+futureFromProviderWithInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+futureWithContextInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+futureWithContextInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+futureWithInputNoOutput.swift │ └── SmokeHTTP1HandlerSelector+futureWithInputWithOutput.swift ├── SmokeHTTP1 │ ├── ChannelHTTP1ResponseHandler.swift │ ├── HTTP1ChannelInboundHandler.swift │ ├── HTTP1RequestHandler.swift │ ├── HTTP1RequestInvocationContext.swift │ ├── HttpHeaderConstants.swift │ ├── KeepAliveStatus.swift │ ├── SmokeHTTP1Server.swift │ ├── SmokeInwardsRequestContext.swift │ └── StandardSmokeHTTP1Server.swift ├── SmokeInvocation │ ├── GlobalDispatchQueueAsyncInvocationStrategy.swift │ ├── GlobalDispatchQueueSyncInvocationStrategy.swift │ └── InvocationStrategy.swift ├── SmokeOperations │ ├── ErrorWithType.swift │ ├── InvocationReporting.swift │ ├── JSONDecoder+getFrameworkDecoder.swift │ ├── JSONEncoder+getFrameworkEncoder.swift │ ├── MetadataProvider+smokeFramework.swift │ ├── OperationDelegate.swift │ ├── OperationFailure.swift │ ├── OperationHandler+blockingWithContextInputNoOutput.swift │ ├── OperationHandler+blockingWithContextInputWithOutput.swift │ ├── OperationHandler+blockingWithInputNoOutput.swift │ ├── OperationHandler+blockingWithInputWithOutput.swift │ ├── OperationHandler+nonblockingWithContextInputNoOutput.swift │ ├── OperationHandler+nonblockingWithContextInputWithOutput.swift │ ├── OperationHandler+nonblockingWithInputNoOutput.swift │ ├── OperationHandler+nonblockingWithInputWithOutput.swift │ ├── OperationHandler+withContextInputNoOutput.swift │ ├── OperationHandler+withContextInputWithOutput.swift │ ├── OperationHandler+withInputNoOutput.swift │ ├── OperationHandler+withInputWithOutput.swift │ ├── OperationHandler.swift │ ├── OperationHandlerExtensions.swift │ ├── OperationIdentity.swift │ ├── OperationTraceContext.swift │ ├── PerInvocationContext.swift │ ├── RequestLoggerDecorator.swift │ ├── ReturnableErrorProtocols.swift │ ├── ServiceContext+invocationContext.swift │ ├── SmokeInvocationContext.swift │ ├── SmokeOperationError.swift │ ├── SmokeOperationReporting.swift │ ├── SmokeReportingConfiguration.swift │ └── Validatable.swift ├── SmokeOperationsHTTP1 │ ├── AdditionalHeadersOperationHTTPOutput.swift │ ├── BodyOperationHTTPInput.swift │ ├── BodyOperationHTTPOutput.swift │ ├── GenericJSONPayloadHTTP1OperationDelegate.swift │ ├── HTTP1OperationDelegate.swift │ ├── HTTP1OperationRequestHandler.swift │ ├── HTTP1ResponseHandler.swift │ ├── HTTP1ServerResponseComponents.swift │ ├── HeadersOperationHTTPInput.swift │ ├── OperationHTTP1InputProtocol.swift │ ├── OperationHTTP1OutputProtocol.swift │ ├── PathOperationHTTPInput.swift │ ├── QueryOperationHTTPInput.swift │ ├── SmokeAsyncPerInvocationContextInitializer.swift │ ├── SmokeAsyncStaticContextInitializer.swift │ ├── SmokeHTTP1HandlerSelector+blockingFromProviderWithInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+blockingFromProviderWithInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+blockingWithContextInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+blockingWithContextInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+blockingWithInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+blockingWithInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+fromProviderWithInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+fromProviderWithInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+nonblockingFromProviderWithInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+nonblockingFromProviderWithInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+nonblockingWithContextInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+nonblockingWithContextInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+nonblockingWithInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+nonblockingWithInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+withContextInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+withContextInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector+withInputNoOutput.swift │ ├── SmokeHTTP1HandlerSelector+withInputWithOutput.swift │ ├── SmokeHTTP1HandlerSelector.swift │ ├── SmokeHTTP1RequestHead.swift │ ├── SmokeInvocationTraceContext.swift │ ├── SmokePerInvocationContextInitializer.swift │ ├── SmokePerInvocationContextInitializerV2.swift │ ├── SmokeStaticContextInitializer.swift │ ├── SmokeStaticContextInitializerV2.swift │ ├── StandardHTTP1OperationRequestHandler.swift │ └── StandardSmokeHTTP1HandlerSelector.swift ├── SmokeOperationsHTTP1Server │ ├── HTTP1OperationTraceContext.swift │ ├── HTTP1RequestInvocationContext.swift │ ├── JSONPayloadHTTP1OperationDelegate.swift │ ├── SmokeAsyncServerPerInvocationContextInitializer.swift │ ├── SmokeAsyncServerStaticContextInitializer.swift │ ├── SmokeHTTP1Server+runAsOperationServer.swift │ ├── SmokeHTTP1Server+startAsOperationServer.swift │ ├── SmokeInvocationTraceContext.swift │ ├── SmokeServerHTTP1RequestHandler.swift │ ├── SmokeServerInvocationContext+HTTP1RequestInvocationContext.swift │ ├── SmokeServerInvocationReporting+withInvocationTraceContext.swift │ ├── SmokeServerInvocationReporting.swift │ ├── SmokeServerPerInvocationContextInitializer.swift │ ├── SmokeServerPerInvocationContextInitializerV2.swift │ ├── SmokeServerStaticContextInitializer.swift │ ├── SmokeServerStaticContextInitializerV2.swift │ ├── StandardHTTP1ResponseHandler.swift │ ├── StandardJSONSmokeAsyncServerPerInvocationContextInitializer.swift │ ├── StandardJSONSmokeAsyncServerStaticContextInitializer.swift │ ├── StandardJSONSmokeServerPerInvocationContextInitializer.swift │ └── StandardJSONSmokeServerStaticContextInitializer.swift ├── _SmokeOperationsConcurrency │ └── Export.swift └── _SmokeOperationsHTTP1Concurrency │ └── Export.swift ├── Tests └── SmokeOperationsHTTP1Tests │ ├── ErrorWithTypeTests.swift │ ├── SmokeOperationsHTTP1AsyncTests.swift │ ├── SmokeOperationsHTTP1SyncTests.swift │ └── TestConfiguration.swift └── docs └── Version_1_x_to_2_x_migration.md /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "smoke-framework-2.x" ] 6 | pull_request: 7 | branches: [ "smoke-framework-2.x" ] 8 | 9 | jobs: 10 | run-codeql-linux: 11 | name: Run CodeQL on Linux 12 | runs-on: ubuntu-latest 13 | container: swift:5.8 14 | permissions: 15 | security-events: write 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v3 20 | 21 | - name: Initialize CodeQL 22 | uses: github/codeql-action/init@v2 23 | with: 24 | languages: swift 25 | 26 | - name: Build 27 | run: swift build 28 | 29 | - name: Perform CodeQL Analysis 30 | uses: github/codeql-action/analyze@v2 31 | -------------------------------------------------------------------------------- /.github/workflows/swift.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: [ smoke-framework-2.x ] 6 | pull_request: 7 | branches: [ smoke-framework-2.x ] 8 | 9 | jobs: 10 | LatestVersionBuild: 11 | name: Swift ${{ matrix.swift }} on ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: [ubuntu-22.04, ubuntu-20.04] 15 | swift: ["5.9"] 16 | runs-on: ${{ matrix.os }} 17 | steps: 18 | - uses: swift-actions/setup-swift@v1.25.0 19 | with: 20 | swift-version: ${{ matrix.swift }} 21 | - uses: actions/checkout@v2 22 | - name: Build 23 | run: swift build -c release 24 | - name: Run tests 25 | run: swift test 26 | OlderVersionBuild: 27 | name: Swift ${{ matrix.swift }} on ${{ matrix.os }} 28 | strategy: 29 | matrix: 30 | os: [ubuntu-20.04] 31 | swift: ["5.8.1", "5.7.3"] 32 | runs-on: ${{ matrix.os }} 33 | steps: 34 | - uses: swift-actions/setup-swift@v1.25.0 35 | with: 36 | swift-version: ${{ matrix.swift }} 37 | - uses: actions/checkout@v2 38 | - name: Build 39 | run: swift build -c release 40 | - name: Run tests 41 | run: swift test 42 | SwiftLint: 43 | name: SwiftLint version 3.2.1 44 | runs-on: ubuntu-latest 45 | steps: 46 | - uses: actions/checkout@v1 47 | - name: GitHub Action for SwiftLint 48 | uses: norio-nomura/action-swiftlint@3.2.1 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .DS_Store 3 | .build/ 4 | .swiftpm/ 5 | *.xcodeproj 6 | *~ 7 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - trailing_whitespace 3 | - void_return 4 | - generic_type_name 5 | - class_delegate_protocol 6 | - identifier_name 7 | - weak_delegate 8 | included: 9 | - Sources 10 | line_length: 150 11 | function_body_length: 12 | warning: 50 13 | error: 75 14 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/amzn/smoke-framework/issues), or [recently closed](https://github.com/amzn/smoke-framework/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/amzn/smoke-framework/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/amzn/smoke-framework/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Smoke Framework 2 | Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "async-http-client", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/swift-server/async-http-client.git", 7 | "state" : { 8 | "revision" : "16f7e62c08c6969899ce6cc277041e868364e5cf", 9 | "version" : "1.19.0" 10 | } 11 | }, 12 | { 13 | "identity" : "smoke-http", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/amzn/smoke-http.git", 16 | "state" : { 17 | "revision" : "a6f386fc42d4758719b01a4e45f20c68bed88d50", 18 | "version" : "3.0.0" 19 | } 20 | }, 21 | { 22 | "identity" : "swift-atomics", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/apple/swift-atomics.git", 25 | "state" : { 26 | "revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10", 27 | "version" : "1.1.0" 28 | } 29 | }, 30 | { 31 | "identity" : "swift-collections", 32 | "kind" : "remoteSourceControl", 33 | "location" : "https://github.com/apple/swift-collections.git", 34 | "state" : { 35 | "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", 36 | "version" : "1.0.4" 37 | } 38 | }, 39 | { 40 | "identity" : "swift-distributed-tracing", 41 | "kind" : "remoteSourceControl", 42 | "location" : "https://github.com/apple/swift-distributed-tracing.git", 43 | "state" : { 44 | "revision" : "49b7617717a09f6b781c9a11e1628e3315d8d4fe", 45 | "version" : "1.0.1" 46 | } 47 | }, 48 | { 49 | "identity" : "swift-log", 50 | "kind" : "remoteSourceControl", 51 | "location" : "https://github.com/apple/swift-log.git", 52 | "state" : { 53 | "revision" : "532d8b529501fb73a2455b179e0bbb6d49b652ed", 54 | "version" : "1.5.3" 55 | } 56 | }, 57 | { 58 | "identity" : "swift-metrics", 59 | "kind" : "remoteSourceControl", 60 | "location" : "https://github.com/apple/swift-metrics.git", 61 | "state" : { 62 | "revision" : "971ba26378ab69c43737ee7ba967a896cb74c0d1", 63 | "version" : "2.4.1" 64 | } 65 | }, 66 | { 67 | "identity" : "swift-nio", 68 | "kind" : "remoteSourceControl", 69 | "location" : "https://github.com/apple/swift-nio.git", 70 | "state" : { 71 | "revision" : "cf281631ff10ec6111f2761052aa81896a83a007", 72 | "version" : "2.58.0" 73 | } 74 | }, 75 | { 76 | "identity" : "swift-nio-extras", 77 | "kind" : "remoteSourceControl", 78 | "location" : "https://github.com/apple/swift-nio-extras.git", 79 | "state" : { 80 | "revision" : "0e0d0aab665ff1a0659ce75ac003081f2b1c8997", 81 | "version" : "1.19.0" 82 | } 83 | }, 84 | { 85 | "identity" : "swift-nio-http2", 86 | "kind" : "remoteSourceControl", 87 | "location" : "https://github.com/apple/swift-nio-http2.git", 88 | "state" : { 89 | "revision" : "a8ccf13fa62775277a5d56844878c828bbb3be1a", 90 | "version" : "1.27.0" 91 | } 92 | }, 93 | { 94 | "identity" : "swift-nio-ssl", 95 | "kind" : "remoteSourceControl", 96 | "location" : "https://github.com/apple/swift-nio-ssl.git", 97 | "state" : { 98 | "revision" : "320bd978cceb8e88c125dcbb774943a92f6286e9", 99 | "version" : "2.25.0" 100 | } 101 | }, 102 | { 103 | "identity" : "swift-nio-transport-services", 104 | "kind" : "remoteSourceControl", 105 | "location" : "https://github.com/apple/swift-nio-transport-services.git", 106 | "state" : { 107 | "revision" : "e7403c35ca6bb539a7ca353b91cc2d8ec0362d58", 108 | "version" : "1.19.0" 109 | } 110 | }, 111 | { 112 | "identity" : "swift-service-context", 113 | "kind" : "remoteSourceControl", 114 | "location" : "https://github.com/apple/swift-service-context.git", 115 | "state" : { 116 | "revision" : "ce0141c8f123132dbd02fd45fea448018762df1b", 117 | "version" : "1.0.0" 118 | } 119 | } 120 | ], 121 | "version" : 2 122 | } 123 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.6 2 | // 3 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | 16 | import PackageDescription 17 | 18 | let package = Package( 19 | name: "smoke-framework", 20 | platforms: [ 21 | .macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6) 22 | ], 23 | products: [ 24 | .library( 25 | name: "SmokeOperations", 26 | targets: ["SmokeOperations"]), 27 | .library( 28 | name: "_SmokeOperationsConcurrency", 29 | targets: ["_SmokeOperationsConcurrency"]), 30 | .library( 31 | name: "SmokeOperationsHTTP1", 32 | targets: ["SmokeOperationsHTTP1"]), 33 | .library( 34 | name: "_SmokeOperationsHTTP1Concurrency", 35 | targets: ["_SmokeOperationsHTTP1Concurrency"]), 36 | .library( 37 | name: "SmokeOperationsHTTP1Server", 38 | targets: ["SmokeOperationsHTTP1Server"]), 39 | .library( 40 | name: "SmokeInvocation", 41 | targets: ["SmokeInvocation"]), 42 | .library( 43 | name: "SmokeHTTP1", 44 | targets: ["SmokeHTTP1"]), 45 | .library( 46 | name: "SmokeAsync", 47 | targets: ["SmokeAsync"]), 48 | .library( 49 | name: "SmokeAsyncHTTP1", 50 | targets: ["SmokeAsyncHTTP1"]), 51 | ], 52 | dependencies: [ 53 | .package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"), 54 | .package(url: "https://github.com/apple/swift-metrics.git", "1.0.0"..<"3.0.0"), 55 | .package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"), 56 | .package(url: "https://github.com/apple/swift-nio-extras.git", from: "1.0.0"), 57 | .package(url: "https://github.com/amzn/smoke-http.git", from: "3.0.0"), 58 | .package(url: "https://github.com/apple/swift-distributed-tracing.git", from: "1.0.0"), 59 | ], 60 | targets: [ 61 | .target( 62 | name: "SmokeInvocation", dependencies: [ 63 | .product(name: "Logging", package: "swift-log"), 64 | ]), 65 | .target( 66 | name: "SmokeHTTP1", dependencies: [ 67 | .product(name: "Logging", package: "swift-log"), 68 | .product(name: "NIO", package: "swift-nio"), 69 | .product(name: "NIOHTTP1", package: "swift-nio"), 70 | .product(name: "NIOFoundationCompat", package: "swift-nio"), 71 | .product(name: "NIOExtras", package: "swift-nio-extras"), 72 | .product(name: "SmokeHTTPClient", package: "smoke-http"), 73 | .target(name: "SmokeInvocation"), 74 | ]), 75 | .target( 76 | name: "SmokeOperations", dependencies: [ 77 | .product(name: "Logging", package: "swift-log"), 78 | .product(name: "Metrics", package: "swift-metrics"), 79 | .product(name: "Tracing", package: "swift-distributed-tracing"), 80 | .target(name: "SmokeInvocation"), 81 | ]), 82 | .target( 83 | name: "_SmokeOperationsConcurrency", dependencies: [ 84 | .target(name: "SmokeOperations"), 85 | ]), 86 | .target( 87 | name: "SmokeOperationsHTTP1", dependencies: [ 88 | .target(name: "SmokeOperations"), 89 | .product(name: "QueryCoding", package: "smoke-http"), 90 | .product(name: "HTTPPathCoding", package: "smoke-http"), 91 | .product(name: "HTTPHeadersCoding", package: "smoke-http"), 92 | .product(name: "SmokeHTTPClient", package: "smoke-http"), 93 | ]), 94 | .target( 95 | name: "_SmokeOperationsHTTP1Concurrency", dependencies: [ 96 | .target(name: "SmokeOperationsHTTP1"), 97 | .target(name: "_SmokeOperationsConcurrency"), 98 | ]), 99 | .target( 100 | name: "SmokeOperationsHTTP1Server", dependencies: [ 101 | .target(name: "SmokeOperationsHTTP1"), 102 | .target(name: "SmokeHTTP1"), 103 | ]), 104 | .target( 105 | name: "SmokeAsync", dependencies: [ 106 | .product(name: "Logging", package: "swift-log"), 107 | .product(name: "NIO", package: "swift-nio"), 108 | .target(name: "SmokeOperations"), 109 | ]), 110 | .target( 111 | name: "SmokeAsyncHTTP1", dependencies: [ 112 | .product(name: "NIOHTTP1", package: "swift-nio"), 113 | .target(name: "SmokeAsync"), 114 | .target(name: "SmokeOperationsHTTP1"), 115 | ]), 116 | .testTarget( 117 | name: "SmokeOperationsHTTP1Tests", dependencies: [ 118 | .target(name: "SmokeOperationsHTTP1"), 119 | .target(name: "SmokeHTTP1"), 120 | ]), 121 | ], 122 | swiftLanguageVersions: [.v5] 123 | ) 124 | -------------------------------------------------------------------------------- /Sources/SmokeAsync/OperationHandler+futureWithContextInputNoOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+futureWithContextInputNoOutput.swift 15 | // SmokeAsync 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import NIO 21 | import SmokeOperations 22 | 23 | public extension OperationHandler { 24 | /** 25 | Initializer for non-blocking operation handler that has input 26 | returns a result with an empty body. 27 | 28 | - Parameters: 29 | - inputProvider: function that obtains the input from the request. 30 | - operation: the handler method for the operation. 31 | - allowedErrors: the errors that can be serialized as responses 32 | from the operation and their error codes. 33 | - operationDelegate: optionally an operation-specific delegate to use when 34 | handling the operation. 35 | */ 36 | init(serverName: String, operationIdentifer: OperationIdentifer, 38 | reportingConfiguration: SmokeReportingConfiguration, 39 | inputProvider: @escaping (RequestHeadType, Data?) throws -> InputType, 40 | operation: @escaping ((InputType, ContextType, 41 | InvocationReportingType) throws -> EventLoopFuture), 42 | allowedErrors: [(ErrorType, Int)], 43 | operationDelegate: OperationDelegateType) 44 | where RequestHeadType == OperationDelegateType.RequestHeadType, 45 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 46 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 47 | /** 48 | * The wrapped input handler takes the provided operation handler and wraps it the responseHandler is 49 | * called to indicate success when the input handler's response handler is called. If the provided operation 50 | * provides an error, the responseHandler is called with that error. 51 | */ 52 | let wrappedInputHandler = { (input: InputType, requestHead: RequestHeadType, context: ContextType, 53 | responseHandler: ResponseHandlerType, invocationContext: SmokeInvocationContext) in 54 | let handlerResult: NoOutputOperationHandlerResult? 55 | do { 56 | let future = try operation(input, context, invocationContext.invocationReporting) 57 | 58 | future.whenComplete { result in 59 | let asyncHandlerResult: NoOutputOperationHandlerResult 60 | 61 | switch result { 62 | case .failure(let error): 63 | if let smokeReturnableError = error as? SmokeReturnableError { 64 | asyncHandlerResult = .smokeReturnableError(smokeReturnableError, 65 | allowedErrors) 66 | } else if case SmokeOperationsError.validationError(reason: let reason) = error { 67 | asyncHandlerResult = .validationError(reason) 68 | } else { 69 | asyncHandlerResult = .internalServerError(error) 70 | } 71 | case .success: 72 | asyncHandlerResult = .success 73 | } 74 | 75 | OperationHandler.handleNoOutputOperationHandlerResult( 76 | handlerResult: asyncHandlerResult, 77 | operationDelegate: operationDelegate, 78 | requestHead: requestHead, 79 | responseHandler: responseHandler, 80 | invocationContext: invocationContext) 81 | } 82 | 83 | // no immediate result 84 | handlerResult = nil 85 | } catch let smokeReturnableError as SmokeReturnableError { 86 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 87 | } catch SmokeOperationsError.validationError(reason: let reason) { 88 | handlerResult = .validationError(reason) 89 | } catch { 90 | handlerResult = .internalServerError(error) 91 | } 92 | 93 | // if this handler is throwing an error immediately 94 | if let handlerResult = handlerResult { 95 | OperationHandler.handleNoOutputOperationHandlerResult( 96 | handlerResult: handlerResult, 97 | operationDelegate: operationDelegate, 98 | requestHead: requestHead, 99 | responseHandler: responseHandler, 100 | invocationContext: invocationContext) 101 | } 102 | } 103 | 104 | self.init(serverName: serverName, operationIdentifer: operationIdentifer, reportingConfiguration: reportingConfiguration, 105 | inputHandler: wrappedInputHandler, 106 | inputProvider: inputProvider, 107 | operationDelegate: operationDelegate) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Sources/SmokeHTTP1/ChannelHTTP1ResponseHandler.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // ChannelHTTP1ResponseHandler.swift 15 | // SmokeHTTP1 16 | // 17 | 18 | import Foundation 19 | import NIO 20 | import NIOHTTP1 21 | 22 | /** 23 | A protocol that specifies a handler for a HTTP response. 24 | */ 25 | public protocol ChannelHTTP1ResponseHandler { 26 | /** 27 | Initializer. 28 | 29 | - Parameters: 30 | - requestHead: the head of the request that this handler will respond to. 31 | - keepAliveStatus: if the request should be kept alive. 32 | - context: the `ChannelHandlerContext` associated with the response. 33 | - wrapOutboundOut: helper function to prepare a `HTTPServerResponsePart` for transmission on the channel. 34 | - onComplete: to be called when the response has been sent on the channel. 35 | */ 36 | init(requestHead: HTTPRequestHead, 37 | keepAliveStatus: KeepAliveStatus, 38 | context: ChannelHandlerContext, 39 | wrapOutboundOut: @escaping (_ value: HTTPServerResponsePart) -> NIOAny, 40 | onComplete: @escaping () -> Void) 41 | 42 | /** 43 | Initializer. 44 | 45 | - Parameters: 46 | - requestHead: the head of the request that this handler will respond to. 47 | - keepAliveStatus: if the request should be kept alive. 48 | - context: the `ChannelHandlerContext` associated with the response. 49 | - smokeInwardsRequestContext: the context of the inwards request. 50 | - wrapOutboundOut: helper function to prepare a `HTTPServerResponsePart` for transmission on the channel. 51 | - onComplete: to be called when the response has been sent on the channel. 52 | */ 53 | init(requestHead: HTTPRequestHead, 54 | keepAliveStatus: KeepAliveStatus, 55 | context: ChannelHandlerContext, 56 | smokeInwardsRequestContext: SmokeInwardsRequestContext?, 57 | wrapOutboundOut: @escaping (_ value: HTTPServerResponsePart) -> NIOAny, 58 | onComplete: @escaping () -> Void) 59 | } 60 | 61 | public extension ChannelHTTP1ResponseHandler { 62 | // The function is being added as a non-breaking change, so add a default implementation that delegates to the existing 63 | // function that must be implemented. 64 | init(requestHead: HTTPRequestHead, 65 | keepAliveStatus: KeepAliveStatus, 66 | context: ChannelHandlerContext, 67 | smokeInwardsRequestContext _: SmokeInwardsRequestContext?, 68 | wrapOutboundOut: @escaping (_ value: HTTPServerResponsePart) -> NIOAny, 69 | onComplete: @escaping () -> Void) { 70 | self.init(requestHead: requestHead, 71 | keepAliveStatus: keepAliveStatus, 72 | context: context, 73 | wrapOutboundOut: wrapOutboundOut, 74 | onComplete: onComplete) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sources/SmokeHTTP1/HTTP1RequestHandler.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HTTP1RequestHandler.swift 15 | // SmokeHTTP1 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import NIO 21 | import NIOHTTP1 22 | import SmokeHTTPClient 23 | import SmokeInvocation 24 | 25 | /** 26 | Protocol that specifies a handler for a HttpRequest. 27 | */ 28 | public protocol HTTP1RequestHandler { 29 | associatedtype ResponseHandlerType: ChannelHTTP1ResponseHandler 30 | 31 | /** 32 | Handles an incoming request. 33 | 34 | - Parameters: 35 | - requestHead: the parameters specified in the head of the HTTP request. 36 | - body: the body of the request, if any. 37 | - responseHandler: a handler that can be used to respond to the request. 38 | - invocationStrategy: the invocationStrategy to use for this request. 39 | - requestLogger: the logger to use for this request. 40 | - internalRequestId: the internal identifier for this request. 41 | */ 42 | func handle(requestHead: HTTPRequestHead, body: Data?, responseHandler: ResponseHandlerType, 43 | invocationStrategy: InvocationStrategy, requestLogger: Logger, internalRequestId: String) 44 | 45 | /** 46 | Handles an incoming request. 47 | 48 | - Parameters: 49 | - requestHead: the parameters specified in the head of the HTTP request. 50 | - body: the body of the request, if any. 51 | - responseHandler: a handler that can be used to respond to the request. 52 | - invocationStrategy: the invocationStrategy to use for this request. 53 | - requestLogger: the logger to use for this request. 54 | - eventLoop: the event loop used for this request. 55 | - internalRequestId: the internal identifier for this request. 56 | */ 57 | func handle(requestHead: HTTPRequestHead, body: Data?, responseHandler: ResponseHandlerType, 58 | invocationStrategy: InvocationStrategy, requestLogger: Logger, eventLoop: EventLoop?, internalRequestId: String) 59 | 60 | /** 61 | Handles an incoming request. 62 | 63 | - Parameters: 64 | - requestHead: the parameters specified in the head of the HTTP request. 65 | - body: the body of the request, if any. 66 | - responseHandler: a handler that can be used to respond to the request. 67 | - invocationStrategy: the invocationStrategy to use for this request. 68 | - requestLogger: the logger to use for this request. 69 | - eventLoop: the event loop used for this request. 70 | - outwardsRequestAggregator: the outwards request aggregator to use. 71 | - internalRequestId: the internal identifier for this request. 72 | */ 73 | func handle(requestHead: HTTPRequestHead, body: Data?, responseHandler: ResponseHandlerType, 74 | invocationStrategy: InvocationStrategy, requestLogger: Logger, eventLoop: EventLoop?, 75 | outwardsRequestAggregator: OutwardsRequestAggregator?, internalRequestId: String) 76 | } 77 | 78 | public extension HTTP1RequestHandler { 79 | // The function is being added as a non-breaking change, so add a default implementation that delegates to the existing 80 | // function that must be implemented. 81 | func handle(requestHead: HTTPRequestHead, body: Data?, responseHandler: ResponseHandlerType, 82 | invocationStrategy: InvocationStrategy, requestLogger: Logger, eventLoop _: EventLoop?, internalRequestId: String) { 83 | self.handle(requestHead: requestHead, body: body, responseHandler: responseHandler, invocationStrategy: invocationStrategy, 84 | requestLogger: requestLogger, internalRequestId: internalRequestId) 85 | } 86 | 87 | // The function is being added as a non-breaking change, so add a default implementation that delegates to the existing 88 | // function that must be implemented. 89 | func handle(requestHead: HTTPRequestHead, body: Data?, responseHandler: ResponseHandlerType, 90 | invocationStrategy: InvocationStrategy, requestLogger: Logger, eventLoop _: EventLoop?, 91 | outwardsRequestAggregator _: OutwardsRequestAggregator?, internalRequestId: String) { 92 | self.handle(requestHead: requestHead, body: body, responseHandler: responseHandler, invocationStrategy: invocationStrategy, 93 | requestLogger: requestLogger, internalRequestId: internalRequestId) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Sources/SmokeHTTP1/HTTP1RequestInvocationContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HTTP1RequestTraceContext.swift 15 | // SmokeHTTP1 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import NIOHTTP1 21 | 22 | public protocol HTTP1RequestInvocationContext { 23 | var logger: Logger { get } 24 | 25 | func handleInwardsRequestComplete(httpHeaders: inout HTTPHeaders, status: HTTPResponseStatus, 26 | body: (contentType: String, data: Data)?) 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SmokeHTTP1/HttpHeaderConstants.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HttpHeaderConstants.swift 15 | // SmokeHTTP1 16 | // 17 | 18 | import Foundation 19 | 20 | public enum HTTP1Headers { 21 | /// Content-Length Header 22 | public static let contentLength = "Content-Length" 23 | 24 | /// Content-Type Header 25 | public static let contentType = "Content-Type" 26 | } 27 | -------------------------------------------------------------------------------- /Sources/SmokeHTTP1/KeepAliveStatus.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // KeepAliveStatus.swift 15 | // SmokeHTTP1 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | Class that shares the keepAlive status of a HTTP Request between the 22 | HTTPChannelInboundHandler and HttpResponseHandler. 23 | */ 24 | public class KeepAliveStatus { 25 | public var state: Bool 26 | 27 | init(state: Bool) { 28 | self.state = state 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SmokeHTTP1/SmokeHTTP1Server.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeHTTP1Server.swift 15 | // SmokeHTTP1 16 | // 17 | 18 | import Foundation 19 | import NIO 20 | 21 | public enum ServerDefaults { 22 | static let defaultHost = "0.0.0.0" 23 | public static let defaultPort = 8080 24 | } 25 | 26 | public enum SmokeHTTP1ServerError: Error { 27 | case shutdownAttemptOnUnstartedServer 28 | } 29 | 30 | /** 31 | A basic non-blocking HTTP server that handles a request with an 32 | optional body and returns a response with an optional body. 33 | 34 | This implementation wraps an `StandardSmokeHTTP1Server` instance internally, type erasing the generic parameters and 35 | presenting the same external methods as SmokeFramework 1.x. 36 | */ 37 | public class SmokeHTTP1Server { 38 | /** 39 | Enumeration specifying how the event loop is provided for a channel established by this client. 40 | */ 41 | public enum EventLoopProvider { 42 | /// The client will create a new EventLoopGroup to be used for channels created from 43 | /// this client. The EventLoopGroup will be closed when this client is closed. 44 | case spawnNewThreads 45 | /// The client will use the provided EventLoopGroup for channels created from 46 | /// this client. This EventLoopGroup will not be closed when this client is closed. 47 | case use(EventLoopGroup) 48 | } 49 | 50 | /** 51 | Enumeration specifying if the server should be shutdown on any signals received. 52 | */ 53 | public enum ShutdownOnSignal { 54 | // do not shut down the server on any signals 55 | case none 56 | // shutdown the server if a SIGINT is received 57 | case sigint 58 | // shutdown the server if a SIGTERM is received 59 | case sigterm 60 | } 61 | 62 | private let startHandler: () throws -> Void 63 | private let shutdownHandler: () throws -> Void 64 | private let waitUntilShutdownHandler: () throws -> Void 65 | private let waitUntilShutdownAndThenHandler: (_ onShutdown: @escaping () -> Void) throws -> Void 66 | private let onShutdownHandler: (_ onShutdown: @escaping () -> Void) throws -> Void 67 | 68 | public init(wrappedServer: StandardSmokeHTTP1Server) { 69 | self.startHandler = { 70 | try wrappedServer.start() 71 | } 72 | 73 | self.shutdownHandler = { 74 | try wrappedServer.shutdown() 75 | } 76 | 77 | self.waitUntilShutdownHandler = { 78 | try wrappedServer.waitUntilShutdown() 79 | } 80 | 81 | self.waitUntilShutdownAndThenHandler = { onShutdown in 82 | try wrappedServer.waitUntilShutdownAndThen(onShutdown: onShutdown) 83 | } 84 | 85 | self.onShutdownHandler = { onShutdown in 86 | try wrappedServer.onShutdown(onShutdown: onShutdown) 87 | } 88 | } 89 | 90 | /** 91 | Starts the server on the provided port. Function returns 92 | when the server is started. The server will continue running until 93 | either shutdown() is called or the surrounding application is being terminated. 94 | */ 95 | public func start() throws { 96 | try self.startHandler() 97 | } 98 | 99 | /** 100 | Initiates the process of shutting down the server. 101 | */ 102 | public func shutdown() throws { 103 | try self.shutdownHandler() 104 | } 105 | 106 | /** 107 | Blocks until the server has been shutdown and all completion handlers 108 | have been executed. 109 | */ 110 | public func waitUntilShutdown() throws { 111 | try self.waitUntilShutdownHandler() 112 | } 113 | 114 | /** 115 | Blocks until the server has been shutdown and all completion handlers 116 | have been executed. The provided closure will be added to the list of 117 | completion handlers to be executed on shutdown. If the server is already 118 | shutdown, the provided closure will be immediately executed. 119 | 120 | - Parameters: 121 | - onShutdown: the closure to be executed after the server has been 122 | fully shutdown. 123 | */ 124 | public func waitUntilShutdownAndThen(onShutdown: @escaping () -> Void) throws { 125 | try self.waitUntilShutdownAndThenHandler(onShutdown) 126 | } 127 | 128 | /** 129 | Provides a closure to be executed after the server has been fully shutdown. 130 | 131 | - Parameters: 132 | - onShutdown: the closure to be executed after the server has been 133 | fully shutdown. 134 | */ 135 | public func onShutdown(onShutdown: @escaping () -> Void) throws { 136 | try self.onShutdownHandler(onShutdown) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Sources/SmokeHTTP1/SmokeInwardsRequestContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeInwardsRequestContext.swift 15 | // SmokeHTTP1 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTPClient 20 | 21 | public protocol SmokeInwardsRequestContext { 22 | var headReceiveDate: Date? { get } 23 | 24 | var requestStart: Date { get } 25 | 26 | var retriableOutputRequestRecords: [RetriableOutputRequestRecord] { get } 27 | 28 | var retryAttemptRecords: [RetryAttemptRecord] { get } 29 | } 30 | 31 | public extension SmokeInwardsRequestContext { 32 | var headReceiveDate: Date? { 33 | return nil 34 | } 35 | } 36 | 37 | internal class StandardSmokeInwardsRequestContext: SmokeInwardsRequestContext, OutwardsRequestAggregator { 38 | let headReceiveDate: Date? 39 | let requestStart: Date 40 | private(set) var retriableOutputRequestRecords: [RetriableOutputRequestRecord] 41 | private(set) var retryAttemptRecords: [RetryAttemptRecord] 42 | 43 | internal let accessQueue = DispatchQueue( 44 | label: "com.amazon.SmokeFramework.StandardSmokeInwardsRequestContext.accessQueue", 45 | target: DispatchQueue.global()) 46 | 47 | init(headReceiveDate: Date?, requestStart: Date) { 48 | self.headReceiveDate = headReceiveDate 49 | self.requestStart = requestStart 50 | self.retriableOutputRequestRecords = [] 51 | self.retryAttemptRecords = [] 52 | } 53 | 54 | func recordOutwardsRequest(outputRequestRecord: OutputRequestRecord, onCompletion: @escaping () -> Void) { 55 | self.accessQueue.async { 56 | let retriableOutwardsRequest = SmokeRetriableOutputRequestRecord(outputRequests: [outputRequestRecord]) 57 | 58 | self.retriableOutputRequestRecords.append(retriableOutwardsRequest) 59 | 60 | onCompletion() 61 | } 62 | } 63 | 64 | func recordRetryAttempt(retryAttemptRecord: RetryAttemptRecord, onCompletion: @escaping () -> Void) { 65 | self.accessQueue.async { 66 | self.retryAttemptRecords.append(retryAttemptRecord) 67 | 68 | onCompletion() 69 | } 70 | } 71 | 72 | func recordRetriableOutwardsRequest(retriableOutwardsRequest: RetriableOutputRequestRecord, onCompletion: @escaping () -> Void) { 73 | self.accessQueue.async { 74 | self.retriableOutputRequestRecords.append(retriableOutwardsRequest) 75 | 76 | onCompletion() 77 | } 78 | } 79 | 80 | @available(swift, deprecated: 2.0, message: "Not thread-safe") 81 | func recordOutwardsRequest(outputRequestRecord: OutputRequestRecord) { 82 | let retriableOutwardsRequest = SmokeRetriableOutputRequestRecord(outputRequests: [outputRequestRecord]) 83 | 84 | self.retriableOutputRequestRecords.append(retriableOutwardsRequest) 85 | } 86 | 87 | @available(swift, deprecated: 2.0, message: "Not thread-safe") 88 | func recordRetryAttempt(retryAttemptRecord: RetryAttemptRecord) { 89 | self.retryAttemptRecords.append(retryAttemptRecord) 90 | } 91 | 92 | @available(swift, deprecated: 2.0, message: "Not thread-safe") 93 | func recordRetriableOutwardsRequest(retriableOutwardsRequest: RetriableOutputRequestRecord) { 94 | self.retriableOutputRequestRecords.append(retriableOutwardsRequest) 95 | } 96 | } 97 | 98 | struct SmokeRetriableOutputRequestRecord: RetriableOutputRequestRecord { 99 | var outputRequests: [OutputRequestRecord] 100 | } 101 | -------------------------------------------------------------------------------- /Sources/SmokeInvocation/GlobalDispatchQueueAsyncInvocationStrategy.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // GlobalDispatchQueueAsyncInvocationStrategy.swift 15 | // SmokeInvocation 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | An InvocationStrategy that will invocate the handler on 22 | DispatchQueue.global(), not waiting for it to complete. 23 | */ 24 | public struct GlobalDispatchQueueAsyncInvocationStrategy: InvocationStrategy { 25 | let queue = DispatchQueue.global() 26 | 27 | public init() {} 28 | 29 | public func invoke(handler: @escaping () -> Void) { 30 | self.queue.async { 31 | handler() 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SmokeInvocation/GlobalDispatchQueueSyncInvocationStrategy.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // GlobalDispatchQueueAsyncInvocationStrategy.swift 15 | // SmokeInvocation 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | An InvocationStrategy that will invocate the handler on 22 | DispatchQueue.global(), waiting for it to complete. 23 | */ 24 | public struct GlobalDispatchQueueSyncInvocationStrategy: InvocationStrategy { 25 | let queue = DispatchQueue.global() 26 | 27 | public init() {} 28 | 29 | public func invoke(handler: @escaping () -> Void) { 30 | self.queue.sync { 31 | handler() 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SmokeInvocation/InvocationStrategy.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // InvocationStrategy.swift 15 | // SmokeInvocation 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | A strategy protocol that manages how to invocate a handler. 22 | */ 23 | public protocol InvocationStrategy { 24 | /** 25 | Function to handle the invocation of the handler. 26 | 27 | - Parameters: 28 | - handler: The handler to invocate. 29 | */ 30 | func invoke(handler: @escaping () -> Void) 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/ErrorWithType.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // ErrorWithReason.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | A struct for encoding errors that preserves the expected output shape 22 | of the error response but adds the reason. 23 | */ 24 | struct ErrorWithType: Encodable { 25 | let type: String 26 | let payload: PayloadType 27 | 28 | enum CodingKeys: String, CodingKey { 29 | case type = "__type" 30 | } 31 | 32 | func encode(to encoder: Encoder) throws { 33 | var container = encoder.container(keyedBy: CodingKeys.self) 34 | try container.encode(self.type, forKey: .type) 35 | 36 | try self.payload.encode(to: encoder) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/InvocationReporting.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // InvocationReporting.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import Tracing 21 | 22 | /** 23 | A protocol that can report on an invocation. 24 | */ 25 | public protocol InvocationReporting { 26 | var logger: Logger { get } 27 | var internalRequestId: String { get } 28 | var span: Span? { get } 29 | 30 | func recordErrorForInvocation(_ error: Swift.Error) 31 | } 32 | 33 | public extension InvocationReporting { 34 | // Add span property while remaining backwards compatible 35 | var span: Span? { 36 | return nil 37 | } 38 | 39 | // Retain backwards-compatibility 40 | func recordErrorForInvocation(_: Swift.Error) { 41 | // be default do nothing 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/JSONDecoder+getFrameworkDecoder.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // JSONDecoder+getFrameworkDecoder.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | 20 | private func createDecoder() -> JSONDecoder { 21 | let jsonDecoder = JSONDecoder() 22 | if #available(OSX 10.12, *) { 23 | jsonDecoder.dateDecodingStrategy = .iso8601 24 | } 25 | 26 | return jsonDecoder 27 | } 28 | 29 | public extension JSONDecoder { 30 | /// Return a SmokeFramework compatible JSON Decoder 31 | static func getFrameworkDecoder() -> JSONDecoder { 32 | return createDecoder() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/JSONEncoder+getFrameworkEncoder.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // JSONEncoder+getFrameworkEncoder.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | 21 | private func createEncoder() -> JSONEncoder { 22 | let jsonEncoder = JSONEncoder() 23 | if #available(OSX 10.12, *) { 24 | jsonEncoder.dateEncodingStrategy = .iso8601 25 | } 26 | 27 | #if DEBUG 28 | jsonEncoder.outputFormatting = .prettyPrinted 29 | #endif 30 | 31 | return jsonEncoder 32 | } 33 | 34 | // swiftlint:disable force_try 35 | // If all else fails, an error payload to use. 36 | private let encodedInternalError = try! createEncoder().encode( 37 | ErrorWithType(type: "InternalError", 38 | payload: SmokeOperationsErrorPayload(errorMessage: nil))) 39 | // swiftlint:enable force_try 40 | 41 | public extension JSONEncoder { 42 | /// Return a SmokeFramework compatible JSON Encoder 43 | static func getFrameworkEncoder() -> JSONEncoder { 44 | return createEncoder() 45 | } 46 | 47 | /** 48 | Encodes a payload for use as a response, optionally with a reason. 49 | 50 | - Parameters: 51 | - payload: The payload to encode. 52 | - reason: Optionally the reason to include in the payload. 53 | */ 54 | static func encodePayload(payload: EncodableType, 55 | logger: Logger, 56 | reason: String? = nil) -> Data { 57 | let encodedError: Data 58 | 59 | do { 60 | if let reason = reason { 61 | let errorWithReason = ErrorWithType(type: reason, 62 | payload: payload) 63 | encodedError = try createEncoder().encode(errorWithReason) 64 | } else { 65 | encodedError = try createEncoder().encode(payload) 66 | } 67 | } catch { 68 | logger.error("Unable to encode error message.", 69 | metadata: ["cause": "\(String(describing: error))"]) 70 | 71 | encodedError = encodedInternalError 72 | } 73 | 74 | return encodedError 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/MetadataProvider+smokeFramework.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // MetadataProvider+smokeFramework 15 | // SmokeOperations 16 | // 17 | 18 | import Logging 19 | import ServiceContextModule 20 | 21 | extension Logger.MetadataProvider { 22 | /// A metadata provider exposing the attributes of the current invocation. 23 | /// 24 | /// - Parameters: 25 | /// - internalRequestIdKey: The metadata key of the internalRequestId. Defaults to "internalRequestId". 26 | /// - incomingOperationKey: The metadata key of the incomingOperation. Defaults to "incomingOperation". 27 | /// - externalRequestIdKey: The metadata key of the externalRequestId. Defaults to "externalRequestId". 28 | /// - Returns: A metadata provider ready to use with Logging. 29 | public static func smokeFramework(internalRequestIdKey: String = "internalRequestId", 30 | incomingOperationKey: String = "incomingOperation", 31 | externalRequestIdKey: String = "externalRequestId") -> Logger.MetadataProvider { 32 | .init { 33 | guard let invocationContext = ServiceContext.current?.invocationContext else { return [:] } 34 | 35 | var metadataProvider: Logger.Metadata = [ 36 | internalRequestIdKey: "\(invocationContext.internalRequestId)", 37 | incomingOperationKey: "\(invocationContext.incomingOperation)", 38 | ] 39 | 40 | if let externalRequestId = invocationContext.externalRequestId { 41 | metadataProvider[externalRequestIdKey] = "\(externalRequestId)" 42 | } 43 | 44 | return metadataProvider 45 | } 46 | } 47 | 48 | /// A metadata provider exposing the attributes of the current invocation with the default key names. 49 | public static let smokeFramework = Logger.MetadataProvider.smokeFramework() 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationDelegate.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | 21 | /** 22 | Delegate protocol for an operation that manages operation handling specific to 23 | a transport protocol. 24 | */ 25 | public protocol OperationDelegate { 26 | /// The type of the request head used with this delegate. 27 | associatedtype RequestHeadType 28 | /// The invocation reporting type used with this delegate 29 | associatedtype InvocationReportingType: InvocationReporting 30 | /// The type of response handler used with this delegate. 31 | associatedtype ResponseHandlerType 32 | 33 | /// The `Logging.Logger` to use for logging for this invocation. 34 | func decorateLoggerForAnonymousRequest(requestLogger: inout Logger) 35 | 36 | /** 37 | Function to handle a successful operation with no response. 38 | 39 | - Parameters: 40 | - requestHead: The original request head corresponding to the operation. Can be used to determine how to 41 | handle the response (such as requested response type). 42 | - responseHander: typically a response handler specific to the transport protocol being used. 43 | - invocationContext: the context for the current invocation. 44 | */ 45 | func handleResponseForOperationWithNoOutput(requestHead: RequestHeadType, responseHandler: ResponseHandlerType, 46 | invocationContext: SmokeInvocationContext) 47 | 48 | /** 49 | Function to handle an operation failure. 50 | 51 | - Parameters: 52 | - requestHead: The original request head corresponding to the operation. Can be used to determine how to 53 | handle the response (such as requested response type). 54 | - operationFailure: The cause of the operation failure. 55 | - responseHander: typically a response handler specific to the transport protocol being used. 56 | - invocationContext: the context for the current invocation. 57 | */ 58 | func handleResponseForOperationFailure(requestHead: RequestHeadType, operationFailure: OperationFailure, 59 | responseHandler: ResponseHandlerType, invocationContext: SmokeInvocationContext) 60 | 61 | /** 62 | Function to handle an internal server error. 63 | 64 | - Parameters: 65 | - requestHead: The original request head corresponding to the operation. Can be used to determine how to 66 | handle the response (such as requested response type). 67 | - responseHander: typically a response handler specific to the transport protocol being used. 68 | - invocationContext: the context for the current invocation. 69 | */ 70 | func handleResponseForInternalServerError(requestHead: RequestHeadType, responseHandler: ResponseHandlerType, 71 | invocationContext: SmokeInvocationContext) 72 | 73 | /** 74 | Function to handle an invalid operation being requested. 75 | 76 | - Parameters: 77 | - requestHead: The original request head corresponding to the operation. Can be used to determine how to 78 | handle the response (such as requested response type). 79 | - message: A message corressponding to the failure. 80 | - responseHander: typically a response handler specific to the transport protocol being used. 81 | - invocationContext: the context for the current invocation. 82 | */ 83 | func handleResponseForInvalidOperation(requestHead: RequestHeadType, message: String, 84 | responseHandler: ResponseHandlerType, invocationContext: SmokeInvocationContext) 85 | 86 | /** 87 | Function to handle a decoding error. 88 | 89 | - Parameters: 90 | - requestHead: The original request head corresponding to the operation. Can be used to determine how to 91 | handle the response (such as requested response type). 92 | - message: A message corressponding to the failure. 93 | - responseHander: typically a response handler specific to the transport protocol being used. 94 | - invocationContext: the context for the current invocation. 95 | */ 96 | func handleResponseForDecodingError(requestHead: RequestHeadType, message: String, 97 | responseHandler: ResponseHandlerType, invocationContext: SmokeInvocationContext) 98 | 99 | /** 100 | Function to handle a validation error. 101 | 102 | - Parameters: 103 | - requestHead: The original request head corresponding to the operation. Can be used to determine how to 104 | handle the response (such as requested response type). 105 | - message: A message corressponding to the failure. 106 | - responseHander: typically a response handler specific to the transport protocol being used. 107 | - invocationContext: the context for the current invocation. 108 | */ 109 | func handleResponseForValidationError(requestHead: RequestHeadType, message: String?, 110 | responseHandler: ResponseHandlerType, invocationContext: SmokeInvocationContext) 111 | } 112 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationFailure.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationFailure.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | 20 | /// The operation failed with the specified code, reason and payload. 21 | public struct OperationFailure { 22 | public let code: Int 23 | public let error: SmokeReturnableError 24 | 25 | public init(code: Int, error: SmokeReturnableError) { 26 | self.code = code 27 | self.error = error 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+blockingWithContextInputNoOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+blockingWithContextInputNoOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | 21 | public extension OperationHandler { 22 | /** 23 | Initializer for blocking operation handler that has input returns 24 | a result with an empty body. 25 | 26 | - Parameters: 27 | - inputProvider: function that obtains the input from the request. 28 | - operation: the handler method for the operation. 29 | - allowedErrors: the errors that can be serialized as responses 30 | from the operation and their error codes. 31 | - operationDelegate: optionally an operation-specific delegate to use when 32 | handling the operation. 33 | */ 34 | init(serverName: String, operationIdentifer: OperationIdentifer, 36 | reportingConfiguration: SmokeReportingConfiguration, 37 | inputProvider: @escaping (OperationDelegateType.RequestHeadType, Data?) throws -> InputType, 38 | operation: @escaping ((InputType, ContextType, InvocationReportingType) throws -> Void), 39 | allowedErrors: [(ErrorType, Int)], 40 | operationDelegate: OperationDelegateType) 41 | where RequestHeadType == OperationDelegateType.RequestHeadType, 42 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 43 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 44 | /** 45 | * The wrapped input handler takes the provided operation handler and wraps it so that if it 46 | * returns, the responseHandler is called to indicate success. If the provided operation 47 | * throws an error, the responseHandler is called with that error. 48 | */ 49 | let wrappedInputHandler = { (input: InputType, requestHead: RequestHeadType, context: ContextType, 50 | responseHandler: ResponseHandlerType, invocationContext: SmokeInvocationContext) in 51 | let handlerResult: NoOutputOperationHandlerResult 52 | do { 53 | try operation(input, context, invocationContext.invocationReporting) 54 | 55 | handlerResult = .success 56 | } catch let smokeReturnableError as SmokeReturnableError { 57 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 58 | } catch SmokeOperationsError.validationError(reason: let reason) { 59 | handlerResult = .validationError(reason) 60 | } catch { 61 | handlerResult = .internalServerError(error) 62 | } 63 | 64 | OperationHandler.handleNoOutputOperationHandlerResult( 65 | handlerResult: handlerResult, 66 | operationDelegate: operationDelegate, 67 | requestHead: requestHead, 68 | responseHandler: responseHandler, 69 | invocationContext: invocationContext) 70 | } 71 | 72 | self.init(serverName: serverName, operationIdentifer: operationIdentifer, reportingConfiguration: reportingConfiguration, 73 | inputHandler: wrappedInputHandler, 74 | inputProvider: inputProvider, 75 | operationDelegate: operationDelegate) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+blockingWithContextInputWithOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+blockingWithContextInputWithOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | 21 | public extension OperationHandler { 22 | /** 23 | Initializer for blocking operation handler that has input returns 24 | a result body. 25 | 26 | - Parameters: 27 | - inputProvider: function that obtains the input from the request. 28 | - operation: the handler method for the operation. 29 | - outputHandler: function that completes the response with the provided output. 30 | - allowedErrors: the errors that can be serialized as responses 31 | from the operation and their error codes. 32 | - operationDelegate: optionally an operation-specific delegate to use when 33 | handling the operation. 34 | */ 35 | init(serverName: String, operationIdentifer: OperationIdentifer, 37 | reportingConfiguration: SmokeReportingConfiguration, 38 | inputProvider: @escaping (RequestHeadType, Data?) throws -> InputType, 39 | operation: @escaping (InputType, ContextType, InvocationReportingType) throws -> OutputType, 40 | outputHandler: @escaping ( 41 | (RequestHeadType, OutputType, ResponseHandlerType, SmokeInvocationContext) -> Void), 42 | allowedErrors: [(ErrorType, Int)], 43 | operationDelegate: OperationDelegateType) 44 | where RequestHeadType == OperationDelegateType.RequestHeadType, 45 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 46 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 47 | /** 48 | * The wrapped input handler takes the provided operation handler and wraps it so that if it 49 | * returns, the responseHandler is called with the result. If the provided operation 50 | * throws an error, the responseHandler is called with that error. 51 | */ 52 | let wrappedInputHandler = { (input: InputType, requestHead: RequestHeadType, context: ContextType, 53 | responseHandler: OperationDelegateType.ResponseHandlerType, 54 | invocationContext: SmokeInvocationContext) in 55 | let handlerResult: WithOutputOperationHandlerResult 56 | do { 57 | let output = try operation(input, context, invocationContext.invocationReporting) 58 | 59 | handlerResult = .success(output) 60 | } catch let smokeReturnableError as SmokeReturnableError { 61 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 62 | } catch SmokeOperationsError.validationError(reason: let reason) { 63 | handlerResult = .validationError(reason) 64 | } catch { 65 | handlerResult = .internalServerError(error) 66 | } 67 | 68 | OperationHandler.handleWithOutputOperationHandlerResult( 69 | handlerResult: handlerResult, 70 | operationDelegate: operationDelegate, 71 | requestHead: requestHead, 72 | responseHandler: responseHandler, 73 | outputHandler: outputHandler, 74 | invocationContext: invocationContext) 75 | } 76 | 77 | self.init(serverName: serverName, operationIdentifer: operationIdentifer, reportingConfiguration: reportingConfiguration, 78 | inputHandler: wrappedInputHandler, 79 | inputProvider: inputProvider, 80 | operationDelegate: operationDelegate) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+blockingWithInputNoOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+blockingWithInputNoOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | 21 | public extension OperationHandler { 22 | /** 23 | Initializer for blocking operation handler that has input returns 24 | a result with an empty body. 25 | 26 | - Parameters: 27 | - serverName: the name of the server this operation is part of. 28 | - operationIdentifer: the identifer for the operation being handled. 29 | - reportingConfiguration: the configuration for how operations on this server should be reported on. 30 | - inputProvider: function that obtains the input from the request. 31 | - operation: the handler method for the operation. 32 | - allowedErrors: the errors that can be serialized as responses 33 | from the operation and their error codes. 34 | - operationDelegate: optionally an operation-specific delegate to use when 35 | handling the operation. 36 | */ 37 | init(serverName: String, operationIdentifer: OperationIdentifer, 39 | reportingConfiguration: SmokeReportingConfiguration, 40 | inputProvider: @escaping (OperationDelegateType.RequestHeadType, Data?) throws -> InputType, 41 | operation: @escaping ((InputType, ContextType) throws -> Void), 42 | allowedErrors: [(ErrorType, Int)], 43 | operationDelegate: OperationDelegateType) 44 | where RequestHeadType == OperationDelegateType.RequestHeadType, 45 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 46 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 47 | /** 48 | * The wrapped input handler takes the provided operation handler and wraps it so that if it 49 | * returns, the responseHandler is called to indicate success. If the provided operation 50 | * throws an error, the responseHandler is called with that error. 51 | */ 52 | let wrappedInputHandler = { (input: InputType, requestHead: RequestHeadType, context: ContextType, 53 | responseHandler: ResponseHandlerType, invocationContext: SmokeInvocationContext) in 54 | let handlerResult: NoOutputOperationHandlerResult 55 | do { 56 | try operation(input, context) 57 | 58 | handlerResult = .success 59 | } catch let smokeReturnableError as SmokeReturnableError { 60 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 61 | } catch SmokeOperationsError.validationError(reason: let reason) { 62 | handlerResult = .validationError(reason) 63 | } catch { 64 | handlerResult = .internalServerError(error) 65 | } 66 | 67 | OperationHandler.handleNoOutputOperationHandlerResult( 68 | handlerResult: handlerResult, 69 | operationDelegate: operationDelegate, 70 | requestHead: requestHead, 71 | responseHandler: responseHandler, 72 | invocationContext: invocationContext) 73 | } 74 | 75 | self.init(serverName: serverName, 76 | operationIdentifer: operationIdentifer, 77 | reportingConfiguration: reportingConfiguration, 78 | inputHandler: wrappedInputHandler, 79 | inputProvider: inputProvider, 80 | operationDelegate: operationDelegate) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+blockingWithInputWithOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+blockingWithInputWithOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | 21 | public extension OperationHandler { 22 | /** 23 | Initializer for blocking operation handler that has input returns 24 | a result body. 25 | 26 | - Parameters: 27 | - serverName: the name of the server this operation is part of. 28 | - operationIdentifer: the identifer for the operation being handled. 29 | - reportingConfiguration: the configuration for how operations on this server should be reported on. 30 | - inputProvider: function that obtains the input from the request. 31 | - operation: the handler method for the operation. 32 | - outputHandler: function that completes the response with the provided output. 33 | - allowedErrors: the errors that can be serialized as responses 34 | from the operation and their error codes. 35 | - operationDelegate: optionally an operation-specific delegate to use when 36 | handling the operation. 37 | */ 38 | init(serverName: String, 40 | operationIdentifer: OperationIdentifer, 41 | reportingConfiguration: SmokeReportingConfiguration, 42 | inputProvider: @escaping (RequestHeadType, Data?) throws -> InputType, 43 | operation: @escaping (InputType, ContextType) throws -> OutputType, 44 | outputHandler: @escaping ( 45 | (RequestHeadType, OutputType, ResponseHandlerType, SmokeInvocationContext) -> Void), 46 | allowedErrors: [(ErrorType, Int)], 47 | operationDelegate: OperationDelegateType) 48 | where RequestHeadType == OperationDelegateType.RequestHeadType, 49 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 50 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 51 | /** 52 | * The wrapped input handler takes the provided operation handler and wraps it so that if it 53 | * returns, the responseHandler is called with the result. If the provided operation 54 | * throws an error, the responseHandler is called with that error. 55 | */ 56 | let wrappedInputHandler = { (input: InputType, requestHead: RequestHeadType, context: ContextType, 57 | responseHandler: OperationDelegateType.ResponseHandlerType, 58 | invocationContext: SmokeInvocationContext) in 59 | let handlerResult: WithOutputOperationHandlerResult 60 | do { 61 | let output = try operation(input, context) 62 | 63 | handlerResult = .success(output) 64 | } catch let smokeReturnableError as SmokeReturnableError { 65 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 66 | } catch SmokeOperationsError.validationError(reason: let reason) { 67 | handlerResult = .validationError(reason) 68 | } catch { 69 | handlerResult = .internalServerError(error) 70 | } 71 | 72 | OperationHandler.handleWithOutputOperationHandlerResult( 73 | handlerResult: handlerResult, 74 | operationDelegate: operationDelegate, 75 | requestHead: requestHead, 76 | responseHandler: responseHandler, 77 | outputHandler: outputHandler, 78 | invocationContext: invocationContext) 79 | } 80 | 81 | self.init(serverName: serverName, 82 | operationIdentifer: operationIdentifer, 83 | reportingConfiguration: reportingConfiguration, 84 | inputHandler: wrappedInputHandler, 85 | inputProvider: inputProvider, 86 | operationDelegate: operationDelegate) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+nonblockingWithContextInputNoOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+nonblockingWithContextInputNoOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | 21 | public extension OperationHandler { 22 | /** 23 | Initializer for non-blocking operation handler that has input 24 | returns a result with an empty body. 25 | 26 | - Parameters: 27 | - inputProvider: function that obtains the input from the request. 28 | - operation: the handler method for the operation. 29 | - allowedErrors: the errors that can be serialized as responses 30 | from the operation and their error codes. 31 | - operationDelegate: optionally an operation-specific delegate to use when 32 | handling the operation. 33 | */ 34 | init(serverName: String, operationIdentifer: OperationIdentifer, 36 | reportingConfiguration: SmokeReportingConfiguration, 37 | inputProvider: @escaping (RequestHeadType, Data?) throws -> InputType, 38 | operation: @escaping ((InputType, ContextType, 39 | InvocationReportingType, @escaping (Swift.Error?) -> Void) throws -> Void), 40 | allowedErrors: [(ErrorType, Int)], 41 | operationDelegate: OperationDelegateType) 42 | where RequestHeadType == OperationDelegateType.RequestHeadType, 43 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 44 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 45 | /** 46 | * The wrapped input handler takes the provided operation handler and wraps it the responseHandler is 47 | * called to indicate success when the input handler's response handler is called. If the provided operation 48 | * provides an error, the responseHandler is called with that error. 49 | */ 50 | let wrappedInputHandler = { (input: InputType, requestHead: RequestHeadType, context: ContextType, 51 | responseHandler: ResponseHandlerType, invocationContext: SmokeInvocationContext) in 52 | let handlerResult: NoOutputOperationHandlerResult? 53 | do { 54 | try operation(input, context, invocationContext.invocationReporting) { error in 55 | let asyncHandlerResult: NoOutputOperationHandlerResult 56 | 57 | if let error = error { 58 | if let smokeReturnableError = error as? SmokeReturnableError { 59 | asyncHandlerResult = .smokeReturnableError(smokeReturnableError, 60 | allowedErrors) 61 | } else if case SmokeOperationsError.validationError(reason: let reason) = error { 62 | asyncHandlerResult = .validationError(reason) 63 | } else { 64 | asyncHandlerResult = .internalServerError(error) 65 | } 66 | } else { 67 | asyncHandlerResult = .success 68 | } 69 | 70 | OperationHandler.handleNoOutputOperationHandlerResult( 71 | handlerResult: asyncHandlerResult, 72 | operationDelegate: operationDelegate, 73 | requestHead: requestHead, 74 | responseHandler: responseHandler, 75 | invocationContext: invocationContext) 76 | } 77 | 78 | // no immediate result 79 | handlerResult = nil 80 | } catch let smokeReturnableError as SmokeReturnableError { 81 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 82 | } catch SmokeOperationsError.validationError(reason: let reason) { 83 | handlerResult = .validationError(reason) 84 | } catch { 85 | handlerResult = .internalServerError(error) 86 | } 87 | 88 | // if this handler is throwing an error immediately 89 | if let handlerResult = handlerResult { 90 | OperationHandler.handleNoOutputOperationHandlerResult( 91 | handlerResult: handlerResult, 92 | operationDelegate: operationDelegate, 93 | requestHead: requestHead, 94 | responseHandler: responseHandler, 95 | invocationContext: invocationContext) 96 | } 97 | } 98 | 99 | self.init(serverName: serverName, operationIdentifer: operationIdentifer, reportingConfiguration: reportingConfiguration, 100 | inputHandler: wrappedInputHandler, 101 | inputProvider: inputProvider, 102 | operationDelegate: operationDelegate) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+nonblockingWithInputNoOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+nonblockingWithInputNoOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | 21 | public extension OperationHandler { 22 | /** 23 | Initializer for non-blocking operation handler that has input 24 | returns a result with an empty body. 25 | 26 | - Parameters: 27 | - serverName: the name of the server this operation is part of. 28 | - operationIdentifer: the identifer for the operation being handled. 29 | - reportingConfiguration: the configuration for how operations on this server should be reported on. 30 | - inputProvider: function that obtains the input from the request. 31 | - operation: the handler method for the operation. 32 | - allowedErrors: the errors that can be serialized as responses 33 | from the operation and their error codes. 34 | - operationDelegate: optionally an operation-specific delegate to use when 35 | handling the operation. 36 | */ 37 | init(serverName: String, operationIdentifer: OperationIdentifer, 39 | reportingConfiguration: SmokeReportingConfiguration, 40 | inputProvider: @escaping (RequestHeadType, Data?) throws -> InputType, 41 | operation: @escaping ((InputType, ContextType, @escaping (Swift.Error?) -> Void) throws -> Void), 42 | allowedErrors: [(ErrorType, Int)], 43 | operationDelegate: OperationDelegateType) 44 | where RequestHeadType == OperationDelegateType.RequestHeadType, 45 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 46 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 47 | /** 48 | * The wrapped input handler takes the provided operation handler and wraps it the responseHandler is 49 | * called to indicate success when the input handler's response handler is called. If the provided operation 50 | * provides an error, the responseHandler is called with that error. 51 | */ 52 | let wrappedInputHandler = { (input: InputType, requestHead: RequestHeadType, context: ContextType, 53 | responseHandler: ResponseHandlerType, invocationContext: SmokeInvocationContext) in 54 | let handlerResult: NoOutputOperationHandlerResult? 55 | do { 56 | try operation(input, context) { error in 57 | let asyncHandlerResult: NoOutputOperationHandlerResult 58 | 59 | if let error = error { 60 | if let smokeReturnableError = error as? SmokeReturnableError { 61 | asyncHandlerResult = .smokeReturnableError(smokeReturnableError, 62 | allowedErrors) 63 | } else if case SmokeOperationsError.validationError(reason: let reason) = error { 64 | asyncHandlerResult = .validationError(reason) 65 | } else { 66 | asyncHandlerResult = .internalServerError(error) 67 | } 68 | } else { 69 | asyncHandlerResult = .success 70 | } 71 | 72 | OperationHandler.handleNoOutputOperationHandlerResult( 73 | handlerResult: asyncHandlerResult, 74 | operationDelegate: operationDelegate, 75 | requestHead: requestHead, 76 | responseHandler: responseHandler, 77 | invocationContext: invocationContext) 78 | } 79 | 80 | // no immediate result 81 | handlerResult = nil 82 | } catch let smokeReturnableError as SmokeReturnableError { 83 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 84 | } catch SmokeOperationsError.validationError(reason: let reason) { 85 | handlerResult = .validationError(reason) 86 | } catch { 87 | handlerResult = .internalServerError(error) 88 | } 89 | 90 | // if this handler is throwing an error immediately 91 | if let handlerResult = handlerResult { 92 | OperationHandler.handleNoOutputOperationHandlerResult( 93 | handlerResult: handlerResult, 94 | operationDelegate: operationDelegate, 95 | requestHead: requestHead, 96 | responseHandler: responseHandler, 97 | invocationContext: invocationContext) 98 | } 99 | } 100 | 101 | self.init(serverName: serverName, 102 | operationIdentifer: operationIdentifer, 103 | reportingConfiguration: reportingConfiguration, 104 | inputHandler: wrappedInputHandler, 105 | inputProvider: inputProvider, 106 | operationDelegate: operationDelegate) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+withContextInputNoOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+withContextInputNoOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import Tracing 21 | 22 | public extension OperationHandler { 23 | /** 24 | Initializer for async operation handler that has input returns 25 | a result with an empty body. 26 | 27 | - Parameters: 28 | - inputProvider: function that obtains the input from the request. 29 | - operation: the handler method for the operation. 30 | - allowedErrors: the errors that can be serialized as responses 31 | from the operation and their error codes. 32 | - operationDelegate: optionally an operation-specific delegate to use when 33 | handling the operation. 34 | */ 35 | init(serverName: String, operationIdentifer: OperationIdentifer, 37 | reportingConfiguration: SmokeReportingConfiguration, 38 | inputProvider: @escaping (OperationDelegateType.RequestHeadType, Data?) throws -> InputType, 39 | operation: @escaping ((InputType, ContextType, InvocationReportingType) async throws -> Void), 40 | allowedErrors: [(ErrorType, Int)], 41 | operationDelegate: OperationDelegateType) 42 | where RequestHeadType == OperationDelegateType.RequestHeadType, 43 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 44 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 45 | /** 46 | * The wrapped input handler takes the provided operation handler and wraps it so that if it 47 | * returns, the responseHandler is called to indicate success. If the provided operation 48 | * throws an error, the responseHandler is called with that error. 49 | */ 50 | func wrappedInputHandler(input: InputType, requestHead: RequestHeadType, context: ContextType, 51 | responseHandler: ResponseHandlerType, 52 | invocationContext: SmokeInvocationContext) { 53 | Task { 54 | await Self.withSpanContext(invocationContext: invocationContext) { 55 | let handlerResult: NoOutputOperationHandlerResult 56 | do { 57 | try await operation(input, context, invocationContext.invocationReporting) 58 | 59 | handlerResult = .success 60 | } catch let smokeReturnableError as SmokeReturnableError { 61 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 62 | } catch SmokeOperationsError.validationError(reason: let reason) { 63 | handlerResult = .validationError(reason) 64 | } catch { 65 | handlerResult = .internalServerError(error) 66 | } 67 | 68 | OperationHandler.handleNoOutputOperationHandlerResult( 69 | handlerResult: handlerResult, 70 | operationDelegate: operationDelegate, 71 | requestHead: requestHead, 72 | responseHandler: responseHandler, 73 | invocationContext: invocationContext) 74 | } 75 | } 76 | } 77 | 78 | self.init(serverName: serverName, operationIdentifer: operationIdentifer, reportingConfiguration: reportingConfiguration, 79 | inputHandler: wrappedInputHandler, 80 | inputProvider: inputProvider, 81 | operationDelegate: operationDelegate, 82 | ignoreInvocationStrategy: true) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+withContextInputWithOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+withContextInputWithOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import Tracing 21 | 22 | public extension OperationHandler { 23 | /** 24 | Initializer for async operation handler that has input returns 25 | a result body. 26 | 27 | - Parameters: 28 | - inputProvider: function that obtains the input from the request. 29 | - operation: the handler method for the operation. 30 | - outputHandler: function that completes the response with the provided output. 31 | - allowedErrors: the errors that can be serialized as responses 32 | from the operation and their error codes. 33 | - operationDelegate: optionally an operation-specific delegate to use when 34 | handling the operation. 35 | */ 36 | init(serverName: String, operationIdentifer: OperationIdentifer, 38 | reportingConfiguration: SmokeReportingConfiguration, 39 | inputProvider: @escaping (RequestHeadType, Data?) throws -> InputType, 40 | operation: @escaping (InputType, ContextType, InvocationReportingType) async throws -> OutputType, 41 | outputHandler: @escaping ( 42 | (RequestHeadType, OutputType, ResponseHandlerType, SmokeInvocationContext) -> Void), 43 | allowedErrors: [(ErrorType, Int)], 44 | operationDelegate: OperationDelegateType) 45 | where RequestHeadType == OperationDelegateType.RequestHeadType, 46 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 47 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 48 | /** 49 | * The wrapped input handler takes the provided operation handler and wraps it so that if it 50 | * returns, the responseHandler is called with the result. If the provided operation 51 | * throws an error, the responseHandler is called with that error. 52 | */ 53 | func wrappedInputHandler(input: InputType, requestHead: RequestHeadType, context: ContextType, 54 | responseHandler: OperationDelegateType.ResponseHandlerType, 55 | invocationContext: SmokeInvocationContext) { 56 | Task { 57 | await Self.withSpanContext(invocationContext: invocationContext) { 58 | let handlerResult: WithOutputOperationHandlerResult 59 | do { 60 | let output = try await operation(input, context, invocationContext.invocationReporting) 61 | 62 | handlerResult = .success(output) 63 | } catch let smokeReturnableError as SmokeReturnableError { 64 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 65 | } catch SmokeOperationsError.validationError(reason: let reason) { 66 | handlerResult = .validationError(reason) 67 | } catch { 68 | handlerResult = .internalServerError(error) 69 | } 70 | 71 | OperationHandler.handleWithOutputOperationHandlerResult( 72 | handlerResult: handlerResult, 73 | operationDelegate: operationDelegate, 74 | requestHead: requestHead, 75 | responseHandler: responseHandler, 76 | outputHandler: outputHandler, 77 | invocationContext: invocationContext) 78 | } 79 | } 80 | } 81 | 82 | self.init(serverName: serverName, operationIdentifer: operationIdentifer, reportingConfiguration: reportingConfiguration, 83 | inputHandler: wrappedInputHandler, 84 | inputProvider: inputProvider, 85 | operationDelegate: operationDelegate, 86 | ignoreInvocationStrategy: true) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+withInputNoOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+withInputNoOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import Tracing 21 | 22 | public extension OperationHandler { 23 | /** 24 | Initializer for async operation handler that has input returns 25 | a result with an empty body. 26 | 27 | - Parameters: 28 | - serverName: the name of the server this operation is part of. 29 | - operationIdentifer: the identifer for the operation being handled. 30 | - reportingConfiguration: the configuration for how operations on this server should be reported on. 31 | - inputProvider: function that obtains the input from the request. 32 | - operation: the handler method for the operation. 33 | - allowedErrors: the errors that can be serialized as responses 34 | from the operation and their error codes. 35 | - operationDelegate: optionally an operation-specific delegate to use when 36 | handling the operation. 37 | */ 38 | init(serverName: String, operationIdentifer: OperationIdentifer, 40 | reportingConfiguration: SmokeReportingConfiguration, 41 | inputProvider: @escaping (OperationDelegateType.RequestHeadType, Data?) throws -> InputType, 42 | operation: @escaping ((InputType, ContextType) async throws -> Void), 43 | allowedErrors: [(ErrorType, Int)], 44 | operationDelegate: OperationDelegateType) 45 | where RequestHeadType == OperationDelegateType.RequestHeadType, 46 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 47 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 48 | /** 49 | * The wrapped input handler takes the provided operation handler and wraps it so that if it 50 | * returns, the responseHandler is called to indicate success. If the provided operation 51 | * throws an error, the responseHandler is called with that error. 52 | */ 53 | func wrappedInputHandler(input: InputType, requestHead: RequestHeadType, context: ContextType, 54 | responseHandler: ResponseHandlerType, 55 | invocationContext: SmokeInvocationContext) { 56 | Task { 57 | await Self.withSpanContext(invocationContext: invocationContext) { 58 | let handlerResult: NoOutputOperationHandlerResult 59 | do { 60 | try await operation(input, context) 61 | 62 | handlerResult = .success 63 | } catch let smokeReturnableError as SmokeReturnableError { 64 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 65 | } catch SmokeOperationsError.validationError(reason: let reason) { 66 | handlerResult = .validationError(reason) 67 | } catch { 68 | handlerResult = .internalServerError(error) 69 | } 70 | 71 | OperationHandler.handleNoOutputOperationHandlerResult( 72 | handlerResult: handlerResult, 73 | operationDelegate: operationDelegate, 74 | requestHead: requestHead, 75 | responseHandler: responseHandler, 76 | invocationContext: invocationContext) 77 | } 78 | } 79 | } 80 | 81 | self.init(serverName: serverName, 82 | operationIdentifer: operationIdentifer, 83 | reportingConfiguration: reportingConfiguration, 84 | inputHandler: wrappedInputHandler, 85 | inputProvider: inputProvider, 86 | operationDelegate: operationDelegate, 87 | ignoreInvocationStrategy: true) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationHandler+withInputWithOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHandler+withInputWithOutput.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import Tracing 21 | 22 | public extension OperationHandler { 23 | /** 24 | Initializer for async operation handler that has input returns 25 | a result body. 26 | 27 | - Parameters: 28 | - serverName: the name of the server this operation is part of. 29 | - operationIdentifer: the identifer for the operation being handled. 30 | - reportingConfiguration: the configuration for how operations on this server should be reported on. 31 | - inputProvider: function that obtains the input from the request. 32 | - operation: the handler method for the operation. 33 | - outputHandler: function that completes the response with the provided output. 34 | - allowedErrors: the errors that can be serialized as responses 35 | from the operation and their error codes. 36 | - operationDelegate: optionally an operation-specific delegate to use when 37 | handling the operation. 38 | */ 39 | init(serverName: String, 41 | operationIdentifer: OperationIdentifer, 42 | reportingConfiguration: SmokeReportingConfiguration, 43 | inputProvider: @escaping (RequestHeadType, Data?) throws -> InputType, 44 | operation: @escaping (InputType, ContextType) async throws -> OutputType, 45 | outputHandler: @escaping ( 46 | (RequestHeadType, OutputType, ResponseHandlerType, SmokeInvocationContext) -> Void), 47 | allowedErrors: [(ErrorType, Int)], 48 | operationDelegate: OperationDelegateType) 49 | where RequestHeadType == OperationDelegateType.RequestHeadType, 50 | InvocationReportingType == OperationDelegateType.InvocationReportingType, 51 | ResponseHandlerType == OperationDelegateType.ResponseHandlerType { 52 | /** 53 | * The wrapped input handler takes the provided operation handler and wraps it so that if it 54 | * returns, the responseHandler is called with the result. If the provided operation 55 | * throws an error, the responseHandler is called with that error. 56 | */ 57 | func wrappedInputHandler(input: InputType, requestHead: RequestHeadType, context: ContextType, 58 | responseHandler: OperationDelegateType.ResponseHandlerType, 59 | invocationContext: SmokeInvocationContext) { 60 | Task { 61 | await Self.withSpanContext(invocationContext: invocationContext) { 62 | let handlerResult: WithOutputOperationHandlerResult 63 | do { 64 | let output = try await operation(input, context) 65 | 66 | handlerResult = .success(output) 67 | } catch let smokeReturnableError as SmokeReturnableError { 68 | handlerResult = .smokeReturnableError(smokeReturnableError, allowedErrors) 69 | } catch SmokeOperationsError.validationError(reason: let reason) { 70 | handlerResult = .validationError(reason) 71 | } catch { 72 | handlerResult = .internalServerError(error) 73 | } 74 | 75 | OperationHandler.handleWithOutputOperationHandlerResult( 76 | handlerResult: handlerResult, 77 | operationDelegate: operationDelegate, 78 | requestHead: requestHead, 79 | responseHandler: responseHandler, 80 | outputHandler: outputHandler, 81 | invocationContext: invocationContext) 82 | } 83 | } 84 | } 85 | 86 | self.init(serverName: serverName, 87 | operationIdentifer: operationIdentifer, 88 | reportingConfiguration: reportingConfiguration, 89 | inputHandler: wrappedInputHandler, 90 | inputProvider: inputProvider, 91 | operationDelegate: operationDelegate, 92 | ignoreInvocationStrategy: true) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationIdentity.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationIdentity.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | 20 | public protocol OperationIdentity: Hashable, CustomStringConvertible { 21 | var operationPath: String { get } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/OperationTraceContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationTraceContext.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import Tracing 21 | 22 | public struct RequestSpanParameters { 23 | public let operationName: String 24 | public let internalRequestId: String 25 | 26 | public init(operationName: String, internalRequestId: String) { 27 | self.operationName = operationName 28 | self.internalRequestId = internalRequestId 29 | } 30 | } 31 | 32 | public enum CreateRequestSpan { 33 | // A `Tracing.Span` should never be created for a request. 34 | case never 35 | // A `Tracing.Span` can be created for a request 36 | // if the `OperationTraceContext` decides to create one. 37 | // It is the responsibility of the OperationTraceContext 38 | // to manage the lifecycle of the span if it creates one, 39 | // most likely closing it in the 40 | // `handleInwardsRequestComplete` function. 41 | case ifRequired(RequestSpanParameters) 42 | } 43 | 44 | public struct OperationTraceContextOptions { 45 | public let createRequestSpan: CreateRequestSpan 46 | 47 | public init(createRequestSpan: CreateRequestSpan) { 48 | self.createRequestSpan = createRequestSpan 49 | } 50 | } 51 | 52 | public protocol OperationTraceContext { 53 | associatedtype RequestHeadType 54 | associatedtype ResponseHeadersType 55 | associatedtype ResponseStatusType 56 | 57 | var span: Span? { get } 58 | 59 | init(requestHead: RequestHeadType, bodyData: Data?) 60 | 61 | init(requestHead: RequestHeadType, bodyData: Data?, options: OperationTraceContextOptions?) 62 | 63 | func handleInwardsRequestStart(requestHead: RequestHeadType, bodyData: Data?, logger: inout Logger, internalRequestId: String) 64 | 65 | func handleInwardsRequestComplete(httpHeaders: inout ResponseHeadersType, status: ResponseStatusType, body: (contentType: String, data: Data)?, 66 | logger: Logger, internalRequestId: String) 67 | 68 | func recordErrorForInvocation(_ error: Swift.Error) 69 | } 70 | 71 | public extension OperationTraceContext { 72 | // Add options accepting initializer while remaining backwards compatible 73 | init(requestHead: RequestHeadType, bodyData: Data?, options _: OperationTraceContextOptions?) { 74 | self.init(requestHead: requestHead, bodyData: bodyData) 75 | } 76 | 77 | // Add span property while remaining backwards compatible 78 | var span: Span? { 79 | return nil 80 | } 81 | 82 | // Retain backwards-compatibility 83 | func recordErrorForInvocation(_: Swift.Error) { 84 | // do nothing by default 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/PerInvocationContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // PerInvocationContext.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | 20 | public enum PerInvocationContext { 21 | case `static`(ContextType) 22 | case provider((InvocationReportingType) -> ContextType) 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/RequestLoggerDecorator.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // RequestLoggerDecorator.swift 15 | // SmokeOperations 16 | // 17 | import Foundation 18 | import Logging 19 | 20 | /** 21 | Defines that a `SmokeServerInvocationReporting` instance can be retrieved from conforming types. 22 | */ 23 | public protocol RequestLoggerDecorator { 24 | /// The `Logging.Logger` to use for logging for this invocation. 25 | func decorate(requestLogger: inout Logger) 26 | } 27 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/ReturnableErrorProtocols.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // ReturnableErrorProtocols 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | 21 | public protocol Identifiable { 22 | var identity: String { get } 23 | } 24 | 25 | /// Type alias for an error that also can be identified by its description 26 | public typealias ErrorIdentifiableByDescription = 27 | Swift.Error & CustomStringConvertible 28 | 29 | /// Type alias for an error that can be returned by the Smoke Framework 30 | /// Just be identifiable and encodable 31 | public typealias SmokeReturnableError = 32 | ErrorIdentifiableByDescription & Encodable 33 | 34 | /// Helper protocol for encoding errors 35 | public protocol ErrorEncoder { 36 | func encode(_ input: InputType, logger: Logger) throws -> Data 37 | } 38 | 39 | public extension Encodable where Self: SmokeReturnableError { 40 | func encode(errorEncoder: ErrorEncoder, logger: Logger) throws -> Data { 41 | return try errorEncoder.encode(self, logger: logger) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/ServiceContext+invocationContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // ServiceContext+invocationContext 15 | // SmokeOperations 16 | // 17 | 18 | import ServiceContextModule 19 | 20 | public struct InvocationContext { 21 | var internalRequestId: String 22 | var incomingOperation: String 23 | var externalRequestId: String? 24 | 25 | public init(internalRequestId: String, incomingOperation: String, externalRequestId: String?) { 26 | self.internalRequestId = internalRequestId 27 | self.incomingOperation = incomingOperation 28 | self.externalRequestId = externalRequestId 29 | } 30 | } 31 | 32 | extension ServiceContext { 33 | public var invocationContext: InvocationContext? { 34 | get { 35 | self[InvocationContextKey.self] 36 | } 37 | set { 38 | self[InvocationContextKey.self] = newValue 39 | } 40 | } 41 | } 42 | 43 | extension InvocationContext: CustomStringConvertible { 44 | public var description: String { 45 | return internalRequestId 46 | } 47 | } 48 | 49 | private enum InvocationContextKey: ServiceContextKey { 50 | typealias Value = InvocationContext 51 | 52 | static var nameOverride: String? = "smoke-framework-invocation-context" 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/SmokeInvocationContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeInvocationContext.swift 15 | // SmokeOperations 16 | // 17 | import Foundation 18 | 19 | public struct SmokeInvocationContext { 20 | public let invocationReporting: InvocationReportingType 21 | public let requestReporting: SmokeOperationReporting 22 | 23 | public init(invocationReporting: InvocationReportingType, 24 | requestReporting: SmokeOperationReporting) { 25 | self.invocationReporting = invocationReporting 26 | self.requestReporting = requestReporting 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/SmokeOperationError.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeOperationsError.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | Errors that can thrown as part of the SmokeOperations library. 22 | */ 23 | public enum SmokeOperationsError: Error { 24 | /// There was an error during validation of input or output. 25 | case validationError(reason: String) 26 | /// There was no registered operation for the incoming request. 27 | case invalidOperation(reason: String) 28 | /// The operation failed due to a serialization error. 29 | case serializationError(description: String, reportableType: String?) 30 | } 31 | 32 | /** 33 | Error payload shape for SmokeOperationsErrors. 34 | */ 35 | public struct SmokeOperationsErrorPayload: Codable { 36 | let errorMessage: String? 37 | 38 | public init(errorMessage: String?) { 39 | self.errorMessage = errorMessage 40 | } 41 | 42 | enum CodingKeys: String, CodingKey { 43 | case errorMessage = "message" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/SmokeOperationReporting.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeOperationReporting.swift 15 | // SmokeOperations 16 | // 17 | import Foundation 18 | import Logging 19 | import Metrics 20 | 21 | private let namespaceDimension = "Namespace" 22 | private let operationNameDimension = "Operation Name" 23 | private let metricNameDimension = "Metric Name" 24 | 25 | private let successCountMetric = "successCount" 26 | private let failure5XXCountMetric = "failure5XXCount" 27 | private let failure4XXCountMetric = "failure4XXCount" 28 | private let requestReadLatencyTimeMetric = "requestReadLatencyTime" 29 | private let specificFailureStatusCountMetricFormat = "failure%dCount" 30 | private let latencyTimeMetric = "latencyTime" 31 | private let serviceLatencyTimeMetric = "serviceLatencyTime" 32 | private let outwardsServiceCallLatencySumMetric = "outwardsServiceCallLatencySum" 33 | private let outwardsServiceCallRetryWaitSumMetric = "outwardsServiceCallRetryWaitSum" 34 | 35 | /** 36 | Stores the counters for reporting on a particular operation. 37 | */ 38 | public struct SmokeOperationReporting { 39 | public let successCounter: Metrics.Counter? 40 | public let failure5XXCounter: Metrics.Counter? 41 | public let failure4XXCounter: Metrics.Counter? 42 | public let requestReadLatencyTimer: Metrics.Timer? 43 | public let specificFailureStatusCounters: [UInt: Metrics.Counter]? 44 | public let latencyTimer: Metrics.Timer? 45 | public let serviceLatencyTimer: Metrics.Timer? 46 | public let outwardsServiceCallLatencySumTimer: Metrics.Timer? 47 | public let outwardsServiceCallRetryWaitSumTimer: Metrics.Timer? 48 | 49 | public init(serverName: String, request: RequestType, 50 | configuration: SmokeReportingConfiguration) { 51 | let operationName = request.description 52 | 53 | func getCounter(metricName: String) -> Counter { 54 | let counterDimensions = [ 55 | (namespaceDimension, serverName), 56 | (operationNameDimension, operationName), 57 | (metricNameDimension, metricName) 58 | ] 59 | return Counter(label: "\(serverName).\(operationName).\(metricName)", 60 | dimensions: counterDimensions) 61 | } 62 | 63 | func getTimer(metricName: String) -> Timer { 64 | let timerDimensions = [ 65 | (namespaceDimension, serverName), 66 | (operationNameDimension, operationName), 67 | (metricNameDimension, metricName) 68 | ] 69 | return Timer(label: "\(serverName).\(operationName).\(metricName)", 70 | dimensions: timerDimensions) 71 | } 72 | 73 | if configuration.reportSuccessForRequest(request) { 74 | self.successCounter = getCounter(metricName: successCountMetric) 75 | } else { 76 | self.successCounter = nil 77 | } 78 | 79 | if configuration.reportFailure5XXForRequest(request) { 80 | self.failure5XXCounter = getCounter(metricName: failure5XXCountMetric) 81 | } else { 82 | self.failure5XXCounter = nil 83 | } 84 | 85 | if configuration.reportFailure4XXForRequest(request) { 86 | self.failure4XXCounter = getCounter(metricName: failure4XXCountMetric) 87 | } else { 88 | self.failure4XXCounter = nil 89 | } 90 | 91 | if configuration.reportRequestReadLatencyForRequest(request) { 92 | self.requestReadLatencyTimer = getTimer(metricName: requestReadLatencyTimeMetric) 93 | } else { 94 | self.requestReadLatencyTimer = nil 95 | } 96 | 97 | if configuration.reportSpecificFailureStatusesForRequest(request), 98 | let specificFailureStatusesToReport = configuration.specificFailureStatusesToReport { 99 | let countersWithStatusCodes: [(UInt, Counter)] = specificFailureStatusesToReport.map { statusCode in 100 | let metricName = String(format: specificFailureStatusCountMetricFormat, statusCode) 101 | let specificFailureStatusCounter = getCounter(metricName: metricName) 102 | return (statusCode, specificFailureStatusCounter) 103 | } 104 | self.specificFailureStatusCounters = Dictionary(uniqueKeysWithValues: countersWithStatusCodes) 105 | } else { 106 | self.specificFailureStatusCounters = nil 107 | } 108 | 109 | if configuration.reportLatencyForRequest(request) { 110 | self.latencyTimer = getTimer(metricName: latencyTimeMetric) 111 | } else { 112 | self.latencyTimer = nil 113 | } 114 | 115 | if configuration.reportServiceLatencyForRequest(request) { 116 | self.serviceLatencyTimer = getTimer(metricName: serviceLatencyTimeMetric) 117 | } else { 118 | self.serviceLatencyTimer = nil 119 | } 120 | 121 | if configuration.reportOutwardsServiceCallLatencySumForRequest(request) { 122 | self.outwardsServiceCallLatencySumTimer = getTimer(metricName: outwardsServiceCallLatencySumMetric) 123 | } else { 124 | self.outwardsServiceCallLatencySumTimer = nil 125 | } 126 | 127 | if configuration.reportOutwardsServiceCallRetryWaitLatencySumForRequest(request) { 128 | self.outwardsServiceCallRetryWaitSumTimer = getTimer(metricName: outwardsServiceCallRetryWaitSumMetric) 129 | } else { 130 | self.outwardsServiceCallRetryWaitSumTimer = nil 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Sources/SmokeOperations/Validatable.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // Validatable.swift 15 | // SmokeOperations 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | Protocol that provides a method to validate an instance. 22 | */ 23 | public protocol Validatable { 24 | /** 25 | Called to validate the current instance. 26 | Throws an error if validation fails. 27 | */ 28 | func validate() throws 29 | } 30 | 31 | public typealias ValidatableCodable = Validatable & Codable 32 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/AdditionalHeadersOperationHTTPOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // AdditionalHeadersOperationHTTPOutput.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | 20 | public struct AdditionalHeadersOperationHTTPOutput: OperationHTTP1OutputProtocol { 21 | public let bodyEncodable: AdditionalHeadersType? 22 | public let additionalHeadersEncodable: AdditionalHeadersType? 23 | 24 | public init(additionalHeadersEncodable: AdditionalHeadersType) { 25 | self.bodyEncodable = nil 26 | self.additionalHeadersEncodable = additionalHeadersEncodable 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/BodyOperationHTTPInput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // BodyOperationHTTPInput.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | Implementation of the OperationHTTP1InputProtocol that only decodes 22 | the HTTP body. 23 | */ 24 | public struct BodyOperationHTTPInput: OperationHTTP1InputProtocol { 25 | // This struct doesn't use these types but we must provide a 26 | // concrete type to satify the protocol 27 | public typealias QueryType = String 28 | public typealias PathType = String 29 | public typealias HeadersType = String 30 | 31 | public let body: BodyType 32 | 33 | public init(body: BodyType) { 34 | self.body = body 35 | } 36 | 37 | public static func compose(queryDecodableProvider _: () throws -> String, 38 | pathDecodableProvider _: () throws -> String, 39 | bodyDecodableProvider: () throws -> BodyType, 40 | headersDecodableProvider _: () throws -> String) throws -> BodyOperationHTTPInput { 41 | let body = try bodyDecodableProvider() 42 | 43 | return .init(body: body) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/BodyOperationHTTPOutput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // BodyOperationHTTPOutput.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | 20 | public struct BodyOperationHTTPOutput: OperationHTTP1OutputProtocol { 21 | public let bodyEncodable: BodyType? 22 | public let additionalHeadersEncodable: BodyType? 23 | 24 | public init(bodyEncodable: BodyType) { 25 | self.bodyEncodable = bodyEncodable 26 | self.additionalHeadersEncodable = nil 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/HTTP1OperationDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HTTP1OperationDelegate.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | import SmokeOperations 20 | 21 | public enum OperationInputHTTPLocation { 22 | case body 23 | case query 24 | case path 25 | case headers 26 | } 27 | 28 | public enum OperationOutputHTTPLocation { 29 | case body 30 | case headers 31 | } 32 | 33 | /** 34 | Delegate protocol for an operation that manages operation handling specific to 35 | a transport protocol. 36 | */ 37 | public protocol HTTP1OperationDelegate: OperationDelegate { 38 | /** 39 | Function to retrieve an instance of the InputType from the request. Will throw an error 40 | if an instance of InputType cannot be constructed from the request. 41 | */ 42 | func getInputForOperation(requestHead: RequestHeadType, body: Data?) throws -> InputType 43 | 44 | /** 45 | Function to retrieve an instance of the InputType from the request. Will throw an error 46 | if an instance of InputType cannot be constructed from the request. 47 | */ 48 | func getInputForOperation(requestHead: RequestHeadType, 49 | body: Data?, 50 | location: OperationInputHTTPLocation) throws -> InputType 51 | 52 | /** 53 | Function to handle a successful response from an operation. 54 | 55 | - Parameters: 56 | - requestHead: The original request head corresponding to the operation. Can be used to determine how to 57 | handle the response (such as requested response type). 58 | - output: The instance of the OutputType to send as a response. 59 | - responseHander: typically a response handler specific to the transport protocol being used. 60 | - invocationContext: the context for the current invocation. 61 | */ 62 | func handleResponseForOperation(requestHead: RequestHeadType, 63 | output: OutputType, 64 | responseHandler: ResponseHandlerType, 65 | invocationContext: SmokeInvocationContext) 66 | 67 | /** 68 | Function to handle a successful response from an operation. 69 | 70 | - Parameters: 71 | - requestHead: The original request head corresponding to the operation. Can be used to determine how to 72 | handle the response (such as requested response type). 73 | - output: The instance of the OutputType to send as a response. 74 | - responseHander: typically a response handler specific to the transport protocol being used. 75 | - invocationContext: the context for the current invocation. 76 | */ 77 | func handleResponseForOperation(requestHead: RequestHeadType, 78 | location: OperationOutputHTTPLocation, 79 | output: OutputType, 80 | responseHandler: ResponseHandlerType, 81 | invocationContext: SmokeInvocationContext) 82 | } 83 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/HTTP1OperationRequestHandler.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HTTP1OperationRequestHandler.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import NIO 21 | import NIOHTTP1 22 | import SmokeInvocation 23 | import SmokeOperations 24 | 25 | /** 26 | Protocol that specifies a handler for a HttpRequest. 27 | */ 28 | public protocol HTTP1OperationRequestHandler { 29 | associatedtype ResponseHandlerType 30 | associatedtype InvocationReportingType: InvocationReporting 31 | 32 | /** 33 | Handles an incoming request. 34 | 35 | - Parameters: 36 | - requestHead: the parameters specified in the head of the HTTP request. 37 | - body: the body of the request, if any. 38 | - responseHandler: a handler that can be used to respond to the request. 39 | - invocationStrategy: the invocationStrategy to use for this request. 40 | */ 41 | func handle(requestHead: HTTPRequestHead, body: Data?, responseHandler: ResponseHandlerType, 42 | invocationStrategy: InvocationStrategy, requestLogger: Logger, internalRequestId: String, 43 | invocationReportingProvider: @escaping (Logger) -> InvocationReportingType) 44 | } 45 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/HTTP1ResponseHandler.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HTTP1ResponseHandler.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | import NIO 20 | import NIOHTTP1 21 | import SmokeOperations 22 | 23 | /** 24 | A protocol that specifies a handler for a HTTP response. 25 | */ 26 | public protocol HTTP1ResponseHandler { 27 | associatedtype InvocationContext 28 | 29 | /** 30 | Function used to provide a response to a HTTP request. 31 | 32 | - Parameters: 33 | - invocationContext: the context for the current invocation. 34 | - status: the status to provide in the response. 35 | - responseComponents: the components to send in the response. 36 | */ 37 | func complete(invocationContext: InvocationContext, status: HTTPResponseStatus, 38 | responseComponents: HTTP1ServerResponseComponents) 39 | 40 | /** 41 | Function used to provide a response to a HTTP request on the server event loop. 42 | 43 | - Parameters: 44 | - invocationContext: the context for the current invocation. 45 | - status: the status to provide in the response. 46 | - responseComponents: the components to send in the response. 47 | */ 48 | func completeInEventLoop(invocationContext: InvocationContext, status: HTTPResponseStatus, 49 | responseComponents: HTTP1ServerResponseComponents) 50 | 51 | /** 52 | Function used to provide a response to a HTTP request. The response will not be 53 | reported at standard logging levels. 54 | 55 | - Parameters: 56 | - invocationContext: the context for the current invocation. 57 | - status: the status to provide in the response. 58 | - body: the content type and data to use for the response. 59 | */ 60 | func completeSilently(invocationContext: InvocationContext, status: HTTPResponseStatus, 61 | responseComponents: HTTP1ServerResponseComponents) 62 | 63 | /** 64 | Function used to provide a response to a HTTP request on the server event loop. The 65 | response will not be reported at standard logging levels. 66 | 67 | - Parameters: 68 | - invocationContext: the context for the current invocation. 69 | - status: the status to provide in the response. 70 | - body: the content type and data to use for the response. 71 | */ 72 | func completeSilentlyInEventLoop(invocationContext: InvocationContext, status: HTTPResponseStatus, 73 | responseComponents: HTTP1ServerResponseComponents) 74 | 75 | /** 76 | Execute the provided closure in the event loop corresponding to the response. 77 | 78 | - Parameters: 79 | - invocationContext: the context for the current invocation. 80 | - execute: the closure to execute. 81 | */ 82 | func executeInEventLoop(invocationContext: InvocationContext, execute: @escaping () -> Void) 83 | } 84 | 85 | public extension HTTP1ResponseHandler { 86 | func completeSilently(invocationContext: InvocationContext, status: HTTPResponseStatus, 87 | responseComponents: HTTP1ServerResponseComponents) { 88 | complete(invocationContext: invocationContext, status: status, responseComponents: responseComponents) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/HTTP1ServerResponseComponents.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HTTP1ServerResponseComponents.swift 15 | // SmokeHTTP1 16 | // 17 | 18 | import Foundation 19 | 20 | /// The parsed components that specify a request. 21 | public struct HTTP1ServerResponseComponents { 22 | /// any additional response headers. 23 | public let additionalHeaders: [(String, String)] 24 | /// The body data of the response. 25 | public let body: (contentType: String, data: Data)? 26 | 27 | public init(additionalHeaders: [(String, String)], 28 | body: (contentType: String, data: Data)?) { 29 | self.additionalHeaders = additionalHeaders 30 | self.body = body 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/HeadersOperationHTTPInput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HeadersOperationHTTPInput.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | Implementation of the OperationHTTP1InputProtocol that only decodes 22 | the HTTP path. 23 | */ 24 | public struct HeadersOperationHTTPInput: OperationHTTP1InputProtocol { 25 | // This struct doesn't use these types but we must provide a 26 | // concrete type to satify the protocol 27 | public typealias QueryType = String 28 | public typealias BodyType = String 29 | public typealias PathType = String 30 | 31 | public let headers: HeadersType 32 | 33 | public init(headers: HeadersType) { 34 | self.headers = headers 35 | } 36 | 37 | public static func compose(queryDecodableProvider _: () throws -> String, 38 | pathDecodableProvider _: () throws -> String, 39 | bodyDecodableProvider _: () throws -> String, 40 | headersDecodableProvider: () throws -> HeadersType) throws -> HeadersOperationHTTPInput { 41 | let headers = try headersDecodableProvider() 42 | 43 | return .init(headers: headers) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/OperationHTTP1InputProtocol.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHTTP1InputProtocol.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | import SmokeOperations 20 | 21 | /** 22 | A protocol that represents the input to an operation from a HTTP request. 23 | */ 24 | public protocol OperationHTTP1InputProtocol { 25 | associatedtype QueryType: Decodable 26 | associatedtype PathType: Decodable 27 | associatedtype BodyType: Decodable 28 | associatedtype HeadersType: Decodable 29 | 30 | /** 31 | Composes an instance from its constituent Decodable parts. 32 | May return one of its constituent parts if of a compatible type. 33 | 34 | - Parameters: 35 | - queryDecodableProvider: provider for the decoded query for this instance. 36 | - pathDecodableProvider: provider for the decoded http path for this instance. 37 | - bodyDecodableProvider: provider for the decoded body for this instance. 38 | - headersDecodableProvider: provider for the decoded headers for this instance. 39 | */ 40 | static func compose(queryDecodableProvider: () throws -> QueryType, 41 | pathDecodableProvider: () throws -> PathType, 42 | bodyDecodableProvider: () throws -> BodyType, 43 | headersDecodableProvider: () throws -> HeadersType) throws -> Self 44 | } 45 | 46 | public typealias ValidatableOperationHTTP1InputProtocol = Validatable & OperationHTTP1InputProtocol 47 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/OperationHTTP1OutputProtocol.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // OperationHTTP1OutputProtocol.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | import SmokeOperations 20 | 21 | /** 22 | A protocol that represents the output from an operation to be 23 | send as a HTTP response. 24 | */ 25 | public protocol OperationHTTP1OutputProtocol { 26 | associatedtype BodyType: Encodable 27 | associatedtype AdditionalHeadersType: Encodable 28 | 29 | /// An instance of a type that is encodable to a body 30 | var bodyEncodable: BodyType? { get } 31 | /// An instance of a type that is encodable to additional headers 32 | var additionalHeadersEncodable: AdditionalHeadersType? { get } 33 | } 34 | 35 | public typealias ValidatableOperationHTTP1OutputProtocol = Validatable & OperationHTTP1OutputProtocol 36 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/PathOperationHTTPInput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // PathOperationHTTPInput.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | Implementation of the OperationHTTP1InputProtocol that only decodes 22 | the HTTP path. 23 | */ 24 | public struct PathOperationHTTPInput: OperationHTTP1InputProtocol { 25 | // This struct doesn't use these types but we must provide a 26 | // concrete type to satify the protocol 27 | public typealias QueryType = String 28 | public typealias BodyType = String 29 | public typealias HeadersType = String 30 | 31 | public let path: PathType 32 | 33 | public init(path: PathType) { 34 | self.path = path 35 | } 36 | 37 | public static func compose(queryDecodableProvider _: () throws -> String, 38 | pathDecodableProvider: () throws -> PathType, 39 | bodyDecodableProvider _: () throws -> String, 40 | headersDecodableProvider _: () throws -> String) throws -> PathOperationHTTPInput { 41 | let path = try pathDecodableProvider() 42 | 43 | return .init(path: path) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/QueryOperationHTTPInput.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // QueryOperationHTTPInput.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | 20 | /** 21 | Implementation of the OperationHTTP1InputProtocol that only decodes 22 | the HTTP query. 23 | */ 24 | public struct QueryOperationHTTPInput: OperationHTTP1InputProtocol { 25 | // This struct doesn't use these types but we must provide a 26 | // concrete type to satify the protocol 27 | public typealias BodyType = String 28 | public typealias PathType = String 29 | public typealias HeadersType = String 30 | 31 | public let query: QueryType 32 | 33 | public init(query: QueryType) { 34 | self.query = query 35 | } 36 | 37 | public static func compose(queryDecodableProvider: () throws -> QueryType, 38 | pathDecodableProvider _: () throws -> String, 39 | bodyDecodableProvider _: () throws -> String, 40 | headersDecodableProvider _: () throws -> String) throws -> QueryOperationHTTPInput { 41 | let query = try queryDecodableProvider() 42 | 43 | return .init(query: query) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/SmokeAsyncPerInvocationContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeAsyncPerInvocationContextInitializer.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Logging 19 | import NIO 20 | import SmokeInvocation 21 | import SmokeOperations 22 | 23 | /** 24 | A protocol for initialization SmokeFramework-based applications that require a per-invocation context. 25 | 26 | This initializer supports async shutdown. 27 | */ 28 | public protocol SmokeAsyncPerInvocationContextInitializer { 29 | associatedtype SelectorType: SmokeHTTP1HandlerSelector 30 | 31 | typealias InvocationReportingType = SelectorType.DefaultOperationDelegateType.InvocationReportingType 32 | 33 | var handlerSelectorProvider: () -> SelectorType { get } 34 | var operationsInitializer: (inout SelectorType) -> Void { get } 35 | 36 | var defaultOperationDelegate: SelectorType.DefaultOperationDelegateType { get } 37 | var serverName: String { get } 38 | var invocationStrategy: InvocationStrategy { get } 39 | var defaultLogger: Logger { get } 40 | var reportingConfiguration: SmokeReportingConfiguration { get } 41 | 42 | func getInvocationContext(invocationReporting: InvocationReportingType) -> SelectorType.ContextType 43 | 44 | func onShutdown() async throws 45 | } 46 | 47 | public extension SmokeAsyncPerInvocationContextInitializer { 48 | var serverName: String { 49 | return "Server" 50 | } 51 | 52 | var invocationStrategy: InvocationStrategy { 53 | return GlobalDispatchQueueAsyncInvocationStrategy() 54 | } 55 | 56 | var defaultLogger: Logger { 57 | return Logger(label: "application.initialization") 58 | } 59 | 60 | var reportingConfiguration: SmokeReportingConfiguration { 61 | return SmokeReportingConfiguration() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/SmokeAsyncStaticContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeAsyncStaticContextInitializer.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Logging 19 | import NIO 20 | import SmokeInvocation 21 | import SmokeOperations 22 | 23 | /** 24 | A protocol for initialization SmokeFramework-based applications that require a static context. 25 | 26 | This initializer supports async shutdown. 27 | */ 28 | public protocol SmokeAsyncStaticContextInitializer { 29 | associatedtype SelectorType: SmokeHTTP1HandlerSelector 30 | 31 | var handlerSelectorProvider: () -> SelectorType { get } 32 | var operationsInitializer: (inout SelectorType) -> Void { get } 33 | 34 | var defaultOperationDelegate: SelectorType.DefaultOperationDelegateType { get } 35 | var serverName: String { get } 36 | var invocationStrategy: InvocationStrategy { get } 37 | var defaultLogger: Logger { get } 38 | var reportingConfiguration: SmokeReportingConfiguration { get } 39 | 40 | func getInvocationContext() -> SelectorType.ContextType 41 | 42 | func onShutdown() async throws 43 | } 44 | 45 | public extension SmokeAsyncStaticContextInitializer { 46 | var serverName: String { 47 | return "Server" 48 | } 49 | 50 | var invocationStrategy: InvocationStrategy { 51 | return GlobalDispatchQueueAsyncInvocationStrategy() 52 | } 53 | 54 | var defaultLogger: Logger { 55 | return Logger(label: "application.initialization") 56 | } 57 | 58 | var reportingConfiguration: SmokeReportingConfiguration { 59 | return SmokeReportingConfiguration() 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/SmokeHTTP1HandlerSelector.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeHTTP1HandlerSelector.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | import Foundation 18 | import Logging 19 | import NIOHTTP1 20 | import ShapeCoding 21 | import SmokeOperations 22 | 23 | /** 24 | Protocol that provides the handler to use for an operation using the 25 | HTTP1 protocol. 26 | */ 27 | public protocol SmokeHTTP1HandlerSelector { 28 | associatedtype ContextType 29 | associatedtype DefaultOperationDelegateType: HTTP1OperationDelegate 30 | associatedtype OperationIdentifer: OperationIdentity 31 | 32 | typealias InvocationReportingType = DefaultOperationDelegateType.InvocationReportingType 33 | typealias RequestHeadType = DefaultOperationDelegateType.RequestHeadType 34 | typealias ResponseHandlerType = DefaultOperationDelegateType.ResponseHandlerType 35 | 36 | /// Get the instance of the Default OperationDelegate type 37 | var defaultOperationDelegate: DefaultOperationDelegateType { get } 38 | 39 | var serverName: String { get } 40 | var reportingConfiguration: SmokeReportingConfiguration { get } 41 | 42 | /** 43 | Gets the handler to use for an operation with the provided http request 44 | head. 45 | 46 | - Parameters 47 | - requestHead: the request head of an incoming operation. 48 | */ 49 | func getHandlerForOperation(_ uri: String, httpMethod: HTTPMethod, requestLogger: Logger) throws 50 | -> (OperationHandler, Shape) 51 | 52 | /** 53 | Adds a handler for the specified uri and http method. 54 | 55 | - Parameters: 56 | - operationIdentifer: The identifer for the handler being added. 57 | - httpMethod: The HTTP method this handler will respond to. 58 | - handler: the handler to add. 59 | */ 60 | mutating func addHandlerForOperation(_ operationIdentifer: OperationIdentifer, 61 | httpMethod: HTTPMethod, 62 | handler: OperationHandler) 63 | } 64 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/SmokeHTTP1RequestHead.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeHTTP1RequestHead.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Foundation 19 | import NIOHTTP1 20 | import ShapeCoding 21 | 22 | /** 23 | Structure representing an incoming HTTP1 request head. 24 | */ 25 | public struct SmokeHTTP1RequestHead { 26 | public let httpRequestHead: HTTPRequestHead 27 | public let query: String 28 | public let pathShape: Shape 29 | 30 | public init(httpRequestHead: HTTPRequestHead, 31 | query: String, 32 | pathShape: Shape) { 33 | self.httpRequestHead = httpRequestHead 34 | self.query = query 35 | self.pathShape = pathShape 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/SmokePerInvocationContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokePerInvocationContextInitializer.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Logging 19 | import NIO 20 | import SmokeInvocation 21 | import SmokeOperations 22 | 23 | /** 24 | A protocol for initialization SmokeFramework-based applications that require a per-invocation context. 25 | */ 26 | public protocol SmokePerInvocationContextInitializer { 27 | associatedtype SelectorType: SmokeHTTP1HandlerSelector 28 | 29 | typealias InvocationReportingType = SelectorType.DefaultOperationDelegateType.InvocationReportingType 30 | 31 | var handlerSelector: SelectorType { get } 32 | var serverName: String { get } 33 | var invocationStrategy: InvocationStrategy { get } 34 | var defaultLogger: Logger { get } 35 | var reportingConfiguration: SmokeReportingConfiguration { get } 36 | 37 | func getInvocationContext(invocationReporting: InvocationReportingType) -> SelectorType.ContextType 38 | 39 | func onShutdown() throws 40 | } 41 | 42 | public extension SmokePerInvocationContextInitializer { 43 | var serverName: String { 44 | return "Server" 45 | } 46 | 47 | var invocationStrategy: InvocationStrategy { 48 | return GlobalDispatchQueueAsyncInvocationStrategy() 49 | } 50 | 51 | var defaultLogger: Logger { 52 | return Logger(label: "application.initialization") 53 | } 54 | 55 | var reportingConfiguration: SmokeReportingConfiguration { 56 | return SmokeReportingConfiguration() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/SmokePerInvocationContextInitializerV2.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokePerInvocationContextInitializerV2.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Logging 19 | import NIO 20 | import SmokeInvocation 21 | import SmokeOperations 22 | 23 | /** 24 | A protocol for initialization SmokeFramework-based applications that require a per-invocation context. 25 | 26 | This is a second generation initializer that uses properties on the initializer to create the SelectorType instance 27 | rather than requiring the user to construct the instance manually. This supports greater abstraction of the 28 | standard initialization path with `StandardSmokeServerPerInvocationContextInitializer`. 29 | */ 30 | public protocol SmokePerInvocationContextInitializerV2 { 31 | associatedtype SelectorType: SmokeHTTP1HandlerSelector 32 | 33 | typealias InvocationReportingType = SelectorType.DefaultOperationDelegateType.InvocationReportingType 34 | 35 | var handlerSelectorProvider: () -> SelectorType { get } 36 | var operationsInitializer: (inout SelectorType) -> Void { get } 37 | 38 | var serverName: String { get } 39 | var invocationStrategy: InvocationStrategy { get } 40 | var defaultLogger: Logger { get } 41 | var reportingConfiguration: SmokeReportingConfiguration { get } 42 | 43 | func getInvocationContext(invocationReporting: InvocationReportingType) -> SelectorType.ContextType 44 | 45 | func onShutdown() throws 46 | } 47 | 48 | public extension SmokePerInvocationContextInitializerV2 { 49 | var serverName: String { 50 | return "Server" 51 | } 52 | 53 | var invocationStrategy: InvocationStrategy { 54 | return GlobalDispatchQueueAsyncInvocationStrategy() 55 | } 56 | 57 | var defaultLogger: Logger { 58 | return Logger(label: "application.initialization") 59 | } 60 | 61 | var reportingConfiguration: SmokeReportingConfiguration { 62 | return SmokeReportingConfiguration() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/SmokeStaticContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeStaticContextInitializer.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Logging 19 | import NIO 20 | import SmokeInvocation 21 | import SmokeOperations 22 | 23 | /** 24 | A protocol for initialization SmokeFramework-based applications that require a static context. 25 | */ 26 | public protocol SmokeStaticContextInitializer { 27 | associatedtype SelectorType: SmokeHTTP1HandlerSelector 28 | 29 | var handlerSelector: SelectorType { get } 30 | var serverName: String { get } 31 | var invocationStrategy: InvocationStrategy { get } 32 | var defaultLogger: Logger { get } 33 | var reportingConfiguration: SmokeReportingConfiguration { get } 34 | 35 | func getInvocationContext() -> SelectorType.ContextType 36 | 37 | func onShutdown() throws 38 | } 39 | 40 | public extension SmokeStaticContextInitializer { 41 | var serverName: String { 42 | return "Server" 43 | } 44 | 45 | var invocationStrategy: InvocationStrategy { 46 | return GlobalDispatchQueueAsyncInvocationStrategy() 47 | } 48 | 49 | var defaultLogger: Logger { 50 | return Logger(label: "application.initialization") 51 | } 52 | 53 | var reportingConfiguration: SmokeReportingConfiguration { 54 | return SmokeReportingConfiguration() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1/SmokeStaticContextInitializerV2.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeStaticContextInitializerV2.swift 15 | // SmokeOperationsHTTP1 16 | // 17 | 18 | import Logging 19 | import NIO 20 | import SmokeInvocation 21 | import SmokeOperations 22 | 23 | /** 24 | A protocol for initialization SmokeFramework-based applications that require a static context. 25 | 26 | This is a second generation initializer that uses properties on the initializer to create the SelectorType instance 27 | rather than requiring the user to construct the instance manually. This supports greater abstraction of the 28 | standard initialization path with `StandardSmokeServerStaticContextInitializer`. 29 | */ 30 | public protocol SmokeStaticContextInitializerV2 { 31 | associatedtype SelectorType: SmokeHTTP1HandlerSelector 32 | 33 | var handlerSelectorProvider: () -> SelectorType { get } 34 | var operationsInitializer: (inout SelectorType) -> Void { get } 35 | 36 | var defaultOperationDelegate: SelectorType.DefaultOperationDelegateType { get } 37 | var serverName: String { get } 38 | var invocationStrategy: InvocationStrategy { get } 39 | var defaultLogger: Logger { get } 40 | var reportingConfiguration: SmokeReportingConfiguration { get } 41 | 42 | func getInvocationContext() -> SelectorType.ContextType 43 | 44 | func onShutdown() throws 45 | } 46 | 47 | public extension SmokeStaticContextInitializerV2 { 48 | var serverName: String { 49 | return "Server" 50 | } 51 | 52 | var invocationStrategy: InvocationStrategy { 53 | return GlobalDispatchQueueAsyncInvocationStrategy() 54 | } 55 | 56 | var defaultLogger: Logger { 57 | return Logger(label: "application.initialization") 58 | } 59 | 60 | var reportingConfiguration: SmokeReportingConfiguration { 61 | return SmokeReportingConfiguration() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/HTTP1OperationTraceContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HTTP1OperationTraceContext.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import NIOHTTP1 20 | import SmokeOperations 21 | 22 | public protocol HTTP1OperationTraceContext: OperationTraceContext 23 | where RequestHeadType == HTTPRequestHead, ResponseHeadersType == HTTPHeaders, ResponseStatusType == HTTPResponseStatus {} 24 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/HTTP1RequestInvocationContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // HTTP1RequestInvocationContext.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import Metrics 21 | import NIOHTTP1 22 | 23 | public protocol HTTP1RequestInvocationContext { 24 | var logger: Logger { get } 25 | 26 | var successCounter: Metrics.Counter? { get } 27 | var failure5XXCounter: Metrics.Counter? { get } 28 | var failure4XXCounter: Metrics.Counter? { get } 29 | var requestReadLatencyTimer: Metrics.Timer? { get } 30 | var specificFailureStatusCounters: [UInt: Metrics.Counter]? { get } 31 | var latencyTimer: Metrics.Timer? { get } 32 | var serviceLatencyTimer: Metrics.Timer? { get } 33 | var outwardsServiceCallLatencySumTimer: Metrics.Timer? { get } 34 | var outwardsServiceCallRetryWaitSumTimer: Metrics.Timer? { get } 35 | 36 | func handleInwardsRequestComplete(httpHeaders: inout HTTPHeaders, status: HTTPResponseStatus, 37 | body: (contentType: String, data: Data)?) 38 | } 39 | 40 | public extension HTTP1RequestInvocationContext { 41 | // The properties is being added as a non-breaking change, so add a default implementation. 42 | var successCounter: Metrics.Counter? { 43 | return nil 44 | } 45 | 46 | var failure5XXCounter: Metrics.Counter? { 47 | return nil 48 | } 49 | 50 | var failure4XXCounter: Metrics.Counter? { 51 | return nil 52 | } 53 | 54 | var requestReadLatencyTimer: Metrics.Timer? { 55 | return nil 56 | } 57 | 58 | var specificFailureStatusCounters: [Int: Metrics.Counter]? { 59 | return nil 60 | } 61 | 62 | var latencyTimer: Metrics.Timer? { 63 | return nil 64 | } 65 | 66 | var serviceLatencyTimer: Metrics.Timer? { 67 | return nil 68 | } 69 | 70 | var outwardsServiceCallLatencySumTimer: Metrics.Timer? { 71 | return nil 72 | } 73 | 74 | var outwardsServiceCallRetryWaitSumTimer: Metrics.Timer? { 75 | return nil 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/JSONPayloadHTTP1OperationDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // JSONPayloadHTTP1OperationDelegate.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import SmokeOperations 19 | import SmokeOperationsHTTP1 20 | 21 | public typealias JSONPayloadHTTP1OperationDelegate = 22 | GenericJSONPayloadHTTP1OperationDelegate< 23 | StandardHTTP1ResponseHandler>>, 24 | SmokeServerInvocationReporting 25 | > 26 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeAsyncServerPerInvocationContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeAsyncServerStaticContextInitializer.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperationsHTTP1 21 | 22 | public protocol SmokeAsyncServerPerInvocationContextInitializer: SmokeAsyncPerInvocationContextInitializer { 23 | var port: Int { get } 24 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { get } 25 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { get } 26 | var requestExecutor: RequestExecutor { get } 27 | var enableTracingWithSwiftConcurrency: Bool { get } 28 | } 29 | 30 | public extension SmokeAsyncServerPerInvocationContextInitializer { 31 | var port: Int { 32 | return ServerDefaults.defaultPort 33 | } 34 | 35 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { 36 | return [.sigint] 37 | } 38 | 39 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { 40 | return .spawnNewThreads 41 | } 42 | 43 | var requestExecutor: RequestExecutor { 44 | return .originalEventLoop 45 | } 46 | 47 | var enableTracingWithSwiftConcurrency: Bool { 48 | return false 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeAsyncServerStaticContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeServerStaticContextInitializerV2.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperationsHTTP1 21 | 22 | public protocol SmokeAsyncServerStaticContextInitializer: SmokeAsyncStaticContextInitializer { 23 | var port: Int { get } 24 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { get } 25 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { get } 26 | var requestExecutor: RequestExecutor { get } 27 | var enableTracingWithSwiftConcurrency: Bool { get } 28 | } 29 | 30 | public extension SmokeAsyncServerStaticContextInitializer { 31 | var port: Int { 32 | return ServerDefaults.defaultPort 33 | } 34 | 35 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { 36 | return [.sigint] 37 | } 38 | 39 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { 40 | return .spawnNewThreads 41 | } 42 | 43 | var requestExecutor: RequestExecutor { 44 | return .originalEventLoop 45 | } 46 | 47 | var enableTracingWithSwiftConcurrency: Bool { 48 | return false 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeInvocationTraceContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeInvocationTraceContext.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import SmokeOperationsHTTP1 19 | 20 | /// Type moved into the `SmokeOperationsHTTP1` library. This typealias retains compatibility 21 | public typealias SmokeInvocationTraceContext = SmokeOperationsHTTP1.SmokeInvocationTraceContext 22 | 23 | extension SmokeInvocationTraceContext: HTTP1OperationTraceContext {} 24 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeServerInvocationContext+HTTP1RequestInvocationContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeServerInvocationContext+HTTP1RequestInvocationContext.swift 15 | // SmokeOperationsHTTP1Server 16 | 17 | import Foundation 18 | import Logging 19 | import Metrics 20 | import NIOHTTP1 21 | import SmokeHTTP1 22 | import SmokeOperations 23 | 24 | extension SmokeInvocationContext: HTTP1RequestInvocationContext where 25 | InvocationReportingType: InvocationReportingWithTraceContext, 26 | InvocationReportingType.TraceContextType.RequestHeadType == HTTPRequestHead, 27 | InvocationReportingType.TraceContextType.ResponseHeadersType == HTTPHeaders, 28 | InvocationReportingType.TraceContextType.ResponseStatusType == HTTPResponseStatus { 29 | public var logger: Logger { 30 | return self.invocationReporting.logger 31 | } 32 | 33 | public var successCounter: Metrics.Counter? { 34 | return self.requestReporting.successCounter 35 | } 36 | 37 | public var failure5XXCounter: Metrics.Counter? { 38 | return self.requestReporting.failure5XXCounter 39 | } 40 | 41 | public var failure4XXCounter: Metrics.Counter? { 42 | return self.requestReporting.failure4XXCounter 43 | } 44 | 45 | public var requestReadLatencyTimer: Metrics.Timer? { 46 | return self.requestReporting.requestReadLatencyTimer 47 | } 48 | 49 | public var specificFailureStatusCounters: [UInt: Metrics.Counter]? { 50 | return self.requestReporting.specificFailureStatusCounters 51 | } 52 | 53 | public var latencyTimer: Metrics.Timer? { 54 | return self.requestReporting.latencyTimer 55 | } 56 | 57 | public var serviceLatencyTimer: Metrics.Timer? { 58 | return self.requestReporting.serviceLatencyTimer 59 | } 60 | 61 | public var outwardsServiceCallLatencySumTimer: Metrics.Timer? { 62 | return self.requestReporting.outwardsServiceCallLatencySumTimer 63 | } 64 | 65 | public var outwardsServiceCallRetryWaitSumTimer: Metrics.Timer? { 66 | return self.requestReporting.outwardsServiceCallRetryWaitSumTimer 67 | } 68 | 69 | public func handleInwardsRequestComplete(httpHeaders: inout HTTPHeaders, status: HTTPResponseStatus, body: (contentType: String, data: Data)?) { 70 | self.invocationReporting.traceContext.handleInwardsRequestComplete(httpHeaders: &httpHeaders, status: status, body: body, 71 | logger: self.invocationReporting.logger, 72 | internalRequestId: self.invocationReporting.internalRequestId) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeServerInvocationReporting+withInvocationTraceContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeServerInvocationReporting+withInvocationTraceContext.swift 15 | // SmokeOperationsHTTP1Server 16 | 17 | import Foundation 18 | import Logging 19 | import NIO 20 | import SmokeHTTPClient 21 | import SmokeOperations 22 | 23 | public struct DelegatedInvocationReporting: HTTPClientCoreInvocationReporting { 24 | public let logger: Logger 25 | public var internalRequestId: String 26 | public var traceContext: TraceContextType 27 | public var eventLoop: EventLoop? 28 | public var outwardsRequestAggregator: OutwardsRequestAggregator? 29 | 30 | public init(logger: Logger, 31 | internalRequestId: String, 32 | traceContext: TraceContextType, 33 | eventLoop: EventLoop? = nil, 34 | outwardsRequestAggregator: OutwardsRequestAggregator? = nil) { 35 | self.logger = logger 36 | self.internalRequestId = internalRequestId 37 | self.traceContext = traceContext 38 | self.eventLoop = eventLoop 39 | self.outwardsRequestAggregator = outwardsRequestAggregator 40 | } 41 | } 42 | 43 | public extension SmokeServerInvocationReporting { 44 | /** 45 | * Creates an instance conforming to the `HTTPClientCoreInvocationReporting` protocol from this instance and the provided trace context. 46 | */ 47 | func withInvocationTraceContext(traceContext: TraceContextType) -> DelegatedInvocationReporting { 48 | return DelegatedInvocationReporting(logger: self.logger, 49 | internalRequestId: self.internalRequestId, 50 | traceContext: traceContext, 51 | eventLoop: self.eventLoop, 52 | outwardsRequestAggregator: self.outwardsRequestAggregator) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeServerInvocationReporting.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeServerInvocationReporting.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import Logging 20 | import NIO 21 | import SmokeHTTPClient 22 | import SmokeOperations 23 | import Tracing 24 | 25 | public protocol InvocationReportingWithTraceContext: InvocationReporting { 26 | associatedtype TraceContextType: OperationTraceContext 27 | 28 | var traceContext: TraceContextType { get } 29 | } 30 | 31 | /** 32 | A context related to reporting on the invocation of the SmokeFramework. 33 | */ 34 | public struct SmokeServerInvocationReporting: InvocationReportingWithTraceContext, 35 | HTTPClientInvocationAttributes { 36 | public let logger: Logger 37 | public let eventLoop: EventLoop? 38 | public let outwardsRequestAggregator: OutwardsRequestAggregator? 39 | public let internalRequestId: String 40 | public let traceContext: TraceContextType 41 | 42 | public var span: Span? { 43 | return self.traceContext.span 44 | } 45 | 46 | public func recordErrorForInvocation(_ error: Swift.Error) { 47 | self.traceContext.recordErrorForInvocation(error) 48 | } 49 | 50 | public init(logger: Logger, internalRequestId: String, traceContext: TraceContextType, 51 | eventLoop: EventLoop? = nil, outwardsRequestAggregator: OutwardsRequestAggregator? = nil) { 52 | self.logger = logger 53 | self.eventLoop = eventLoop 54 | self.internalRequestId = internalRequestId 55 | self.traceContext = traceContext 56 | self.outwardsRequestAggregator = outwardsRequestAggregator 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeServerPerInvocationContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeServerStaticContextInitializer.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperationsHTTP1 21 | 22 | public protocol SmokeServerPerInvocationContextInitializer: SmokePerInvocationContextInitializer { 23 | var port: Int { get } 24 | @available(swift, deprecated: 3.0, message: "Migrate to use shutdownOnSignals.") 25 | var shutdownOnSignal: SmokeHTTP1Server.ShutdownOnSignal { get } 26 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { get } 27 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { get } 28 | } 29 | 30 | public extension SmokeServerPerInvocationContextInitializer { 31 | var port: Int { 32 | return ServerDefaults.defaultPort 33 | } 34 | 35 | @available(swift, deprecated: 3.0, message: "Migrate to use shutdownOnSignals.") 36 | var shutdownOnSignal: SmokeHTTP1Server.ShutdownOnSignal { 37 | return .sigint 38 | } 39 | 40 | @available(swift, deprecated: 3.0, message: "To avoid a breaking change, by default shutdownOnSignals() is a singleton list of `shutdownOnSignal`") 41 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { 42 | return [self.shutdownOnSignal] 43 | } 44 | 45 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { 46 | return .spawnNewThreads 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeServerPerInvocationContextInitializerV2.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeServerStaticContextInitializerV2.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperationsHTTP1 21 | 22 | public protocol SmokeServerPerInvocationContextInitializerV2: SmokePerInvocationContextInitializerV2 { 23 | var port: Int { get } 24 | @available(swift, deprecated: 3.0, message: "Migrate to use shutdownOnSignals.") 25 | var shutdownOnSignal: SmokeHTTP1Server.ShutdownOnSignal { get } 26 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { get } 27 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { get } 28 | } 29 | 30 | public extension SmokeServerPerInvocationContextInitializerV2 { 31 | var port: Int { 32 | return ServerDefaults.defaultPort 33 | } 34 | 35 | @available(swift, deprecated: 3.0, message: "Migrate to use shutdownOnSignals.") 36 | var shutdownOnSignal: SmokeHTTP1Server.ShutdownOnSignal { 37 | return .sigint 38 | } 39 | 40 | @available(swift, deprecated: 3.0, message: "To avoid a breaking change, by default shutdownOnSignals() is a singleton list of `shutdownOnSignal`") 41 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { 42 | return [self.shutdownOnSignal] 43 | } 44 | 45 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { 46 | return .spawnNewThreads 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeServerStaticContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeServerStaticContextInitializer.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperationsHTTP1 21 | 22 | public protocol SmokeServerStaticContextInitializer: SmokeStaticContextInitializer { 23 | var port: Int { get } 24 | @available(swift, deprecated: 3.0, message: "Migrate to use shutdownOnSignals.") 25 | var shutdownOnSignal: SmokeHTTP1Server.ShutdownOnSignal { get } 26 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { get } 27 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { get } 28 | } 29 | 30 | public extension SmokeServerStaticContextInitializer { 31 | var port: Int { 32 | return ServerDefaults.defaultPort 33 | } 34 | 35 | @available(swift, deprecated: 3.0, message: "Migrate to use shutdownOnSignals.") 36 | var shutdownOnSignal: SmokeHTTP1Server.ShutdownOnSignal { 37 | return .sigint 38 | } 39 | 40 | @available(swift, deprecated: 3.0, message: "To avoid a breaking change, by default shutdownOnSignals() is a singleton list of `shutdownOnSignal`") 41 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { 42 | return [self.shutdownOnSignal] 43 | } 44 | 45 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { 46 | return .spawnNewThreads 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/SmokeServerStaticContextInitializerV2.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // SmokeServerStaticContextInitializerV2.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperationsHTTP1 21 | 22 | public protocol SmokeServerStaticContextInitializerV2: SmokeStaticContextInitializerV2 { 23 | var port: Int { get } 24 | @available(swift, deprecated: 3.0, message: "Migrate to use shutdownOnSignals.") 25 | var shutdownOnSignal: SmokeHTTP1Server.ShutdownOnSignal { get } 26 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { get } 27 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { get } 28 | } 29 | 30 | public extension SmokeServerStaticContextInitializerV2 { 31 | var port: Int { 32 | return ServerDefaults.defaultPort 33 | } 34 | 35 | @available(swift, deprecated: 3.0, message: "Migrate to use shutdownOnSignals.") 36 | var shutdownOnSignal: SmokeHTTP1Server.ShutdownOnSignal { 37 | return .sigint 38 | } 39 | 40 | @available(swift, deprecated: 3.0, message: "To avoid a breaking change, by default shutdownOnSignals() is a singleton list of `shutdownOnSignal`") 41 | var shutdownOnSignals: [SmokeHTTP1Server.ShutdownOnSignal] { 42 | return [self.shutdownOnSignal] 43 | } 44 | 45 | var eventLoopProvider: SmokeHTTP1Server.EventLoopProvider { 46 | return .spawnNewThreads 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/StandardJSONSmokeAsyncServerPerInvocationContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // StandardSmokeAsyncServerPerInvocationContextInitializer.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperations 21 | import SmokeOperationsHTTP1 22 | 23 | /** 24 | A protocol that is derived from `SmokeAsyncServerPerInvocationContextInitializerV3` that uses the `StandardSmokeHTTP1HandlerSelector` 25 | type as the `SelectorType` and `JSONPayloadHTTP1OperationDelegate` as the `DefaultOperationDelegateType`. 26 | 27 | This reduces the configuration required for applications that use these standard components. 28 | */ 29 | public protocol StandardJSONSmokeAsyncServerPerInvocationContextInitializer: SmokeAsyncServerPerInvocationContextInitializer 30 | where SelectorType == 31 | StandardSmokeHTTP1HandlerSelector, 32 | OperationIdentifer> { 33 | associatedtype ContextType 34 | associatedtype OperationIdentifer 35 | 36 | typealias OperationsInitializerType = 37 | (inout StandardSmokeHTTP1HandlerSelector, OperationIdentifer>) -> Void 38 | } 39 | 40 | public extension StandardJSONSmokeAsyncServerPerInvocationContextInitializer { 41 | var handlerSelectorProvider: () -> SelectorType { 42 | func provider() -> SelectorType { 43 | return SelectorType(defaultOperationDelegate: self.defaultOperationDelegate, 44 | serverName: self.serverName, 45 | reportingConfiguration: self.reportingConfiguration) 46 | } 47 | 48 | return provider 49 | } 50 | 51 | var defaultOperationDelegate: SelectorType.DefaultOperationDelegateType { 52 | return JSONPayloadHTTP1OperationDelegate() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/StandardJSONSmokeAsyncServerStaticContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // StandardSmokeAsyncServerStaticContextInitializer.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperations 21 | import SmokeOperationsHTTP1 22 | 23 | /** 24 | A protocol that is derived from `SmokeAsyncServerStaticContextInitializerV3` that uses the `StandardSmokeHTTP1HandlerSelector` 25 | type as the `SelectorType` and `JSONPayloadHTTP1OperationDelegate` as the `DefaultOperationDelegateType`. 26 | 27 | This reduces the configuration required for applications that use these standard components. 28 | */ 29 | public protocol StandardJSONSmokeAsyncServerStaticContextInitializer: SmokeAsyncServerStaticContextInitializer 30 | where SelectorType == 31 | StandardSmokeHTTP1HandlerSelector, 32 | OperationIdentifer> { 33 | associatedtype ContextType 34 | associatedtype OperationIdentifer 35 | 36 | typealias OperationsInitializerType = 37 | (inout StandardSmokeHTTP1HandlerSelector, OperationIdentifer>) -> Void 38 | } 39 | 40 | public extension StandardJSONSmokeAsyncServerStaticContextInitializer { 41 | var handlerSelectorProvider: () -> SelectorType { 42 | func provider() -> SelectorType { 43 | return SelectorType(defaultOperationDelegate: self.defaultOperationDelegate, 44 | serverName: self.serverName, 45 | reportingConfiguration: self.reportingConfiguration) 46 | } 47 | 48 | return provider 49 | } 50 | 51 | var defaultOperationDelegate: SelectorType.DefaultOperationDelegateType { 52 | return JSONPayloadHTTP1OperationDelegate() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/StandardJSONSmokeServerPerInvocationContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // StandardSmokeServerPerInvocationContextInitializer.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperations 21 | import SmokeOperationsHTTP1 22 | 23 | /** 24 | A protocol that is derived from `SmokeServerPerInvocationContextInitializerV2` that uses the `StandardSmokeHTTP1HandlerSelector` 25 | type as the `SelectorType` and `JSONPayloadHTTP1OperationDelegate` as the `DefaultOperationDelegateType`. 26 | 27 | This reduces the configuration required for applications that use these standard components. 28 | */ 29 | public protocol StandardJSONSmokeServerPerInvocationContextInitializer: SmokeServerPerInvocationContextInitializerV2 30 | where SelectorType == 31 | StandardSmokeHTTP1HandlerSelector, 32 | OperationIdentifer> { 33 | associatedtype ContextType 34 | associatedtype OperationIdentifer 35 | 36 | typealias OperationsInitializerType = 37 | (inout StandardSmokeHTTP1HandlerSelector, OperationIdentifer>) -> Void 38 | } 39 | 40 | public extension StandardJSONSmokeServerPerInvocationContextInitializer { 41 | var handlerSelectorProvider: () -> SelectorType { 42 | func provider() -> SelectorType { 43 | return SelectorType(defaultOperationDelegate: self.defaultOperationDelegate, 44 | serverName: self.serverName, 45 | reportingConfiguration: self.reportingConfiguration) 46 | } 47 | 48 | return provider 49 | } 50 | 51 | var defaultOperationDelegate: SelectorType.DefaultOperationDelegateType { 52 | return JSONPayloadHTTP1OperationDelegate() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/SmokeOperationsHTTP1Server/StandardJSONSmokeServerStaticContextInitializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // StandardSmokeServerStaticContextInitializer.swift 15 | // SmokeOperationsHTTP1Server 16 | // 17 | 18 | import Foundation 19 | import SmokeHTTP1 20 | import SmokeOperations 21 | import SmokeOperationsHTTP1 22 | 23 | /** 24 | A protocol that is derived from `SmokeServerStaticContextInitializerV2` that uses the `StandardSmokeHTTP1HandlerSelector` 25 | type as the `SelectorType` and `JSONPayloadHTTP1OperationDelegate` as the `DefaultOperationDelegateType`. 26 | 27 | This reduces the configuration required for applications that use these standard components. 28 | */ 29 | public protocol StandardJSONSmokeServerStaticContextInitializer: SmokeServerStaticContextInitializerV2 30 | where SelectorType == 31 | StandardSmokeHTTP1HandlerSelector, 32 | OperationIdentifer> { 33 | associatedtype ContextType 34 | associatedtype OperationIdentifer 35 | 36 | typealias OperationsInitializerType = 37 | (inout StandardSmokeHTTP1HandlerSelector, OperationIdentifer>) -> Void 38 | } 39 | 40 | public extension StandardJSONSmokeServerStaticContextInitializer { 41 | var handlerSelectorProvider: () -> SelectorType { 42 | func provider() -> SelectorType { 43 | return SelectorType(defaultOperationDelegate: self.defaultOperationDelegate, 44 | serverName: self.serverName, 45 | reportingConfiguration: self.reportingConfiguration) 46 | } 47 | 48 | return provider 49 | } 50 | 51 | var defaultOperationDelegate: SelectorType.DefaultOperationDelegateType { 52 | return JSONPayloadHTTP1OperationDelegate() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/_SmokeOperationsConcurrency/Export.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // Export.swift 15 | // _SmokeOperationsConcurrency 16 | // 17 | 18 | // TODO: https://github.com/amzn/smoke-framework/issues/85 19 | @_exported import SmokeOperations 20 | -------------------------------------------------------------------------------- /Sources/_SmokeOperationsHTTP1Concurrency/Export.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // Export.swift 15 | // _SmokeOperationsHTTP1Concurrency 16 | // 17 | 18 | // TODO: https://github.com/amzn/smoke-framework/issues/85 19 | @_exported import SmokeOperationsHTTP1 20 | -------------------------------------------------------------------------------- /Tests/SmokeOperationsHTTP1Tests/ErrorWithTypeTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | // 14 | // ErrorWithTypeTests.swift 15 | // SmokeOperations 16 | // 17 | 18 | @testable import SmokeOperations 19 | import XCTest 20 | 21 | struct ExampleErrorShape: Encodable { 22 | let message: String 23 | } 24 | 25 | struct ExpectedShape: Codable { 26 | let message: String 27 | let type: String 28 | 29 | enum CodingKeys: String, CodingKey { 30 | case message 31 | case type = "__type" 32 | } 33 | } 34 | 35 | extension ExpectedShape: Equatable { 36 | static func == (lhs: ExpectedShape, rhs: ExpectedShape) -> Bool { 37 | return lhs.message == rhs.message && lhs.type == rhs.type 38 | } 39 | } 40 | 41 | class ErrorWithTypeTests: XCTestCase { 42 | func testEncoding() { 43 | let errorShape = ExampleErrorShape(message: "The message") 44 | let errorWithType = ErrorWithType(type: "BadError", payload: errorShape) 45 | 46 | let encodedData = try! JSONEncoder.getFrameworkEncoder().encode(errorWithType) 47 | let recovered = try! JSONDecoder.getFrameworkDecoder().decode(ExpectedShape.self, from: encodedData) 48 | 49 | let expected = ExpectedShape(message: "The message", type: "BadError") 50 | 51 | XCTAssertEqual(expected, recovered) 52 | } 53 | } 54 | --------------------------------------------------------------------------------