Merge branch 'main' into enable_macos_ci_prs

This commit is contained in:
Rick Newton-Rogers 2025-04-01 18:04:26 +01:00 committed by GitHub
commit aa55df982c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 106 additions and 73 deletions

View File

@ -50,7 +50,8 @@ var targets: [PackageDescription.Target] = [
.product(name: "NIO", package: "swift-nio"), .product(name: "NIO", package: "swift-nio"),
.product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOHTTP1", package: "swift-nio"), .product(name: "NIOHTTP1", package: "swift-nio"),
] ],
swiftSettings: strictConcurrencySettings
), ),
.executableTarget( .executableTarget(
name: "HTTPServerWithQuiescingDemo", name: "HTTPServerWithQuiescingDemo",
@ -68,7 +69,8 @@ var targets: [PackageDescription.Target] = [
.product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"), .product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOHTTP1", package: "swift-nio"), .product(name: "NIOHTTP1", package: "swift-nio"),
] ],
swiftSettings: strictConcurrencySettings
), ),
.executableTarget( .executableTarget(
name: "NIOWritePartialPCAPDemo", name: "NIOWritePartialPCAPDemo",
@ -77,7 +79,8 @@ var targets: [PackageDescription.Target] = [
.product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"), .product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOHTTP1", package: "swift-nio"), .product(name: "NIOHTTP1", package: "swift-nio"),
] ],
swiftSettings: strictConcurrencySettings
), ),
.executableTarget( .executableTarget(
name: "NIOExtrasPerformanceTester", name: "NIOExtrasPerformanceTester",
@ -94,7 +97,8 @@ var targets: [PackageDescription.Target] = [
dependencies: [ dependencies: [
.product(name: "NIO", package: "swift-nio"), .product(name: "NIO", package: "swift-nio"),
.product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOCore", package: "swift-nio"),
] ],
swiftSettings: strictConcurrencySettings
), ),
.executableTarget( .executableTarget(
name: "NIOSOCKSClient", name: "NIOSOCKSClient",
@ -102,7 +106,8 @@ var targets: [PackageDescription.Target] = [
.product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"), .product(name: "NIOPosix", package: "swift-nio"),
"NIOSOCKS", "NIOSOCKS",
] ],
swiftSettings: strictConcurrencySettings
), ),
.target( .target(
name: "CNIOExtrasZlib", name: "CNIOExtrasZlib",
@ -132,7 +137,8 @@ var targets: [PackageDescription.Target] = [
.product(name: "NIOEmbedded", package: "swift-nio"), .product(name: "NIOEmbedded", package: "swift-nio"),
.product(name: "NIOHTTP1", package: "swift-nio"), .product(name: "NIOHTTP1", package: "swift-nio"),
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"), .product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
] ],
swiftSettings: strictConcurrencySettings
), ),
.testTarget( .testTarget(
name: "NIOSOCKSTests", name: "NIOSOCKSTests",
@ -140,7 +146,8 @@ var targets: [PackageDescription.Target] = [
"NIOSOCKS", "NIOSOCKS",
.product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOEmbedded", package: "swift-nio"), .product(name: "NIOEmbedded", package: "swift-nio"),
] ],
swiftSettings: strictConcurrencySettings
), ),
.target( .target(
name: "NIONFS3", name: "NIONFS3",
@ -162,33 +169,38 @@ var targets: [PackageDescription.Target] = [
dependencies: [ dependencies: [
.product(name: "HTTPTypes", package: "swift-http-types"), .product(name: "HTTPTypes", package: "swift-http-types"),
.product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOCore", package: "swift-nio"),
] ],
swiftSettings: strictConcurrencySettings
), ),
.target( .target(
name: "NIOHTTPTypesHTTP1", name: "NIOHTTPTypesHTTP1",
dependencies: [ dependencies: [
"NIOHTTPTypes", "NIOHTTPTypes",
.product(name: "NIOHTTP1", package: "swift-nio"), .product(name: "NIOHTTP1", package: "swift-nio"),
] ],
swiftSettings: strictConcurrencySettings
), ),
.target( .target(
name: "NIOHTTPTypesHTTP2", name: "NIOHTTPTypesHTTP2",
dependencies: [ dependencies: [
"NIOHTTPTypes", "NIOHTTPTypes",
.product(name: "NIOHTTP2", package: "swift-nio-http2"), .product(name: "NIOHTTP2", package: "swift-nio-http2"),
] ],
swiftSettings: strictConcurrencySettings
), ),
.testTarget( .testTarget(
name: "NIOHTTPTypesHTTP1Tests", name: "NIOHTTPTypesHTTP1Tests",
dependencies: [ dependencies: [
"NIOHTTPTypesHTTP1" "NIOHTTPTypesHTTP1"
] ],
swiftSettings: strictConcurrencySettings
), ),
.testTarget( .testTarget(
name: "NIOHTTPTypesHTTP2Tests", name: "NIOHTTPTypesHTTP2Tests",
dependencies: [ dependencies: [
"NIOHTTPTypesHTTP2" "NIOHTTPTypesHTTP2"
] ],
swiftSettings: strictConcurrencySettings
), ),
.target( .target(
name: "NIOResumableUpload", name: "NIOResumableUpload",
@ -225,9 +237,7 @@ var targets: [PackageDescription.Target] = [
.product(name: "HTTPTypes", package: "swift-http-types"), .product(name: "HTTPTypes", package: "swift-http-types"),
.product(name: "Algorithms", package: "swift-algorithms"), .product(name: "Algorithms", package: "swift-algorithms"),
], ],
swiftSettings: [ swiftSettings: strictConcurrencySettings
.enableExperimentalFeature("StrictConcurrency")
]
), ),
.testTarget( .testTarget(
name: "NIOHTTPResponsivenessTests", name: "NIOHTTPResponsivenessTests",
@ -238,9 +248,7 @@ var targets: [PackageDescription.Target] = [
.product(name: "NIOEmbedded", package: "swift-nio"), .product(name: "NIOEmbedded", package: "swift-nio"),
.product(name: "HTTPTypes", package: "swift-http-types"), .product(name: "HTTPTypes", package: "swift-http-types"),
], ],
swiftSettings: [ swiftSettings: strictConcurrencySettings
.enableExperimentalFeature("StrictConcurrency")
]
), ),
] ]

