From 284119704adf860bdafeaef7dc7ec81ea19f5e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Fri, 12 Jun 2020 13:17:49 +0200 Subject: [PATCH 01/18] allow the users of client to provide headers --- Sources/AWSLambdaRuntimeCore/HTTPClient.swift | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift index f3d073d3..54f80933 100644 --- a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift +++ b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift @@ -35,21 +35,27 @@ internal final class HTTPClient { self.targetHost = "\(self.configuration.ip):\(self.configuration.port)" } - func get(url: String, timeout: TimeAmount? = nil) -> EventLoopFuture { - self.execute(Request(targetHost: self.targetHost, + func get(url: String, timeout: TimeAmount? = nil, additionalHeaders: HTTPHeaders? = nil) -> EventLoopFuture { + var headers = HTTPClient.headers + additionalHeaders.flatMap { headers.add(contentsOf: $0) } + + return self.execute(Request(targetHost: self.targetHost, url: url, method: .GET, - headers: HTTPClient.headers, + headers: headers, timeout: timeout ?? self.configuration.requestTimeout)) } - func post(url: String, body: ByteBuffer?, timeout: TimeAmount? = nil) -> EventLoopFuture { - self.execute(Request(targetHost: self.targetHost, - url: url, - method: .POST, - headers: HTTPClient.headers, - body: body, - timeout: timeout ?? self.configuration.requestTimeout)) + func post(url: String, body: ByteBuffer?, timeout: TimeAmount? = nil, additionalHeaders: HTTPHeaders? = nil) -> EventLoopFuture { + var headers = HTTPClient.headers + additionalHeaders.flatMap { headers.add(contentsOf: $0) } + + return self.execute(Request(targetHost: self.targetHost, + url: url, + method: .POST, + headers: headers, + body: body, + timeout: timeout ?? self.configuration.requestTimeout)) } /// cancels the current request if there is one From 4162c6b1fb9583b2eb978a2c2263bfa612a7f8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Fri, 12 Jun 2020 13:18:05 +0200 Subject: [PATCH 02/18] add initialization error header --- Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift index 2976a8c2..3ede00e1 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift @@ -22,10 +22,14 @@ import NIOHTTP1 /// * /runtime/invocation/error /// * /runtime/init/error extension Lambda { + internal struct RuntimeClient { private let eventLoop: EventLoop private let allocator = ByteBufferAllocator() private let httpClient: HTTPClient + + /// Headers that must be sent along an invocation or initialization error response + private static let errorHeaders = HTTPHeaders([("Lambda-Runtime-Function-Error-Type", "Unhandled")]) init(eventLoop: EventLoop, configuration: Configuration.RuntimeEngine) { self.eventLoop = eventLoop @@ -98,7 +102,7 @@ extension Lambda { var body = self.allocator.buffer(capacity: bytes.count) body.writeBytes(bytes) logger.warning("reporting initialization error to lambda runtime engine using \(url)") - return self.httpClient.post(url: url, body: body).flatMapThrowing { response in + return self.httpClient.post(url: url, body: body, additionalHeaders: RuntimeClient.errorHeaders).flatMapThrowing { response in guard response.status == .accepted else { throw RuntimeError.badStatusCode(response.status) } From a2073849aabe50a25543d4b0a1e924132c3ba70a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Fri, 12 Jun 2020 13:21:59 +0200 Subject: [PATCH 03/18] add error header to failed invocations --- Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift index 3ede00e1..e0cc6e08 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift @@ -65,6 +65,8 @@ extension Lambda { func reportResults(logger: Logger, invocation: Invocation, result: Result) -> EventLoopFuture { var url = Consts.invocationURLPrefix + "/" + invocation.requestID var body: ByteBuffer? + var additionalHeaders: HTTPHeaders? + switch result { case .success(let buffer): url += Consts.postResponseURLSuffix @@ -75,9 +77,10 @@ extension Lambda { let bytes = errorResponse.toJSONBytes() body = self.allocator.buffer(capacity: bytes.count) body!.writeBytes(bytes) + additionalHeaders = RuntimeClient.errorHeaders } logger.debug("reporting results to lambda runtime engine using \(url)") - return self.httpClient.post(url: url, body: body).flatMapThrowing { response in + return self.httpClient.post(url: url, body: body, additionalHeaders: additionalHeaders).flatMapThrowing { response in guard response.status == .accepted else { throw RuntimeError.badStatusCode(response.status) } From 03c33da82538b25576b8976ca93b42cc9f787988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Fri, 12 Jun 2020 13:21:59 +0200 Subject: [PATCH 04/18] add error header to failed invocations --- Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift index 3ede00e1..86c676fa 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift @@ -28,7 +28,7 @@ extension Lambda { private let allocator = ByteBufferAllocator() private let httpClient: HTTPClient - /// Headers that must be sent along an invocation or initialization error response + /// Headers that must be sent along an invocation or initialization error report private static let errorHeaders = HTTPHeaders([("Lambda-Runtime-Function-Error-Type", "Unhandled")]) init(eventLoop: EventLoop, configuration: Configuration.RuntimeEngine) { @@ -65,6 +65,8 @@ extension Lambda { func reportResults(logger: Logger, invocation: Invocation, result: Result) -> EventLoopFuture { var url = Consts.invocationURLPrefix + "/" + invocation.requestID var body: ByteBuffer? + var additionalHeaders: HTTPHeaders? + switch result { case .success(let buffer): url += Consts.postResponseURLSuffix @@ -75,9 +77,10 @@ extension Lambda { let bytes = errorResponse.toJSONBytes() body = self.allocator.buffer(capacity: bytes.count) body!.writeBytes(bytes) + additionalHeaders = RuntimeClient.errorHeaders } logger.debug("reporting results to lambda runtime engine using \(url)") - return self.httpClient.post(url: url, body: body).flatMapThrowing { response in + return self.httpClient.post(url: url, body: body, additionalHeaders: additionalHeaders).flatMapThrowing { response in guard response.status == .accepted else { throw RuntimeError.badStatusCode(response.status) } From d75e2f29f59bda80169742eca419d08e6d2da7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Fri, 12 Jun 2020 16:17:00 +0200 Subject: [PATCH 05/18] enable external setting of ip and port of RuntimeEngine If we want to use The NIOHTTP1TestServer for testing connections we need to use its ip and port. The default (currently unchangeable) port of the RuntimeEngine is 7000, the one of of NIOHTTP1TestServer is 0 --- Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift | 4 ++-- Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift b/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift index 44352d2f..b6bcb006 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift @@ -67,8 +67,8 @@ extension Lambda { let keepAlive: Bool let requestTimeout: TimeAmount? - init(baseURL: String? = nil, keepAlive: Bool? = nil, requestTimeout: TimeAmount? = nil) { - let ipPort = env("AWS_LAMBDA_RUNTIME_API")?.split(separator: ":") ?? ["127.0.0.1", "7000"] + init(baseURL: String? = nil, keepAlive: Bool? = nil, requestTimeout: TimeAmount? = nil, ipPort: String? = nil) { + let ipPort = (ipPort ?? env("AWS_LAMBDA_RUNTIME_API"))?.split(separator: ":") ?? ["127.0.0.1", "7000"] guard ipPort.count == 2, let port = Int(ipPort[1]) else { preconditionFailure("invalid ip+port configuration \(ipPort)") } diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift index 86c676fa..0af27901 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift @@ -29,7 +29,7 @@ extension Lambda { private let httpClient: HTTPClient /// Headers that must be sent along an invocation or initialization error report - private static let errorHeaders = HTTPHeaders([("Lambda-Runtime-Function-Error-Type", "Unhandled")]) + internal static let errorHeaders = HTTPHeaders([("Lambda-Runtime-Function-Error-Type", "Unhandled")]) init(eventLoop: EventLoop, configuration: Configuration.RuntimeEngine) { self.eventLoop = eventLoop From 5c8158861b216281944a3bd3712825605a25cbc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Fri, 12 Jun 2020 16:17:22 +0200 Subject: [PATCH 06/18] test headers in failed initialization --- Package.swift | 1 + .../LambdaRuntimeClientTest.swift | 75 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/Package.swift b/Package.swift index 42e4c3ed..4f1cb8da 100644 --- a/Package.swift +++ b/Package.swift @@ -35,6 +35,7 @@ let package = Package( ]), .testTarget(name: "AWSLambdaRuntimeCoreTests", dependencies: [ .byName(name: "AWSLambdaRuntimeCore"), + .product(name: "NIOTestUtils", package: "swift-nio"), ]), .testTarget(name: "AWSLambdaRuntimeTests", dependencies: [ .byName(name: "AWSLambdaRuntimeCore"), diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index 2f2529c4..c4995571 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -13,6 +13,10 @@ //===----------------------------------------------------------------------===// @testable import AWSLambdaRuntimeCore +@testable import NIOHTTP1 +import NIOTestUtils +import NIO +import Logging import XCTest class LambdaRuntimeClientTest: XCTestCase { @@ -208,6 +212,33 @@ class LambdaRuntimeClientTest: XCTestCase { let emojiBytes = emojiError.toJSONBytes() XCTAssertEqual(#"{"errorType":"error","errorMessage":"๐Ÿฅ‘๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง"}"#, String(decoding: emojiBytes, as: Unicode.UTF8.self)) } + + func testInitializationErrorReportHeaders() { + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) + let server = NIOHTTP1TestServer(group: eventLoopGroup) + + defer { + XCTAssertNoThrow(try server.stop()) + XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) + } + + let logger = Logger(label: "TestLogger") + let engine = Lambda.Configuration.RuntimeEngine(requestTimeout: .milliseconds(100), ipPort: "127.0.0.1:\(server.serverPort)") + let configuration = Lambda.Configuration(runtimeEngine: engine) + let runner = Lambda.Runner(eventLoop: eventLoopGroup.next(), configuration: configuration) + + let failingInitializer: Lambda.HandlerFactory = { $0.makeFailedFuture(TestError("boom")) } + let result = runner.initialize(logger: logger, factory: failingInitializer) + + let headerContent = Lambda.RuntimeClient.errorHeaders.headers + XCTAssertNoThrow(try server.readInbound().assertHead(expectedMethod: .POST, expectedHeaderContent: headerContent)) + XCTAssertNoThrow(try server.readInbound().assertBody()) + XCTAssertNoThrow(try server.readInbound().assertEnd()) + + XCTAssertThrowsError(try result.wait()) { (error) in + XCTAssertEqual(error as? TestError, TestError("boom")) + } + } class Behavior: LambdaServerBehavior { var state = 0 @@ -233,3 +264,47 @@ class LambdaRuntimeClientTest: XCTestCase { } } } + +private extension HTTPServerRequestPart { + + func assertHead(expectedMethod: HTTPMethod? = nil, expectedHeaderContent: [(String,String)]? = nil, file: StaticString = (#file), line: UInt = #line) { + let head: HTTPRequestHead + + switch self { + case .head(let h): + head = h + default: + XCTFail("Expected head, got \(self)", file: file, line: line) + return + } + + if let expectedMethod = expectedMethod { + XCTAssertEqual(head.method, expectedMethod) + } + + if let expectedHeaderContent = expectedHeaderContent { + for (key, value) in expectedHeaderContent { + XCTAssertTrue(head.headers[key].contains(value), "Could not find \(value) for \(key) in head") + } + } + } + + func assertBody(file: StaticString = (#file), line: UInt = #line) { + switch self { + case .body(_): + () + default: + XCTFail("Expected body, got \(self)", file: file, line: line) + } + } + + func assertEnd(file: StaticString = (#file), line: UInt = #line) { + switch self { + case .end(_): + () + default: + XCTFail("Expected end, got \(self)", file: file, line: line) + } + } + +} From 1e57c4b35435fd1d6bc6bf913fef15d4ff00e23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Fri, 12 Jun 2020 22:24:12 +0200 Subject: [PATCH 07/18] use baseUrl instead of ip in RuntieEngine --- Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift b/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift index b6bcb006..c64bd4e6 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift @@ -67,8 +67,8 @@ extension Lambda { let keepAlive: Bool let requestTimeout: TimeAmount? - init(baseURL: String? = nil, keepAlive: Bool? = nil, requestTimeout: TimeAmount? = nil, ipPort: String? = nil) { - let ipPort = (ipPort ?? env("AWS_LAMBDA_RUNTIME_API"))?.split(separator: ":") ?? ["127.0.0.1", "7000"] + init(baseURL: String? = nil, keepAlive: Bool? = nil, requestTimeout: TimeAmount? = nil) { + let ipPort = (baseURL ?? env("AWS_LAMBDA_RUNTIME_API"))?.split(separator: ":") ?? ["127.0.0.1", "7000"] guard ipPort.count == 2, let port = Int(ipPort[1]) else { preconditionFailure("invalid ip+port configuration \(ipPort)") } From f8da566fee90de06dbc602d88480c203756e5b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Fri, 12 Jun 2020 22:25:56 +0200 Subject: [PATCH 08/18] refactor test - use runtimClient instead of runner - remove extensions for requests and test directly in the method --- Package.swift | 1 + .../LambdaRuntimeClient.swift | 2 +- .../LambdaRuntimeClientTest.swift | 84 +++++-------------- 3 files changed, 23 insertions(+), 64 deletions(-) diff --git a/Package.swift b/Package.swift index 4f1cb8da..1d56806e 100644 --- a/Package.swift +++ b/Package.swift @@ -36,6 +36,7 @@ let package = Package( .testTarget(name: "AWSLambdaRuntimeCoreTests", dependencies: [ .byName(name: "AWSLambdaRuntimeCore"), .product(name: "NIOTestUtils", package: "swift-nio"), + .product(name: "NIOFoundationCompat", package: "swift-nio"), ]), .testTarget(name: "AWSLambdaRuntimeTests", dependencies: [ .byName(name: "AWSLambdaRuntimeCore"), diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift index 0af27901..db27de83 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift @@ -29,7 +29,7 @@ extension Lambda { private let httpClient: HTTPClient /// Headers that must be sent along an invocation or initialization error report - internal static let errorHeaders = HTTPHeaders([("Lambda-Runtime-Function-Error-Type", "Unhandled")]) + internal static let errorHeaders = HTTPHeaders([("lambda-runtime-function-error-type", "Unhandled")]) init(eventLoop: EventLoop, configuration: Configuration.RuntimeEngine) { self.eventLoop = eventLoop diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index c4995571..b1c0bf02 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -16,6 +16,7 @@ @testable import NIOHTTP1 import NIOTestUtils import NIO +import NIOFoundationCompat import Logging import XCTest @@ -214,30 +215,31 @@ class LambdaRuntimeClientTest: XCTestCase { } func testInitializationErrorReportHeaders() { - let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) - let server = NIOHTTP1TestServer(group: eventLoopGroup) + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) + defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - defer { - XCTAssertNoThrow(try server.stop()) - XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) - } + let server = NIOHTTP1TestServer(group: eventLoopGroup) + defer { XCTAssertNoThrow(try server.stop()) } let logger = Logger(label: "TestLogger") - let engine = Lambda.Configuration.RuntimeEngine(requestTimeout: .milliseconds(100), ipPort: "127.0.0.1:\(server.serverPort)") - let configuration = Lambda.Configuration(runtimeEngine: engine) - let runner = Lambda.Runner(eventLoop: eventLoopGroup.next(), configuration: configuration) - - let failingInitializer: Lambda.HandlerFactory = { $0.makeFailedFuture(TestError("boom")) } - let result = runner.initialize(logger: logger, factory: failingInitializer) + let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(baseURL: "127.0.0.1:\(server.serverPort)")) + let result = client.reportInitializationError(logger: logger, error: TestError("boom")) - let headerContent = Lambda.RuntimeClient.errorHeaders.headers - XCTAssertNoThrow(try server.readInbound().assertHead(expectedMethod: .POST, expectedHeaderContent: headerContent)) - XCTAssertNoThrow(try server.readInbound().assertBody()) - XCTAssertNoThrow(try server.readInbound().assertEnd()) + var inboundHeader: HTTPServerRequestPart? + XCTAssertNoThrow(inboundHeader = try server.readInbound()) + guard case .head(let head) = try? XCTUnwrap(inboundHeader) else { XCTFail("Expected to get a head first"); return } + XCTAssertEqual(head.headers["lambda-runtime-function-error-type"], ["Unhandled"]) - XCTAssertThrowsError(try result.wait()) { (error) in - XCTAssertEqual(error as? TestError, TestError("boom")) - } + var inboundBody: HTTPServerRequestPart? + XCTAssertNoThrow(inboundBody = try server.readInbound()) + guard case .body(let body) = try? XCTUnwrap(inboundBody) else { XCTFail("Expected body after head"); return } + XCTAssertEqual(try JSONDecoder().decode(ErrorResponse.self, from: body).errorMessage, "boom") + + XCTAssertEqual(try server.readInbound(), .end(nil)) + + XCTAssertNoThrow(try server.writeOutbound(.head(.init(version: .init(major: 1, minor: 1), status: .accepted)))) + XCTAssertNoThrow(try server.writeOutbound(.end(nil))) + XCTAssertNoThrow(try result.wait()) } class Behavior: LambdaServerBehavior { @@ -264,47 +266,3 @@ class LambdaRuntimeClientTest: XCTestCase { } } } - -private extension HTTPServerRequestPart { - - func assertHead(expectedMethod: HTTPMethod? = nil, expectedHeaderContent: [(String,String)]? = nil, file: StaticString = (#file), line: UInt = #line) { - let head: HTTPRequestHead - - switch self { - case .head(let h): - head = h - default: - XCTFail("Expected head, got \(self)", file: file, line: line) - return - } - - if let expectedMethod = expectedMethod { - XCTAssertEqual(head.method, expectedMethod) - } - - if let expectedHeaderContent = expectedHeaderContent { - for (key, value) in expectedHeaderContent { - XCTAssertTrue(head.headers[key].contains(value), "Could not find \(value) for \(key) in head") - } - } - } - - func assertBody(file: StaticString = (#file), line: UInt = #line) { - switch self { - case .body(_): - () - default: - XCTFail("Expected body, got \(self)", file: file, line: line) - } - } - - func assertEnd(file: StaticString = (#file), line: UInt = #line) { - switch self { - case .end(_): - () - default: - XCTFail("Expected end, got \(self)", file: file, line: line) - } - } - -} From 72c2b8ee5928579c94cfc458df7b2b265e9ca1ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Fri, 12 Jun 2020 23:28:39 +0200 Subject: [PATCH 09/18] invocation error test --- .../LambdaRuntimeClientTest.swift | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index b1c0bf02..0225ba09 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -214,7 +214,7 @@ class LambdaRuntimeClientTest: XCTestCase { XCTAssertEqual(#"{"errorType":"error","errorMessage":"๐Ÿฅ‘๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง"}"#, String(decoding: emojiBytes, as: Unicode.UTF8.self)) } - func testInitializationErrorReportHeaders() { + func testInitializationErrorReport() { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } @@ -242,6 +242,45 @@ class LambdaRuntimeClientTest: XCTestCase { XCTAssertNoThrow(try result.wait()) } + func testInvocationErrorReport() { + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) + defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } + + let server = NIOHTTP1TestServer(group: eventLoopGroup) + defer { XCTAssertNoThrow(try server.stop()) } + + let logger = Logger(label: "TestLogger") + let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(baseURL: "127.0.0.1:\(server.serverPort)")) + + let header = HTTPHeaders([ + (AmazonHeaders.requestID, "test"), + (AmazonHeaders.deadline, String(Date(timeIntervalSinceNow: 60).millisSinceEpoch)), + (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:123456789012:function:custom-runtime"), + (AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1") + ]) + var inv: Lambda.Invocation? + XCTAssertNoThrow(inv = try Lambda.Invocation(headers: header)) + guard let invocation = inv else { return } + + let result = client.reportResults(logger: logger, invocation: invocation, result: Result.failure(TestError("boom"))) + + var inboundHeader: HTTPServerRequestPart? + XCTAssertNoThrow(inboundHeader = try server.readInbound()) + guard case .head(let head) = try? XCTUnwrap(inboundHeader) else { XCTFail("Expected to get a head first"); return } + XCTAssertEqual(head.headers["lambda-runtime-function-error-type"], ["Unhandled"]) + + var inboundBody: HTTPServerRequestPart? + XCTAssertNoThrow(inboundBody = try server.readInbound()) + guard case .body(let body) = try? XCTUnwrap(inboundBody) else { XCTFail("Expected body after head"); return } + XCTAssertEqual(try JSONDecoder().decode(ErrorResponse.self, from: body).errorMessage, "boom") + + XCTAssertEqual(try server.readInbound(), .end(nil)) + + XCTAssertNoThrow(try server.writeOutbound(.head(.init(version: .init(major: 1, minor: 1), status: .accepted)))) + XCTAssertNoThrow(try server.writeOutbound(.end(nil))) + XCTAssertNoThrow(try result.wait()) + } + class Behavior: LambdaServerBehavior { var state = 0 From d0b3712f09c47086d478e5ac304e2dc3307e9977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Sat, 13 Jun 2020 23:05:42 +0200 Subject: [PATCH 10/18] remove header change from get method --- Sources/AWSLambdaRuntimeCore/HTTPClient.swift | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift index 54f80933..a0945592 100644 --- a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift +++ b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift @@ -35,14 +35,11 @@ internal final class HTTPClient { self.targetHost = "\(self.configuration.ip):\(self.configuration.port)" } - func get(url: String, timeout: TimeAmount? = nil, additionalHeaders: HTTPHeaders? = nil) -> EventLoopFuture { - var headers = HTTPClient.headers - additionalHeaders.flatMap { headers.add(contentsOf: $0) } - + func get(url: String, timeout: TimeAmount? = nil) -> EventLoopFuture { return self.execute(Request(targetHost: self.targetHost, url: url, method: .GET, - headers: headers, + headers: HTTPClient.headers, timeout: timeout ?? self.configuration.requestTimeout)) } From 196b33517aa895ae886ea784e280e9cdf3ec7142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Sat, 13 Jun 2020 23:20:54 +0200 Subject: [PATCH 11/18] test that previous headers are present --- Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index 0225ba09..1bc59b93 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -229,6 +229,7 @@ class LambdaRuntimeClientTest: XCTestCase { XCTAssertNoThrow(inboundHeader = try server.readInbound()) guard case .head(let head) = try? XCTUnwrap(inboundHeader) else { XCTFail("Expected to get a head first"); return } XCTAssertEqual(head.headers["lambda-runtime-function-error-type"], ["Unhandled"]) + XCTAssertEqual(head.headers["user-agent"], ["Swift-Lambda/Unknown"]) var inboundBody: HTTPServerRequestPart? XCTAssertNoThrow(inboundBody = try server.readInbound()) @@ -268,6 +269,7 @@ class LambdaRuntimeClientTest: XCTestCase { XCTAssertNoThrow(inboundHeader = try server.readInbound()) guard case .head(let head) = try? XCTUnwrap(inboundHeader) else { XCTFail("Expected to get a head first"); return } XCTAssertEqual(head.headers["lambda-runtime-function-error-type"], ["Unhandled"]) + XCTAssertEqual(head.headers["user-agent"], ["Swift-Lambda/Unknown"]) var inboundBody: HTTPServerRequestPart? XCTAssertNoThrow(inboundBody = try server.readInbound()) From 1ccd68ed2833d14b9e9867dd79a72b78466a0a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Sat, 13 Jun 2020 23:21:15 +0200 Subject: [PATCH 12/18] check success case does not have error headers --- .../LambdaRuntimeClientTest.swift | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index 1bc59b93..6343be48 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -283,6 +283,42 @@ class LambdaRuntimeClientTest: XCTestCase { XCTAssertNoThrow(try result.wait()) } + func testSuccessHeaders() { + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) + defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } + + let server = NIOHTTP1TestServer(group: eventLoopGroup) + defer { XCTAssertNoThrow(try server.stop()) } + + let logger = Logger(label: "TestLogger") + let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(baseURL: "127.0.0.1:\(server.serverPort)")) + + let header = HTTPHeaders([ + (AmazonHeaders.requestID, "test"), + (AmazonHeaders.deadline, String(Date(timeIntervalSinceNow: 60).millisSinceEpoch)), + (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:123456789012:function:custom-runtime"), + (AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1") + ]) + var inv: Lambda.Invocation? + XCTAssertNoThrow(inv = try Lambda.Invocation(headers: header)) + guard let invocation = inv else { return } + + let result = client.reportResults(logger: logger, invocation: invocation, result: Result.success(nil)) + + var inboundHeader: HTTPServerRequestPart? + XCTAssertNoThrow(inboundHeader = try server.readInbound()) + guard case .head(let head) = try? XCTUnwrap(inboundHeader) else { XCTFail("Expected to get a head first"); return } + XCTAssertFalse(head.headers.contains(name: "lambda-runtime-function-error-type")) + XCTAssertEqual(head.headers["user-agent"], ["Swift-Lambda/Unknown"]) + + XCTAssertEqual(try server.readInbound(), .end(nil)) + + XCTAssertNoThrow(try server.writeOutbound(.head(.init(version: .init(major: 1, minor: 1), status: .accepted)))) + XCTAssertNoThrow(try server.writeOutbound(.end(nil))) + XCTAssertNoThrow(try result.wait()) + } + + class Behavior: LambdaServerBehavior { var state = 0 From c520b22884c79b3979c10d40f9112822f5b06893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Sat, 13 Jun 2020 23:56:42 +0200 Subject: [PATCH 13/18] swiftformat --- Sources/AWSLambdaRuntimeCore/HTTPClient.swift | 4 +- .../LambdaRuntimeClient.swift | 5 +- .../LambdaRuntimeClientTest.swift | 59 +++++++++---------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift index a0945592..02dfd25d 100644 --- a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift +++ b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift @@ -36,7 +36,7 @@ internal final class HTTPClient { } func get(url: String, timeout: TimeAmount? = nil) -> EventLoopFuture { - return self.execute(Request(targetHost: self.targetHost, + self.execute(Request(targetHost: self.targetHost, url: url, method: .GET, headers: HTTPClient.headers, @@ -46,7 +46,7 @@ internal final class HTTPClient { func post(url: String, body: ByteBuffer?, timeout: TimeAmount? = nil, additionalHeaders: HTTPHeaders? = nil) -> EventLoopFuture { var headers = HTTPClient.headers additionalHeaders.flatMap { headers.add(contentsOf: $0) } - + return self.execute(Request(targetHost: self.targetHost, url: url, method: .POST, diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift index db27de83..d5c1957f 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift @@ -22,12 +22,11 @@ import NIOHTTP1 /// * /runtime/invocation/error /// * /runtime/init/error extension Lambda { - internal struct RuntimeClient { private let eventLoop: EventLoop private let allocator = ByteBufferAllocator() private let httpClient: HTTPClient - + /// Headers that must be sent along an invocation or initialization error report internal static let errorHeaders = HTTPHeaders([("lambda-runtime-function-error-type", "Unhandled")]) @@ -66,7 +65,7 @@ extension Lambda { var url = Consts.invocationURLPrefix + "/" + invocation.requestID var body: ByteBuffer? var additionalHeaders: HTTPHeaders? - + switch result { case .success(let buffer): url += Consts.postResponseURLSuffix diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index 6343be48..06fbd86d 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -13,11 +13,11 @@ //===----------------------------------------------------------------------===// @testable import AWSLambdaRuntimeCore -@testable import NIOHTTP1 -import NIOTestUtils +import Logging import NIO import NIOFoundationCompat -import Logging +@testable import NIOHTTP1 +import NIOTestUtils import XCTest class LambdaRuntimeClientTest: XCTestCase { @@ -213,31 +213,31 @@ class LambdaRuntimeClientTest: XCTestCase { let emojiBytes = emojiError.toJSONBytes() XCTAssertEqual(#"{"errorType":"error","errorMessage":"๐Ÿฅ‘๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง"}"#, String(decoding: emojiBytes, as: Unicode.UTF8.self)) } - + func testInitializationErrorReport() { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - + let server = NIOHTTP1TestServer(group: eventLoopGroup) defer { XCTAssertNoThrow(try server.stop()) } - + let logger = Logger(label: "TestLogger") let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(baseURL: "127.0.0.1:\(server.serverPort)")) let result = client.reportInitializationError(logger: logger, error: TestError("boom")) - + var inboundHeader: HTTPServerRequestPart? XCTAssertNoThrow(inboundHeader = try server.readInbound()) guard case .head(let head) = try? XCTUnwrap(inboundHeader) else { XCTFail("Expected to get a head first"); return } XCTAssertEqual(head.headers["lambda-runtime-function-error-type"], ["Unhandled"]) XCTAssertEqual(head.headers["user-agent"], ["Swift-Lambda/Unknown"]) - + var inboundBody: HTTPServerRequestPart? XCTAssertNoThrow(inboundBody = try server.readInbound()) guard case .body(let body) = try? XCTUnwrap(inboundBody) else { XCTFail("Expected body after head"); return } XCTAssertEqual(try JSONDecoder().decode(ErrorResponse.self, from: body).errorMessage, "boom") - + XCTAssertEqual(try server.readInbound(), .end(nil)) - + XCTAssertNoThrow(try server.writeOutbound(.head(.init(version: .init(major: 1, minor: 1), status: .accepted)))) XCTAssertNoThrow(try server.writeOutbound(.end(nil))) XCTAssertNoThrow(try result.wait()) @@ -246,79 +246,78 @@ class LambdaRuntimeClientTest: XCTestCase { func testInvocationErrorReport() { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - + let server = NIOHTTP1TestServer(group: eventLoopGroup) defer { XCTAssertNoThrow(try server.stop()) } - + let logger = Logger(label: "TestLogger") let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(baseURL: "127.0.0.1:\(server.serverPort)")) - + let header = HTTPHeaders([ (AmazonHeaders.requestID, "test"), (AmazonHeaders.deadline, String(Date(timeIntervalSinceNow: 60).millisSinceEpoch)), (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:123456789012:function:custom-runtime"), - (AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1") + (AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1"), ]) var inv: Lambda.Invocation? XCTAssertNoThrow(inv = try Lambda.Invocation(headers: header)) guard let invocation = inv else { return } - + let result = client.reportResults(logger: logger, invocation: invocation, result: Result.failure(TestError("boom"))) - + var inboundHeader: HTTPServerRequestPart? XCTAssertNoThrow(inboundHeader = try server.readInbound()) guard case .head(let head) = try? XCTUnwrap(inboundHeader) else { XCTFail("Expected to get a head first"); return } XCTAssertEqual(head.headers["lambda-runtime-function-error-type"], ["Unhandled"]) XCTAssertEqual(head.headers["user-agent"], ["Swift-Lambda/Unknown"]) - + var inboundBody: HTTPServerRequestPart? XCTAssertNoThrow(inboundBody = try server.readInbound()) guard case .body(let body) = try? XCTUnwrap(inboundBody) else { XCTFail("Expected body after head"); return } XCTAssertEqual(try JSONDecoder().decode(ErrorResponse.self, from: body).errorMessage, "boom") - + XCTAssertEqual(try server.readInbound(), .end(nil)) - + XCTAssertNoThrow(try server.writeOutbound(.head(.init(version: .init(major: 1, minor: 1), status: .accepted)))) XCTAssertNoThrow(try server.writeOutbound(.end(nil))) XCTAssertNoThrow(try result.wait()) } - + func testSuccessHeaders() { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - + let server = NIOHTTP1TestServer(group: eventLoopGroup) defer { XCTAssertNoThrow(try server.stop()) } - + let logger = Logger(label: "TestLogger") let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(baseURL: "127.0.0.1:\(server.serverPort)")) - + let header = HTTPHeaders([ (AmazonHeaders.requestID, "test"), (AmazonHeaders.deadline, String(Date(timeIntervalSinceNow: 60).millisSinceEpoch)), (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:123456789012:function:custom-runtime"), - (AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1") + (AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1"), ]) var inv: Lambda.Invocation? XCTAssertNoThrow(inv = try Lambda.Invocation(headers: header)) guard let invocation = inv else { return } - + let result = client.reportResults(logger: logger, invocation: invocation, result: Result.success(nil)) - + var inboundHeader: HTTPServerRequestPart? XCTAssertNoThrow(inboundHeader = try server.readInbound()) guard case .head(let head) = try? XCTUnwrap(inboundHeader) else { XCTFail("Expected to get a head first"); return } XCTAssertFalse(head.headers.contains(name: "lambda-runtime-function-error-type")) XCTAssertEqual(head.headers["user-agent"], ["Swift-Lambda/Unknown"]) - + XCTAssertEqual(try server.readInbound(), .end(nil)) - + XCTAssertNoThrow(try server.writeOutbound(.head(.init(version: .init(major: 1, minor: 1), status: .accepted)))) XCTAssertNoThrow(try server.writeOutbound(.end(nil))) XCTAssertNoThrow(try result.wait()) } - - + class Behavior: LambdaServerBehavior { var state = 0 From e5dd619ee8cdfcd8b276483f0cc82f9d8ee3744f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Sun, 14 Jun 2020 00:09:11 +0200 Subject: [PATCH 14/18] removed unneeded @testable --- Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index 06fbd86d..032b4f3c 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -16,7 +16,7 @@ import Logging import NIO import NIOFoundationCompat -@testable import NIOHTTP1 +import NIOHTTP1 import NIOTestUtils import XCTest From 84e19d2ede1e7cc7095392aad67db5d15ed73746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Wed, 17 Jun 2020 00:22:44 +0200 Subject: [PATCH 15/18] rename test method --- Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index a15f017c..da75445d 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -283,7 +283,7 @@ class LambdaRuntimeClientTest: XCTestCase { XCTAssertNoThrow(try result.wait()) } - func testSuccessHeaders() { + func testInvocationSuccessResponse() { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } From 60c4dc43fd0cd4353c82fc84acbe6fc9057680eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Wed, 17 Jun 2020 00:24:37 +0200 Subject: [PATCH 16/18] rename runtimeEngines baseUrl to address --- Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift | 4 ++-- .../AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift b/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift index c64bd4e6..9b9ec8fb 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift @@ -67,8 +67,8 @@ extension Lambda { let keepAlive: Bool let requestTimeout: TimeAmount? - init(baseURL: String? = nil, keepAlive: Bool? = nil, requestTimeout: TimeAmount? = nil) { - let ipPort = (baseURL ?? env("AWS_LAMBDA_RUNTIME_API"))?.split(separator: ":") ?? ["127.0.0.1", "7000"] + init(address: String? = nil, keepAlive: Bool? = nil, requestTimeout: TimeAmount? = nil) { + let ipPort = (address ?? env("AWS_LAMBDA_RUNTIME_API"))?.split(separator: ":") ?? ["127.0.0.1", "7000"] guard ipPort.count == 2, let port = Int(ipPort[1]) else { preconditionFailure("invalid ip+port configuration \(ipPort)") } diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index da75445d..728672e6 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -222,7 +222,7 @@ class LambdaRuntimeClientTest: XCTestCase { defer { XCTAssertNoThrow(try server.stop()) } let logger = Logger(label: "TestLogger") - let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(baseURL: "127.0.0.1:\(server.serverPort)")) + let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(address: "127.0.0.1:\(server.serverPort)")) let result = client.reportInitializationError(logger: logger, error: TestError("boom")) var inboundHeader: HTTPServerRequestPart? @@ -251,7 +251,7 @@ class LambdaRuntimeClientTest: XCTestCase { defer { XCTAssertNoThrow(try server.stop()) } let logger = Logger(label: "TestLogger") - let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(baseURL: "127.0.0.1:\(server.serverPort)")) + let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(address: "127.0.0.1:\(server.serverPort)")) let header = HTTPHeaders([ (AmazonHeaders.requestID, "test"), @@ -291,7 +291,7 @@ class LambdaRuntimeClientTest: XCTestCase { defer { XCTAssertNoThrow(try server.stop()) } let logger = Logger(label: "TestLogger") - let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(baseURL: "127.0.0.1:\(server.serverPort)")) + let client = Lambda.RuntimeClient(eventLoop: eventLoopGroup.next(), configuration: .init(address: "127.0.0.1:\(server.serverPort)")) let header = HTTPHeaders([ (AmazonHeaders.requestID, "test"), From 24c9d1b8b136a6dcb0fda01c1a6081e58d6a5cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Wed, 17 Jun 2020 00:43:16 +0200 Subject: [PATCH 17/18] move headers from HTTPClient into RuntimeClient --- Sources/AWSLambdaRuntimeCore/HTTPClient.swift | 11 ++----- .../LambdaRuntimeClient.swift | 30 +++++++++++++------ 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift index 02dfd25d..872bb647 100644 --- a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift +++ b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift @@ -27,26 +27,21 @@ internal final class HTTPClient { private var state = State.disconnected private var executing = false - private static let headers = HTTPHeaders([("user-agent", "Swift-Lambda/Unknown")]) - init(eventLoop: EventLoop, configuration: Lambda.Configuration.RuntimeEngine) { self.eventLoop = eventLoop self.configuration = configuration self.targetHost = "\(self.configuration.ip):\(self.configuration.port)" } - func get(url: String, timeout: TimeAmount? = nil) -> EventLoopFuture { + func get(url: String, headers: HTTPHeaders, timeout: TimeAmount? = nil) -> EventLoopFuture { self.execute(Request(targetHost: self.targetHost, url: url, method: .GET, - headers: HTTPClient.headers, + headers: headers, timeout: timeout ?? self.configuration.requestTimeout)) } - func post(url: String, body: ByteBuffer?, timeout: TimeAmount? = nil, additionalHeaders: HTTPHeaders? = nil) -> EventLoopFuture { - var headers = HTTPClient.headers - additionalHeaders.flatMap { headers.add(contentsOf: $0) } - + func post(url: String, headers: HTTPHeaders, body: ByteBuffer?, timeout: TimeAmount? = nil) -> EventLoopFuture { return self.execute(Request(targetHost: self.targetHost, url: url, method: .POST, diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift index d5c1957f..b340be0f 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift @@ -16,6 +16,8 @@ import Logging import NIO import NIOHTTP1 + + /// An HTTP based client for AWS Runtime Engine. This encapsulates the RESTful methods exposed by the Runtime Engine: /// * /runtime/invocation/next /// * /runtime/invocation/response @@ -26,10 +28,7 @@ extension Lambda { private let eventLoop: EventLoop private let allocator = ByteBufferAllocator() private let httpClient: HTTPClient - - /// Headers that must be sent along an invocation or initialization error report - internal static let errorHeaders = HTTPHeaders([("lambda-runtime-function-error-type", "Unhandled")]) - + init(eventLoop: EventLoop, configuration: Configuration.RuntimeEngine) { self.eventLoop = eventLoop self.httpClient = HTTPClient(eventLoop: eventLoop, configuration: configuration) @@ -39,7 +38,7 @@ extension Lambda { func getNextInvocation(logger: Logger) -> EventLoopFuture<(Invocation, ByteBuffer)> { let url = Consts.invocationURLPrefix + Consts.getNextInvocationURLSuffix logger.debug("requesting work from lambda runtime engine using \(url)") - return self.httpClient.get(url: url).flatMapThrowing { response in + return self.httpClient.get(url: url, headers: RuntimeClient.defaultHeaders).flatMapThrowing { response in guard response.status == .ok else { throw RuntimeError.badStatusCode(response.status) } @@ -64,22 +63,23 @@ extension Lambda { func reportResults(logger: Logger, invocation: Invocation, result: Result) -> EventLoopFuture { var url = Consts.invocationURLPrefix + "/" + invocation.requestID var body: ByteBuffer? - var additionalHeaders: HTTPHeaders? + let headers: HTTPHeaders switch result { case .success(let buffer): url += Consts.postResponseURLSuffix body = buffer + headers = RuntimeClient.defaultHeaders case .failure(let error): url += Consts.postErrorURLSuffix let errorResponse = ErrorResponse(errorType: Consts.functionError, errorMessage: "\(error)") let bytes = errorResponse.toJSONBytes() body = self.allocator.buffer(capacity: bytes.count) body!.writeBytes(bytes) - additionalHeaders = RuntimeClient.errorHeaders + headers = RuntimeClient.errorHeaders } logger.debug("reporting results to lambda runtime engine using \(url)") - return self.httpClient.post(url: url, body: body, additionalHeaders: additionalHeaders).flatMapThrowing { response in + return self.httpClient.post(url: url, headers: headers, body: body).flatMapThrowing { response in guard response.status == .accepted else { throw RuntimeError.badStatusCode(response.status) } @@ -104,7 +104,7 @@ extension Lambda { var body = self.allocator.buffer(capacity: bytes.count) body.writeBytes(bytes) logger.warning("reporting initialization error to lambda runtime engine using \(url)") - return self.httpClient.post(url: url, body: body, additionalHeaders: RuntimeClient.errorHeaders).flatMapThrowing { response in + return self.httpClient.post(url: url, headers: RuntimeClient.errorHeaders, body: body).flatMapThrowing { response in guard response.status == .accepted else { throw RuntimeError.badStatusCode(response.status) } @@ -192,3 +192,15 @@ extension Lambda { } } } + +extension Lambda.RuntimeClient { + + internal static let defaultHeaders = HTTPHeaders([("user-agent", "Swift-Lambda/Unknown")]) + + /// These headers must be sent along an invocation or initialization error report + internal static let errorHeaders = HTTPHeaders([ + ("user-agent", "Swift-Lambda/Unknown"), + ("lambda-runtime-function-error-type", "Unhandled"), + ]) + +} From d8a18e1d5578299093d747eaae66e7c6e4852a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Mo=CC=88ller?= Date: Wed, 17 Jun 2020 11:43:38 +0200 Subject: [PATCH 18/18] run sanity script --- Sources/AWSLambdaRuntimeCore/HTTPClient.swift | 12 ++++++------ .../LambdaRuntimeClient.swift | 18 +++++++----------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift index 872bb647..fcd2a450 100644 --- a/Sources/AWSLambdaRuntimeCore/HTTPClient.swift +++ b/Sources/AWSLambdaRuntimeCore/HTTPClient.swift @@ -42,12 +42,12 @@ internal final class HTTPClient { } func post(url: String, headers: HTTPHeaders, body: ByteBuffer?, timeout: TimeAmount? = nil) -> EventLoopFuture { - return self.execute(Request(targetHost: self.targetHost, - url: url, - method: .POST, - headers: headers, - body: body, - timeout: timeout ?? self.configuration.requestTimeout)) + self.execute(Request(targetHost: self.targetHost, + url: url, + method: .POST, + headers: headers, + body: body, + timeout: timeout ?? self.configuration.requestTimeout)) } /// cancels the current request if there is one diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift index b340be0f..fe43ac0a 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift @@ -16,8 +16,6 @@ import Logging import NIO import NIOHTTP1 - - /// An HTTP based client for AWS Runtime Engine. This encapsulates the RESTful methods exposed by the Runtime Engine: /// * /runtime/invocation/next /// * /runtime/invocation/response @@ -28,7 +26,7 @@ extension Lambda { private let eventLoop: EventLoop private let allocator = ByteBufferAllocator() private let httpClient: HTTPClient - + init(eventLoop: EventLoop, configuration: Configuration.RuntimeEngine) { self.eventLoop = eventLoop self.httpClient = HTTPClient(eventLoop: eventLoop, configuration: configuration) @@ -194,13 +192,11 @@ extension Lambda { } extension Lambda.RuntimeClient { - internal static let defaultHeaders = HTTPHeaders([("user-agent", "Swift-Lambda/Unknown")]) - - /// These headers must be sent along an invocation or initialization error report - internal static let errorHeaders = HTTPHeaders([ - ("user-agent", "Swift-Lambda/Unknown"), - ("lambda-runtime-function-error-type", "Unhandled"), - ]) - + + /// These headers must be sent along an invocation or initialization error report + internal static let errorHeaders = HTTPHeaders([ + ("user-agent", "Swift-Lambda/Unknown"), + ("lambda-runtime-function-error-type", "Unhandled"), + ]) }