Skip to content

Commit 393ada5

Browse files
committed
Fix potentially flaky HTTPClientTests.testNoBytesSentOverBodyLimit
1 parent 0c36de2 commit 393ada5

File tree

1 file changed

+41
-18
lines changed

1 file changed

+41
-18
lines changed

Diff for: Tests/AsyncHTTPClientTests/HTTPClientTests.swift

+41-18
Original file line numberDiff line numberDiff line change
@@ -968,11 +968,8 @@ class HTTPClientTests: XCTestCase {
968968
request.body = .byteBuffer(ByteBuffer(bytes: [120, 156, 75, 76, 28, 5, 200, 0, 0, 248, 66, 103, 17]))
969969
request.headers.add(name: "Accept-Encoding", value: "deflate")
970970

971-
XCTAssertThrowsError(try localClient.execute(request: request).wait()) { error in
972-
guard case .some(.limit) = error as? NIOHTTPDecompression.DecompressionError else {
973-
XCTFail("wrong error: \(error)")
974-
return
975-
}
971+
XCTAssertThrowsError(try localClient.execute(request: request).wait()) {
972+
XCTAssertEqual($0 as? NIOHTTPDecompression.DecompressionError, .limit)
976973
}
977974
}
978975

@@ -2644,19 +2641,45 @@ class HTTPClientTests: XCTestCase {
26442641
}
26452642

26462643
let tooLong = "XBAD BAD BAD NOT HTTP/1.1\r\n\r\n"
2647-
let future = self.defaultClient.execute(
2648-
request: try Request(url: "http://localhost:\(server.serverPort)",
2649-
body: .stream(length: 1) { streamWriter in
2650-
streamWriter.write(.byteBuffer(ByteBuffer(string: tooLong)))
2651-
}))
2652-
2653-
XCTAssertNoThrow(try server.readInbound()) // .head
2654-
// this should fail if client detects that we are about to send more bytes than body limit and closes the connection
2655-
// We can test that this test actually fails if we remove limit check in `writeBodyPart` - it will send bytes, meaning that the next
2656-
// call will not throw, but the future will still throw body mismatch error
2657-
XCTAssertThrowsError(try server.readInbound()) { error in XCTAssertEqual(error as? HTTPParserError, HTTPParserError.invalidEOFState) }
2658-
2659-
XCTAssertThrowsError(try future.wait())
2644+
2645+
let request = try Request(
2646+
url: "http://localhost:\(server.serverPort)",
2647+
body: .stream(length: 1) { streamWriter in
2648+
streamWriter.write(.byteBuffer(ByteBuffer(string: tooLong)))
2649+
}
2650+
)
2651+
2652+
let future = self.defaultClient.execute(request: request)
2653+
2654+
// Okay, what happens here needs an explanation:
2655+
//
2656+
// In the request state machine, we should start the request, which will lead to an
2657+
// invocation of `context.write(HTTPRequestHead)`. Since we will receive a streamed request
2658+
// body a `context.flush()` will be issued. Further the request stream will be started.
2659+
// Since the request stream immediately produces to much data, the request will be failed
2660+
// and the connection will be closed.
2661+
//
2662+
// Even though a flush was issued after the request head, there is no guarantee that the
2663+
// request head was written to the network. For this reason we must accept not receiving a
2664+
// request and receiving a request head.
2665+
2666+
do {
2667+
_ = try server.receiveHead()
2668+
2669+
// A request head was sent. We expect the request now to fail with a parsing error,
2670+
// since the client ended the connection to early (from the server's point of view.)
2671+
XCTAssertThrowsError(try server.readInbound()) {
2672+
XCTAssertEqual($0 as? HTTPParserError, HTTPParserError.invalidEOFState)
2673+
}
2674+
} catch {
2675+
// TBD: We sadly can't verify the error type, since it is private in `NIOTestUtils`:
2676+
// NIOTestUtils.BlockingQueue<Element>.TimeoutError
2677+
}
2678+
2679+
// request must always be failed with this error
2680+
XCTAssertThrowsError(try future.wait()) {
2681+
XCTAssertEqual($0 as? HTTPClientError, .bodyLengthMismatch)
2682+
}
26602683
}
26612684

26622685
func testDoubleError() throws {

0 commit comments

Comments
 (0)