View File

@ -16,7 +16,7 @@ import CNIOExtrasZlib
import NIOCore import NIOCore
/// Namespace for compression code. /// Namespace for compression code.
public enum NIOCompression { public enum NIOCompression: Sendable {
/// Which algorithm should be used for compression. /// Which algorithm should be used for compression.
public struct Algorithm: CustomStringConvertible, Equatable, Sendable { public struct Algorithm: CustomStringConvertible, Equatable, Sendable {

View File

@ -16,7 +16,7 @@ import CNIOExtrasZlib
import NIOCore import NIOCore
/// Namespace for decompression code. /// Namespace for decompression code.
public enum NIOHTTPDecompression { public enum NIOHTTPDecompression: Sendable {
/// Specifies how to limit decompression inflation. /// Specifies how to limit decompression inflation.
public struct DecompressionLimit: Sendable { public struct DecompressionLimit: Sendable {
private enum Limit { private enum Limit {

View File

@ -253,3 +253,6 @@ public final class HTTPDrippingDownloadHandler: ChannelDuplexHandler {
} }
} }
} }
@available(*, unavailable)
extension HTTPDrippingDownloadHandler: Sendable {}

View File

@ -88,3 +88,6 @@ public final class HTTPReceiveDiscardHandler: ChannelInboundHandler {
context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil) context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil)
} }
} }
@available(*, unavailable)
extension HTTPReceiveDiscardHandler: Sendable {}

View File

@ -143,3 +143,6 @@ public final class SimpleResponsivenessRequestMux: ChannelInboundHandler {
context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil) context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil)
} }
} }
@available(*, unavailable)
extension SimpleResponsivenessRequestMux: Sendable {}

