|
12 | 12 | //
|
13 | 13 | //===----------------------------------------------------------------------===//
|
14 | 14 |
|
15 |
| -#if false |
16 | 15 | @testable import AWSLambdaRuntime
|
17 | 16 | @testable import AWSLambdaRuntimeCore
|
| 17 | +import Logging |
18 | 18 | import NIO
|
| 19 | +import NIOFoundationCompat |
19 | 20 | import XCTest
|
20 | 21 |
|
21 | 22 | class CodableLambdaTest: XCTestCase {
|
22 |
| - func testCallbackSuccess() { |
23 |
| - let server = MockLambdaServer(behavior: Behavior()) |
24 |
| - XCTAssertNoThrow(try server.start().wait()) |
25 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
| 23 | + var eventLoopGroup: EventLoopGroup! |
| 24 | + let allocator = ByteBufferAllocator() |
26 | 25 |
|
27 |
| - struct Handler: LambdaHandler { |
28 |
| - typealias In = Request |
29 |
| - typealias Out = Response |
30 |
| - |
31 |
| - func handle(context: Lambda.Context, payload: Request, callback: (Result<Response, Error>) -> Void) { |
32 |
| - callback(.success(Response(requestId: payload.requestId))) |
33 |
| - } |
34 |
| - } |
35 |
| - |
36 |
| - let maxTimes = Int.random(in: 1 ... 10) |
37 |
| - let configuration = Lambda.Configuration(lifecycle: .init(maxTimes: maxTimes)) |
38 |
| - let result = Lambda.run(configuration: configuration, handler: Handler()) |
39 |
| - assertLambdaLifecycleResult(result, shoudHaveRun: maxTimes) |
40 |
| - } |
41 |
| - |
42 |
| - func testVoidCallbackSuccess() { |
43 |
| - let server = MockLambdaServer(behavior: Behavior(result: .success(nil))) |
44 |
| - XCTAssertNoThrow(try server.start().wait()) |
45 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
46 |
| - |
47 |
| - struct Handler: LambdaHandler { |
48 |
| - typealias In = Request |
49 |
| - typealias Out = Void |
50 |
| - |
51 |
| - func handle(context: Lambda.Context, payload: Request, callback: (Result<Void, Error>) -> Void) { |
52 |
| - callback(.success(())) |
53 |
| - } |
54 |
| - } |
55 |
| - |
56 |
| - let maxTimes = Int.random(in: 1 ... 10) |
57 |
| - let configuration = Lambda.Configuration(lifecycle: .init(maxTimes: maxTimes)) |
58 |
| - let result = Lambda.run(configuration: configuration, handler: Handler()) |
59 |
| - assertLambdaLifecycleResult(result, shoudHaveRun: maxTimes) |
60 |
| - } |
61 |
| - |
62 |
| - func testCallbackFailure() { |
63 |
| - let server = MockLambdaServer(behavior: Behavior(result: .failure(TestError("boom")))) |
64 |
| - XCTAssertNoThrow(try server.start().wait()) |
65 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
66 |
| - |
67 |
| - struct Handler: LambdaHandler { |
68 |
| - typealias In = Request |
69 |
| - typealias Out = Response |
70 |
| - |
71 |
| - func handle(context: Lambda.Context, payload: Request, callback: (Result<Response, Error>) -> Void) { |
72 |
| - callback(.failure(TestError("boom"))) |
73 |
| - } |
74 |
| - } |
75 |
| - |
76 |
| - let maxTimes = Int.random(in: 1 ... 10) |
77 |
| - let configuration = Lambda.Configuration(lifecycle: .init(maxTimes: maxTimes)) |
78 |
| - let result = Lambda.run(configuration: configuration, handler: Handler()) |
79 |
| - assertLambdaLifecycleResult(result, shoudHaveRun: maxTimes) |
80 |
| - } |
81 |
| - |
82 |
| - func testEventLoopSuccess() { |
83 |
| - let server = MockLambdaServer(behavior: Behavior()) |
84 |
| - XCTAssertNoThrow(try server.start().wait()) |
85 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
86 |
| - |
87 |
| - struct Handler: EventLoopLambdaHandler { |
88 |
| - typealias In = Request |
89 |
| - typealias Out = Response |
90 |
| - |
91 |
| - func handle(context: Lambda.Context, payload: Request) -> EventLoopFuture<Response> { |
92 |
| - context.eventLoop.makeSucceededFuture(Response(requestId: payload.requestId)) |
93 |
| - } |
94 |
| - } |
95 |
| - |
96 |
| - let maxTimes = Int.random(in: 1 ... 10) |
97 |
| - let configuration = Lambda.Configuration(lifecycle: .init(maxTimes: maxTimes)) |
98 |
| - let result = Lambda.run(configuration: configuration, handler: Handler()) |
99 |
| - assertLambdaLifecycleResult(result, shoudHaveRun: maxTimes) |
100 |
| - } |
101 |
| - |
102 |
| - func testVoidEventLoopSuccess() { |
103 |
| - let server = MockLambdaServer(behavior: Behavior(result: .success(nil))) |
104 |
| - XCTAssertNoThrow(try server.start().wait()) |
105 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
106 |
| - |
107 |
| - struct Handler: EventLoopLambdaHandler { |
108 |
| - typealias In = Request |
109 |
| - typealias Out = Void |
110 |
| - |
111 |
| - func handle(context: Lambda.Context, payload: Request) -> EventLoopFuture<Void> { |
112 |
| - context.eventLoop.makeSucceededFuture(()) |
113 |
| - } |
114 |
| - } |
115 |
| - |
116 |
| - let maxTimes = Int.random(in: 1 ... 10) |
117 |
| - let configuration = Lambda.Configuration(lifecycle: .init(maxTimes: maxTimes)) |
118 |
| - let result = Lambda.run(configuration: configuration, handler: Handler()) |
119 |
| - assertLambdaLifecycleResult(result, shoudHaveRun: maxTimes) |
120 |
| - } |
121 |
| - |
122 |
| - func testEventLoopFailure() { |
123 |
| - let server = MockLambdaServer(behavior: Behavior(result: .failure(TestError("boom")))) |
124 |
| - XCTAssertNoThrow(try server.start().wait()) |
125 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
126 |
| - |
127 |
| - struct Handler: EventLoopLambdaHandler { |
128 |
| - typealias In = Request |
129 |
| - typealias Out = Response |
130 |
| - |
131 |
| - func handle(context: Lambda.Context, payload: Request) -> EventLoopFuture<Response> { |
132 |
| - context.eventLoop.makeFailedFuture(TestError("boom")) |
133 |
| - } |
134 |
| - } |
135 |
| - |
136 |
| - let maxTimes = Int.random(in: 1 ... 10) |
137 |
| - let configuration = Lambda.Configuration(lifecycle: .init(maxTimes: maxTimes)) |
138 |
| - let result = Lambda.run(configuration: configuration, handler: Handler()) |
139 |
| - assertLambdaLifecycleResult(result, shoudHaveRun: maxTimes) |
140 |
| - } |
141 |
| - |
142 |
| - func testClosureSuccess() { |
143 |
| - let server = MockLambdaServer(behavior: Behavior()) |
144 |
| - XCTAssertNoThrow(try server.start().wait()) |
145 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
146 |
| - |
147 |
| - let maxTimes = Int.random(in: 1 ... 10) |
148 |
| - let configuration = Lambda.Configuration(lifecycle: .init(maxTimes: maxTimes)) |
149 |
| - let result = Lambda.run(configuration: configuration) { (_, payload: Request, callback) in |
150 |
| - callback(.success(Response(requestId: payload.requestId))) |
151 |
| - } |
152 |
| - assertLambdaLifecycleResult(result, shoudHaveRun: maxTimes) |
| 26 | + override func setUp() { |
| 27 | + self.eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) |
153 | 28 | }
|
154 | 29 |
|
155 |
| - func testVoidClosureSuccess() { |
156 |
| - let server = MockLambdaServer(behavior: Behavior(result: .success(nil))) |
157 |
| - XCTAssertNoThrow(try server.start().wait()) |
158 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
159 |
| - |
160 |
| - let maxTimes = Int.random(in: 1 ... 10) |
161 |
| - let configuration = Lambda.Configuration(lifecycle: .init(maxTimes: maxTimes)) |
162 |
| - let result = Lambda.run(configuration: configuration) { (_, _: Request, callback: (Result<Void, Error>) -> Void) in |
163 |
| - callback(.success(())) |
164 |
| - } |
165 |
| - assertLambdaLifecycleResult(result, shoudHaveRun: maxTimes) |
166 |
| - } |
167 |
| - |
168 |
| - func testClosureFailure() { |
169 |
| - let server = MockLambdaServer(behavior: Behavior(result: .failure(TestError("boom")))) |
170 |
| - XCTAssertNoThrow(try server.start().wait()) |
171 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
172 |
| - |
173 |
| - let maxTimes = Int.random(in: 1 ... 10) |
174 |
| - let configuration = Lambda.Configuration(lifecycle: .init(maxTimes: maxTimes)) |
175 |
| - let result: Result<Int, Error> = Lambda.run(configuration: configuration) { (_, _: Request, callback: (Result<Response, Error>) -> Void) in |
176 |
| - callback(.failure(TestError("boom"))) |
177 |
| - } |
178 |
| - assertLambdaLifecycleResult(result, shoudHaveRun: maxTimes) |
| 30 | + override func tearDown() { |
| 31 | + try! self.eventLoopGroup.syncShutdownGracefully() |
179 | 32 | }
|
180 | 33 |
|
181 |
| - func testBootstrapFailure() { |
182 |
| - let server = MockLambdaServer(behavior: FailedBootstrapBehavior()) |
183 |
| - XCTAssertNoThrow(try server.start().wait()) |
184 |
| - defer { XCTAssertNoThrow(try server.stop().wait()) } |
185 |
| - |
186 |
| - struct Handler: LambdaHandler { |
187 |
| - typealias In = Request |
188 |
| - typealias Out = Response |
| 34 | + func testCodableVoidClosureWrapper() { |
| 35 | + let request = Request(requestId: UUID().uuidString) |
| 36 | + var inputBuffer: ByteBuffer? |
| 37 | + var outputBuffer: ByteBuffer? |
189 | 38 |
|
190 |
| - init(eventLoop: EventLoop) throws { |
191 |
| - throw TestError("kaboom") |
192 |
| - } |
193 |
| - |
194 |
| - func handle(context: Lambda.Context, payload: Request, callback: (Result<Response, Error>) -> Void) { |
195 |
| - callback(.failure(TestError("should not be called"))) |
196 |
| - } |
| 39 | + let closureWrapper = CodableVoidClosureWrapper { (_, _: Request, completion) in |
| 40 | + XCTAssertEqual(request, request) |
| 41 | + completion(.success(())) |
197 | 42 | }
|
198 | 43 |
|
199 |
| - let result = Lambda.run(factory: Handler.init) |
200 |
| - assertLambdaLifecycleResult(result, shouldFailWithError: TestError("kaboom")) |
201 |
| - } |
202 |
| -} |
203 |
| - |
204 |
| -// TODO: taking advantage of the fact we know the serialization is json |
205 |
| -private struct Behavior: LambdaServerBehavior { |
206 |
| - let requestId: String |
207 |
| - let payload: String |
208 |
| - let result: Result<String?, TestError> |
209 |
| - |
210 |
| - init(requestId: String = UUID().uuidString, payload: String = "hello", result: Result<String?, TestError> = .success("hello")) { |
211 |
| - self.requestId = requestId |
212 |
| - self.payload = payload |
213 |
| - self.result = result |
| 44 | + XCTAssertNoThrow(inputBuffer = try JSONEncoder().encode(request, using: self.allocator)) |
| 45 | + XCTAssertNoThrow(outputBuffer = try closureWrapper.handle(context: self.newContext(), payload: XCTUnwrap(inputBuffer)).wait()) |
| 46 | + XCTAssertNil(outputBuffer) |
214 | 47 | }
|
215 | 48 |
|
216 |
| - func getWork() -> GetWorkResult { |
217 |
| - guard let payload = try? JSONEncoder().encode(Request(requestId: requestId)) else { |
218 |
| - XCTFail("encoding error") |
219 |
| - return .failure(.internalServerError) |
220 |
| - } |
221 |
| - guard let payloadAsString = String(data: payload, encoding: .utf8) else { |
222 |
| - XCTFail("encoding error") |
223 |
| - return .failure(.internalServerError) |
224 |
| - } |
225 |
| - return .success((requestId: self.requestId, payload: payloadAsString)) |
226 |
| - } |
| 49 | + func testCodableClosureWrapper() { |
| 50 | + let request = Request(requestId: UUID().uuidString) |
| 51 | + var inputBuffer: ByteBuffer? |
| 52 | + var outputBuffer: ByteBuffer? |
| 53 | + var response: Response? |
227 | 54 |
|
228 |
| - func processResponse(requestId: String, response: String?) -> Result<Void, ProcessResponseError> { |
229 |
| - switch self.result { |
230 |
| - case .success(let expected) where expected != nil: |
231 |
| - guard let data = response?.data(using: .utf8) else { |
232 |
| - XCTFail("decoding error") |
233 |
| - return .failure(.internalServerError) |
234 |
| - } |
235 |
| - guard let response = try? JSONDecoder().decode(Response.self, from: data) else { |
236 |
| - XCTFail("decoding error") |
237 |
| - return .failure(.internalServerError) |
238 |
| - } |
239 |
| - XCTAssertEqual(self.requestId, response.requestId, "expecting requestId to match") |
240 |
| - return .success(()) |
241 |
| - case .success(let expected) where expected == nil: |
242 |
| - XCTAssertNil(response) |
243 |
| - return .success(()) |
244 |
| - case .failure: |
245 |
| - XCTFail("unexpected to fail, but succeeded with: \(response ?? "undefined")") |
246 |
| - return .failure(.internalServerError) |
247 |
| - default: |
248 |
| - preconditionFailure("invalid state") |
| 55 | + let closureWrapper = CodableClosureWrapper { (_, req: Request, completion: (Result<Response, Error>) -> Void) in |
| 56 | + XCTAssertEqual(request, request) |
| 57 | + completion(.success(Response(requestId: req.requestId))) |
249 | 58 | }
|
250 |
| - } |
251 | 59 |
|
252 |
| - func processError(requestId: String, error: ErrorResponse) -> Result<Void, ProcessErrorError> { |
253 |
| - XCTAssertEqual(self.requestId, requestId, "expecting requestId to match") |
254 |
| - switch self.result { |
255 |
| - case .success: |
256 |
| - XCTFail("unexpected to succeed, but failed with: \(error)") |
257 |
| - return .failure(.internalServerError) |
258 |
| - case .failure(let expected): |
259 |
| - XCTAssertEqual(expected.description, error.errorMessage, "expecting error to match") |
260 |
| - return .success(()) |
261 |
| - } |
| 60 | + XCTAssertNoThrow(inputBuffer = try JSONEncoder().encode(request, using: self.allocator)) |
| 61 | + XCTAssertNoThrow(outputBuffer = try closureWrapper.handle(context: self.newContext(), payload: XCTUnwrap(inputBuffer)).wait()) |
| 62 | + XCTAssertNoThrow(response = try JSONDecoder().decode(Response.self, from: XCTUnwrap(outputBuffer))) |
| 63 | + XCTAssertEqual(response?.requestId, request.requestId) |
262 | 64 | }
|
263 | 65 |
|
264 |
| - func processInitError(error: ErrorResponse) -> Result<Void, ProcessErrorError> { |
265 |
| - XCTFail("should not report init error") |
266 |
| - return .failure(.internalServerError) |
| 66 | + // convencience method |
| 67 | + func newContext() -> Lambda.Context { |
| 68 | + Lambda.Context(requestId: UUID().uuidString, |
| 69 | + traceId: "abc123", |
| 70 | + invokedFunctionArn: "aws:arn:", |
| 71 | + deadline: .now() + .seconds(3), |
| 72 | + cognitoIdentity: nil, |
| 73 | + clientContext: nil, |
| 74 | + logger: Logger(label: "test"), |
| 75 | + eventLoop: self.eventLoopGroup.next()) |
267 | 76 | }
|
268 | 77 | }
|
269 | 78 |
|
270 |
| -private struct Request: Codable { |
| 79 | +private struct Request: Codable, Equatable { |
271 | 80 | let requestId: String
|
272 | 81 | init(requestId: String) {
|
273 | 82 | self.requestId = requestId
|
274 | 83 | }
|
275 | 84 | }
|
276 | 85 |
|
277 |
| -private struct Response: Codable { |
| 86 | +private struct Response: Codable, Equatable { |
278 | 87 | let requestId: String
|
279 | 88 | init(requestId: String) {
|
280 | 89 | self.requestId = requestId
|
281 | 90 | }
|
282 | 91 | }
|
283 |
| -#endif |
0 commit comments