diff --git a/Sources/NIO/Bootstrap.swift b/Sources/NIO/Bootstrap.swift index b00dff3a..a949f356 100644 --- a/Sources/NIO/Bootstrap.swift +++ b/Sources/NIO/Bootstrap.swift @@ -234,10 +234,11 @@ public final class ServerBootstrap { return eventLoop.submit { serverChannelOptions.applyAllChannelOptions(to: serverChannel).flatMap { - serverChannel.pipeline.addHandler(AcceptHandler(childChannelInitializer: childChannelInit, - childChannelOptions: childChannelOptions)) - }.flatMap { serverChannelInit(serverChannel) + }.flatMap { + serverChannel.pipeline.addHandler(AcceptHandler(childChannelInitializer: childChannelInit, + childChannelOptions: childChannelOptions), + name: "AcceptHandler") }.flatMap { register(eventLoop, serverChannel) }.map { diff --git a/Tests/NIOTests/BootstrapTest+XCTest.swift b/Tests/NIOTests/BootstrapTest+XCTest.swift index 97c72205..eac2fbf9 100644 --- a/Tests/NIOTests/BootstrapTest+XCTest.swift +++ b/Tests/NIOTests/BootstrapTest+XCTest.swift @@ -39,6 +39,7 @@ extension BootstrapTest { ("testPreConnectedSocketSetsChannelOptionsBeforeChannelInitializer", testPreConnectedSocketSetsChannelOptionsBeforeChannelInitializer), ("testDatagramBootstrapSetsChannelOptionsBeforeChannelInitializer", testDatagramBootstrapSetsChannelOptionsBeforeChannelInitializer), ("testPipeBootstrapSetsChannelOptionsBeforeChannelInitializer", testPipeBootstrapSetsChannelOptionsBeforeChannelInitializer), + ("testServerBootstrapAddsAcceptHandlerAfterServerChannelInitialiser", testServerBootstrapAddsAcceptHandlerAfterServerChannelInitialiser), ] } } diff --git a/Tests/NIOTests/BootstrapTest.swift b/Tests/NIOTests/BootstrapTest.swift index 5bf6e0d6..f91ada82 100644 --- a/Tests/NIOTests/BootstrapTest.swift +++ b/Tests/NIOTests/BootstrapTest.swift @@ -388,6 +388,43 @@ class BootstrapTest: XCTestCase { return [] }) } + + func testServerBootstrapAddsAcceptHandlerAfterServerChannelInitialiser() { + // It's unclear if this is the right solution, see https://github.com/apple/swift-nio/issues/1392 + let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) + defer { + XCTAssertNoThrow(try group.syncShutdownGracefully()) + } + + struct FoundHandlerThatWasNotSupposedToBeThereError: Error {} + + var maybeServer: Channel? = nil + XCTAssertNoThrow(maybeServer = try ServerBootstrap(group: group) + .serverChannelInitializer { channel in + // Here, we test that we can't find the AcceptHandler + return channel.pipeline.context(name: "AcceptHandler").flatMap { context -> EventLoopFuture in + XCTFail("unexpectedly found \(context)") + return channel.eventLoop.makeFailedFuture(FoundHandlerThatWasNotSupposedToBeThereError()) + }.flatMapError { error -> EventLoopFuture in + XCTAssertEqual(.notFound, error as? ChannelPipelineError) + if case .some(.notFound) = error as? ChannelPipelineError { + return channel.eventLoop.makeSucceededFuture(()) + } + return channel.eventLoop.makeFailedFuture(error) + } + } + .bind(host: "127.0.0.1", port: 0) + .wait()) + + guard let server = maybeServer else { + XCTFail("couldn't bootstrap server") + return + } + + // But now, it should be there. + XCTAssertNoThrow(_ = try server.pipeline.context(name: "AcceptHandler").wait()) + XCTAssertNoThrow(try server.close().wait()) + } } private final class MakeSureAutoReadIsOffInChannelInitializer: ChannelInboundHandler {