Skip to content

Commit 03dc004

Browse files
author
Sebastien Stormacq
committed
add Sendable to LambdaResponseStreamWriter
1 parent a500f39 commit 03dc004

File tree

2 files changed

+45
-45
lines changed

2 files changed

+45
-45
lines changed

Sources/AWSLambdaRuntime/LambdaHandlers.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public protocol StreamingLambdaHandler: _Lambda_SendableMetatype {
4848

4949
/// A writer object to write the Lambda response stream into. The HTTP response is started lazily.
5050
/// before the first call to ``write(_:)`` or ``writeAndFinish(_:)``.
51-
public protocol LambdaResponseStreamWriter {
51+
public protocol LambdaResponseStreamWriter: Sendable {
5252
/// Write a response part into the stream. Bytes written are streamed continually.
5353
/// - Parameter buffer: The buffer to write.
5454
/// - Parameter hasCustomHeaders: If `true`, the response will be sent with custom HTTP status code and headers.

Tests/AWSLambdaRuntimeTests/LambdaResponseStreamWriter+HeadersTests.swift

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ struct LambdaResponseStreamWriterHeadersTests {
3636
try await writer.writeStatusAndHeaders(response)
3737

3838
// Verify we have exactly 1 buffer written (single write operation)
39-
#expect(writer.writtenBuffers.count == 1)
39+
#expect(await writer.writtenBuffers.count == 1)
4040

4141
// Verify buffer contains valid JSON
42-
let buffer = writer.writtenBuffers[0]
42+
let buffer = await writer.writtenBuffers[0]
4343
let content = String(buffer: buffer)
4444
#expect(content.contains("\"statusCode\":200"))
4545
}
@@ -63,10 +63,10 @@ struct LambdaResponseStreamWriterHeadersTests {
6363
try await writer.writeStatusAndHeaders(response)
6464

6565
// Verify we have exactly 1 buffer written (single write operation)
66-
#expect(writer.writtenBuffers.count == 1)
66+
#expect(await writer.writtenBuffers.count == 1)
6767

6868
// Extract JSON from the buffer
69-
let buffer = writer.writtenBuffers[0]
69+
let buffer = await writer.writtenBuffers[0]
7070
let content = String(buffer: buffer)
7171

7272
// Verify all expected fields are present in the JSON
@@ -97,10 +97,10 @@ struct LambdaResponseStreamWriterHeadersTests {
9797
try await writer.writeStatusAndHeaders(response, encoder: customEncoder)
9898

9999
// Verify we have exactly 1 buffer written (single write operation)
100-
#expect(writer.writtenBuffers.count == 1)
100+
#expect(await writer.writtenBuffers.count == 1)
101101

102102
// Verify JSON content with sorted keys
103-
let buffer = writer.writtenBuffers[0]
103+
let buffer = await writer.writtenBuffers[0]
104104
let content = String(buffer: buffer)
105105

106106
// With sorted keys, "headers" should come before "statusCode"
@@ -121,10 +121,10 @@ struct LambdaResponseStreamWriterHeadersTests {
121121
try await writer.writeStatusAndHeaders(response)
122122

123123
// Verify we have exactly 1 buffer written
124-
#expect(writer.writtenBuffers.count == 1)
124+
#expect(await writer.writtenBuffers.count == 1)
125125

126126
// Verify JSON structure
127-
let buffer = writer.writtenBuffers[0]
127+
let buffer = await writer.writtenBuffers[0]
128128
let content = String(buffer: buffer)
129129

130130
// Check expected fields
@@ -149,10 +149,10 @@ struct LambdaResponseStreamWriterHeadersTests {
149149
try await writer.writeStatusAndHeaders(response)
150150

151151
// Verify we have exactly 1 buffer written
152-
#expect(writer.writtenBuffers.count == 1)
152+
#expect(await writer.writtenBuffers.count == 1)
153153

154154
// Verify JSON structure
155-
let buffer = writer.writtenBuffers[0]
155+
let buffer = await writer.writtenBuffers[0]
156156
let content = String(buffer: buffer)
157157

158158
// Check expected fields
@@ -179,10 +179,10 @@ struct LambdaResponseStreamWriterHeadersTests {
179179
try await writer.writeStatusAndHeaders(response)
180180

181181
// Verify we have exactly 1 buffer written
182-
#expect(writer.writtenBuffers.count == 1)
182+
#expect(await writer.writtenBuffers.count == 1)
183183

184184
// Extract JSON part from the buffer
185-
let buffer = writer.writtenBuffers[0]
185+
let buffer = await writer.writtenBuffers[0]
186186
let content = String(buffer: buffer)
187187

188188
// Find the JSON part (everything before any null bytes)
@@ -213,10 +213,10 @@ struct LambdaResponseStreamWriterHeadersTests {
213213
try await writer.writeStatusAndHeaders(response)
214214

215215
// Verify we have exactly 1 buffer written
216-
#expect(writer.writtenBuffers.count == 1)
216+
#expect(await writer.writtenBuffers.count == 1)
217217

218218
// Get the buffer content
219-
let buffer = writer.writtenBuffers[0]
219+
let buffer = await writer.writtenBuffers[0]
220220
let content = String(buffer: buffer)
221221

222222
// Verify it contains JSON
@@ -240,7 +240,7 @@ struct LambdaResponseStreamWriterHeadersTests {
240240
}
241241

242242
// Verify no data was written when encoding fails
243-
#expect(writer.writtenBuffers.isEmpty)
243+
#expect(await writer.writtenBuffers.isEmpty)
244244
}
245245

246246
@Test("Write method error propagation")
@@ -255,7 +255,7 @@ struct LambdaResponseStreamWriterHeadersTests {
255255
}
256256

257257
// Verify the writer attempted to write once
258-
#expect(writer.writeCallCount == 1)
258+
#expect(await writer.writeCallCount == 1)
259259
}
260260

261261
// This test is no longer needed since we only have one write operation now
@@ -298,7 +298,7 @@ struct LambdaResponseStreamWriterHeadersTests {
298298
}
299299

300300
// Verify no data was written when encoding fails
301-
#expect(writer.writtenBuffers.isEmpty)
301+
#expect(await writer.writtenBuffers.isEmpty)
302302
}
303303

304304
// MARK: - Integration Tests
@@ -329,21 +329,21 @@ struct LambdaResponseStreamWriterHeadersTests {
329329
try await writer.writeAndFinish(moreBuffer)
330330

331331
// Verify the sequence: headers + body + more body
332-
#expect(writer.writtenBuffers.count == 3)
333-
#expect(writer.isFinished == true)
332+
#expect(await writer.writtenBuffers.count == 3)
333+
#expect(await writer.isFinished == true)
334334

335335
// Verify headers content
336-
let headersBuffer = writer.writtenBuffers[0]
336+
let headersBuffer = await writer.writtenBuffers[0]
337337
let headersContent = String(buffer: headersBuffer)
338338
#expect(headersContent.contains("\"statusCode\":200"))
339339
#expect(headersContent.contains("\"Content-Type\":\"text/plain\""))
340340

341341
// Verify body content
342-
let firstBodyBuffer = writer.writtenBuffers[1]
342+
let firstBodyBuffer = await writer.writtenBuffers[1]
343343
let firstBodyString = String(buffer: firstBodyBuffer)
344344
#expect(firstBodyString == "Hello, World!")
345345

346-
let secondBodyBuffer = writer.writtenBuffers[2]
346+
let secondBodyBuffer = await writer.writtenBuffers[2]
347347
let secondBodyString = String(buffer: secondBodyBuffer)
348348
#expect(secondBodyString == " Additional content.")
349349
}
@@ -368,16 +368,16 @@ struct LambdaResponseStreamWriterHeadersTests {
368368
try await writer.writeStatusAndHeaders(secondResponse)
369369

370370
// Verify both header writes were successful
371-
#expect(writer.writtenBuffers.count == 2) // One buffer per header write
371+
#expect(await writer.writtenBuffers.count == 2) // One buffer per header write
372372

373373
// Verify first header write
374-
let firstBuffer = writer.writtenBuffers[0]
374+
let firstBuffer = await writer.writtenBuffers[0]
375375
let firstContent = String(buffer: firstBuffer)
376376
#expect(firstContent.contains("\"statusCode\":200"))
377377
#expect(firstContent.contains("\"Content-Type\":\"application/json\""))
378378

379379
// Verify second header write
380-
let secondBuffer = writer.writtenBuffers[1]
380+
let secondBuffer = await writer.writtenBuffers[1]
381381
let secondContent = String(buffer: secondBuffer)
382382
#expect(secondContent.contains("\"statusCode\":201"))
383383
#expect(secondContent.contains("\"Location\":\"https://example.com/resource/123\""))
@@ -417,16 +417,16 @@ struct LambdaResponseStreamWriterHeadersTests {
417417
}
418418

419419
// Verify the complete sequence
420-
#expect(writer.writtenBuffers.count == 5) // 1 header + 4 body chunks
421-
#expect(writer.isFinished == true)
420+
#expect(await writer.writtenBuffers.count == 5) // 1 header + 4 body chunks
421+
#expect(await writer.isFinished == true)
422422

423423
// Verify headers were written correctly
424-
let jsonBuffer = writer.writtenBuffers[0]
424+
let jsonBuffer = await writer.writtenBuffers[0]
425425
let jsonString = String(buffer: jsonBuffer)
426426
#expect(jsonString.contains("\"statusCode\":200"))
427427

428428
// Verify body chunks
429-
let bodyChunks = writer.writtenBuffers[1...4].map { String(buffer: $0) }
429+
let bodyChunks = await writer.writtenBuffers[1...4].map { String(buffer: $0) }
430430
let completeBody = bodyChunks.joined()
431431
let expectedBody = #"{"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}"#
432432
#expect(completeBody == expectedBody)
@@ -440,20 +440,20 @@ struct LambdaResponseStreamWriterHeadersTests {
440440
let response = StreamingLambdaStatusAndHeadersResponse(statusCode: 200)
441441

442442
try await basicWriter.writeStatusAndHeaders(response)
443-
#expect(basicWriter.writtenBuffers.count == 1)
443+
#expect(await basicWriter.writtenBuffers.count == 1)
444444

445445
// Test with a writer that tracks additional state
446446
let trackingWriter = TrackingLambdaResponseStreamWriter()
447447
try await trackingWriter.writeStatusAndHeaders(response)
448-
#expect(trackingWriter.writtenBuffers.count == 1)
449-
#expect(trackingWriter.writeCallCount == 1) // Single write operation
450-
#expect(trackingWriter.finishCallCount == 0)
448+
#expect(await trackingWriter.writtenBuffers.count == 1)
449+
#expect(await trackingWriter.writeCallCount == 1) // Single write operation
450+
#expect(await trackingWriter.finishCallCount == 0)
451451

452452
// Test with a writer that has custom behavior
453453
let customWriter = CustomBehaviorLambdaResponseStreamWriter()
454454
try await customWriter.writeStatusAndHeaders(response)
455-
#expect(customWriter.writtenBuffers.count == 1)
456-
#expect(customWriter.customBehaviorTriggered == true)
455+
#expect(await customWriter.writtenBuffers.count == 1)
456+
#expect(await customWriter.customBehaviorTriggered == true)
457457
}
458458

459459
@Test("Integration: complex scenario with headers, streaming, and finish")
@@ -495,12 +495,12 @@ struct LambdaResponseStreamWriterHeadersTests {
495495

496496
// Verify the complete sequence
497497
// 2 header writes + 3 events + 1 final event = 6 buffers
498-
#expect(writer.writtenBuffers.count == 6)
499-
#expect(writer.isFinished == true)
498+
#expect(await writer.writtenBuffers.count == 6)
499+
#expect(await writer.isFinished == true)
500500

501501
// Verify events (we know the first two buffers are headers)
502502
let eventBuffers = [
503-
writer.writtenBuffers[2], writer.writtenBuffers[3], writer.writtenBuffers[4], writer.writtenBuffers[5],
503+
await writer.writtenBuffers[2], await writer.writtenBuffers[3], await writer.writtenBuffers[4], await writer.writtenBuffers[5],
504504
]
505505
let eventStrings = eventBuffers.map { String(buffer: $0) }
506506
#expect(eventStrings[0] == "data: Event 1\n\n")
@@ -522,22 +522,22 @@ struct LambdaResponseStreamWriterHeadersTests {
522522

523523
// This should compile and work without issues
524524
try await testWithGenericWriter(writer)
525-
#expect(writer.writtenBuffers.count == 1)
525+
#expect(await writer.writtenBuffers.count == 1)
526526

527527
// Verify it works with protocol existential
528528
let protocolWriter: any LambdaResponseStreamWriter = MockLambdaResponseStreamWriter()
529529
try await protocolWriter.writeStatusAndHeaders(response)
530530

531531
if let mockWriter = protocolWriter as? MockLambdaResponseStreamWriter {
532-
#expect(mockWriter.writtenBuffers.count == 1)
532+
#expect(await mockWriter.writtenBuffers.count == 1)
533533
}
534534
}
535535
}
536536

537537
// MARK: - Mock Implementation
538538

539539
/// Mock implementation of LambdaResponseStreamWriter for testing
540-
final class MockLambdaResponseStreamWriter: LambdaResponseStreamWriter {
540+
final actor MockLambdaResponseStreamWriter: LambdaResponseStreamWriter {
541541
private(set) var writtenBuffers: [ByteBuffer] = []
542542
private(set) var isFinished = false
543543
private(set) var hasCustomHeaders = false
@@ -576,7 +576,7 @@ final class MockLambdaResponseStreamWriter: LambdaResponseStreamWriter {
576576
// MARK: - Error Handling Mock Implementations
577577

578578
/// Mock implementation that fails on specific write calls for testing error propagation
579-
final class FailingMockLambdaResponseStreamWriter: LambdaResponseStreamWriter {
579+
final actor FailingMockLambdaResponseStreamWriter: LambdaResponseStreamWriter {
580580
private(set) var writtenBuffers: [ByteBuffer] = []
581581
private(set) var writeCallCount = 0
582582
private(set) var isFinished = false
@@ -690,7 +690,7 @@ struct FailingJSONEncoder: LambdaOutputEncoder {
690690
// MARK: - Additional Mock Implementations for Integration Tests
691691

692692
/// Mock implementation that tracks additional state for integration testing
693-
final class TrackingLambdaResponseStreamWriter: LambdaResponseStreamWriter {
693+
final actor TrackingLambdaResponseStreamWriter: LambdaResponseStreamWriter {
694694
private(set) var writtenBuffers: [ByteBuffer] = []
695695
private(set) var writeCallCount = 0
696696
private(set) var finishCallCount = 0
@@ -727,7 +727,7 @@ final class TrackingLambdaResponseStreamWriter: LambdaResponseStreamWriter {
727727
}
728728

729729
/// Mock implementation with custom behavior for integration testing
730-
final class CustomBehaviorLambdaResponseStreamWriter: LambdaResponseStreamWriter {
730+
final actor CustomBehaviorLambdaResponseStreamWriter: LambdaResponseStreamWriter {
731731
private(set) var writtenBuffers: [ByteBuffer] = []
732732
private(set) var customBehaviorTriggered = false
733733
private(set) var isFinished = false

0 commit comments

Comments
 (0)