Skip to content

Replace tests that depend on TaskHandler #444

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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Tests/AsyncHTTPClientTests/HTTP1ConnectionTests+XCTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ extension HTTP1ConnectionTests {
("testConnectionClosesAfterTheRequestWithoutHavingSentAnCloseHeader", testConnectionClosesAfterTheRequestWithoutHavingSentAnCloseHeader),
("testConnectionIsClosedAfterSwitchingProtocols", testConnectionIsClosedAfterSwitchingProtocols),
("testConnectionDoesntCrashAfterConnectionCloseAndEarlyHints", testConnectionDoesntCrashAfterConnectionCloseAndEarlyHints),
("testConnectionIsClosedIfResponseIsReceivedBeforeRequest", testConnectionIsClosedIfResponseIsReceivedBeforeRequest),
("testDoubleHTTPResponseLine", testDoubleHTTPResponseLine),
("testDownloadStreamingBackpressure", testDownloadStreamingBackpressure),
]
}
Expand Down
87 changes: 87 additions & 0 deletions Tests/AsyncHTTPClientTests/HTTP1ConnectionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,93 @@ class HTTP1ConnectionTests: XCTestCase {
}
}

func testConnectionIsClosedIfResponseIsReceivedBeforeRequest() {
let embedded = EmbeddedChannel()
let logger = Logger(label: "test.http1.connection")

XCTAssertNoThrow(try embedded.connect(to: SocketAddress(ipAddress: "127.0.0.1", port: 0)).wait())

let connectionDelegate = MockConnectionDelegate()
XCTAssertNoThrow(try HTTP1Connection.start(
channel: embedded,
connectionID: 0,
delegate: connectionDelegate,
configuration: .init(decompression: .enabled(limit: .ratio(4))),
logger: logger
))

let responseString = """
HTTP/1.1 200 OK\r\n\
date: Mon, 27 Sep 2021 17:53:14 GMT\r\n\
\r\n\
\r\n
"""

XCTAssertEqual(connectionDelegate.hitConnectionClosed, 0)
XCTAssertEqual(connectionDelegate.hitConnectionReleased, 0)

XCTAssertThrowsError(try embedded.writeInbound(ByteBuffer(string: responseString))) {
XCTAssertEqual($0 as? NIOHTTPDecoderError, .unsolicitedResponse)
}
XCTAssertFalse(embedded.isActive)
(embedded.eventLoop as! EmbeddedEventLoop).run() // tick once to run futures.
XCTAssertEqual(connectionDelegate.hitConnectionClosed, 1)
XCTAssertEqual(connectionDelegate.hitConnectionReleased, 0)
}

func testDoubleHTTPResponseLine() {
let embedded = EmbeddedChannel()
let logger = Logger(label: "test.http1.connection")

XCTAssertNoThrow(try embedded.connect(to: SocketAddress(ipAddress: "127.0.0.1", port: 0)).wait())

var maybeConnection: HTTP1Connection?
let connectionDelegate = MockConnectionDelegate()
XCTAssertNoThrow(maybeConnection = try HTTP1Connection.start(
channel: embedded,
connectionID: 0,
delegate: connectionDelegate,
configuration: .init(decompression: .enabled(limit: .ratio(4))),
logger: logger
))
guard let connection = maybeConnection else { return XCTFail("Expected to have a connection at this point.") }

var maybeRequest: HTTPClient.Request?
XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://swift.org/"))
guard let request = maybeRequest else { return XCTFail("Expected to be able to create a request") }

let delegate = ResponseAccumulator(request: request)
var maybeRequestBag: RequestBag<ResponseAccumulator>?
XCTAssertNoThrow(maybeRequestBag = try RequestBag(
request: request,
eventLoopPreference: .delegate(on: embedded.eventLoop),
task: .init(eventLoop: embedded.eventLoop, logger: logger),
redirectHandler: nil,
connectionDeadline: .now() + .seconds(30),
requestOptions: .forTests(),
delegate: delegate
))
guard let requestBag = maybeRequestBag else { return XCTFail("Expected to be able to create a request bag") }

connection.executeRequest(requestBag)

let responseString = """
HTTP/1.0 200 OK\r\n\
HTTP/1.0 200 OK\r\n\r\n
"""

XCTAssertNoThrow(try embedded.readOutbound(as: ByteBuffer.self)) // head
XCTAssertNoThrow(try embedded.readOutbound(as: ByteBuffer.self)) // end

XCTAssertEqual(connectionDelegate.hitConnectionClosed, 0)
XCTAssertEqual(connectionDelegate.hitConnectionReleased, 0)
XCTAssertNoThrow(try embedded.writeInbound(ByteBuffer(string: responseString)))
XCTAssertFalse(embedded.isActive)
(embedded.eventLoop as! EmbeddedEventLoop).run() // tick once to run futures.
XCTAssertEqual(connectionDelegate.hitConnectionClosed, 1)
XCTAssertEqual(connectionDelegate.hitConnectionReleased, 0)
}

