Skip to content

Commit 8f6c5a8

Browse files
committed
Refactor + add test for reportError
1 parent 258fd35 commit 8f6c5a8

File tree

2 files changed

+88
-22
lines changed

2 files changed

+88
-22
lines changed

Tests/AWSLambdaRuntimeCoreTests/LambdaMockClient.swift

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,27 @@ struct LambdaMockWriter: LambdaResponseStreamWriter {
2828
try await self.underlying.write(buffer)
2929
}
3030

31-
consuming func finish() async throws {
31+
func finish() async throws {
3232
try await self.underlying.finish()
3333
}
3434

35-
consuming func writeAndFinish(_ buffer: ByteBuffer) async throws {
36-
try await self.write(buffer)
37-
try await self.finish()
35+
func writeAndFinish(_ buffer: ByteBuffer) async throws {
36+
try await self.underlying.write(buffer)
37+
try await self.underlying.finish()
3838
}
3939

4040
func reportError(_ error: any Error) async throws {
41+
try await self.underlying.write(ByteBuffer(string: "\(error)"))
42+
try await self.underlying.finish()
4143
}
4244
}
4345

4446
enum LambdaError: Error, Equatable {
4547
case cannotCallNextEndpointWhenAlreadyWaitingForEvent
4648
case cannotCallNextEndpointWhenAlreadyProcessingAnEvent
4749
case cannotReportResultWhenNoEventHasBeenProcessed
50+
case cancelError
51+
case handlerError
4852
}
4953

5054
final actor LambdaMockClient: LambdaRuntimeClientProtocol {
@@ -89,6 +93,12 @@ final actor LambdaMockClient: LambdaRuntimeClientProtocol {
8993
case fail(LambdaError)
9094
}
9195

96+
enum CancelNextAction {
97+
case none
98+
99+
case cancelContinuation(CheckedContinuation<Invocation, any Error>)
100+
}
101+
92102
enum ResultAction {
93103
case readyForMore
94104

@@ -165,6 +175,16 @@ final actor LambdaMockClient: LambdaRuntimeClientProtocol {
165175
throw LambdaError.cannotReportResultWhenNoEventHasBeenProcessed
166176
}
167177
}
178+
179+
mutating func cancelNext() -> CancelNextAction {
180+
switch self.state {
181+
case .initialState, .handlerIsProcessing:
182+
return .none
183+
case .waitingForNextEvent(let eventArrivedHandler):
184+
self.state = .initialState
185+
return .cancelContinuation(eventArrivedHandler)
186+
}
187+
}
168188
}
169189

170190
private var stateMachine: StateMachine = .init()
@@ -208,18 +228,32 @@ final actor LambdaMockClient: LambdaRuntimeClientProtocol {
208228
}
209229

210230
func nextInvocation() async throws -> (Invocation, Writer) {
211-
let invocation = try await withCheckedThrowingContinuation { eventArrivedHandler in
212-
switch self.stateMachine.next(eventArrivedHandler) {
213-
case .readyToProcess(let event):
214-
eventArrivedHandler.resume(returning: event)
215-
case .fail(let error):
216-
eventArrivedHandler.resume(throwing: error)
217-
case .wait:
218-
break
231+
try await withTaskCancellationHandler {
232+
let invocation = try await withCheckedThrowingContinuation { eventArrivedHandler in
233+
switch self.stateMachine.next(eventArrivedHandler) {
234+
case .readyToProcess(let event):
235+
eventArrivedHandler.resume(returning: event)
236+
case .fail(let error):
237+
eventArrivedHandler.resume(throwing: error)
238+
case .wait:
239+
break
240+
}
241+
}
242+
return (invocation, Writer(underlying: self))
243+
} onCancel: {
244+
Task {
245+
await self.cancelNextInvocation()
219246
}
220247
}
248+
}
221249

222-
return (invocation, Writer(underlying: self))
250+
private func cancelNextInvocation() {
251+
switch self.stateMachine.cancelNext() {
252+
case .none:
253+
break
254+
case .cancelContinuation(let continuation):
255+
continuation.resume(throwing: LambdaError.cancelError)
256+
}
223257
}
224258

225259
func write(_ buffer: ByteBuffer) async throws {

Tests/AWSLambdaRuntimeCoreTests/LambdaRunLoopTests.swift

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,55 @@ struct LambdaRunLoopTests {
3131
}
3232
}
3333

34+
struct FailingHandler: StreamingLambdaHandler {
35+
func handle(
36+
_ event: ByteBuffer,
37+
responseWriter: some LambdaResponseStreamWriter,
38+
context: NewLambdaContext
39+
) async throws {
40+
throw LambdaError.handlerError
41+
}
42+
}
43+
3444
let mockClient = LambdaMockClient()
3545
let mockEchoHandler = MockEchoHandler()
46+
let failingHandler = FailingHandler()
3647

3748
@Test func testRunLoop() async throws {
38-
let runLoopTask = Task { () in
39-
try await Lambda.runLoop(
40-
runtimeClient: self.mockClient,
41-
handler: self.mockEchoHandler,
42-
logger: Logger(label: "RunLoopTest")
43-
)
49+
let inputEvent = ByteBuffer(string: "Test Invocation Event")
50+
51+
try await withThrowingTaskGroup(of: Void.self) { group in
52+
group.addTask {
53+
try await Lambda.runLoop(
54+
runtimeClient: self.mockClient,
55+
handler: self.mockEchoHandler,
56+
logger: Logger(label: "RunLoopTest")
57+
)
58+
}
59+
60+
let response = try await self.mockClient.invoke(event: inputEvent)
61+
#expect(response == inputEvent)
62+
63+
group.cancelAll()
4464
}
65+
}
4566

67+
@Test func testRunLoopError() async throws {
4668
let inputEvent = ByteBuffer(string: "Test Invocation Event")
47-
let response = try await self.mockClient.invoke(event: inputEvent)
4869

49-
runLoopTask.cancel()
70+
try await withThrowingTaskGroup(of: Void.self) { group in
71+
group.addTask {
72+
try await Lambda.runLoop(
73+
runtimeClient: self.mockClient,
74+
handler: self.failingHandler,
75+
logger: Logger(label: "RunLoopTest")
76+
)
77+
}
78+
79+
let response = try await self.mockClient.invoke(event: inputEvent)
80+
#expect(String(buffer: response) == "\(LambdaError.handlerError)")
5081

51-
#expect(response == inputEvent)
82+
group.cancelAll()
83+
}
5284
}
5385
}

0 commit comments

Comments
 (0)