diff --git a/Tests/HTTPServerTests/HTTPRequestConcludingAsyncReaderTests.swift b/Tests/HTTPServerTests/HTTPRequestConcludingAsyncReaderTests.swift index 3bf8bc6..9149dbb 100644 --- a/Tests/HTTPServerTests/HTTPRequestConcludingAsyncReaderTests.swift +++ b/Tests/HTTPServerTests/HTTPRequestConcludingAsyncReaderTests.swift @@ -1,3 +1,4 @@ +import AsyncStreaming @testable import HTTPServer import HTTPTypes import NIOCore @@ -26,7 +27,7 @@ struct HTTPRequestConcludingAsyncReaderTests { _ = try await requestReader.consumeAndConclude { bodyReader in var bodyReader = bodyReader - try await bodyReader.read { element in () } + try await bodyReader.read(maximumCount: nil) { element in () } } } } @@ -54,20 +55,16 @@ struct HTTPRequestConcludingAsyncReaderTests { var bodyReader = bodyReader var buffer = ByteBuffer() - // Read just once: we only sent one body chunk - try await bodyReader.read { element in - if let element { - buffer.writeBytes(element.bytes) - } else { - Issue.record("Unexpectedly failed to read the client's request body") - } + // Read the body chunk + try await bodyReader.read(maximumCount: nil) { element in + buffer.writeBytes(element.bytes) + return } - // Attempting to read again should result in a `nil` element (we only sent one body chunk) - try await bodyReader.read { element in - if element != nil { - Issue.record("Received a non-nil value after the request body was completely read") - } + // Now read the trailer. We should get back an empty element here, but the trailer should be available in + // the tuple returned by `consumeAndConclude` + try await bodyReader.read(maximumCount: nil) { element in + #expect(element.count == 0) } return buffer @@ -80,7 +77,6 @@ struct HTTPRequestConcludingAsyncReaderTests { @Test( "Streamed request with concluding element", arguments: [ - (0..<10).map { i in ByteBuffer() }, // 10 empty ByteBuffers (0..<100).map { i in ByteBuffer(bytes: [i]) } // 100 single-byte ByteBuffers ], [ @@ -107,25 +103,15 @@ struct HTTPRequestConcludingAsyncReaderTests { iterator: stream.makeAsyncIterator(), readerState: .init() ) - let finalElement = try await requestReader.consumeAndConclude { bodyReader in - var bodyReader = bodyReader - - for chunk in bodyChunks { - try await bodyReader.read { element in - if let element { - var buffer = ByteBuffer() - buffer.writeBytes(element.bytes) - #expect(chunk == buffer) - } else { - Issue.record("Received a nil element before the request body was completely read") - } - } - } - - try await bodyReader.read { element in - if element != nil { - Issue.record("Received a non-nil element after the request body was completely read") - } + let (_, finalElement) = try await requestReader.consumeAndConclude { bodyReader in + // Read all body chunks + var chunksProcessed = 0 + try await bodyReader.forEach { element in + var buffer = ByteBuffer() + buffer.writeBytes(element.bytes) + #expect(bodyChunks[chunksProcessed] == buffer) + + chunksProcessed += 1 } } @@ -146,18 +132,22 @@ struct HTTPRequestConcludingAsyncReaderTests { source.yield(.end([.cookie: "test"])) source.finish() - // Check that the read error is propagated - try await #require(throws: TestError.errorWhileReading) { - let requestReader = HTTPRequestConcludingAsyncReader( - iterator: stream.makeAsyncIterator(), - readerState: .init() - ) + let requestReader = HTTPRequestConcludingAsyncReader( + iterator: stream.makeAsyncIterator(), + readerState: .init() + ) - _ = try await requestReader.consumeAndConclude { bodyReader in - var bodyReader = bodyReader + _ = await requestReader.consumeAndConclude { bodyReader in + var bodyReader = bodyReader - try await bodyReader.read { element in - throw TestError.errorWhileReading + // Check that the read error is propagated + await #expect(throws: TestError.errorWhileReading) { + do { + try await bodyReader.read(maximumCount: nil) { (element) throws(TestError) in + throw TestError.errorWhileReading + } + } catch let eitherError as EitherError { + try eitherError.unwrap() } } } @@ -166,19 +156,19 @@ struct HTTPRequestConcludingAsyncReaderTests { @available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *) @Test("More bytes available than consumption limit") func testCollectMoreBytesThanAvailable() async throws { - let (stream, source) = NIOAsyncChannelInboundStream.makeTestingStream() + await #expect(processExitsWith: .failure) { + let (stream, source) = NIOAsyncChannelInboundStream.makeTestingStream() - // Write 10 bytes - source.yield(.body(.init(repeating: 5, count: 10))) - source.finish() + // Write 10 bytes + source.yield(.body(.init(repeating: 5, count: 10))) + source.finish() - let requestReader = HTTPRequestConcludingAsyncReader(iterator: stream.makeAsyncIterator(), readerState: .init()) + let requestReader = HTTPRequestConcludingAsyncReader(iterator: stream.makeAsyncIterator(), readerState: .init()) - _ = try await requestReader.consumeAndConclude { requestBodyReader in - var requestBodyReader = requestBodyReader + _ = try await requestReader.consumeAndConclude { requestBodyReader in + var requestBodyReader = requestBodyReader - // Attempting to collect a maximum of 9 bytes should result in a LimitExceeded error. - await #expect(throws: LimitExceeded.self) { + // Since there are more bytes than requested, this should fail. try await requestBodyReader.collect(upTo: 9) { element in () } diff --git a/Tests/HTTPServerTests/HTTPResponseConcludingAsyncWriterTests.swift b/Tests/HTTPServerTests/HTTPResponseConcludingAsyncWriterTests.swift index a0586a2..b7c1295 100644 --- a/Tests/HTTPServerTests/HTTPResponseConcludingAsyncWriterTests.swift +++ b/Tests/HTTPServerTests/HTTPResponseConcludingAsyncWriterTests.swift @@ -6,8 +6,9 @@ import Testing @Suite struct HTTPResponseConcludingAsyncWriterTests { - let bodySampleOne: [UInt8] = [1, 2] - let bodySampleTwo: [UInt8] = [3, 4] + let bodySampleOne: UInt8 = 1 + let bodySampleTwo: UInt8 = 2 + let trailerSampleOne: HTTPFields = [.serverTiming: "test"] let trailerSampleTwo: HTTPFields = [.serverTiming: "test", .cookie: "cookie"] @@ -17,13 +18,14 @@ struct HTTPResponseConcludingAsyncWriterTests { let (writer, sink) = NIOAsyncChannelOutboundWriter.makeTestingWriter() let responseWriter = HTTPResponseConcludingAsyncWriter(writer: writer, writerState: .init()) - try await responseWriter.writeAndConclude(element: self.bodySampleOne.span, finalElement: self.trailerSampleOne) + try await responseWriter.writeAndConclude(self.bodySampleOne, finalElement: self.trailerSampleOne) // Now read the response var responseIterator = sink.makeAsyncIterator() let element = try #require(await responseIterator.next()) - #expect(element == .body(.init(bytes: self.bodySampleOne))) + #expect(element == .body(.init(bytes: [self.bodySampleOne]))) + let trailer = try #require(await responseIterator.next()) #expect(trailer == .end(self.trailerSampleOne)) } @@ -38,8 +40,8 @@ struct HTTPResponseConcludingAsyncWriterTests { var bodyWriter = bodyWriter // Write multiple elements - try await bodyWriter.write(self.bodySampleOne.span) - try await bodyWriter.write(self.bodySampleTwo.span) + try await bodyWriter.write(self.bodySampleOne) + try await bodyWriter.write(self.bodySampleTwo) return self.trailerSampleOne } @@ -48,8 +50,8 @@ struct HTTPResponseConcludingAsyncWriterTests { let firstElement = try #require(await responseIterator.next()) let secondElement = try #require(await responseIterator.next()) - #expect(firstElement == .body(.init(bytes: self.bodySampleOne))) - #expect(secondElement == .body(.init(bytes: self.bodySampleTwo))) + #expect(firstElement == .body(.init(bytes: [self.bodySampleOne]))) + #expect(secondElement == .body(.init(bytes: [self.bodySampleTwo]))) let trailer = try #require(await responseIterator.next()) #expect(trailer == .end(self.trailerSampleOne)) @@ -67,7 +69,7 @@ struct HTTPResponseConcludingAsyncWriterTests { var bodyWriter = bodyWriter // Write an element - try await bodyWriter.write(self.bodySampleOne.span) + try await bodyWriter.write(self.bodySampleOne) // Then throw throw TestError.errorWhileWriting } @@ -76,7 +78,7 @@ struct HTTPResponseConcludingAsyncWriterTests { var responseIterator = sink.makeAsyncIterator() let firstElement = try #require(await responseIterator.next()) - #expect(firstElement == .body(.init(bytes: self.bodySampleOne))) + #expect(firstElement == .body(.init(bytes: [self.bodySampleOne]))) } @Test("Write multiple elements and multiple trailers") @@ -89,8 +91,8 @@ struct HTTPResponseConcludingAsyncWriterTests { var bodyWriter = bodyWriter // Write multiple elements - try await bodyWriter.write(self.bodySampleOne.span) - try await bodyWriter.write(self.bodySampleTwo.span) + try await bodyWriter.write(self.bodySampleOne) + try await bodyWriter.write(self.bodySampleTwo) return self.trailerSampleTwo } @@ -99,8 +101,8 @@ struct HTTPResponseConcludingAsyncWriterTests { let firstElement = try #require(await responseIterator.next()) let secondElement = try #require(await responseIterator.next()) - #expect(firstElement == .body(.init(bytes: self.bodySampleOne))) - #expect(secondElement == .body(.init(bytes: self.bodySampleTwo))) + #expect(firstElement == .body(.init(bytes: [self.bodySampleOne]))) + #expect(secondElement == .body(.init(bytes: [self.bodySampleTwo]))) let trailer = try #require(await responseIterator.next()) #expect(trailer == .end(self.trailerSampleTwo)) diff --git a/Tests/HTTPServerTests/NIOHTTPServerTests.swift b/Tests/HTTPServerTests/NIOHTTPServerTests.swift index 683e0f8..f036997 100644 --- a/Tests/HTTPServerTests/NIOHTTPServerTests.swift +++ b/Tests/HTTPServerTests/NIOHTTPServerTests.swift @@ -91,7 +91,7 @@ struct NIOHTTPServerTests { #expect(request.path == "/") var buffer = ByteBuffer() - let finalElement = try await reader.consumeAndConclude { bodyReader in + let (_, finalElement) = try await reader.consumeAndConclude { bodyReader in var bodyReader = bodyReader return try await bodyReader.collect(upTo: Self.bodyData.readableBytes + 1) { body in buffer.writeBytes(body.bytes)