// In order to test backpressure we need to make sure that reads will not happen
// until the backpressure promise is succeeded. Since we cannot guarantee when
// messages will be delivered to a client pipeline and we need this test to be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ extension HTTPClientInternalTests {
static var allTests: [(String, (HTTPClientInternalTests) -> () throws -> Void)] {
return [
("testHTTPPartsHandler", testHTTPPartsHandler),
("testBadHTTPRequest", testBadHTTPRequest),
("testHostPort", testHostPort),
("testHTTPPartsHandlerMultiBody", testHTTPPartsHandlerMultiBody),
("testHTTPResponseHeadBeforeRequestHead", testHTTPResponseHeadBeforeRequestHead),
("testHTTPResponseDoubleHead", testHTTPResponseDoubleHead),
("testRequestFinishesAfterRedirectIfServerRespondsBeforeClientFinishes", testRequestFinishesAfterRedirectIfServerRespondsBeforeClientFinishes),
("testProxyStreaming", testProxyStreaming),
("testProxyStreamingFailure", testProxyStreamingFailure),
Expand Down
108 changes: 0 additions & 108 deletions Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,65 +75,6 @@ class HTTPClientInternalTests: XCTestCase {
XCTAssertNoThrow(try channel.writeInbound(HTTPClientResponsePart.end(nil)))
}

func testBadHTTPRequest() throws {
let channel = EmbeddedChannel()
let recorder = RecordingHandler<HTTPClientResponsePart, HTTPClientRequestPart>()
let task = Task<Void>(eventLoop: channel.eventLoop, logger: HTTPClient.loggingDisabled)

XCTAssertNoThrow(try channel.pipeline.addHandler(recorder).wait())
XCTAssertNoThrow(try channel.pipeline.addHandler(TaskHandler(task: task,
kind: .host,
delegate: TestHTTPDelegate(),
redirectHandler: nil,
ignoreUncleanSSLShutdown: false,
logger: HTTPClient.loggingDisabled)).wait())

var request = try Request(url: "http://localhost/get")
request.headers.add(name: "X-Test-Header", value: "X-Test-Value")
request.headers.add(name: "Transfer-Encoding", value: "identity")
request.body = .string("1234")

XCTAssertThrowsError(try channel.writeOutbound(request)) { error in
XCTAssertEqual(HTTPClientError.identityCodingIncorrectlyPresent, error as? HTTPClientError)
}
}

func testHostPort() throws {
let channel = EmbeddedChannel()
let recorder = RecordingHandler<HTTPClientResponsePart, HTTPClientRequestPart>()
let task = Task<Void>(eventLoop: channel.eventLoop, logger: HTTPClient.loggingDisabled)

try channel.pipeline.addHandler(recorder).wait()
try channel.pipeline.addHandler(TaskHandler(task: task,
kind: .host,
delegate: TestHTTPDelegate(),
redirectHandler: nil,
ignoreUncleanSSLShutdown: false,
logger: HTTPClient.loggingDisabled)).wait()

let request1 = try Request(url: "http://localhost:80/get")
XCTAssertNoThrow(try channel.writeOutbound(request1))
let request2 = try Request(url: "https://localhost/get")
XCTAssertNoThrow(try channel.writeOutbound(request2))
let request3 = try Request(url: "http://localhost:8080/get")
XCTAssertNoThrow(try channel.writeOutbound(request3))
let request4 = try Request(url: "http://localhost:443/get")
XCTAssertNoThrow(try channel.writeOutbound(request4))
let request5 = try Request(url: "https://localhost:80/get")
XCTAssertNoThrow(try channel.writeOutbound(request5))

let head1 = HTTPRequestHead(version: HTTPVersion(major: 1, minor: 1), method: .GET, uri: "/get", headers: ["host": "localhost"])
XCTAssertEqual(HTTPClientRequestPart.head(head1), recorder.writes[0])
let head2 = HTTPRequestHead(version: HTTPVersion(major: 1, minor: 1), method: .GET, uri: "/get", headers: ["host": "localhost"])
XCTAssertEqual(HTTPClientRequestPart.head(head2), recorder.writes[2])
let head3 = HTTPRequestHead(version: HTTPVersion(major: 1, minor: 1), method: .GET, uri: "/get", headers: ["host": "localhost:8080"])
XCTAssertEqual(HTTPClientRequestPart.head(head3), recorder.writes[4])
let head4 = HTTPRequestHead(version: HTTPVersion(major: 1, minor: 1), method: .GET, uri: "/get", headers: ["host": "localhost:443"])
XCTAssertEqual(HTTPClientRequestPart.head(head4), recorder.writes[6])
let head5 = HTTPRequestHead(version: HTTPVersion(major: 1, minor: 1), method: .GET, uri: "/get", headers: ["host": "localhost:80"])
XCTAssertEqual(HTTPClientRequestPart.head(head5), recorder.writes[8])
}

func testHTTPPartsHandlerMultiBody() throws {
let channel = EmbeddedChannel()
let delegate = TestHTTPDelegate()
Expand Down Expand Up @@ -163,55 +104,6 @@ class HTTPClientInternalTests: XCTestCase {
}
}

func testHTTPResponseHeadBeforeRequestHead() throws {
let channel = EmbeddedChannel()
XCTAssertNoThrow(try channel.connect(to: try SocketAddress(unixDomainSocketPath: "/fake")).wait())

let delegate = TestHTTPDelegate()
let task = Task<Void>(eventLoop: channel.eventLoop, logger: HTTPClient.loggingDisabled)
let handler = TaskHandler(task: task,
kind: .host,
delegate: delegate,
redirectHandler: nil,
ignoreUncleanSSLShutdown: false,
logger: HTTPClient.loggingDisabled)

XCTAssertNoThrow(try channel.pipeline.addHTTPClientHandlers().wait())
XCTAssertNoThrow(try channel.pipeline.addHandler(handler).wait())

XCTAssertNoThrow(try channel.writeInbound(ByteBuffer(string: "HTTP/1.0 200 OK\r\n\r\n")))

XCTAssertThrowsError(try task.futureResult.wait()) { error in
XCTAssertEqual(error as? NIOHTTPDecoderError, NIOHTTPDecoderError.unsolicitedResponse)
}
}

func testHTTPResponseDoubleHead() throws {
let channel = EmbeddedChannel()
XCTAssertNoThrow(try channel.connect(to: try SocketAddress(unixDomainSocketPath: "/fake")).wait())

let delegate = TestHTTPDelegate()
let task = Task<Void>(eventLoop: channel.eventLoop, logger: HTTPClient.loggingDisabled)
let handler = TaskHandler(task: task,
kind: .host,
delegate: delegate,
redirectHandler: nil,
ignoreUncleanSSLShutdown: false,
logger: HTTPClient.loggingDisabled)

XCTAssertNoThrow(try channel.pipeline.addHTTPClientHandlers().wait())
XCTAssertNoThrow(try channel.pipeline.addHandler(handler).wait())

let request = try HTTPClient.Request(url: "http://localhost/get")
XCTAssertNoThrow(try channel.writeOutbound(request))

XCTAssertNoThrow(try channel.writeInbound(ByteBuffer(string: "HTTP/1.0 200 OK\r\nHTTP/1.0 200 OK\r\n\r\n")))

XCTAssertThrowsError(try task.futureResult.wait()) { error in
XCTAssertEqual((error as? HTTPParserError)?.debugDescription, "invalid character in header")
}
}

func testRequestFinishesAfterRedirectIfServerRespondsBeforeClientFinishes() throws {
let channel = EmbeddedChannel()

Expand Down
1 change: 1 addition & 0 deletions Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ extension HTTPClientTests {
("testErrorAfterCloseWhileBackpressureExerted", testErrorAfterCloseWhileBackpressureExerted),
("testRequestSpecificTLS", testRequestSpecificTLS),
("testConnectionPoolSizeConfigValueIsRespected", testConnectionPoolSizeConfigValueIsRespected),
("testRequestWithHeaderTransferEncodingIdentityFails", testRequestWithHeaderTransferEncodingIdentityFails),
]
}
}
19 changes: 19 additions & 0 deletions Tests/AsyncHTTPClientTests/HTTPClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3103,4 +3103,23 @@ class HTTPClientTests: XCTestCase {

XCTAssertEqual(httpBin.createdConnections, poolSize)
}

func testRequestWithHeaderTransferEncodingIdentityFails() {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) }