View File

@ -19,7 +19,7 @@ import NIOHTTPTypes
/// A simple channel handler that translates HTTP/1 messages into shared HTTP types, /// A simple channel handler that translates HTTP/1 messages into shared HTTP types,
/// and vice versa, for use on the client side. /// and vice versa, for use on the client side.
public final class HTTP1ToHTTPClientCodec: ChannelDuplexHandler, RemovableChannelHandler { public final class HTTP1ToHTTPClientCodec: ChannelDuplexHandler, RemovableChannelHandler, Sendable {
public typealias InboundIn = HTTPClientResponsePart public typealias InboundIn = HTTPClientResponsePart
public typealias InboundOut = HTTPResponsePart public typealias InboundOut = HTTPResponsePart
@ -66,7 +66,7 @@ public final class HTTP1ToHTTPClientCodec: ChannelDuplexHandler, RemovableChanne
/// A simple channel handler that translates HTTP/1 messages into shared HTTP types, /// A simple channel handler that translates HTTP/1 messages into shared HTTP types,
/// and vice versa, for use on the server side. /// and vice versa, for use on the server side.
public final class HTTP1ToHTTPServerCodec: ChannelDuplexHandler, RemovableChannelHandler { public final class HTTP1ToHTTPServerCodec: ChannelDuplexHandler, RemovableChannelHandler, Sendable {
public typealias InboundIn = HTTPServerRequestPart public typealias InboundIn = HTTPServerRequestPart
public typealias InboundOut = HTTPRequestPart public typealias InboundOut = HTTPRequestPart

View File

@ -23,7 +23,7 @@ import NIOHTTPTypes
/// This is intended for compatibility purposes where a channel handler working with /// This is intended for compatibility purposes where a channel handler working with
/// HTTP/1 messages needs to work on top of the new version-independent HTTP types /// HTTP/1 messages needs to work on top of the new version-independent HTTP types
/// abstraction. /// abstraction.
public final class HTTPToHTTP1ClientCodec: ChannelDuplexHandler, RemovableChannelHandler { public final class HTTPToHTTP1ClientCodec: ChannelDuplexHandler, RemovableChannelHandler, Sendable {
public typealias InboundIn = HTTPResponsePart public typealias InboundIn = HTTPResponsePart
public typealias InboundOut = HTTPClientResponsePart public typealias InboundOut = HTTPClientResponsePart
@ -86,7 +86,7 @@ public final class HTTPToHTTP1ClientCodec: ChannelDuplexHandler, RemovableChanne
/// This is intended for compatibility purposes where a channel handler working with /// This is intended for compatibility purposes where a channel handler working with
/// HTTP/1 messages needs to work on top of the new version-independent HTTP types /// HTTP/1 messages needs to work on top of the new version-independent HTTP types
/// abstraction. /// abstraction.
public final class HTTPToHTTP1ServerCodec: ChannelDuplexHandler, RemovableChannelHandler { public final class HTTPToHTTP1ServerCodec: ChannelDuplexHandler, RemovableChannelHandler, Sendable {
public typealias InboundIn = HTTPRequestPart public typealias InboundIn = HTTPRequestPart
public typealias InboundOut = HTTPServerRequestPart public typealias InboundOut = HTTPServerRequestPart

View File

@ -162,6 +162,9 @@ public final class HTTP2FramePayloadToHTTPClientCodec: ChannelDuplexHandler, Rem
} }
} }
@available(*, unavailable)
extension HTTP2FramePayloadToHTTPClientCodec: Sendable {}
// MARK: - Server // MARK: - Server
private struct BaseServerCodec { private struct BaseServerCodec {
@ -280,6 +283,9 @@ public final class HTTP2FramePayloadToHTTPServerCodec: ChannelDuplexHandler, Rem
} }
} }
@available(*, unavailable)
extension HTTP2FramePayloadToHTTPServerCodec: Sendable {}
/// Events that can be sent by the application to be handled by the `HTTP2StreamChannel` /// Events that can be sent by the application to be handled by the `HTTP2StreamChannel`
public struct NIOHTTP2FramePayloadToHTTPEvent: Hashable, Sendable { public struct NIOHTTP2FramePayloadToHTTPEvent: Hashable, Sendable {
private enum Kind: Hashable, Sendable { private enum Kind: Hashable, Sendable {

View File

@ -101,9 +101,11 @@ if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
let server = try ServerBootstrap(group: group).childChannelInitializer { channel in let server = try ServerBootstrap(group: group).childChannelInitializer { channel in
channel.pipeline.configureHTTPServerPipeline().flatMap { channel.eventLoop.makeCompletedFuture {
channel.pipeline.addHandlers([ let sync = channel.pipeline.syncOperations
HTTP1ToHTTPServerCodec(secure: false), try sync.configureHTTPServerPipeline()
try sync.addHandler(HTTP1ToHTTPServerCodec(secure: false))
try sync.addHandler(
HTTPResumableUploadHandler( HTTPResumableUploadHandler(
context: uploadContext, context: uploadContext,
handlers: [ handlers: [
@ -111,8 +113,8 @@ if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
directory: URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true) directory: URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true)
) )
] ]
), )
]) )
} }
} }
.bind(host: "0.0.0.0", port: 8080) .bind(host: "0.0.0.0", port: 8080)

View File

@ -12,8 +12,8 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Wrapper for SOCKS protcol error. /// Wrapper for SOCKS protocol error.
public enum SOCKSError { public enum SOCKSError: Sendable {
/// The SOCKS client was in a different state to that required. /// The SOCKS client was in a different state to that required.
public struct InvalidClientState: Error, Hashable { public struct InvalidClientState: Error, Hashable {

View File

@ -40,7 +40,7 @@ private class PromiseOrderer {
let thisPromiseIndex = promiseArray.count let thisPromiseIndex = promiseArray.count
promiseArray.append(promise) promiseArray.append(promise)
promise.futureResult.whenComplete { (_: Result<Void, Error>) in promise.futureResult.hop(to: self.eventLoop).assumeIsolated().whenComplete { (_: Result<Void, Error>) in
let priorFutures = self.promiseArray[0..<thisPromiseIndex] let priorFutures = self.promiseArray[0..<thisPromiseIndex]
let subsequentFutures = self.promiseArray[(thisPromiseIndex + 1)...] let subsequentFutures = self.promiseArray[(thisPromiseIndex + 1)...]
let allPriorFuturesFired = priorFutures.map { $0.futureResult.isFulfilled }.allSatisfy { $0 } let allPriorFuturesFired = priorFutures.map { $0.futureResult.isFulfilled }.allSatisfy { $0 }
@ -772,9 +772,11 @@ class HTTPResponseCompressorTest: XCTestCase {
} }
func testConditionalCompressionEnabled() throws { func testConditionalCompressionEnabled() throws {
let predicateWasCalled = expectation(description: "Predicate was called") let loop = EmbeddedEventLoop()
defer { try! loop.syncShutdownGracefully() }
let predicateWasCalled = loop.makePromise(of: Void.self)
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
defer { predicateWasCalled.fulfill() } defer { predicateWasCalled.succeed() }
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"]) XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
XCTAssertEqual(isCompressionSupported, true) XCTAssertEqual(isCompressionSupported, true)
return .compressIfPossible return .compressIfPossible
@ -796,13 +798,15 @@ class HTTPResponseCompressorTest: XCTestCase {
] ]
) )
waitForExpectations(timeout: 0) try predicateWasCalled.futureResult.wait()
} }
func testUnsupportedRequestConditionalCompressionEnabled() throws { func testUnsupportedRequestConditionalCompressionEnabled() throws {
let predicateWasCalled = expectation(description: "Predicate was called") let loop = EmbeddedEventLoop()
defer { try! loop.syncShutdownGracefully() }
let predicateWasCalled = loop.makePromise(of: Void.self)
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
defer { predicateWasCalled.fulfill() } defer { predicateWasCalled.succeed() }
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"]) XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
XCTAssertEqual(isCompressionSupported, false) XCTAssertEqual(isCompressionSupported, false)
return .compressIfPossible return .compressIfPossible
@ -823,13 +827,15 @@ class HTTPResponseCompressorTest: XCTestCase {
] ]
) )
waitForExpectations(timeout: 0) try predicateWasCalled.futureResult.wait()
} }
func testUnsupportedStatusConditionalCompressionEnabled() throws { func testUnsupportedStatusConditionalCompressionEnabled() throws {
let predicateWasCalled = expectation(description: "Predicate was called") let loop = EmbeddedEventLoop()
defer { try! loop.syncShutdownGracefully() }
let predicateWasCalled = loop.makePromise(of: Void.self)
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
defer { predicateWasCalled.fulfill() } defer { predicateWasCalled.succeed() }
XCTAssertEqual(responseHeaders.status, .notModified) XCTAssertEqual(responseHeaders.status, .notModified)
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"]) XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
XCTAssertEqual(isCompressionSupported, false) XCTAssertEqual(isCompressionSupported, false)
@ -862,13 +868,15 @@ class HTTPResponseCompressorTest: XCTestCase {
} }
} }
waitForExpectations(timeout: 0) try predicateWasCalled.futureResult.wait()
} }
func testConditionalCompressionDisabled() throws { func testConditionalCompressionDisabled() throws {
let predicateWasCalled = expectation(description: "Predicate was called") let loop = EmbeddedEventLoop()
defer { try! loop.syncShutdownGracefully() }
let predicateWasCalled = loop.makePromise(of: Void.self)
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
defer { predicateWasCalled.fulfill() } defer { predicateWasCalled.succeed() }
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"]) XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
XCTAssertEqual(isCompressionSupported, true) XCTAssertEqual(isCompressionSupported, true)
return .doNotCompress return .doNotCompress
@ -889,13 +897,15 @@ class HTTPResponseCompressorTest: XCTestCase {
] ]
) )
waitForExpectations(timeout: 0) try predicateWasCalled.futureResult.wait()
} }
func testUnsupportedRequestConditionalCompressionDisabled() throws { func testUnsupportedRequestConditionalCompressionDisabled() throws {
let predicateWasCalled = expectation(description: "Predicate was called") let loop = EmbeddedEventLoop()
defer { try! loop.syncShutdownGracefully() }
let predicateWasCalled = loop.makePromise(of: Void.self)
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
defer { predicateWasCalled.fulfill() } defer { predicateWasCalled.succeed() }
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"]) XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
XCTAssertEqual(isCompressionSupported, false) XCTAssertEqual(isCompressionSupported, false)
return .doNotCompress return .doNotCompress
@ -916,13 +926,15 @@ class HTTPResponseCompressorTest: XCTestCase {
] ]
) )
waitForExpectations(timeout: 0) try predicateWasCalled.futureResult.wait()
} }
func testUnsupportedStatusConditionalCompressionDisabled() throws { func testUnsupportedStatusConditionalCompressionDisabled() throws {
let predicateWasCalled = expectation(description: "Predicate was called") let loop = EmbeddedEventLoop()
defer { try! loop.syncShutdownGracefully() }
let predicateWasCalled = loop.makePromise(of: Void.self)
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
defer { predicateWasCalled.fulfill() } defer { predicateWasCalled.succeed() }
XCTAssertEqual(responseHeaders.status, .notModified) XCTAssertEqual(responseHeaders.status, .notModified)
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"]) XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
XCTAssertEqual(isCompressionSupported, false) XCTAssertEqual(isCompressionSupported, false)
@ -955,14 +967,13 @@ class HTTPResponseCompressorTest: XCTestCase {
} }
} }
waitForExpectations(timeout: 0) try predicateWasCalled.futureResult.wait()
} }
func testConditionalCompressionModifiedHeaders() throws { func testConditionalCompressionModifiedHeaders() throws {
let predicateWasCalled = expectation(description: "Predicate was called") let counter = NIOLockedValueBox(0)
predicateWasCalled.expectedFulfillmentCount = 2
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
defer { predicateWasCalled.fulfill() } defer { counter.withLockedValue { $0 += 1 } }
let isEnabled = responseHeaders.headers[canonicalForm: "x-compression"].first == "enable" let isEnabled = responseHeaders.headers[canonicalForm: "x-compression"].first == "enable"
XCTAssertEqual( XCTAssertEqual(
responseHeaders.headers, responseHeaders.headers,
@ -999,7 +1010,7 @@ class HTTPResponseCompressorTest: XCTestCase {
] ]
) )
waitForExpectations(timeout: 0) XCTAssertEqual(counter.withLockedValue { $0 }, 2)
} }
} }
@ -1009,25 +1020,22 @@ extension EventLoopFuture {
// Easy, we're on the EventLoop. Let's just use our knowledge that we run completed future callbacks // Easy, we're on the EventLoop. Let's just use our knowledge that we run completed future callbacks
// immediately. // immediately.
var fulfilled = false var fulfilled = false
self.whenComplete { _ in self.assumeIsolated().whenComplete { _ in
fulfilled = true fulfilled = true
} }
return fulfilled return fulfilled
} else { } else {
let lock = NIOLock()
let group = DispatchGroup() let group = DispatchGroup()
var fulfilled = false // protected by lock let fulfilled = NIOLockedValueBox(false)
group.enter() group.enter()
self.eventLoop.execute { self.eventLoop.execute {
let isFulfilled = self.isFulfilled // This will now enter the above branch. let isFulfilled = self.isFulfilled // This will now enter the above branch.
lock.withLock { fulfilled.withLockedValue { $0 = isFulfilled }
fulfilled = isFulfilled
}
group.leave() group.leave()
} }
group.wait() // this is very nasty but this is for tests only, so... group.wait() // this is very nasty but this is for tests only, so...
return lock.withLock { fulfilled } return fulfilled.withLockedValue { $0 }
} }
} }
} }

