Skip to content

Commit c70e085

Browse files
authored
testPlatformConnectErrorIsForwardedOnTimeout port reuse (#716)
Motivation: The above test has been seen to fail with port already in use. The test assumes that a port can be bound to twice in a row. It's possible that another process takes the port between the two binds - this can be stopped by binding a second time before stopping the first. Modifications: Allow port reuse and reorder the test to bind a second time before releasing the first. Result: Test should no longer be flaky.
1 parent 4824907 commit c70e085

File tree

2 files changed

+11
-6
lines changed

2 files changed

+11
-6
lines changed

Tests/AsyncHTTPClientTests/HTTP2ClientTests.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ class HTTP2ClientTests: XCTestCase {
376376
}
377377

378378
func testPlatformConnectErrorIsForwardedOnTimeout() {
379-
let bin = HTTPBin(.http2(compress: false))
379+
let bin = HTTPBin(.http2(compress: false), reusePort: true)
380380
let clientGroup = MultiThreadedEventLoopGroup(numberOfThreads: 2)
381381
let el1 = clientGroup.next()
382382
let el2 = clientGroup.next()
@@ -404,20 +404,22 @@ class HTTP2ClientTests: XCTestCase {
404404
XCTAssertEqual(.ok, response1?.status)
405405
XCTAssertEqual(response1?.version, .http2)
406406
let serverPort = bin.port
407-
XCTAssertNoThrow(try bin.shutdown())
408-
// client is now in HTTP/2 state and the HTTPBin is closed
409-
// start a new server on the old port which closes all connections immediately
407+
410408
let serverGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
411409
defer { XCTAssertNoThrow(try serverGroup.syncShutdownGracefully()) }
412410
var maybeServer: Channel?
413411
XCTAssertNoThrow(maybeServer = try ServerBootstrap(group: serverGroup)
414412
.serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
413+
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEPORT), value: 1)
415414
.childChannelInitializer { channel in
416415
channel.close()
417416
}
418417
.childChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
419418
.bind(host: "127.0.0.1", port: serverPort)
420419
.wait())
420+
// shutting down the old server closes all connections immediately
421+
XCTAssertNoThrow(try bin.shutdown())
422+
// client is now in HTTP/2 state and the HTTPBin is closed
421423
guard let server = maybeServer else { return }
422424
defer { XCTAssertNoThrow(try server.close().wait()) }
423425

Tests/AsyncHTTPClientTests/HTTPClientTestUtils.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ internal final class HTTPBin<RequestHandler: ChannelInboundHandler> where
438438
_ mode: Mode = .http1_1(ssl: false, compress: false),
439439
proxy: Proxy = .none,
440440
bindTarget: BindTarget = .localhostIPv4RandomPort,
441+
reusePort: Bool = false,
441442
handlerFactory: @escaping (Int) -> (RequestHandler)
442443
) {
443444
self.mode = mode
@@ -460,6 +461,7 @@ internal final class HTTPBin<RequestHandler: ChannelInboundHandler> where
460461

461462
self.serverChannel = try! ServerBootstrap(group: self.group)
462463
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
464+
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEPORT), value: reusePort ? 1 : 0)
463465
.serverChannelInitializer { channel in
464466
channel.pipeline.addHandler(self.activeConnCounterHandler)
465467
}.childChannelInitializer { channel in
@@ -642,9 +644,10 @@ extension HTTPBin where RequestHandler == HTTPBinHandler {
642644
convenience init(
643645
_ mode: Mode = .http1_1(ssl: false, compress: false),
644646
proxy: Proxy = .none,
645-
bindTarget: BindTarget = .localhostIPv4RandomPort
647+
bindTarget: BindTarget = .localhostIPv4RandomPort,
648+
reusePort: Bool = false
646649
) {
647-
self.init(mode, proxy: proxy, bindTarget: bindTarget) { HTTPBinHandler(connectionID: $0) }
650+
self.init(mode, proxy: proxy, bindTarget: bindTarget, reusePort: reusePort) { HTTPBinHandler(connectionID: $0) }
648651
}
649652
}
650653

0 commit comments

Comments
 (0)