let client = HTTPClient(eventLoopGroupProvider: .shared(group))
defer { XCTAssertNoThrow(try client.syncShutdown()) }

guard var request = try? Request(url: "http://localhost/get") else {
return XCTFail("Expected to have a request here.")
}
request.headers.add(name: "X-Test-Header", value: "X-Test-Value")
request.headers.add(name: "Transfer-Encoding", value: "identity")
request.body = .string("1234")

XCTAssertThrowsError(try client.execute(request: request).wait()) {
XCTAssertEqual($0 as? HTTPClientError, .identityCodingIncorrectlyPresent)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ extension RequestValidationTests {
("testTransferEncodingHeaderHasBody", testTransferEncodingHeaderHasBody),
("testBothHeadersNoBody", testBothHeadersNoBody),
("testBothHeadersHasBody", testBothHeadersHasBody),
("testHostHeaderIsSetCorrectlyInCreateRequestHead", testHostHeaderIsSetCorrectlyInCreateRequestHead),
]
}
}
20 changes: 20 additions & 0 deletions Tests/AsyncHTTPClientTests/RequestValidationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,24 @@ class RequestValidationTests: XCTestCase {
XCTAssertThrowsError(try headers.validate(method: method, body: .byteBuffer(ByteBuffer(bytes: [0]))))
}
}

func testHostHeaderIsSetCorrectlyInCreateRequestHead() {
let req1 = try! HTTPClient.Request(url: "http://localhost:80/get")
XCTAssertEqual(try req1.createRequestHead().0.headers["host"].first, "localhost")

let req2 = try! HTTPClient.Request(url: "https://localhost/get")
XCTAssertEqual(try req2.createRequestHead().0.headers["host"].first, "localhost")

let req3 = try! HTTPClient.Request(url: "http://localhost:8080/get")
XCTAssertEqual(try req3.createRequestHead().0.headers["host"].first, "localhost:8080")

let req4 = try! HTTPClient.Request(url: "http://localhost:443/get")
XCTAssertEqual(try req4.createRequestHead().0.headers["host"].first, "localhost:443")

let req5 = try! HTTPClient.Request(url: "https://localhost:80/get")
XCTAssertEqual(try req5.createRequestHead().0.headers["host"].first, "localhost:80")

let req6 = try! HTTPClient.Request(url: "https://localhost/get", headers: ["host": "foo"])
XCTAssertEqual(try req6.createRequestHead().0.headers["host"].first, "foo")
}
}