From 0e7e53b8f49dbbbdef858582bfe9c193b9c012d5 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Fri, 17 Dec 2021 14:45:08 +0100 Subject: [PATCH 1/7] Fix HTTP1 to HTTP2 migration while shutdown is in progress ### Motivation Calling `HTTPClient.shutdown()` may never return if connections are still starting and one new established connection results in a state migration (i.e. from HTTP1 to HTTP2 or vice versa). We forgot to migrate the shutdown state. This could result in a large dealy until `.shutdown()` returns because we wait until connections are closed because of idle timeout. Worse, it could also never return if more requests are queued because the connections would not be idle and therefore not close itself. ###Changes - Mirgrate shutdown state too - add tests for this specific case --- ...onnectionPool+HTTP2StateMachineTests.swift | 141 +++++++----------- 1 file changed, 55 insertions(+), 86 deletions(-) diff --git a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift index 825ffc9b3..939b1c0b8 100644 --- a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift @@ -680,24 +680,44 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { var queuer = MockRequestQueuer() var state = HTTPConnectionPool.StateMachine(idGenerator: .init(), maximumConcurrentHTTP1Connections: 8) - /// create a new connection - let mockRequest = MockHTTPRequest(eventLoop: el1) - let request = HTTPConnectionPool.Request(mockRequest) - let action = state.executeRequest(request) - guard case .createConnection(let conn1ID, let eventLoop) = action.connection else { - return XCTFail("Unexpected connection action \(action.connection)") + /// first 8 request should create a new connection + var connectionIDs: [HTTPConnectionPool.Connection.ID] = [] + for _ in 0..<8 { + let mockRequest = MockHTTPRequest(eventLoop: el1) + let request = HTTPConnectionPool.Request(mockRequest) + let action = state.executeRequest(request) + guard case .createConnection(let connID, let eventLoop) = action.connection else { + return XCTFail("Unexpected connection action \(action.connection)") + } + connectionIDs.append(connID) + XCTAssertTrue(eventLoop === el1) + XCTAssertEqual(action.request, .scheduleRequestTimeout(for: request, on: mockRequest.eventLoop)) + XCTAssertNoThrow(try connections.createConnection(connID, on: el1)) + XCTAssertNoThrow(try queuer.queue(mockRequest, id: request.id)) } - XCTAssertTrue(eventLoop === el1) - XCTAssertEqual(action.request, .scheduleRequestTimeout(for: request, on: mockRequest.eventLoop)) - XCTAssertNoThrow(try connections.createConnection(conn1ID, on: el1)) - XCTAssertNoThrow(try queuer.queue(mockRequest, id: request.id)) + guard let conn1ID = connectionIDs.first else { + return XCTFail("could not create connection") + } + + /// after we reached the `maximumConcurrentHTTP1Connections`, we will not create new connections + for _ in 0..<8 { + let mockRequest = MockHTTPRequest(eventLoop: el1) + let request = HTTPConnectionPool.Request(mockRequest) + let action = state.executeRequest(request) + XCTAssertEqual(action.connection, .none) + XCTAssertEqual(action.request, .scheduleRequestTimeout(for: request, on: mockRequest.eventLoop)) + + XCTAssertNoThrow(try queuer.queue(mockRequest, id: request.id)) + } /// we now no longer want anything of it let shutdownAction = state.shutdown() + guard case .failRequestsAndCancelTimeouts(let requestsToCancel, let error) = shutdownAction.request else { return XCTFail("unexpected shutdown action \(shutdownAction)") } + XCTAssertEqualTypeAndValue(error, HTTPClientError.cancelled) for request in requestsToCancel { @@ -705,13 +725,34 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { } XCTAssertTrue(queuer.isEmpty) - /// new HTTP2 connection should migrate from HTTP1 to HTTP2, close the connection and shutdown the pool + /// first new HTTP2 connection should migrate from HTTP1 to HTTP2 and execute requests let conn1: HTTPConnectionPool.Connection = .__testOnly_connection(id: conn1ID, eventLoop: el1) XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP2(conn1ID, maxConcurrentStreams: 10)) let migrationAction = state.newHTTP2ConnectionCreated(conn1, maxConcurrentStreams: 10) XCTAssertEqual(migrationAction.request, .none) - XCTAssertEqual(migrationAction.connection, .closeConnection(conn1, isShutdown: .yes(unclean: true))) + XCTAssertEqual(migrationAction.connection, .migration( + createConnections: [], + closeConnections: [conn1], + scheduleTimeout: nil + )) XCTAssertNoThrow(try connections.closeConnection(conn1)) + + /// remaining connections should be closed immediately without executing any request + for connID in connectionIDs.dropFirst().dropLast() { + let conn: HTTPConnectionPool.Connection = .__testOnly_connection(id: connID, eventLoop: el1) + XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP2(connID, maxConcurrentStreams: 10)) + let action = state.newHTTP2ConnectionCreated(conn, maxConcurrentStreams: 10) + XCTAssertEqual(action.request, .none) + XCTAssertEqual(action.connection, .closeConnection(conn, isShutdown: .no)) + XCTAssertNoThrow(try connections.closeConnection(conn)) + } + let lastConnID = connectionIDs.last! + let lastConn: HTTPConnectionPool.Connection = .__testOnly_connection(id: lastConnID, eventLoop: el1) + XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP2(lastConnID, maxConcurrentStreams: 10)) + let action = state.newHTTP2ConnectionCreated(lastConn, maxConcurrentStreams: 10) + XCTAssertEqual(action.request, .none) + XCTAssertEqual(action.connection, .closeConnection(lastConn, isShutdown: .yes(unclean: true))) + XCTAssertNoThrow(try connections.closeConnection(lastConn)) XCTAssertTrue(connections.isEmpty) } @@ -915,78 +956,6 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { XCTAssertNoThrow(try connections.closeConnection(http2Conn)) } - func testHTTP2toHTTP1MigrationDuringShutdown() { - let elg = EmbeddedEventLoopGroup(loops: 2) - let el1 = elg.next() - let el2 = elg.next() - var connections = MockConnectionPool() - var queuer = MockRequestQueuer() - var state = HTTPConnectionPool.StateMachine(idGenerator: .init(), maximumConcurrentHTTP1Connections: 8) - - // create http2 connection - let mockRequest = MockHTTPRequest(eventLoop: el1) - let request1 = HTTPConnectionPool.Request(mockRequest) - let action1 = state.executeRequest(request1) - guard case .createConnection(let http2ConnID, let http2EventLoop) = action1.connection else { - return XCTFail("Unexpected connection action \(action1.connection)") - } - XCTAssertTrue(http2EventLoop === el1) - XCTAssertEqual(action1.request, .scheduleRequestTimeout(for: request1, on: mockRequest.eventLoop)) - XCTAssertNoThrow(try connections.createConnection(http2ConnID, on: el1)) - XCTAssertNoThrow(try queuer.queue(mockRequest, id: request1.id)) - let http2Conn: HTTPConnectionPool.Connection = .__testOnly_connection(id: http2ConnID, eventLoop: el1) - XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP2(http2ConnID, maxConcurrentStreams: 10)) - let migrationAction1 = state.newHTTP2ConnectionCreated(http2Conn, maxConcurrentStreams: 10) - guard case .executeRequestsAndCancelTimeouts(let requests, http2Conn) = migrationAction1.request else { - return XCTFail("unexpected request action \(migrationAction1.request)") - } - XCTAssertEqual(migrationAction1.connection, .migration(createConnections: [], closeConnections: [], scheduleTimeout: nil)) - XCTAssertEqual(requests.count, 1) - for request in requests { - XCTAssertNoThrow(try queuer.get(request.id, request: request.__testOnly_wrapped_request())) - XCTAssertNoThrow(try connections.execute(request.__testOnly_wrapped_request(), on: http2Conn)) - } - - // a request with new required event loop should create a new connection - let mockRequestWithRequiredEventLoop = MockHTTPRequest(eventLoop: el2, requiresEventLoopForChannel: true) - let requestWithRequiredEventLoop = HTTPConnectionPool.Request(mockRequestWithRequiredEventLoop) - let action2 = state.executeRequest(requestWithRequiredEventLoop) - guard case .createConnection(let http1ConnId, let http1EventLoop) = action2.connection else { - return XCTFail("Unexpected connection action \(action2.connection)") - } - XCTAssertTrue(http1EventLoop === el2) - XCTAssertEqual(action2.request, .scheduleRequestTimeout(for: requestWithRequiredEventLoop, on: mockRequestWithRequiredEventLoop.eventLoop)) - XCTAssertNoThrow(try connections.createConnection(http1ConnId, on: el2)) - XCTAssertNoThrow(try queuer.queue(mockRequestWithRequiredEventLoop, id: requestWithRequiredEventLoop.id)) - - /// we now no longer want anything of it - let shutdownAction = state.shutdown() - guard case .failRequestsAndCancelTimeouts(let requestsToCancel, let error) = shutdownAction.request else { - return XCTFail("unexpected shutdown action \(shutdownAction)") - } - XCTAssertEqualTypeAndValue(error, HTTPClientError.cancelled) - - for request in requestsToCancel { - XCTAssertNoThrow(try queuer.cancel(request.id)) - } - XCTAssertTrue(queuer.isEmpty) - - // if we established a new http/1 connection we should migrate back to http/1, - // close the connection and shutdown the pool - let http1Conn: HTTPConnectionPool.Connection = .__testOnly_connection(id: http1ConnId, eventLoop: el2) - XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP1(http1ConnId)) - let migrationAction2 = state.newHTTP1ConnectionCreated(http1Conn) - XCTAssertEqual(migrationAction2.request, .none) - XCTAssertEqual(migrationAction2.connection, .migration(createConnections: [], closeConnections: [http1Conn], scheduleTimeout: nil)) - - // in http/1 state, we should close idle http2 connections - XCTAssertNoThrow(try connections.finishExecution(http2Conn.id)) - let releaseAction = state.http2ConnectionStreamClosed(http2Conn.id) - XCTAssertEqual(releaseAction.connection, .closeConnection(http2Conn, isShutdown: .yes(unclean: true))) - XCTAssertEqual(releaseAction.request, .none) - XCTAssertNoThrow(try connections.closeConnection(http2Conn)) - } - func testConnectionIsImmediatelyCreatedAfterBackoffTimerFires() { let elg = EmbeddedEventLoopGroup(loops: 2) let el1 = elg.next() @@ -1226,8 +1195,8 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { } } -/// Should be used if you have a value of statically unknown type and want to compare its value to another `Equatable` value. -/// The assert will fail if both values don't have the same type or don't have the same value. +/// Should be used if you have a value of statically unknown type and want to compare its value to an `Equatable` type. +/// The assert will fail if the boths /// - Note: if the type of both values are statically know, prefer `XCTAssertEqual`. /// - Parameters: /// - lhs: value of a statically unknown type From ba85d77168518525e36a49dcdfbe8fdd96e5532b Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Fri, 17 Dec 2021 13:31:07 +0100 Subject: [PATCH 2/7] simplify testMigrationFromHTTP1ToHTTP2WhileShuttingDown --- ...onnectionPool+HTTP2StateMachineTests.swift | 66 ++++--------------- 1 file changed, 13 insertions(+), 53 deletions(-) diff --git a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift index 939b1c0b8..93b10f689 100644 --- a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift @@ -680,40 +680,21 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { var queuer = MockRequestQueuer() var state = HTTPConnectionPool.StateMachine(idGenerator: .init(), maximumConcurrentHTTP1Connections: 8) - /// first 8 request should create a new connection - var connectionIDs: [HTTPConnectionPool.Connection.ID] = [] - for _ in 0..<8 { - let mockRequest = MockHTTPRequest(eventLoop: el1) - let request = HTTPConnectionPool.Request(mockRequest) - let action = state.executeRequest(request) - guard case .createConnection(let connID, let eventLoop) = action.connection else { - return XCTFail("Unexpected connection action \(action.connection)") - } - connectionIDs.append(connID) - XCTAssertTrue(eventLoop === el1) - XCTAssertEqual(action.request, .scheduleRequestTimeout(for: request, on: mockRequest.eventLoop)) - XCTAssertNoThrow(try connections.createConnection(connID, on: el1)) - XCTAssertNoThrow(try queuer.queue(mockRequest, id: request.id)) - } - - guard let conn1ID = connectionIDs.first else { - return XCTFail("could not create connection") - } - - /// after we reached the `maximumConcurrentHTTP1Connections`, we will not create new connections - for _ in 0..<8 { - let mockRequest = MockHTTPRequest(eventLoop: el1) - let request = HTTPConnectionPool.Request(mockRequest) - let action = state.executeRequest(request) - XCTAssertEqual(action.connection, .none) - XCTAssertEqual(action.request, .scheduleRequestTimeout(for: request, on: mockRequest.eventLoop)) - - XCTAssertNoThrow(try queuer.queue(mockRequest, id: request.id)) + /// create a new connection + let mockRequest = MockHTTPRequest(eventLoop: el1) + let request = HTTPConnectionPool.Request(mockRequest) + let action = state.executeRequest(request) + guard case .createConnection(let conn1ID, let eventLoop) = action.connection else { + return XCTFail("Unexpected connection action \(action.connection)") } + + XCTAssertTrue(eventLoop === el1) + XCTAssertEqual(action.request, .scheduleRequestTimeout(for: request, on: mockRequest.eventLoop)) + XCTAssertNoThrow(try connections.createConnection(conn1ID, on: el1)) + XCTAssertNoThrow(try queuer.queue(mockRequest, id: request.id)) /// we now no longer want anything of it let shutdownAction = state.shutdown() - guard case .failRequestsAndCancelTimeouts(let requestsToCancel, let error) = shutdownAction.request else { return XCTFail("unexpected shutdown action \(shutdownAction)") } @@ -725,34 +706,13 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { } XCTAssertTrue(queuer.isEmpty) - /// first new HTTP2 connection should migrate from HTTP1 to HTTP2 and execute requests + /// new HTTP2 connection should migrate from HTTP1 to HTTP2, close the connection and shutdown the pool let conn1: HTTPConnectionPool.Connection = .__testOnly_connection(id: conn1ID, eventLoop: el1) XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP2(conn1ID, maxConcurrentStreams: 10)) let migrationAction = state.newHTTP2ConnectionCreated(conn1, maxConcurrentStreams: 10) XCTAssertEqual(migrationAction.request, .none) - XCTAssertEqual(migrationAction.connection, .migration( - createConnections: [], - closeConnections: [conn1], - scheduleTimeout: nil - )) + XCTAssertEqual(migrationAction.connection, .closeConnection(conn1, isShutdown: .yes(unclean: true))) XCTAssertNoThrow(try connections.closeConnection(conn1)) - - /// remaining connections should be closed immediately without executing any request - for connID in connectionIDs.dropFirst().dropLast() { - let conn: HTTPConnectionPool.Connection = .__testOnly_connection(id: connID, eventLoop: el1) - XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP2(connID, maxConcurrentStreams: 10)) - let action = state.newHTTP2ConnectionCreated(conn, maxConcurrentStreams: 10) - XCTAssertEqual(action.request, .none) - XCTAssertEqual(action.connection, .closeConnection(conn, isShutdown: .no)) - XCTAssertNoThrow(try connections.closeConnection(conn)) - } - let lastConnID = connectionIDs.last! - let lastConn: HTTPConnectionPool.Connection = .__testOnly_connection(id: lastConnID, eventLoop: el1) - XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP2(lastConnID, maxConcurrentStreams: 10)) - let action = state.newHTTP2ConnectionCreated(lastConn, maxConcurrentStreams: 10) - XCTAssertEqual(action.request, .none) - XCTAssertEqual(action.connection, .closeConnection(lastConn, isShutdown: .yes(unclean: true))) - XCTAssertNoThrow(try connections.closeConnection(lastConn)) XCTAssertTrue(connections.isEmpty) } From ee6829fe0eb171e85e68b2701591a057fc46ea00 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Fri, 17 Dec 2021 14:09:51 +0100 Subject: [PATCH 3/7] add http2 to http1 migration test --- ...onnectionPool+HTTP2StateMachineTests.swift | 75 ++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift index 93b10f689..e92523796 100644 --- a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift @@ -687,7 +687,7 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { guard case .createConnection(let conn1ID, let eventLoop) = action.connection else { return XCTFail("Unexpected connection action \(action.connection)") } - + XCTAssertTrue(eventLoop === el1) XCTAssertEqual(action.request, .scheduleRequestTimeout(for: request, on: mockRequest.eventLoop)) XCTAssertNoThrow(try connections.createConnection(conn1ID, on: el1)) @@ -698,7 +698,6 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { guard case .failRequestsAndCancelTimeouts(let requestsToCancel, let error) = shutdownAction.request else { return XCTFail("unexpected shutdown action \(shutdownAction)") } - XCTAssertEqualTypeAndValue(error, HTTPClientError.cancelled) for request in requestsToCancel { @@ -916,6 +915,78 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { XCTAssertNoThrow(try connections.closeConnection(http2Conn)) } + func testHTTP2toHTTP1MigrationDuringShutdown() { + let elg = EmbeddedEventLoopGroup(loops: 2) + let el1 = elg.next() + let el2 = elg.next() + var connections = MockConnectionPool() + var queuer = MockRequestQueuer() + var state = HTTPConnectionPool.StateMachine(idGenerator: .init(), maximumConcurrentHTTP1Connections: 8) + + // create http2 connection + let mockRequest = MockHTTPRequest(eventLoop: el1) + let request1 = HTTPConnectionPool.Request(mockRequest) + let action1 = state.executeRequest(request1) + guard case .createConnection(let http2ConnID, let http2EventLoop) = action1.connection else { + return XCTFail("Unexpected connection action \(action1.connection)") + } + XCTAssertTrue(http2EventLoop === el1) + XCTAssertEqual(action1.request, .scheduleRequestTimeout(for: request1, on: mockRequest.eventLoop)) + XCTAssertNoThrow(try connections.createConnection(http2ConnID, on: el1)) + XCTAssertNoThrow(try queuer.queue(mockRequest, id: request1.id)) + let http2Conn: HTTPConnectionPool.Connection = .__testOnly_connection(id: http2ConnID, eventLoop: el1) + XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP2(http2ConnID, maxConcurrentStreams: 10)) + let migrationAction1 = state.newHTTP2ConnectionCreated(http2Conn, maxConcurrentStreams: 10) + guard case .executeRequestsAndCancelTimeouts(let requests, http2Conn) = migrationAction1.request else { + return XCTFail("unexpected request action \(migrationAction1.request)") + } + XCTAssertEqual(migrationAction1.connection, .migration(createConnections: [], closeConnections: [], scheduleTimeout: nil)) + XCTAssertEqual(requests.count, 1) + for request in requests { + XCTAssertNoThrow(try queuer.get(request.id, request: request.__testOnly_wrapped_request())) + XCTAssertNoThrow(try connections.execute(request.__testOnly_wrapped_request(), on: http2Conn)) + } + + // a request with new required event loop should create a new connection + let mockRequestWithRequiredEventLoop = MockHTTPRequest(eventLoop: el2, requiresEventLoopForChannel: true) + let requestWithRequiredEventLoop = HTTPConnectionPool.Request(mockRequestWithRequiredEventLoop) + let action2 = state.executeRequest(requestWithRequiredEventLoop) + guard case .createConnection(let http1ConnId, let http1EventLoop) = action2.connection else { + return XCTFail("Unexpected connection action \(action2.connection)") + } + XCTAssertTrue(http1EventLoop === el2) + XCTAssertEqual(action2.request, .scheduleRequestTimeout(for: requestWithRequiredEventLoop, on: mockRequestWithRequiredEventLoop.eventLoop)) + XCTAssertNoThrow(try connections.createConnection(http1ConnId, on: el2)) + XCTAssertNoThrow(try queuer.queue(mockRequestWithRequiredEventLoop, id: requestWithRequiredEventLoop.id)) + + /// we now no longer want anything of it + let shutdownAction = state.shutdown() + guard case .failRequestsAndCancelTimeouts(let requestsToCancel, let error) = shutdownAction.request else { + return XCTFail("unexpected shutdown action \(shutdownAction)") + } + XCTAssertEqualTypeAndValue(error, HTTPClientError.cancelled) + + for request in requestsToCancel { + XCTAssertNoThrow(try queuer.cancel(request.id)) + } + XCTAssertTrue(queuer.isEmpty) + + // if we established a new http/1 connection we should migrate back to http/1, + // close the connection and shutdown the pool + let http1Conn: HTTPConnectionPool.Connection = .__testOnly_connection(id: http1ConnId, eventLoop: el2) + XCTAssertNoThrow(try connections.succeedConnectionCreationHTTP1(http1ConnId)) + let migrationAction2 = state.newHTTP1ConnectionCreated(http1Conn) + XCTAssertEqual(migrationAction2.request, .none) + XCTAssertEqual(migrationAction2.connection, .migration(createConnections: [], closeConnections: [http1Conn], scheduleTimeout: nil)) + + // in http/1 state, we should close idle http2 connections + XCTAssertNoThrow(try connections.finishExecution(http2Conn.id)) + let releaseAction = state.http2ConnectionStreamClosed(http2Conn.id) + XCTAssertEqual(releaseAction.connection, .closeConnection(http2Conn, isShutdown: .yes(unclean: true))) + XCTAssertEqual(releaseAction.request, .none) + XCTAssertNoThrow(try connections.closeConnection(http2Conn)) + } + func testConnectionIsImmediatelyCreatedAfterBackoffTimerFires() { let elg = EmbeddedEventLoopGroup(loops: 2) let el1 = elg.next() From 02eeb9f6074f2b67b55cdff5cfab435e3e438be6 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Fri, 17 Dec 2021 14:11:44 +0100 Subject: [PATCH 4/7] fix documentation of `XCTAssertEqualTypeAndValue` --- .../HTTPConnectionPool+HTTP2StateMachineTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift index e92523796..825ffc9b3 100644 --- a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift @@ -1226,8 +1226,8 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase { } } -/// Should be used if you have a value of statically unknown type and want to compare its value to an `Equatable` type. -/// The assert will fail if the boths +/// Should be used if you have a value of statically unknown type and want to compare its value to another `Equatable` value. +/// The assert will fail if both values don't have the same type or don't have the same value. /// - Note: if the type of both values are statically know, prefer `XCTAssertEqual`. /// - Parameters: /// - lhs: value of a statically unknown type From 8933da3497d135651465c38b119b89ee3f6f1c20 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Fri, 17 Dec 2021 14:44:46 +0100 Subject: [PATCH 5/7] make async/await available on older platforms ### Motivation With Xcode 13.2, and therefore Swift 5.5.2, Swift Concurrecy is supported on older Apple OSs. async/await suport will no longer be available on Swift before `5.5.2` but this isn't a breaking change because we have not yet made anything of it public. ### Changes - replace all `#if compiler(>=5.5) && canImport(_Concurrency)` with `#if compiler(>=5.5.2) && canImport(_Concurrency)` - replace all `available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)` with `available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)` --- .../AsyncAwait/HTTPClient+execute.swift | 8 +-- .../HTTPClientRequest+Prepared.swift | 10 +-- .../AsyncAwait/HTTPClientRequest.swift | 10 +-- .../AsyncAwait/HTTPClientResponse.swift | 10 +-- .../AsyncAwait/Transaction+StateMachine.swift | 4 +- .../AsyncAwait/Transaction.swift | 10 +-- .../AsyncAwaitEndToEndTests.swift | 58 ++++++++-------- .../AsyncTestHelpers.swift | 2 +- .../HTTPClientRequestTests.swift | 66 +++++++++---------- .../Transaction+StateMachineTests.swift | 28 ++++---- .../TransactionTests.swift | 46 ++++++------- .../XCTest+AsyncAwait.swift | 6 +- 12 files changed, 129 insertions(+), 129 deletions(-) diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClient+execute.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClient+execute.swift index 3c0566c9e..6c45a590b 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClient+execute.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClient+execute.swift @@ -12,13 +12,13 @@ // //===----------------------------------------------------------------------===// -#if compiler(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) import struct Foundation.URL import Logging import NIOCore import NIOHTTP1 -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClient { /// Execute arbitrary HTTP requests. /// @@ -41,7 +41,7 @@ extension HTTPClient { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClient { private func executeAndFollowRedirectsIfNeeded( _ request: HTTPClientRequest, @@ -124,7 +124,7 @@ extension HTTPClient { /// There is currently no good way to asynchronously cancel an object that is initiated inside the `body` closure of `with*Continuation`. /// As a workaround we use `TransactionCancelHandler` which will take care of the race between instantiation of `Transaction` /// in the `body` closure and cancelation from the `onCancel` closure of `withTaskCancellationHandler`. -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) private actor TransactionCancelHandler { enum CancelReason { /// swift concurrency task was canceled diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Prepared.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Prepared.swift index 974616143..7899588e1 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Prepared.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Prepared.swift @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// -#if compiler(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) import struct Foundation.URL import NIOHTTP1 -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClientRequest { struct Prepared { var url: URL @@ -27,7 +27,7 @@ extension HTTPClientRequest { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClientRequest.Prepared { init(_ request: HTTPClientRequest) throws { guard let url = URL(string: request.url) else { @@ -58,7 +58,7 @@ extension HTTPClientRequest.Prepared { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension RequestBodyLength { init(_ body: HTTPClientRequest.Body?) { switch body?.mode { @@ -74,7 +74,7 @@ extension RequestBodyLength { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClientRequest.Prepared { func followingRedirect(to redirectURL: URL, status: HTTPResponseStatus) -> HTTPClientRequest { let (method, headers, body) = transformRequestForRedirect( diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift index 3c729b75c..89689225d 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// -#if compiler(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) import NIOCore import NIOHTTP1 -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) struct HTTPClientRequest { var url: String var method: HTTPMethod @@ -32,7 +32,7 @@ struct HTTPClientRequest { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClientRequest { struct Body { internal enum Mode { @@ -49,7 +49,7 @@ extension HTTPClientRequest { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClientRequest.Body { static func byteBuffer(_ byteBuffer: ByteBuffer) -> Self { self.init(.byteBuffer(byteBuffer)) @@ -131,7 +131,7 @@ extension HTTPClientRequest.Body { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Optional where Wrapped == HTTPClientRequest.Body { internal var canBeConsumedMultipleTimes: Bool { switch self?.mode { diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientResponse.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientResponse.swift index 2df1b808c..1ecfed9e5 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientResponse.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientResponse.swift @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// -#if compiler(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) import NIOCore import NIOHTTP1 -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) struct HTTPClientResponse { var version: HTTPVersion var status: HTTPResponseStatus @@ -46,7 +46,7 @@ struct HTTPClientResponse { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClientResponse.Body: AsyncSequence { typealias Element = ByteBuffer typealias AsyncIterator = Iterator @@ -70,7 +70,7 @@ extension HTTPClientResponse.Body: AsyncSequence { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClientResponse.Body { /// The purpose of this object is to inform the transaction about the response body being deinitialized. /// If the users has not called `makeAsyncIterator` on the body, before it is deinited, the http @@ -88,7 +88,7 @@ extension HTTPClientResponse.Body { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension HTTPClientResponse.Body { internal class IteratorStream { struct ID: Hashable { diff --git a/Sources/AsyncHTTPClient/AsyncAwait/Transaction+StateMachine.swift b/Sources/AsyncHTTPClient/AsyncAwait/Transaction+StateMachine.swift index 98fce4aed..dea1093db 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/Transaction+StateMachine.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/Transaction+StateMachine.swift @@ -11,12 +11,12 @@ // SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// -#if compiler(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) import Logging import NIOCore import NIOHTTP1 -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Transaction { struct StateMachine { struct ExecutionContext { diff --git a/Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift b/Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift index f7a3ab03d..c2ce52eeb 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift @@ -12,14 +12,14 @@ // //===----------------------------------------------------------------------===// -#if compiler(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) import Logging import NIOConcurrencyHelpers import NIOCore import NIOHTTP1 import NIOSSL -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) final class Transaction: @unchecked Sendable { let logger: Logger @@ -145,7 +145,7 @@ final class Transaction: @unchecked Sendable { // MARK: - Protocol Methods - -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Transaction: HTTPSchedulableRequest { var poolKey: ConnectionPool.Key { self.request.poolKey } var tlsConfiguration: TLSConfiguration? { return nil } @@ -158,7 +158,7 @@ extension Transaction: HTTPSchedulableRequest { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Transaction: HTTPExecutableRequest { var requestHead: HTTPRequestHead { self.request.head } @@ -316,7 +316,7 @@ extension Transaction: HTTPExecutableRequest { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Transaction { func responseBodyDeinited() { let deinitedAction = self.stateLock.withLock { diff --git a/Tests/AsyncHTTPClientTests/AsyncAwaitEndToEndTests.swift b/Tests/AsyncHTTPClientTests/AsyncAwaitEndToEndTests.swift index 7c5f61681..314695e97 100644 --- a/Tests/AsyncHTTPClientTests/AsyncAwaitEndToEndTests.swift +++ b/Tests/AsyncHTTPClientTests/AsyncAwaitEndToEndTests.swift @@ -34,8 +34,8 @@ private func makeDefaultHTTPClient( final class AsyncAwaitEndToEndTests: XCTestCase { func testSimpleGet() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -57,8 +57,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testSimplePost() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -80,8 +80,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testPostWithByteBuffer() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) { _ in HTTPEchoHandler() } defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -105,8 +105,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testPostWithSequenceOfUInt8() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) { _ in HTTPEchoHandler() } defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -130,8 +130,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testPostWithCollectionOfUInt8() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) { _ in HTTPEchoHandler() } defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -155,8 +155,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testPostWithRandomAccessCollectionOfUInt8() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) { _ in HTTPEchoHandler() } defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -180,8 +180,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testPostWithAsyncSequenceOfByteBuffers() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) { _ in HTTPEchoHandler() } defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -209,8 +209,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testPostWithAsyncSequenceOfUInt8() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) { _ in HTTPEchoHandler() } defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -234,8 +234,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testPostWithFragmentedAsyncSequenceOfByteBuffers() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) { _ in HTTPEchoHandler() } defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -276,8 +276,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testPostWithFragmentedAsyncSequenceOfLargeByteBuffers() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let bin = HTTPBin(.http2(compress: false)) { _ in HTTPEchoHandler() } defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -319,8 +319,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testCanceling() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest(timeout: 5) { let bin = HTTPBin(.http2(compress: false)) defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -344,8 +344,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testDeadline() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest(timeout: 5) { let bin = HTTPBin(.http2(compress: false)) defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -365,8 +365,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testImmediateDeadline() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest(timeout: 5) { let bin = HTTPBin(.http2(compress: false)) defer { XCTAssertNoThrow(try bin.shutdown()) } @@ -386,8 +386,8 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } func testInvalidURL() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest(timeout: 5) { let client = makeDefaultHTTPClient() defer { XCTAssertNoThrow(try client.syncShutdown()) } @@ -402,7 +402,7 @@ final class AsyncAwaitEndToEndTests: XCTestCase { } } -#if compiler(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) extension AsyncSequence where Element == ByteBuffer { func collect() async rethrows -> ByteBuffer { try await self.reduce(into: ByteBuffer()) { accumulatingBuffer, nextBuffer in diff --git a/Tests/AsyncHTTPClientTests/AsyncTestHelpers.swift b/Tests/AsyncHTTPClientTests/AsyncTestHelpers.swift index 36813091f..7167e6a2b 100644 --- a/Tests/AsyncHTTPClientTests/AsyncTestHelpers.swift +++ b/Tests/AsyncHTTPClientTests/AsyncTestHelpers.swift @@ -16,7 +16,7 @@ import NIOConcurrencyHelpers import NIOCore -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) class AsyncSequenceWriter: AsyncSequence { typealias AsyncIterator = Iterator diff --git a/Tests/AsyncHTTPClientTests/HTTPClientRequestTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientRequestTests.swift index 082f37761..f47b0ef93 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientRequestTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientRequestTests.swift @@ -17,17 +17,17 @@ import NIOCore import XCTest class HTTPClientRequestTests: XCTestCase { - #if compiler(>=5.5) && canImport(_Concurrency) - @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) + #if compiler(>=5.5.2) && canImport(_Concurrency) + @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) private typealias Request = HTTPClientRequest - @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) + @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) private typealias PreparedRequest = HTTPClientRequest.Prepared #endif func testCustomHeadersAreRespected() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "https://example.com/get") request.headers = [ @@ -62,8 +62,8 @@ class HTTPClientRequestTests: XCTestCase { } func testUnixScheme() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "unix://%2Fexample%2Ffolder.sock/some_path") request.headers = ["custom-header": "custom-value"] @@ -93,8 +93,8 @@ class HTTPClientRequestTests: XCTestCase { } func testHTTPUnixScheme() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "http+unix://%2Fexample%2Ffolder.sock/some_path") request.headers = ["custom-header": "custom-value"] @@ -124,8 +124,8 @@ class HTTPClientRequestTests: XCTestCase { } func testHTTPSUnixScheme() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "https+unix://%2Fexample%2Ffolder.sock/some_path") request.headers = ["custom-header": "custom-value"] @@ -155,8 +155,8 @@ class HTTPClientRequestTests: XCTestCase { } func testGetWithoutBody() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let request = Request(url: "https://example.com/get") var preparedRequest: PreparedRequest? @@ -185,8 +185,8 @@ class HTTPClientRequestTests: XCTestCase { } func testPostWithoutBody() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "http://example.com/post") request.method = .POST @@ -220,8 +220,8 @@ class HTTPClientRequestTests: XCTestCase { } func testPostWithEmptyByteBuffer() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "http://example.com/post") request.method = .POST @@ -256,8 +256,8 @@ class HTTPClientRequestTests: XCTestCase { } func testPostWithByteBuffer() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "http://example.com/post") request.method = .POST @@ -291,8 +291,8 @@ class HTTPClientRequestTests: XCTestCase { } func testPostWithSequenceOfUnknownLength() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "http://example.com/post") request.method = .POST @@ -327,8 +327,8 @@ class HTTPClientRequestTests: XCTestCase { } func testPostWithSequenceWithFixedLength() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "http://example.com/post") request.method = .POST @@ -364,8 +364,8 @@ class HTTPClientRequestTests: XCTestCase { } func testPostWithRandomAccessCollection() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "http://example.com/post") request.method = .POST @@ -400,8 +400,8 @@ class HTTPClientRequestTests: XCTestCase { } func testPostWithAsyncSequenceOfUnknownLength() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "http://example.com/post") request.method = .POST @@ -441,8 +441,8 @@ class HTTPClientRequestTests: XCTestCase { } func testPostWithAsyncSequenceWithKnownLength() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { var request = Request(url: "http://example.com/post") request.method = .POST @@ -482,13 +482,13 @@ class HTTPClientRequestTests: XCTestCase { } } -#if compiler(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) private struct LengthMismatch: Error { var announcedLength: Int var actualLength: Int } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Optional where Wrapped == HTTPClientRequest.Body { /// Accumulates all data from `self` into a single `ByteBuffer` and checks that the user specified length matches /// the length of the accumulated data. @@ -549,7 +549,7 @@ extension Collection { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) struct AsyncSequenceFromSyncSequence: AsyncSequence { typealias Element = Wrapped.Element struct AsyncIterator: AsyncIteratorProtocol { @@ -566,7 +566,7 @@ struct AsyncSequenceFromSyncSequence: AsyncSequence { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Sequence { /// Turns `self` into an `AsyncSequence` by wending each element of `self` asynchronously. func asAsyncSequence() -> AsyncSequenceFromSyncSequence { diff --git a/Tests/AsyncHTTPClientTests/Transaction+StateMachineTests.swift b/Tests/AsyncHTTPClientTests/Transaction+StateMachineTests.swift index 3237d19e8..ff1972330 100644 --- a/Tests/AsyncHTTPClientTests/Transaction+StateMachineTests.swift +++ b/Tests/AsyncHTTPClientTests/Transaction+StateMachineTests.swift @@ -20,8 +20,8 @@ import XCTest final class Transaction_StateMachineTests: XCTestCase { func testRequestWasQueuedAfterWillExecuteRequestWasCalled() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } let eventLoop = EmbeddedEventLoop() XCTAsyncTest { func workaround(_ continuation: CheckedContinuation) { @@ -50,8 +50,8 @@ final class Transaction_StateMachineTests: XCTestCase { } func testRequestBodyStreamWasPaused() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } let eventLoop = EmbeddedEventLoop() XCTAsyncTest { func workaround(_ continuation: CheckedContinuation) { @@ -73,8 +73,8 @@ final class Transaction_StateMachineTests: XCTestCase { } func testQueuedRequestGetsRemovedWhenDeadlineExceeded() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { func workaround(_ continuation: CheckedContinuation) { var state = Transaction.StateMachine(continuation) @@ -97,8 +97,8 @@ final class Transaction_StateMachineTests: XCTestCase { } func testScheduledRequestGetsRemovedWhenDeadlineExceeded() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } let eventLoop = EmbeddedEventLoop() XCTAsyncTest { func workaround(_ continuation: CheckedContinuation) { @@ -124,8 +124,8 @@ final class Transaction_StateMachineTests: XCTestCase { } func testRequestWithHeadReceivedGetNotCancelledWhenDeadlineExceeded() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } let eventLoop = EmbeddedEventLoop() XCTAsyncTest { func workaround(_ continuation: CheckedContinuation) { @@ -154,8 +154,8 @@ final class Transaction_StateMachineTests: XCTestCase { } } -#if compiler(>=5.5) && canImport(_Concurrency) -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +#if compiler(>=5.5.2) && canImport(_Concurrency) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Transaction.StateMachine.StartExecutionAction: Equatable { public static func == (lhs: Self, rhs: Self) -> Bool { switch (lhs, rhs) { @@ -172,7 +172,7 @@ extension Transaction.StateMachine.StartExecutionAction: Equatable { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Transaction.StateMachine.ResumeProducingAction: Equatable { public static func == (lhs: Self, rhs: Self) -> Bool { switch (lhs, rhs) { @@ -188,7 +188,7 @@ extension Transaction.StateMachine.ResumeProducingAction: Equatable { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Transaction.StateMachine.NextWriteAction: Equatable { public static func == (lhs: Self, rhs: Self) -> Bool { switch (lhs, rhs) { diff --git a/Tests/AsyncHTTPClientTests/TransactionTests.swift b/Tests/AsyncHTTPClientTests/TransactionTests.swift index 9513605f7..8857253b6 100644 --- a/Tests/AsyncHTTPClientTests/TransactionTests.swift +++ b/Tests/AsyncHTTPClientTests/TransactionTests.swift @@ -21,15 +21,15 @@ import NIOHTTP1 import NIOPosix import XCTest -#if compiler(>=5.5) && canImport(_Concurrency) -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +#if compiler(>=5.5.2) && canImport(_Concurrency) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) typealias PreparedRequest = HTTPClientRequest.Prepared #endif final class TransactionTests: XCTestCase { func testCancelAsyncRequest() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let embeddedEventLoop = EmbeddedEventLoop() defer { XCTAssertNoThrow(try embeddedEventLoop.syncShutdownGracefully()) } @@ -64,8 +64,8 @@ final class TransactionTests: XCTestCase { } func testResponseStreamingWorks() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let embeddedEventLoop = EmbeddedEventLoop() defer { XCTAssertNoThrow(try embeddedEventLoop.syncShutdownGracefully()) } @@ -127,8 +127,8 @@ final class TransactionTests: XCTestCase { } func testIgnoringResponseBodyWorks() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let embeddedEventLoop = EmbeddedEventLoop() defer { XCTAssertNoThrow(try embeddedEventLoop.syncShutdownGracefully()) } @@ -178,8 +178,8 @@ final class TransactionTests: XCTestCase { } func testWriteBackpressureWorks() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let embeddedEventLoop = EmbeddedEventLoop() defer { XCTAssertNoThrow(try embeddedEventLoop.syncShutdownGracefully()) } @@ -252,8 +252,8 @@ final class TransactionTests: XCTestCase { } func testSimpleGetRequest() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) let eventLoop = eventLoopGroup.next() @@ -310,8 +310,8 @@ final class TransactionTests: XCTestCase { } func testSimplePostRequest() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let embeddedEventLoop = EmbeddedEventLoop() defer { XCTAssertNoThrow(try embeddedEventLoop.syncShutdownGracefully()) } @@ -350,8 +350,8 @@ final class TransactionTests: XCTestCase { } func testPostStreamFails() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let embeddedEventLoop = EmbeddedEventLoop() defer { XCTAssertNoThrow(try embeddedEventLoop.syncShutdownGracefully()) } @@ -395,8 +395,8 @@ final class TransactionTests: XCTestCase { } func testResponseStreamFails() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let embeddedEventLoop = EmbeddedEventLoop() defer { XCTAssertNoThrow(try embeddedEventLoop.syncShutdownGracefully()) } @@ -458,8 +458,8 @@ final class TransactionTests: XCTestCase { } func testBiDirectionalStreamingHTTP2() { - #if compiler(>=5.5) && canImport(_Concurrency) - guard #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) else { return } + #if compiler(>=5.5.2) && canImport(_Concurrency) + guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return } XCTAsyncTest { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) let eventLoop = eventLoopGroup.next() @@ -533,12 +533,12 @@ final class TransactionTests: XCTestCase { } } -#if compiler(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) // This needs a small explanation. If an iterator is a struct, it can't be used across multiple // tasks. Since we want to wait for things to happen in tests, we need to `async let`, which creates // implicit tasks. Therefore we need to wrap our iterator struct. -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) actor SharedIterator { private var iterator: Iterator @@ -553,7 +553,7 @@ actor SharedIterator { } } -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) extension Transaction { fileprivate static func makeWithResultTask( request: PreparedRequest, diff --git a/Tests/AsyncHTTPClientTests/XCTest+AsyncAwait.swift b/Tests/AsyncHTTPClientTests/XCTest+AsyncAwait.swift index f26e11582..66a8d6bb5 100644 --- a/Tests/AsyncHTTPClientTests/XCTest+AsyncAwait.swift +++ b/Tests/AsyncHTTPClientTests/XCTest+AsyncAwait.swift @@ -30,7 +30,7 @@ import XCTest extension XCTestCase { - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) /// Cross-platform XCTest support for async-await tests. /// /// Currently the Linux implementation of XCTest doesn't have async-await support. @@ -61,7 +61,7 @@ extension XCTestCase { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) internal func XCTAssertThrowsError( _ expression: @autoclosure () async throws -> T, verify: (Error) -> Void = { _ in }, @@ -76,7 +76,7 @@ internal func XCTAssertThrowsError( } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) internal func XCTAssertNoThrowWithResult( _ expression: @autoclosure () async throws -> Result, file: StaticString = #file, From 27cdfa438372e7ffd352f2c513221a2e9fb3bfdb Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Fri, 17 Dec 2021 15:21:08 +0100 Subject: [PATCH 6/7] use compiler instead of swift --- Tests/AsyncHTTPClientTests/AsyncTestHelpers.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/AsyncHTTPClientTests/AsyncTestHelpers.swift b/Tests/AsyncHTTPClientTests/AsyncTestHelpers.swift index 7167e6a2b..312008959 100644 --- a/Tests/AsyncHTTPClientTests/AsyncTestHelpers.swift +++ b/Tests/AsyncHTTPClientTests/AsyncTestHelpers.swift @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#if swift(>=5.5) && canImport(_Concurrency) +#if compiler(>=5.5.2) && canImport(_Concurrency) import NIOConcurrencyHelpers import NIOCore From 6b47d268174f5aeb90bbfa7878524ce038648a04 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Fri, 17 Dec 2021 15:52:46 +0100 Subject: [PATCH 7/7] replace last outstanding 5.5 reference with 5.5.2 --- Tests/AsyncHTTPClientTests/XCTest+AsyncAwait.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/AsyncHTTPClientTests/XCTest+AsyncAwait.swift b/Tests/AsyncHTTPClientTests/XCTest+AsyncAwait.swift index 66a8d6bb5..fbc429b10 100644 --- a/Tests/AsyncHTTPClientTests/XCTest+AsyncAwait.swift +++ b/Tests/AsyncHTTPClientTests/XCTest+AsyncAwait.swift @@ -26,7 +26,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#if compiler(>=5.5) +#if compiler(>=5.5.2) && canImport(_Concurrency) import XCTest extension XCTestCase { @@ -90,4 +90,4 @@ internal func XCTAssertNoThrowWithResult( return nil } -#endif // compiler(>=5.5) +#endif