Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: check that body stream gets finalised when client disappears #2779

Merged
merged 3 commits into from
Mar 10, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 58 additions & 0 deletions Tests/VaporTests/ServerTests.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Vapor
import XCTest
import protocol AsyncHTTPClient.HTTPClientResponseDelegate
import NIO
import NIOHTTP1

final class ServerTests: XCTestCase {
func testPortOverride() throws {
Expand Down Expand Up @@ -688,6 +690,62 @@ final class ServerTests: XCTestCase {
XCTAssertEqual(a.headers.connection, .keepAlive)
}

func testRequestBodyStreamGetsFinalisedEvenIfClientDisappears() {
let app = Application(.testing)
app.http.server.configuration.hostname = "127.0.0.1"
app.http.server.configuration.port = 0
defer { app.shutdown() }

let serverIsFinalisedPromise = app.eventLoopGroup.any().makePromise(of: Void.self)
let allDonePromise = app.eventLoopGroup.any().makePromise(of: Void.self)

app.on(.POST, "hello", body: .stream) { req -> Response in
return Response(body: .init(stream: { writer in
req.body.drain { stream in
switch stream {
case .buffer:
()
case .end:
serverIsFinalisedPromise.succeed(())
writer.write(.end, promise: nil)
case .error(let error):
serverIsFinalisedPromise.fail(error)
writer.write(.error(error), promise: nil)
}
return allDonePromise.futureResult
}
}))
}

app.environment.arguments = ["serve"]
XCTAssertNoThrow(try app.start())

XCTAssertNotNil(app.http.server.shared.localAddress)
guard let localAddress = app.http.server.shared.localAddress,
let ip = localAddress.ipAddress,
let port = localAddress.port else {
XCTFail("couldn't get ip/port from \(app.http.server.shared.localAddress.debugDescription)")
return
}

let tenMB = ByteBuffer(repeating: 0x41, count: 10 * 1024 * 1024)
XCTAssertThrowsError(try app.http.client.shared.execute(.POST,
url: "http://\(ip):\(port)/hello",
body: .byteBuffer(tenMB),
deadline: .now() + .milliseconds(100)).wait()) { error in
if let error = error as? HTTPClientError {
XCTAssert(error == .readTimeout || error == .deadlineExceeded)
} else {
XCTFail("unexpected error: \(error)")
}
}

allDonePromise.succeed(()) // This unblocks the server
XCTAssertThrowsError(try serverIsFinalisedPromise.futureResult.wait()) { error in
XCTAssertEqual(HTTPParserError.invalidEOFState, error as? HTTPParserError)
}
}

override class func setUp() {
XCTAssertTrue(isLoggingConfigured)
}
Expand Down