View File

@ -115,7 +115,7 @@ final class NIOHTTPTypesHTTP1Tests: XCTestCase {
func testClientHTTP1ToHTTP() throws { func testClientHTTP1ToHTTP() throws {
let recorder = InboundRecorder<HTTPResponsePart>() let recorder = InboundRecorder<HTTPResponsePart>()
try self.channel.pipeline.addHandlers(HTTP1ToHTTPClientCodec(), recorder).wait() try self.channel.pipeline.syncOperations.addHandlers(HTTP1ToHTTPClientCodec(), recorder)
try self.channel.writeOutbound(HTTPRequestPart.head(Self.request)) try self.channel.writeOutbound(HTTPRequestPart.head(Self.request))
try self.channel.writeOutbound(HTTPRequestPart.end(Self.trailers)) try self.channel.writeOutbound(HTTPRequestPart.end(Self.trailers))
@ -135,7 +135,7 @@ final class NIOHTTPTypesHTTP1Tests: XCTestCase {
func testServerHTTP1ToHTTP() throws { func testServerHTTP1ToHTTP() throws {
let recorder = InboundRecorder<HTTPRequestPart>() let recorder = InboundRecorder<HTTPRequestPart>()
try self.channel.pipeline.addHandlers(HTTP1ToHTTPServerCodec(secure: true), recorder).wait() try self.channel.pipeline.syncOperations.addHandlers(HTTP1ToHTTPServerCodec(secure: true), recorder)
try self.channel.writeInbound(HTTPServerRequestPart.head(Self.oldRequest)) try self.channel.writeInbound(HTTPServerRequestPart.head(Self.oldRequest))
try self.channel.writeInbound(HTTPServerRequestPart.end(Self.oldTrailers)) try self.channel.writeInbound(HTTPServerRequestPart.end(Self.oldTrailers))
@ -155,7 +155,7 @@ final class NIOHTTPTypesHTTP1Tests: XCTestCase {
func testClientHTTPToHTTP1() throws { func testClientHTTPToHTTP1() throws {
let recorder = InboundRecorder<HTTPClientResponsePart>() let recorder = InboundRecorder<HTTPClientResponsePart>()
try self.channel.pipeline.addHandlers(HTTPToHTTP1ClientCodec(secure: true), recorder).wait() try self.channel.pipeline.syncOperations.addHandlers(HTTPToHTTP1ClientCodec(secure: true), recorder)
try self.channel.writeOutbound(HTTPClientRequestPart.head(Self.oldRequest)) try self.channel.writeOutbound(HTTPClientRequestPart.head(Self.oldRequest))
try self.channel.writeOutbound(HTTPClientRequestPart.end(Self.oldTrailers)) try self.channel.writeOutbound(HTTPClientRequestPart.end(Self.oldTrailers))
@ -175,7 +175,7 @@ final class NIOHTTPTypesHTTP1Tests: XCTestCase {
func testServerHTTPToHTTP1() throws { func testServerHTTPToHTTP1() throws {
let recorder = InboundRecorder<HTTPServerRequestPart>() let recorder = InboundRecorder<HTTPServerRequestPart>()
try self.channel.pipeline.addHandlers(HTTPToHTTP1ServerCodec(), recorder).wait() try self.channel.pipeline.syncOperations.addHandlers(HTTPToHTTP1ServerCodec(), recorder)
try self.channel.writeInbound(HTTPRequestPart.head(Self.request)) try self.channel.writeInbound(HTTPRequestPart.head(Self.request))
try self.channel.writeInbound(HTTPRequestPart.end(Self.trailers)) try self.channel.writeInbound(HTTPRequestPart.end(Self.trailers))

View File

@ -112,7 +112,7 @@ final class NIOHTTPTypesHTTP2Tests: XCTestCase {
func testClientHTTP2ToHTTP() throws { func testClientHTTP2ToHTTP() throws {
let recorder = InboundRecorder<HTTPResponsePart>() let recorder = InboundRecorder<HTTPResponsePart>()
try self.channel.pipeline.addHandlers(HTTP2FramePayloadToHTTPClientCodec(), recorder).wait() try self.channel.pipeline.syncOperations.addHandlers(HTTP2FramePayloadToHTTPClientCodec(), recorder)
try self.channel.writeOutbound(HTTPRequestPart.head(Self.request)) try self.channel.writeOutbound(HTTPRequestPart.head(Self.request))
try self.channel.writeOutbound(HTTPRequestPart.end(Self.trailers)) try self.channel.writeOutbound(HTTPRequestPart.end(Self.trailers))
@ -139,7 +139,7 @@ final class NIOHTTPTypesHTTP2Tests: XCTestCase {
func testServerHTTP2ToHTTP() throws { func testServerHTTP2ToHTTP() throws {
let recorder = InboundRecorder<HTTPRequestPart>() let recorder = InboundRecorder<HTTPRequestPart>()
try self.channel.pipeline.addHandlers(HTTP2FramePayloadToHTTPServerCodec(), recorder).wait() try self.channel.pipeline.syncOperations.addHandlers(HTTP2FramePayloadToHTTPServerCodec(), recorder)
try self.channel.writeInbound(HTTP2Frame.FramePayload(headers: Self.oldRequest)) try self.channel.writeInbound(HTTP2Frame.FramePayload(headers: Self.oldRequest))
try self.channel.writeInbound(HTTP2Frame.FramePayload(headers: Self.oldTrailers)) try self.channel.writeInbound(HTTP2Frame.FramePayload(headers: Self.oldTrailers))

View File

@ -139,7 +139,7 @@ class SOCKSServerHandlerTests: XCTestCase {
expectedRequest: expectedRequest, expectedRequest: expectedRequest,
expectedData: expectedData expectedData: expectedData
) )
XCTAssertNoThrow(try self.channel.pipeline.addHandler(testHandler).wait()) XCTAssertNoThrow(try self.channel.pipeline.syncOperations.addHandler(testHandler))
// wait for the greeting // wait for the greeting
XCTAssertFalse(testHandler.hadGreeting) XCTAssertFalse(testHandler.hadGreeting)
@ -184,7 +184,7 @@ class SOCKSServerHandlerTests: XCTestCase {
expectedRequest: expectedRequest, expectedRequest: expectedRequest,
expectedData: expectedData expectedData: expectedData
) )
XCTAssertNoThrow(try self.channel.pipeline.addHandler(testHandler).wait()) XCTAssertNoThrow(try self.channel.pipeline.syncOperations.addHandler(testHandler))
// wait for the greeting // wait for the greeting
XCTAssertFalse(testHandler.hadGreeting) XCTAssertFalse(testHandler.hadGreeting)

View File

@ -173,7 +173,7 @@ class SocksClientHandlerTests: XCTestCase {
// server requests an auth method we don't support // server requests an auth method we don't support
let promise = self.channel.eventLoop.makePromise(of: Void.self) let promise = self.channel.eventLoop.makePromise(of: Void.self)
try! self.channel.pipeline.addHandler(ErrorHandler(promise: promise), position: .last).wait() try! self.channel.pipeline.syncOperations.addHandler(ErrorHandler(promise: promise), position: .last)
self.writeInbound([0x05, 0x01]) self.writeInbound([0x05, 0x01])
XCTAssertThrowsError(try promise.futureResult.wait()) { e in XCTAssertThrowsError(try promise.futureResult.wait()) { e in
XCTAssertTrue(e is SOCKSError.InvalidAuthenticationSelection) XCTAssertTrue(e is SOCKSError.InvalidAuthenticationSelection)
@ -204,7 +204,7 @@ class SocksClientHandlerTests: XCTestCase {
// server replies with an error // server replies with an error
let promise = self.channel.eventLoop.makePromise(of: Void.self) let promise = self.channel.eventLoop.makePromise(of: Void.self)
try! self.channel.pipeline.addHandler(ErrorHandler(promise: promise), position: .last).wait() try! self.channel.pipeline.syncOperations.addHandler(ErrorHandler(promise: promise), position: .last)
self.writeInbound([0x05, 0x01, 0x00, 0x01, 192, 168, 1, 1, 0x00, 0x50]) self.writeInbound([0x05, 0x01, 0x00, 0x01, 192, 168, 1, 1, 0x00, 0x50])
XCTAssertThrowsError(try promise.futureResult.wait()) { e in XCTAssertThrowsError(try promise.futureResult.wait()) { e in
XCTAssertEqual(e as? SOCKSError.ConnectionFailed, .init(reply: .serverFailure)) XCTAssertEqual(e as? SOCKSError.ConnectionFailed, .init(reply: .serverFailure))
@ -262,12 +262,12 @@ class SocksClientHandlerTests: XCTestCase {
let establishPromise = self.channel.eventLoop.makePromise(of: Void.self) let establishPromise = self.channel.eventLoop.makePromise(of: Void.self)
let removalPromise = self.channel.eventLoop.makePromise(of: Void.self) let removalPromise = self.channel.eventLoop.makePromise(of: Void.self)
establishPromise.futureResult.whenSuccess { _ in establishPromise.futureResult.assumeIsolated().whenSuccess { _ in
self.channel.pipeline.syncOperations.removeHandler(self.handler).cascade(to: removalPromise) self.channel.pipeline.syncOperations.removeHandler(self.handler).cascade(to: removalPromise)
} }
XCTAssertNoThrow( XCTAssertNoThrow(
try self.channel.pipeline.addHandler(SOCKSEventHandler(establishedPromise: establishPromise)).wait() try self.channel.pipeline.syncOperations.addHandler(SOCKSEventHandler(establishedPromise: establishPromise))
) )
self.connect() self.connect()