From 56fc64ed3a0e658871ae1b84e801b50041efe61d Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Fri, 27 Dec 2024 10:28:26 -0800 Subject: [PATCH 01/18] Unchecked sendable everywhere but builds with a change in C and a lot of warnings --- Package.swift | 2 +- .../auth/credentials/Credentials.swift | 2 +- .../credentials/CredentialsProvider.swift | 13 +++++----- .../auth/imds/IMDSClient.swift | 2 +- .../auth/imds/IMDSInstanceInfo.swift | 2 +- .../auth/signing/Signer.swift | 5 ++-- .../AwsCommonRuntimeKit/crt/Allocator.swift | 5 +++- .../crt/CommonRuntimeError.swift | 2 +- Source/AwsCommonRuntimeKit/crt/Logger.swift | 2 +- .../AwsCommonRuntimeKit/crt/Utilities.swift | 6 +++++ .../http/HTTPClientConnection.swift | 2 +- ...PClientConnectionManagerCallbackCore.swift | 2 +- .../AwsCommonRuntimeKit/http/HTTPStream.swift | 2 +- .../AwsCommonRuntimeKit/io/HostAddress.swift | 2 +- .../AwsCommonRuntimeKit/io/HostResolver.swift | 2 +- .../io/retryer/RetryToken.swift | 2 +- Source/Elasticurl/CommandLine.swift | 9 ++++--- Source/Elasticurl/Elasticurl.swift | 26 +++++++++++-------- 18 files changed, 52 insertions(+), 36 deletions(-) diff --git a/Package.swift b/Package.swift index 98535e612..b452e5b58 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.7 +// swift-tools-version:6.0 import PackageDescription let excludesFromAll = ["tests", "cmake", "CONTRIBUTING.md", diff --git a/Source/AwsCommonRuntimeKit/auth/credentials/Credentials.swift b/Source/AwsCommonRuntimeKit/auth/credentials/Credentials.swift index 0cedf7c29..45cf854e4 100644 --- a/Source/AwsCommonRuntimeKit/auth/credentials/Credentials.swift +++ b/Source/AwsCommonRuntimeKit/auth/credentials/Credentials.swift @@ -4,7 +4,7 @@ import AwsCAuth import Foundation -public final class Credentials { +public final class Credentials : @unchecked Sendable { let rawValue: OpaquePointer diff --git a/Source/AwsCommonRuntimeKit/auth/credentials/CredentialsProvider.swift b/Source/AwsCommonRuntimeKit/auth/credentials/CredentialsProvider.swift index 5d9b4b9e9..13aad59b8 100644 --- a/Source/AwsCommonRuntimeKit/auth/credentials/CredentialsProvider.swift +++ b/Source/AwsCommonRuntimeKit/auth/credentials/CredentialsProvider.swift @@ -10,7 +10,7 @@ public protocol CredentialsProviding { func getCredentials() async throws -> Credentials } -public class CredentialsProvider: CredentialsProviding { +public class CredentialsProvider: CredentialsProviding, @unchecked Sendable { let rawValue: UnsafeMutablePointer @@ -590,7 +590,7 @@ private func onGetCredentials(credentials: OpaquePointer?, // We need to share this pointer to C in a task block but Swift compiler complains // that Pointer does not conform to Sendable. Wrap the pointer in a @unchecked Sendable block // for Swift compiler to stop complaining. -struct SendablePointer: @unchecked Sendable { +struct SendableRawPointer: @unchecked Sendable { let pointer: UnsafeMutableRawPointer } @@ -600,12 +600,13 @@ private func getCredentialsDelegateFn(_ delegatePtr: UnsafeMutableRawPointer!, Int32, UnsafeMutableRawPointer?) -> Void)!, _ userData: UnsafeMutableRawPointer!) -> Int32 { - let delegate = Unmanaged> - .fromOpaque(delegatePtr) - .takeUnretainedValue().contents - let userData = SendablePointer(pointer: userData) + let userData = SendableRawPointer(pointer: userData) + let delegatePtr = SendableRawPointer(pointer: delegatePtr) Task { do { + let delegate = Unmanaged> + .fromOpaque(delegatePtr.pointer) + .takeUnretainedValue().contents let credentials = try await delegate.getCredentials() callbackFn(credentials.rawValue, AWS_OP_SUCCESS, userData.pointer) } catch CommonRunTimeError.crtError(let crtError) { diff --git a/Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift b/Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift index de3622a94..1344d9e9f 100644 --- a/Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift +++ b/Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift @@ -4,7 +4,7 @@ import AwsCAuth // swiftlint:disable type_body_length -public class IMDSClient { +public class IMDSClient: @unchecked Sendable { let rawValue: OpaquePointer /// Creates an IMDSClient that always uses IMDSv2 diff --git a/Source/AwsCommonRuntimeKit/auth/imds/IMDSInstanceInfo.swift b/Source/AwsCommonRuntimeKit/auth/imds/IMDSInstanceInfo.swift index e10fd4b2d..4837e1d56 100644 --- a/Source/AwsCommonRuntimeKit/auth/imds/IMDSInstanceInfo.swift +++ b/Source/AwsCommonRuntimeKit/auth/imds/IMDSInstanceInfo.swift @@ -4,7 +4,7 @@ import AwsCAuth import Foundation -public struct IMDSInstanceInfo { +public struct IMDSInstanceInfo: Sendable { public let marketPlaceProductCodes: [String] public let availabilityZone: String public let privateIp: String diff --git a/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift b/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift index e815f071a..cee289eae 100644 --- a/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift +++ b/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift @@ -164,7 +164,7 @@ public class Signer { } } -class SignRequestCore { +class SignRequestCore : @unchecked Sendable { let request: HTTPRequestBase var continuation: CheckedContinuation let shouldSignHeader: ((String) -> Bool)? @@ -220,9 +220,10 @@ private func onSigningComplete(signingResult: UnsafeMutablePointer! + let signature = AWSString("signature") guard aws_signing_result_get_property( signingResult!, - g_aws_signature_property_name, + signature.rawValue, &awsStringPointer) == AWS_OP_SUCCESS else { chunkSignerCore.continuation.resume(throwing: CommonRunTimeError.crtError(.makeFromLastError())) return diff --git a/Source/AwsCommonRuntimeKit/crt/Allocator.swift b/Source/AwsCommonRuntimeKit/crt/Allocator.swift index 1923ff779..eeece7269 100644 --- a/Source/AwsCommonRuntimeKit/crt/Allocator.swift +++ b/Source/AwsCommonRuntimeKit/crt/Allocator.swift @@ -6,7 +6,10 @@ import AwsCCommon The default allocator. You are probably looking to use `allocator` instead. */ -var allocator = aws_default_allocator()! +// TODO: Is there a better way to do this? +extension UnsafeMutablePointer: @unchecked @retroactive Sendable where Pointee == aws_allocator {} + +let allocator = aws_default_allocator()! /// An allocator is used to allocate memory on the heap. protocol Allocator { diff --git a/Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift b/Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift index c57b21820..258b020a4 100644 --- a/Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift +++ b/Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift @@ -8,7 +8,7 @@ public enum CommonRunTimeError: Error { case crtError(CRTError) } -public struct CRTError: Equatable { +public struct CRTError: Equatable, Sendable { public let code: Int32 public let message: String public let name: String diff --git a/Source/AwsCommonRuntimeKit/crt/Logger.swift b/Source/AwsCommonRuntimeKit/crt/Logger.swift index 03d24ba6b..1c3aa0992 100644 --- a/Source/AwsCommonRuntimeKit/crt/Logger.swift +++ b/Source/AwsCommonRuntimeKit/crt/Logger.swift @@ -10,7 +10,7 @@ public enum LogTarget { case filePath(String) } -public struct Logger { +public actor Logger { private static var logger: aws_logger? private static let lock = NSLock() diff --git a/Source/AwsCommonRuntimeKit/crt/Utilities.swift b/Source/AwsCommonRuntimeKit/crt/Utilities.swift index 8dda4c10f..455215c35 100644 --- a/Source/AwsCommonRuntimeKit/crt/Utilities.swift +++ b/Source/AwsCommonRuntimeKit/crt/Utilities.swift @@ -5,6 +5,12 @@ import struct Foundation.Data import struct Foundation.TimeInterval import AwsCCal + + +struct SendablePointer: @unchecked Sendable { + let pointer: UnsafeMutablePointer +} + /// This class is used to add reference counting to stuff that do not support it /// like Structs, Closures, and Protocols etc by wrapping it in a Class. /// This also allows us to use anything with Unmanaged which we required for C callbacks. diff --git a/Source/AwsCommonRuntimeKit/http/HTTPClientConnection.swift b/Source/AwsCommonRuntimeKit/http/HTTPClientConnection.swift index a38643b2f..b547c180c 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTPClientConnection.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTPClientConnection.swift @@ -6,7 +6,7 @@ import AwsCIo import Foundation // swiftlint:disable force_try -public class HTTPClientConnection { +public class HTTPClientConnection: @unchecked Sendable { let rawValue: UnsafeMutablePointer /// This will keep the connection manager alive until connection is alive let manager: HTTPClientConnectionManager diff --git a/Source/AwsCommonRuntimeKit/http/HTTPClientConnectionManagerCallbackCore.swift b/Source/AwsCommonRuntimeKit/http/HTTPClientConnectionManagerCallbackCore.swift index 82b11a499..7658bca41 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTPClientConnectionManagerCallbackCore.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTPClientConnectionManagerCallbackCore.swift @@ -47,7 +47,7 @@ private func onConnectionSetup(connection: UnsafeMutablePointer var callbackData: HTTPStreamCallbackCore diff --git a/Source/AwsCommonRuntimeKit/io/HostAddress.swift b/Source/AwsCommonRuntimeKit/io/HostAddress.swift index 1ce7646d1..27cca3c32 100644 --- a/Source/AwsCommonRuntimeKit/io/HostAddress.swift +++ b/Source/AwsCommonRuntimeKit/io/HostAddress.swift @@ -4,7 +4,7 @@ import AwsCIo /// Represents a single HostAddress resolved by the Host Resolver -public struct HostAddress: CStruct { +public struct HostAddress: CStruct, @unchecked Sendable { /// Address type is ipv4 or ipv6 public let addressType: HostAddressType diff --git a/Source/AwsCommonRuntimeKit/io/HostResolver.swift b/Source/AwsCommonRuntimeKit/io/HostResolver.swift index ca17a9cd8..2fe598b46 100644 --- a/Source/AwsCommonRuntimeKit/io/HostResolver.swift +++ b/Source/AwsCommonRuntimeKit/io/HostResolver.swift @@ -24,7 +24,7 @@ public protocol HostResolverProtocol { } /// CRT Host Resolver which performs async DNS lookups -public class HostResolver: HostResolverProtocol { +public class HostResolver: HostResolverProtocol, @unchecked Sendable { let rawValue: UnsafeMutablePointer let maxTTL: Int diff --git a/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift b/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift index 745c60d20..424f33957 100644 --- a/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift +++ b/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift @@ -4,7 +4,7 @@ import AwsCIo /// This is just a wrapper for aws_retry_token which user can not create themself but pass around once acquired. -public class RetryToken { +public class RetryToken: @unchecked Sendable { let rawValue: UnsafeMutablePointer init(rawValue: UnsafeMutablePointer) { diff --git a/Source/Elasticurl/CommandLine.swift b/Source/Elasticurl/CommandLine.swift index 4b2f3748f..5bde795b3 100644 --- a/Source/Elasticurl/CommandLine.swift +++ b/Source/Elasticurl/CommandLine.swift @@ -5,7 +5,7 @@ import Foundation import AwsCCommon // swiftlint:disable trailing_whitespace -struct CommandLineParser { +struct CommandLineParser : @unchecked Sendable { /// A function to parse command line arguments /// - Parameters: /// - argc: The number of arguments @@ -16,6 +16,7 @@ struct CommandLineParser { /// - Returns: A dictionary of`[String: Any] ` with `String` as the name of the flag and `Any` as the /// value passed in public static func parseArguments(argc: Int32, + arguments: UnsafeMutablePointer?>, optionString: String, options: [aws_cli_option]) -> [String: Any] { @@ -27,8 +28,8 @@ struct CommandLineParser { break } if let char = UnicodeScalar(Int(opt)) { - if aws_cli_optarg != nil { - argumentsDict[String(char)] = String(cString: aws_cli_optarg) + if get_cli_optarg() != nil { + argumentsDict[String(char)] = String(cString: get_cli_optarg()) } else { // if argument doesnt have a value just mark it as present in the dictionary argumentsDict[String(char)] = true @@ -60,7 +61,7 @@ extension CLIHasArg: RawRepresentable, CaseIterable { } } -class AWSCLIOption { +class AWSCLIOption: @unchecked Sendable { let rawValue: aws_cli_option let name: UnsafeMutablePointer init(name: String, hasArg: CLIHasArg, flag: UnsafeMutablePointer? = nil, val: String) { diff --git a/Source/Elasticurl/Elasticurl.swift b/Source/Elasticurl/Elasticurl.swift index bc782e230..4ecfa2564 100644 --- a/Source/Elasticurl/Elasticurl.swift +++ b/Source/Elasticurl/Elasticurl.swift @@ -6,7 +6,7 @@ import AwsCommonRuntimeKit import Foundation // swiftlint:disable cyclomatic_complexity function_body_length -struct Context { +struct Context : @unchecked Sendable { // args public var logLevel: LogLevel = .trace public var verb: String = "GET" @@ -27,11 +27,10 @@ struct Context { } @main -struct Elasticurl { +struct Elasticurl : @unchecked Sendable { private static let version = "0.1.0" - private static var context = Context() - static func parseArguments() { + static func parseArguments() -> Context { let optionString = "a:b:c:e:f:H:d:g:j:l:m:M:GPHiko:t:v:VwWh" let options = [ElasticurlOptions.caCert.rawValue, ElasticurlOptions.caPath.rawValue, @@ -63,6 +62,8 @@ struct Elasticurl { arguments: CommandLine.unsafeArgv, optionString: optionString, options: options) + + var context = Context() if let caCert = argumentsDict["a"] as? String { context.caCert = caCert } @@ -176,6 +177,7 @@ struct Elasticurl { exit(-1) } context.url = url + return context } static func showHelp() { @@ -202,22 +204,24 @@ struct Elasticurl { print(" -h, --help: Display this message and quit.") } - static func createOutputFile() { + static func createOutputFile(context: Context) -> Context { + var context = context if let fileName = context.outputFileName { let fileManager = FileManager.default let path = FileManager.default.currentDirectoryPath + "/" + fileName fileManager.createFile(atPath: path, contents: nil, attributes: nil) context.outputStream = FileHandle(forWritingAtPath: fileName) ?? FileHandle.standardOutput } + return context } - static func writeData(data: Data) { + static func writeData(data: Data, context: Context) { context.outputStream.write(data) } static func main() async { - parseArguments() - createOutputFile() + var context = parseArguments() + context = createOutputFile(context: context) if let traceFile = context.traceFile { print("enable logging with trace file") try? Logger.initialize(target: .filePath(traceFile), level: context.logLevel) @@ -226,10 +230,10 @@ struct Elasticurl { try? Logger.initialize(target: .standardOutput, level: context.logLevel) } - await run() + await run(context) } - static func run() async { + static func run(_ context: Context) async { do { guard let host = context.url.host else { print("no proper host was parsed from the url. quitting.") @@ -291,7 +295,7 @@ struct Elasticurl { } let onBody: HTTPRequestOptions.OnIncomingBody = { bodyChunk in - writeData(data: bodyChunk) + writeData(data: bodyChunk, context: context) } let onComplete: HTTPRequestOptions.OnStreamComplete = { result in From 2e659acf6406fa380b9c9cd8f4fd0699b41b1532 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Fri, 27 Dec 2024 16:05:32 -0800 Subject: [PATCH 02/18] some docs --- Source/AwsCommonRuntimeKit/auth/credentials/Credentials.swift | 4 +++- .../auth/credentials/CredentialsProvider.swift | 2 ++ Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift | 2 ++ Source/AwsCommonRuntimeKit/auth/signing/Signer.swift | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/AwsCommonRuntimeKit/auth/credentials/Credentials.swift b/Source/AwsCommonRuntimeKit/auth/credentials/Credentials.swift index 45cf854e4..4ad30d200 100644 --- a/Source/AwsCommonRuntimeKit/auth/credentials/Credentials.swift +++ b/Source/AwsCommonRuntimeKit/auth/credentials/Credentials.swift @@ -4,7 +4,9 @@ import AwsCAuth import Foundation -public final class Credentials : @unchecked Sendable { +// We can't mutate this class after initialization. Swift can not verify the sendability due to OpaquePointer, +// So mark it unchecked Sendable +public final class Credentials: @unchecked Sendable { let rawValue: OpaquePointer diff --git a/Source/AwsCommonRuntimeKit/auth/credentials/CredentialsProvider.swift b/Source/AwsCommonRuntimeKit/auth/credentials/CredentialsProvider.swift index 13aad59b8..4c278e2b5 100644 --- a/Source/AwsCommonRuntimeKit/auth/credentials/CredentialsProvider.swift +++ b/Source/AwsCommonRuntimeKit/auth/credentials/CredentialsProvider.swift @@ -10,6 +10,8 @@ public protocol CredentialsProviding { func getCredentials() async throws -> Credentials } +// We can't mutate this class after initialization. Swift can not verify the sendability due to pointer, +// So mark it unchecked Sendable public class CredentialsProvider: CredentialsProviding, @unchecked Sendable { let rawValue: UnsafeMutablePointer diff --git a/Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift b/Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift index 1344d9e9f..4e58ab73f 100644 --- a/Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift +++ b/Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift @@ -4,6 +4,8 @@ import AwsCAuth // swiftlint:disable type_body_length +// We can't mutate this class after initialization. Swift can not verify the sendability due to OpaquePointer, +// So mark it unchecked Sendable public class IMDSClient: @unchecked Sendable { let rawValue: OpaquePointer diff --git a/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift b/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift index cee289eae..00ac6d4bb 100644 --- a/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift +++ b/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift @@ -164,7 +164,7 @@ public class Signer { } } -class SignRequestCore : @unchecked Sendable { +class SignRequestCore: @unchecked Sendable { let request: HTTPRequestBase var continuation: CheckedContinuation let shouldSignHeader: ((String) -> Bool)? From 16c705bd9400650808715b4a47d04d7fb4178c24 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 30 Dec 2024 11:45:11 -0800 Subject: [PATCH 03/18] warning fix plus tests in progress --- .../auth/imds/IAMProfile.swift | 2 +- .../AwsCommonRuntimeKit/crt/Allocator.swift | 14 +- .../http/HTTP1Stream.swift | 2 +- .../http/HTTP2ClientConnection.swift | 2 +- .../http/HTTP2Stream.swift | 2 +- .../http/HTTPClientTestFixture.swift | 127 +++++++++--------- .../http/HTTPTests.swift | 23 ++-- .../io/RetryerTests.swift | 2 +- 8 files changed, 88 insertions(+), 86 deletions(-) diff --git a/Source/AwsCommonRuntimeKit/auth/imds/IAMProfile.swift b/Source/AwsCommonRuntimeKit/auth/imds/IAMProfile.swift index 95a604d7d..3df71909d 100644 --- a/Source/AwsCommonRuntimeKit/auth/imds/IAMProfile.swift +++ b/Source/AwsCommonRuntimeKit/auth/imds/IAMProfile.swift @@ -4,7 +4,7 @@ import AwsCAuth import Foundation -public struct IAMProfile { +public struct IAMProfile: Sendable { public let lastUpdated: Date public let profileArn: String public let profileId: String diff --git a/Source/AwsCommonRuntimeKit/crt/Allocator.swift b/Source/AwsCommonRuntimeKit/crt/Allocator.swift index eeece7269..dde614f0a 100644 --- a/Source/AwsCommonRuntimeKit/crt/Allocator.swift +++ b/Source/AwsCommonRuntimeKit/crt/Allocator.swift @@ -2,14 +2,14 @@ // SPDX-License-Identifier: Apache-2.0. import AwsCCommon -/** - The default allocator. - You are probably looking to use `allocator` instead. - */ -// TODO: Is there a better way to do this? -extension UnsafeMutablePointer: @unchecked @retroactive Sendable where Pointee == aws_allocator {} -let allocator = aws_default_allocator()! +/* + * The default allocator. + * You are probably looking to use `allocator` instead. + * We need to declare `allocator` as mutable (`var`) instead of `let` because we override it with a tracing allocator in tests. This is not mutated anywhere else apart from the start of tests. + * Swift compiler doesn't let us compile this code due to global shared mutable state without locks, and complains that this is not safe. Disable the safety here since we know better than the compiler. + */ +nonisolated(unsafe) var allocator = aws_default_allocator()!.rawValue /// An allocator is used to allocate memory on the heap. protocol Allocator { diff --git a/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift b/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift index 089b3a8e3..eec089372 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift @@ -4,7 +4,7 @@ import AwsCHttp import Foundation /// An HTTP1Stream represents a single HTTP/1.1 specific Http Request/Response. -public class HTTP1Stream: HTTPStream { +public class HTTP1Stream: HTTPStream, @unchecked Sendable { /// Stream keeps a reference to HttpConnection to keep it alive private let httpConnection: HTTPClientConnection diff --git a/Source/AwsCommonRuntimeKit/http/HTTP2ClientConnection.swift b/Source/AwsCommonRuntimeKit/http/HTTP2ClientConnection.swift index c4e2c1321..c6ce6c715 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP2ClientConnection.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP2ClientConnection.swift @@ -5,7 +5,7 @@ import AwsCHttp import AwsCIo import Foundation -public class HTTP2ClientConnection: HTTPClientConnection { +public class HTTP2ClientConnection: HTTPClientConnection, @unchecked Sendable { /// Creates a new http2 stream from the `HTTPRequestOptions` given. /// - Parameter requestOptions: An `HTTPRequestOptions` struct containing callbacks on diff --git a/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift b/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift index c51c24b14..2a2c0cc04 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift @@ -5,7 +5,7 @@ import AwsCHttp import Foundation /// An HTTP2Stream represents a single HTTP/2 specific HTTP Request/Response. -public class HTTP2Stream: HTTPStream { +public class HTTP2Stream: HTTPStream, @unchecked Sendable { private let httpConnection: HTTPClientConnection? // Called by Connection Manager diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift index 80b87f9d4..63f7e5910 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift @@ -33,44 +33,43 @@ class HTTPClientTestFixture: XCBaseTestCase { onComplete: HTTPRequestOptions.OnStreamComplete? = nil) async throws -> HTTPResponse { var httpResponse = HTTPResponse() - let semaphore = DispatchSemaphore(value: 0) - - let httpRequestOptions: HTTPRequestOptions - if requestVersion == HTTPVersion.version_2 { - httpRequestOptions = try getHTTP2RequestOptions( - method: method, - path: path, - authority: endpoint, - body: body, - response: &httpResponse, - semaphore: semaphore, - onResponse: onResponse, - onBody: onBody, - onComplete: onComplete) - } else { - httpRequestOptions = try getHTTPRequestOptions( - method: method, - endpoint: endpoint, - path: path, - body: body, - response: &httpResponse, - semaphore: semaphore, - onResponse: onResponse, - onBody: onBody, - onComplete: onComplete) - } - - for i in 1...numRetries+1 where httpResponse.statusCode != expectedStatus { - print("Attempt#\(i) to send an HTTP request") - let connection = try await connectionManager.acquireConnection() - XCTAssertTrue(connection.isOpen) - httpResponse.version = connection.httpVersion - XCTAssertEqual(connection.httpVersion, expectedVersion) - let stream = try connection.makeRequest(requestOptions: httpRequestOptions) - try stream.activate() - semaphore.wait() + await withCheckedContinuation { (continuation: CheckedContinuation) in + Task { + let httpRequestOptions: HTTPRequestOption + if requestVersion == HTTPVersion.version_2 { + httpRequestOptions = try getHTTP2RequestOptions( + method: method, + path: path, + authority: endpoint, + body: body, + response: &httpResponse, + continuation: continuation, + onResponse: onResponse, + onBody: onBody, + onComplete: onComplete) + } else { + httpRequestOptions = try getHTTPRequestOptions( + method: method, + endpoint: endpoint, + path: path, + body: body, + response: &httpResponse, + continuation: continuation, + onResponse: onResponse, + onBody: onBody, + onComplete: onComplete) + } + + for i in 1...numRetries+1 where httpResponse.statusCode != expectedStatus { + print("Attempt#\(i) to send an HTTP request") + let connection = try await connectionManager.acquireConnection() + XCTAssertTrue(connection.isOpen) + httpResponse.version = connection.httpVersion + XCTAssertEqual(connection.httpVersion, expectedVersion) + let stream = try connection.makeRequest(requestOptions: httpRequestOptions) + try stream.activate() + } } - XCTAssertNil(httpResponse.error) XCTAssertEqual(httpResponse.statusCode, expectedStatus) return httpResponse @@ -90,28 +89,28 @@ class HTTPClientTestFixture: XCBaseTestCase { onComplete: HTTPRequestOptions.OnStreamComplete? = nil) async throws -> HTTPResponse { var httpResponse = HTTPResponse() - let semaphore = DispatchSemaphore(value: 0) - - let httpRequestOptions = try getHTTP2RequestOptions( - method: method, - path: path, - scheme: scheme, - authority: authority, - body: body, - response: &httpResponse, - semaphore: semaphore, - onResponse: onResponse, - onBody: onBody, - onComplete: onComplete, - http2ManualDataWrites: http2ManualDataWrites) - - for i in 1...numRetries+1 where httpResponse.statusCode != expectedStatus { - print("Attempt#\(i) to send an HTTP request") - let stream = try await streamManager.acquireStream(requestOptions: httpRequestOptions) - try stream.activate() - semaphore.wait() + await withCheckedContinuation { (continuation: CheckedContinuation) in + Task { + let httpRequestOptions = try getHTTP2RequestOptions( + method: method, + path: path, + scheme: scheme, + authority: authority, + body: body, + response: &httpResponse, + continutaion: continuation, + onResponse: onResponse, + onBody: onBody, + onComplete: onComplete, + http2ManualDataWrites: http2ManualDataWrites) + + for i in 1...numRetries+1 where httpResponse.statusCode != expectedStatus { + print("Attempt#\(i) to send an HTTP request") + let stream = try await streamManager.acquireStream(requestOptions: httpRequestOptions) + try stream.activate() + } + } } - XCTAssertNil(httpResponse.error) XCTAssertEqual(httpResponse.statusCode, expectedStatus) return httpResponse @@ -146,7 +145,7 @@ class HTTPClientTestFixture: XCBaseTestCase { func getRequestOptions(request: HTTPRequestBase, response: UnsafeMutablePointer? = nil, - semaphore: DispatchSemaphore? = nil, + continutaion: CheckedContinuation? = nil, onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, onComplete: HTTPRequestOptions.OnStreamComplete? = nil, @@ -170,7 +169,7 @@ class HTTPClientTestFixture: XCBaseTestCase { response?.pointee.error = error } onComplete?(result) - semaphore?.signal() + continutaion?.resume() }, http2ManualDataWrites: http2ManualDataWrites) } @@ -181,7 +180,7 @@ class HTTPClientTestFixture: XCBaseTestCase { path: String, body: String = "", response: UnsafeMutablePointer? = nil, - semaphore: DispatchSemaphore? = nil, + continutaion: CheckedContinuation? = nil, headers: [HTTPHeader] = [HTTPHeader](), onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, @@ -200,7 +199,7 @@ class HTTPClientTestFixture: XCBaseTestCase { return getRequestOptions( request: httpRequest, response: response, - semaphore: semaphore, + continutaion: continutaion, onResponse: onResponse, onBody: onBody, onComplete: onComplete) @@ -213,7 +212,7 @@ class HTTPClientTestFixture: XCBaseTestCase { body: String = "", manualDataWrites: Bool = false, response: UnsafeMutablePointer? = nil, - semaphore: DispatchSemaphore? = nil, + continutaion: CheckedContinuation? = nil, onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, onComplete: HTTPRequestOptions.OnStreamComplete? = nil, @@ -229,7 +228,7 @@ class HTTPClientTestFixture: XCBaseTestCase { return getRequestOptions( request: http2Request, response: response, - semaphore: semaphore, + continutaion: continutaion, onResponse: onResponse, onBody: onBody, onComplete: onComplete, diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift index c7c6ef796..0f44fb6c4 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift @@ -151,16 +151,18 @@ class HTTPTests: HTTPClientTestFixture { } func testStreamLivesUntilComplete() async throws { - let semaphore = DispatchSemaphore(value: 0) - - do { - let httpRequestOptions = try getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, semaphore: semaphore) - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) - let connection = try await connectionManager.acquireConnection() - let stream = try connection.makeRequest(requestOptions: httpRequestOptions) - try stream.activate() + // let semaphore = DispatchSemaphore(value: 0) + await withCheckedContinuation { continuation in + do { + let httpRequestOptions = try getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, continutaion: continuation) + let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let connection = try await connectionManager.acquireConnection() + let stream = try connection.makeRequest(requestOptions: httpRequestOptions) + try stream.activate() + } } - semaphore.wait() + + // semaphore.wait() } func testManagerLivesUntilComplete() async throws { @@ -179,8 +181,9 @@ class HTTPTests: HTTPClientTestFixture { func testConnectionLivesUntilComplete() async throws { var stream: HTTPStream! = nil - let semaphore = DispatchSemaphore(value: 0) + let semaphore = DispatchSemaphore(value: 0) + do { let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) let connection = try await connectionManager.acquireConnection() diff --git a/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift b/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift index 13218b0a9..c4280207d 100644 --- a/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift +++ b/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift @@ -59,6 +59,6 @@ class RetryerTests: XCBaseTestCase { XCTAssertNotNil(token) _ = try await retryer.scheduleRetry(token: token, errorType: RetryError.serverError) } - wait(for: [generateRandomWasCalled, shutdownWasCalled], timeout: 15) + await fulfilment(of: [generateRandomWasCalled, shutdownWasCalled], timeout: 15, enforceOrder: true) } } From 149abc4bdd6fd683cfbaa0e5cf08a3127b205889 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 30 Dec 2024 11:51:49 -0800 Subject: [PATCH 04/18] non working --- .../http/HTTP2StreamManager.swift | 2 +- .../http/HTTPClientTestFixture.swift | 57 +++++++++---------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift b/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift index 34d4e3e8b..903e5b81c 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift @@ -3,7 +3,7 @@ import AwsCHttp /// Manages a Pool of HTTP/2 Streams. Creates and manages HTTP/2 connections under the hood. -public class HTTP2StreamManager { +public class HTTP2StreamManager: @unchecked Sendable { let rawValue: UnsafeMutablePointer public init(options: HTTP2StreamManagerOptions) throws { diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift index 63f7e5910..34949dbbc 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift @@ -34,35 +34,34 @@ class HTTPClientTestFixture: XCBaseTestCase { var httpResponse = HTTPResponse() await withCheckedContinuation { (continuation: CheckedContinuation) in - Task { - let httpRequestOptions: HTTPRequestOption + let httpRequestOptions: HTTPRequestOptions if requestVersion == HTTPVersion.version_2 { httpRequestOptions = try getHTTP2RequestOptions( - method: method, - path: path, - authority: endpoint, - body: body, - response: &httpResponse, - continuation: continuation, - onResponse: onResponse, - onBody: onBody, - onComplete: onComplete) + method: method, + path: path, + authority: endpoint, + body: body, + response: &httpResponse, + continuation: continuation, + onResponse: onResponse, + onBody: onBody, + onComplete: onComplete) } else { httpRequestOptions = try getHTTPRequestOptions( - method: method, - endpoint: endpoint, - path: path, - body: body, - response: &httpResponse, - continuation: continuation, - onResponse: onResponse, - onBody: onBody, - onComplete: onComplete) + method: method, + endpoint: endpoint, + path: path, + body: body, + response: &httpResponse, + continuation: continuation, + onResponse: onResponse, + onBody: onBody, + onComplete: onComplete) } - + for i in 1...numRetries+1 where httpResponse.statusCode != expectedStatus { print("Attempt#\(i) to send an HTTP request") - let connection = try await connectionManager.acquireConnection() + XCTAssertTrue(connection.isOpen) httpResponse.version = connection.httpVersion XCTAssertEqual(connection.httpVersion, expectedVersion) @@ -98,7 +97,7 @@ class HTTPClientTestFixture: XCBaseTestCase { authority: authority, body: body, response: &httpResponse, - continutaion: continuation, + continuation: continuation, onResponse: onResponse, onBody: onBody, onComplete: onComplete, @@ -145,7 +144,7 @@ class HTTPClientTestFixture: XCBaseTestCase { func getRequestOptions(request: HTTPRequestBase, response: UnsafeMutablePointer? = nil, - continutaion: CheckedContinuation? = nil, + continuation: CheckedContinuation? = nil, onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, onComplete: HTTPRequestOptions.OnStreamComplete? = nil, @@ -169,7 +168,7 @@ class HTTPClientTestFixture: XCBaseTestCase { response?.pointee.error = error } onComplete?(result) - continutaion?.resume() + continuation?.resume() }, http2ManualDataWrites: http2ManualDataWrites) } @@ -180,7 +179,7 @@ class HTTPClientTestFixture: XCBaseTestCase { path: String, body: String = "", response: UnsafeMutablePointer? = nil, - continutaion: CheckedContinuation? = nil, + continuation: CheckedContinuation? = nil, headers: [HTTPHeader] = [HTTPHeader](), onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, @@ -199,7 +198,7 @@ class HTTPClientTestFixture: XCBaseTestCase { return getRequestOptions( request: httpRequest, response: response, - continutaion: continutaion, + continuation: continuation, onResponse: onResponse, onBody: onBody, onComplete: onComplete) @@ -212,7 +211,7 @@ class HTTPClientTestFixture: XCBaseTestCase { body: String = "", manualDataWrites: Bool = false, response: UnsafeMutablePointer? = nil, - continutaion: CheckedContinuation? = nil, + continuation: CheckedContinuation? = nil, onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, onComplete: HTTPRequestOptions.OnStreamComplete? = nil, @@ -228,7 +227,7 @@ class HTTPClientTestFixture: XCBaseTestCase { return getRequestOptions( request: http2Request, response: response, - continutaion: continutaion, + continuation: continuation, onResponse: onResponse, onBody: onBody, onComplete: onComplete, From 853fa9e42d0f8009d0ccf80806f8f5d13a47c5e6 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 30 Dec 2024 15:03:51 -0800 Subject: [PATCH 05/18] More fixes --- .../auth/signing/Signer.swift | 2 +- .../AwsCommonRuntimeKit/crt/Allocator.swift | 3 +- .../AwsCommonRuntimeKit/crt/Utilities.swift | 6 - .../AwsCommonRuntimeKit/http/HTTPStream.swift | 2 +- Source/Elasticurl/CommandLine.swift | 2 +- .../auth/CredentialsProviderTests.swift | 20 +-- .../crt/ShutDownCallbackOptionsTests.swift | 2 +- .../event-stream/EventStreamTests.swift | 10 +- .../http/HTTP2ClientConnectionTests.swift | 44 ++--- .../http/HTTP2StreamManagerTests.swift | 26 ++- .../HTTPClientConnectionManagerTests.swift | 2 +- .../http/HTTPClientTestFixture.swift | 168 ++++++++++-------- .../http/HTTPProxyTests.swift | 6 +- .../http/HTTPTests.swift | 90 +++++----- .../io/BootstrapTests.swift | 2 +- .../io/EventLoopGroupTests.swift | 2 +- .../io/HostResolverTests.swift | 2 +- .../io/RetryerTests.swift | 4 +- 18 files changed, 203 insertions(+), 190 deletions(-) diff --git a/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift b/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift index 00ac6d4bb..3c24c34b2 100644 --- a/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift +++ b/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift @@ -166,7 +166,7 @@ public class Signer { class SignRequestCore: @unchecked Sendable { let request: HTTPRequestBase - var continuation: CheckedContinuation + let continuation: CheckedContinuation let shouldSignHeader: ((String) -> Bool)? init(request: HTTPRequestBase, continuation: CheckedContinuation, diff --git a/Source/AwsCommonRuntimeKit/crt/Allocator.swift b/Source/AwsCommonRuntimeKit/crt/Allocator.swift index dde614f0a..1f293e5f8 100644 --- a/Source/AwsCommonRuntimeKit/crt/Allocator.swift +++ b/Source/AwsCommonRuntimeKit/crt/Allocator.swift @@ -2,14 +2,13 @@ // SPDX-License-Identifier: Apache-2.0. import AwsCCommon - /* * The default allocator. * You are probably looking to use `allocator` instead. * We need to declare `allocator` as mutable (`var`) instead of `let` because we override it with a tracing allocator in tests. This is not mutated anywhere else apart from the start of tests. * Swift compiler doesn't let us compile this code due to global shared mutable state without locks, and complains that this is not safe. Disable the safety here since we know better than the compiler. */ -nonisolated(unsafe) var allocator = aws_default_allocator()!.rawValue +nonisolated(unsafe) var allocator = aws_default_allocator()! /// An allocator is used to allocate memory on the heap. protocol Allocator { diff --git a/Source/AwsCommonRuntimeKit/crt/Utilities.swift b/Source/AwsCommonRuntimeKit/crt/Utilities.swift index 455215c35..8dda4c10f 100644 --- a/Source/AwsCommonRuntimeKit/crt/Utilities.swift +++ b/Source/AwsCommonRuntimeKit/crt/Utilities.swift @@ -5,12 +5,6 @@ import struct Foundation.Data import struct Foundation.TimeInterval import AwsCCal - - -struct SendablePointer: @unchecked Sendable { - let pointer: UnsafeMutablePointer -} - /// This class is used to add reference counting to stuff that do not support it /// like Structs, Closures, and Protocols etc by wrapping it in a Class. /// This also allows us to use anything with Unmanaged which we required for C callbacks. diff --git a/Source/AwsCommonRuntimeKit/http/HTTPStream.swift b/Source/AwsCommonRuntimeKit/http/HTTPStream.swift index bb84432da..515e35158 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTPStream.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTPStream.swift @@ -5,7 +5,7 @@ import Foundation /// An base abstract class that represents a single Http Request/Response for both HTTP/1.1 and HTTP/2. /// Can be used to update the Window size, and get status code. -public class HTTPStream : @unchecked Sendable { +public class HTTPStream: @unchecked Sendable { let rawValue: UnsafeMutablePointer var callbackData: HTTPStreamCallbackCore diff --git a/Source/Elasticurl/CommandLine.swift b/Source/Elasticurl/CommandLine.swift index 5bde795b3..a26f9274f 100644 --- a/Source/Elasticurl/CommandLine.swift +++ b/Source/Elasticurl/CommandLine.swift @@ -4,7 +4,7 @@ import Foundation import AwsCCommon // swiftlint:disable trailing_whitespace - +// TODO: what is swift parser? struct CommandLineParser : @unchecked Sendable { /// A function to parse command line arguments /// - Parameters: diff --git a/Test/AwsCommonRuntimeKitTests/auth/CredentialsProviderTests.swift b/Test/AwsCommonRuntimeKitTests/auth/CredentialsProviderTests.swift index 2e12bdcc4..cb88b135d 100644 --- a/Test/AwsCommonRuntimeKitTests/auth/CredentialsProviderTests.swift +++ b/Test/AwsCommonRuntimeKitTests/auth/CredentialsProviderTests.swift @@ -66,7 +66,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertNotNil(credentials) assertCredentials(credentials: credentials) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } // TODO: change this test to not pass accountId separately once the source function handles it @@ -81,7 +81,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertNotNil(credentials) assertCredentials(credentials: credentials) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } func testCredentialsProviderEnvThrow() async { @@ -92,7 +92,7 @@ class CredentialsProviderTests: XCBaseTestCase { } catch { exceptionWasThrown.fulfill() } - wait(for: [exceptionWasThrown], timeout: 15) + await fulfillment(of: [exceptionWasThrown], timeout: 15) } func withEnvironmentCredentialsClosure(closure: () async throws -> T) async rethrows -> T { @@ -129,7 +129,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertEqual("accessKey", credentials.getAccessKey()) XCTAssertEqual("secretKey", credentials.getSecret()) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } func testCreateCredentialsProviderProcess() async throws { @@ -145,7 +145,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertEqual("SecretAccessKey123", credentials.getSecret()) XCTAssertEqual("SessionToken123", credentials.getSessionToken()) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } func testCreateCredentialsProviderSSO() async throws { @@ -162,7 +162,7 @@ class CredentialsProviderTests: XCBaseTestCase { // get credentials will fail in CI due to expired token, so do not assert on credentials. _ = try? await provider.getCredentials() } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } func testCreateCredentialsProviderImds() async throws { @@ -170,7 +170,7 @@ class CredentialsProviderTests: XCBaseTestCase { _ = try CredentialsProvider(source: .imds(bootstrap: getClientBootstrap(), shutdownCallback: getShutdownCallback())) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } func testCreateCredentialsProviderCache() async throws { @@ -184,7 +184,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertNotNil(credentials) assertCredentials(credentials: credentials) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } func testCreateAWSCredentialsProviderDefaultChain() async throws { @@ -202,7 +202,7 @@ class CredentialsProviderTests: XCBaseTestCase { assertCredentials(credentials: credentials) } } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } func testCreateDestroyStsWebIdentityInvalidEnv() async throws { @@ -250,6 +250,6 @@ class CredentialsProviderTests: XCBaseTestCase { } catch { exceptionWasThrown.fulfill() } - wait(for: [exceptionWasThrown], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } } diff --git a/Test/AwsCommonRuntimeKitTests/crt/ShutDownCallbackOptionsTests.swift b/Test/AwsCommonRuntimeKitTests/crt/ShutDownCallbackOptionsTests.swift index 9b9e00ae6..26de8e2d4 100644 --- a/Test/AwsCommonRuntimeKitTests/crt/ShutDownCallbackOptionsTests.swift +++ b/Test/AwsCommonRuntimeKitTests/crt/ShutDownCallbackOptionsTests.swift @@ -13,6 +13,6 @@ class ShutdownCallbackOptionsTests: XCBaseTestCase { shutdownWasCalled.fulfill() } } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } } diff --git a/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift b/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift index 18bfd7b9a..f89fbe62f 100644 --- a/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift +++ b/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift @@ -48,7 +48,7 @@ class EventStreamTests: XCBaseTestCase { }) try decoder.decode(data: encoded) XCTAssertTrue(headers.elementsEqual(decodedHeaders)) - wait(for: [onCompleteWasCalled], timeout: 1) + await fulfillment(of: [onCompleteWasCalled], timeout: 1) } func testEncodeDecodePayload() async throws { @@ -76,7 +76,7 @@ class EventStreamTests: XCBaseTestCase { }) try decoder.decode(data: encoded) XCTAssertEqual(payload, decodedPayload) - wait(for: [onCompleteWasCalled], timeout: 1) + await fulfillment(of: [onCompleteWasCalled], timeout: 1) } func testEncodeOutOfScope() async throws { @@ -114,7 +114,7 @@ class EventStreamTests: XCBaseTestCase { let expectedHeaders = [EventStreamHeader(name: "int16", value: .int32(value: 16))] XCTAssertTrue(expectedHeaders.elementsEqual(decodedHeaders)) - wait(for: [onCompleteWasCalled], timeout: 1) + await fulfillment(of: [onCompleteWasCalled], timeout: 1) } func testDecodeByteByByte() async throws { @@ -150,7 +150,7 @@ class EventStreamTests: XCBaseTestCase { XCTAssertEqual(payload, decodedPayload) XCTAssertTrue(headers.elementsEqual(decodedHeaders)) - wait(for: [onCompleteWasCalled], timeout: 1) + await fulfillment(of: [onCompleteWasCalled], timeout: 1) } func testEmpty() async throws { @@ -175,6 +175,6 @@ class EventStreamTests: XCBaseTestCase { XCTFail("Error occurred. Code: \(code)\nMessage:\(message)") }) try decoder.decode(data: encoded) - wait(for: [onCompleteWasCalled], timeout: 1) + await fulfillment(of: [onCompleteWasCalled], timeout: 1) } } diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift index fc41097ed..b2b0a6d67 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift @@ -3,19 +3,19 @@ import XCTest @testable import AwsCommonRuntimeKit -class HTTP2ClientConnectionTests: HTTPClientTestFixture { +class HTTP2ClientConnectionTests { let expectedVersion = HTTPVersion.version_2 func testGetHTTP2RequestVersion() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) let connection = try await connectionManager.acquireConnection() XCTAssertEqual(connection.httpVersion, HTTPVersion.version_2) } // Test that the binding works not the actual functionality. C part has tests for functionality func testHTTP2UpdateSetting() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) let connection = try await connectionManager.acquireConnection() if let connection = connection as? HTTP2ClientConnection { try await connection.updateSetting(setting: HTTP2Settings(enablePush: false)) @@ -26,7 +26,7 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { // Test that the binding works not the actual functionality. C part has tests for functionality func testHTTP2UpdateSettingEmpty() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) let connection = try await connectionManager.acquireConnection() if let connection = connection as? HTTP2ClientConnection { try await connection.updateSetting(setting: HTTP2Settings()) @@ -37,7 +37,7 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { // Test that the binding works not the actual functionality. C part has tests for functionality func testHTTP2SendPing() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) let connection = try await connectionManager.acquireConnection() if let connection = connection as? HTTP2ClientConnection { var time = try await connection.sendPing() @@ -51,7 +51,7 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { // Test that the binding works not the actual functionality. C part has tests for functionality func testHTTP2SendGoAway() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) let connection = try await connectionManager.acquireConnection() if let connection = connection as? HTTP2ClientConnection { connection.sendGoAway(error: .internalError, allowMoreStreams: false) @@ -61,8 +61,8 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { } func testGetHttpsRequest() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) - let response = try await sendHTTPRequest( + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) + let response = try await HTTPClientTestFixture.sendHTTPRequest( method: "GET", endpoint: "httpbin.org", path: "/get", @@ -71,7 +71,7 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { requestVersion: .version_2) // The first header of response has to be ":status" for HTTP/2 response XCTAssertEqual(response.headers[0].name, ":status") - let response2 = try await sendHTTPRequest( + let response2 = try await HTTPClientTestFixture.sendHTTPRequest( method: "GET", endpoint: "httpbin.org", path: "/delete", @@ -84,8 +84,8 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { func testGetHttpsRequestWithHTTP1_1Request() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) - let response = try await sendHTTPRequest( + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "httpbin.org", alpnList: ["h2","http/1.1"]) + let response = try await HTTPClientTestFixture.sendHTTPRequest( method: "GET", endpoint: "httpbin.org", path: "/get", @@ -94,7 +94,7 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { requestVersion: .version_1_1) // The first header of response has to be ":status" for HTTP/2 response XCTAssertEqual(response.headers[0].name, ":status") - let response2 = try await sendHTTPRequest( + let response2 = try await HTTPClientTestFixture.sendHTTPRequest( method: "GET", endpoint: "httpbin.org", path: "/delete", @@ -106,8 +106,8 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { } func testHTTP2Download() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "d1cz66xoahf9cl.cloudfront.net", alpnList: ["h2","http/1.1"]) - let response = try await sendHTTPRequest( + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "d1cz66xoahf9cl.cloudfront.net", alpnList: ["h2","http/1.1"]) + let response = try await HTTPClientTestFixture.sendHTTPRequest( method: "GET", endpoint: "d1cz66xoahf9cl.cloudfront.net", path: "/http_test_doc.txt", @@ -121,8 +121,8 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { } func testHTTP2DownloadWithHTTP1_1Request() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "d1cz66xoahf9cl.cloudfront.net", alpnList: ["h2","http/1.1"]) - let response = try await sendHTTPRequest( + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "d1cz66xoahf9cl.cloudfront.net", alpnList: ["h2","http/1.1"]) + let response = try await HTTPClientTestFixture.sendHTTPRequest( method: "GET", endpoint: "d1cz66xoahf9cl.cloudfront.net", path: "/http_test_doc.txt", @@ -136,12 +136,12 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { } func testHTTP2StreamUpload() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: "nghttp2.org", alpnList: ["h2"]) - let semaphore = DispatchSemaphore(value: 0) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "nghttp2.org", alpnList: ["h2"]) + let semaphore = Semaphore(value: 0) var httpResponse = HTTPResponse() var onCompleteCalled = false let testBody = "testBody" - let http2RequestOptions = try getHTTP2RequestOptions( + let http2RequestOptions = try HTTPClientTestFixture.getHTTP2RequestOptions( method: "PUT", path: "/httpbin/put", authority: "nghttp2.org", @@ -156,7 +156,7 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { let streamBase = try connection.makeRequest(requestOptions: http2RequestOptions) try streamBase.activate() XCTAssertFalse(onCompleteCalled) - let data = TEST_DOC_LINE.data(using: .utf8)! + let data = HTTPClientTestFixture.TEST_DOC_LINE.data(using: .utf8)! for chunk in data.chunked(into: 5) { try await streamBase.writeChunk(chunk: chunk, endOfStream: false) XCTAssertFalse(onCompleteCalled) @@ -167,7 +167,7 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { try await Task.sleep(nanoseconds: 5_000_000_000) XCTAssertFalse(onCompleteCalled) try await streamBase.writeChunk(chunk: Data(), endOfStream: true) - semaphore.wait() + await semaphore.wait() XCTAssertTrue(onCompleteCalled) XCTAssertNil(httpResponse.error) XCTAssertEqual(httpResponse.statusCode, 200) @@ -178,6 +178,6 @@ class HTTP2ClientConnectionTests: HTTPClientTestFixture { } let body: Response = try! JSONDecoder().decode(Response.self, from: httpResponse.body) - XCTAssertEqual(body.data, testBody + TEST_DOC_LINE) + XCTAssertEqual(body.data, testBody + HTTPClientTestFixture.TEST_DOC_LINE) } } diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift index 110a60761..165ad92b5 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift @@ -4,7 +4,7 @@ import XCTest @testable import AwsCommonRuntimeKit -class HTT2StreamManagerTests: HTTPClientTestFixture { +class HTT2StreamManagerTests { let endpoint = "d1cz66xoahf9cl.cloudfront.net"; // Use cloudfront for HTTP/2 let path = "/random_32_byte.data"; @@ -102,16 +102,16 @@ class HTT2StreamManagerTests: HTTPClientTestFixture { func testHTTP2Stream() async throws { let streamManager = try makeStreamManger(host: endpoint) - _ = try await sendHTTP2Request(method: "GET", path: path, authority: endpoint, streamManager: streamManager) + _ = try await HTTPClientTestFixture.sendHTTP2Request(method: "GET", path: path, authority: endpoint, streamManager: streamManager) } func testHTTP2StreamUpload() async throws { let streamManager = try makeStreamManger(host: "nghttp2.org") - let semaphore = DispatchSemaphore(value: 0) + let semaphore = Semaphore(value: 0) var httpResponse = HTTPResponse() var onCompleteCalled = false let testBody = "testBody" - let http2RequestOptions = try getHTTP2RequestOptions( + let http2RequestOptions = try HTTPClientTestFixture.getHTTP2RequestOptions( method: "PUT", path: "/httpbin/put", authority: "nghttp2.org", @@ -128,7 +128,7 @@ class HTT2StreamManagerTests: HTTPClientTestFixture { let metrics = streamManager.fetchMetrics() XCTAssertTrue(metrics.availableConcurrency > 0) XCTAssertTrue(metrics.leasedConcurrency > 0) - let data = TEST_DOC_LINE.data(using: .utf8)! + let data = HTTPClientTestFixture.TEST_DOC_LINE.data(using: .utf8)! for chunk in data.chunked(into: 5) { try await stream.writeChunk(chunk: chunk, endOfStream: false) XCTAssertFalse(onCompleteCalled) @@ -139,7 +139,7 @@ class HTT2StreamManagerTests: HTTPClientTestFixture { try await Task.sleep(nanoseconds: 5_000_000_000) XCTAssertFalse(onCompleteCalled) try await stream.writeChunk(chunk: Data(), endOfStream: true) - semaphore.wait() + await semaphore.wait() XCTAssertTrue(onCompleteCalled) XCTAssertNil(httpResponse.error) XCTAssertEqual(httpResponse.statusCode, 200) @@ -150,13 +150,13 @@ class HTT2StreamManagerTests: HTTPClientTestFixture { } let body: Response = try! JSONDecoder().decode(Response.self, from: httpResponse.body) - XCTAssertEqual(body.data, testBody + TEST_DOC_LINE) + XCTAssertEqual(body.data, testBody + HTTPClientTestFixture.TEST_DOC_LINE) } // Test that the binding works not the actual functionality. C part has tests for functionality func testHTTP2StreamReset() async throws { let streamManager = try makeStreamManger(host: endpoint) - let http2RequestOptions = try getHTTP2RequestOptions( + let http2RequestOptions = try HTTPClientTestFixture.getHTTP2RequestOptions( method: "PUT", path: "/httpbin/put", authority: "nghttp2.org") @@ -171,18 +171,12 @@ class HTT2StreamManagerTests: HTTPClientTestFixture { func testHTTP2ParallelStreams(count: Int) async throws { let streamManager = try makeStreamManger(host: "nghttp2.org") - let requestCompleteExpectation = XCTestExpectation(description: "Request was completed successfully") - requestCompleteExpectation.expectedFulfillmentCount = count - await withTaskGroup(of: Void.self) { taskGroup in + return await withTaskGroup(of: Void.self) { taskGroup in for _ in 1...count { taskGroup.addTask { - _ = try! await self.sendHTTP2Request(method: "GET", path: "/httpbin/get", authority: "nghttp2.org", streamManager: streamManager, onComplete: { _ in - requestCompleteExpectation.fulfill() - }) + _ = try! await HTTPClientTestFixture.sendHTTP2Request(method: "GET", path: "/httpbin/get", authority: "nghttp2.org", streamManager: streamManager) } } } - wait(for: [requestCompleteExpectation], timeout: 15) - print("Request were successfully completed.") } } diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPClientConnectionManagerTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPClientConnectionManagerTests.swift index 748db1973..8ff6d9128 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPClientConnectionManagerTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPClientConnectionManagerTests.swift @@ -37,6 +37,6 @@ class HTTPClientConnectionManagerTests: XCBaseTestCase { } _ = try HTTPClientConnectionManager(options: httpClientOptions) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } } diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift index 34949dbbc..942f3bcc6 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift @@ -12,14 +12,40 @@ struct HTTPResponse { var version: HTTPVersion? } +actor Semaphore { + private var count: Int + private var waiters: [CheckedContinuation] = [] + + init(value: Int = 0) { + self.count = value + } + + func wait() async { + count -= 1 + if count >= 0 { return } + await withCheckedContinuation { + waiters.append($0) + } + } + + func signal(count: Int = 1) { + assert(count >= 1) + self.count += count + for _ in 0.. HTTPResponse { var httpResponse = HTTPResponse() - await withCheckedContinuation { (continuation: CheckedContinuation) in - let httpRequestOptions: HTTPRequestOptions - if requestVersion == HTTPVersion.version_2 { - httpRequestOptions = try getHTTP2RequestOptions( - method: method, - path: path, - authority: endpoint, - body: body, - response: &httpResponse, - continuation: continuation, - onResponse: onResponse, - onBody: onBody, - onComplete: onComplete) - } else { - httpRequestOptions = try getHTTPRequestOptions( - method: method, - endpoint: endpoint, - path: path, - body: body, - response: &httpResponse, - continuation: continuation, - onResponse: onResponse, - onBody: onBody, - onComplete: onComplete) - } - - for i in 1...numRetries+1 where httpResponse.statusCode != expectedStatus { - print("Attempt#\(i) to send an HTTP request") - - XCTAssertTrue(connection.isOpen) - httpResponse.version = connection.httpVersion - XCTAssertEqual(connection.httpVersion, expectedVersion) - let stream = try connection.makeRequest(requestOptions: httpRequestOptions) - try stream.activate() - } + let semaphore = Semaphore(value: 0) + + let httpRequestOptions: HTTPRequestOptions + if requestVersion == HTTPVersion.version_2 { + httpRequestOptions = try getHTTP2RequestOptions( + method: method, + path: path, + authority: endpoint, + body: body, + response: &httpResponse, + semaphore: semaphore, + onResponse: onResponse, + onBody: onBody, + onComplete: onComplete) + } else { + httpRequestOptions = try getHTTPRequestOptions( + method: method, + endpoint: endpoint, + path: path, + body: body, + response: &httpResponse, + semaphore: semaphore, + onResponse: onResponse, + onBody: onBody, + onComplete: onComplete) + } + + for i in 1...numRetries+1 where httpResponse.statusCode != expectedStatus { + print("Attempt#\(i) to send an HTTP request") + let connection = try await connectionManager.acquireConnection() + XCTAssertTrue(connection.isOpen) + httpResponse.version = connection.httpVersion + XCTAssertEqual(connection.httpVersion, expectedVersion) + let stream = try connection.makeRequest(requestOptions: httpRequestOptions) + try stream.activate() + await semaphore.wait() } + XCTAssertNil(httpResponse.error) XCTAssertEqual(httpResponse.statusCode, expectedStatus) return httpResponse } - func sendHTTP2Request(method: String, + static func sendHTTP2Request(method: String, path: String, scheme: String = "https", authority: String, @@ -88,34 +116,34 @@ class HTTPClientTestFixture: XCBaseTestCase { onComplete: HTTPRequestOptions.OnStreamComplete? = nil) async throws -> HTTPResponse { var httpResponse = HTTPResponse() - await withCheckedContinuation { (continuation: CheckedContinuation) in - Task { - let httpRequestOptions = try getHTTP2RequestOptions( - method: method, - path: path, - scheme: scheme, - authority: authority, - body: body, - response: &httpResponse, - continuation: continuation, - onResponse: onResponse, - onBody: onBody, - onComplete: onComplete, - http2ManualDataWrites: http2ManualDataWrites) - - for i in 1...numRetries+1 where httpResponse.statusCode != expectedStatus { - print("Attempt#\(i) to send an HTTP request") - let stream = try await streamManager.acquireStream(requestOptions: httpRequestOptions) - try stream.activate() - } - } + let semaphore = Semaphore(value: 0) + + let httpRequestOptions = try getHTTP2RequestOptions( + method: method, + path: path, + scheme: scheme, + authority: authority, + body: body, + response: &httpResponse, + semaphore: semaphore, + onResponse: onResponse, + onBody: onBody, + onComplete: onComplete, + http2ManualDataWrites: http2ManualDataWrites) + + for i in 1...numRetries+1 where httpResponse.statusCode != expectedStatus { + print("Attempt#\(i) to send an HTTP request") + let stream = try await streamManager.acquireStream(requestOptions: httpRequestOptions) + try stream.activate() + await semaphore.wait() } + XCTAssertNil(httpResponse.error) XCTAssertEqual(httpResponse.statusCode, expectedStatus) return httpResponse } - func getHttpConnectionManager(endpoint: String, + static func getHttpConnectionManager(endpoint: String, ssh: Bool = true, port: Int = 443, alpnList: [String] = ["http/1.1"], @@ -142,9 +170,9 @@ class HTTPClientTestFixture: XCBaseTestCase { return try HTTPClientConnectionManager(options: httpClientOptions) } - func getRequestOptions(request: HTTPRequestBase, + static func getRequestOptions(request: HTTPRequestBase, response: UnsafeMutablePointer? = nil, - continuation: CheckedContinuation? = nil, + semaphore: Semaphore? = nil, onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, onComplete: HTTPRequestOptions.OnStreamComplete? = nil, @@ -168,18 +196,18 @@ class HTTPClientTestFixture: XCBaseTestCase { response?.pointee.error = error } onComplete?(result) - continuation?.resume() + Task { await semaphore?.signal() } }, http2ManualDataWrites: http2ManualDataWrites) } - func getHTTPRequestOptions(method: String, + static func getHTTPRequestOptions(method: String, endpoint: String, path: String, body: String = "", response: UnsafeMutablePointer? = nil, - continuation: CheckedContinuation? = nil, + semaphore: Semaphore? = nil, headers: [HTTPHeader] = [HTTPHeader](), onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, @@ -198,20 +226,20 @@ class HTTPClientTestFixture: XCBaseTestCase { return getRequestOptions( request: httpRequest, response: response, - continuation: continuation, + semaphore: semaphore, onResponse: onResponse, onBody: onBody, onComplete: onComplete) } - func getHTTP2RequestOptions(method: String, + static func getHTTP2RequestOptions(method: String, path: String, scheme: String = "https", authority: String, body: String = "", manualDataWrites: Bool = false, response: UnsafeMutablePointer? = nil, - continuation: CheckedContinuation? = nil, + semaphore: Semaphore? = nil, onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, onComplete: HTTPRequestOptions.OnStreamComplete? = nil, @@ -227,7 +255,7 @@ class HTTPClientTestFixture: XCBaseTestCase { return getRequestOptions( request: http2Request, response: response, - continuation: continuation, + semaphore: semaphore, onResponse: onResponse, onBody: onBody, onComplete: onComplete, diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPProxyTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPProxyTests.swift index 59f75a9a8..dfea036c0 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPProxyTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPProxyTests.swift @@ -6,7 +6,7 @@ import AwsCAuth import Foundation @testable import AwsCommonRuntimeKit -class HTTPProxyTests: HTTPClientTestFixture { +class HTTPProxyTests: XCBaseTestCase { let HTTPProxyHost = ProcessInfo.processInfo.environment["AWS_TEST_HTTP_PROXY_HOST"] let HTTPProxyPort = ProcessInfo.processInfo.environment["AWS_TEST_HTTP_PROXY_PORT"] @@ -185,13 +185,13 @@ class HTTPProxyTests: HTTPClientTestFixture { let uri = getURIFromTestType(type: type) let port = getPortFromTestType(type: type) let proxyOptions = try getProxyOptions(type: type, authType: authType) - let manager = try await getHttpConnectionManager( + let manager = try await HTTPClientTestFixture.getHttpConnectionManager( endpoint: uri, ssh: getSSH(type: type), port: port, alpnList: ["http/1.1"], proxyOptions: proxyOptions) - _ = try await sendHTTPRequest(method: "GET", endpoint: uri, connectionManager: manager) + _ = try await HTTPClientTestFixture.sendHTTPRequest(method: "GET", endpoint: uri, connectionManager: manager) } } diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift index 0f44fb6c4..1394ec1ee 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift @@ -6,35 +6,35 @@ import XCTest import AwsCCommon import AwsCHttp -class HTTPTests: HTTPClientTestFixture { +class HTTPTests { let host = "postman-echo.com" let getPath = "/get" func testGetHTTPSRequest() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) - _ = try await sendHTTPRequest(method: "GET", endpoint: host, path: getPath, connectionManager: connectionManager) - _ = try await sendHTTPRequest(method: "GET", endpoint: host, path: "/delete", expectedStatus: 404, connectionManager: connectionManager) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + _ = try await HTTPClientTestFixture.sendHTTPRequest(method: "GET", endpoint: host, path: getPath, connectionManager: connectionManager) + _ = try await HTTPClientTestFixture.sendHTTPRequest(method: "GET", endpoint: host, path: "/delete", expectedStatus: 404, connectionManager: connectionManager) } func testGetHTTPSRequestWithUtf8Header() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) let utf8Header = HTTPHeader(name: "TestHeader", value: "TestValueWithEmoji🤯") - let headers = try await sendHTTPRequest(method: "GET", endpoint: host, path: "/response-headers?\(utf8Header.name)=\(utf8Header.value)", connectionManager: connectionManager).headers + let headers = try await HTTPClientTestFixture.sendHTTPRequest(method: "GET", endpoint: host, path: "/response-headers?\(utf8Header.name)=\(utf8Header.value)", connectionManager: connectionManager).headers XCTAssertTrue(headers.contains(where: {$0.name == utf8Header.name && $0.value==utf8Header.value})) } func testGetHTTPRequest() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: false, port: 80) - _ = try await sendHTTPRequest(method: "GET", endpoint: host, path: getPath, connectionManager: connectionManager) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: false, port: 80) + _ = try await HTTPClientTestFixture.sendHTTPRequest(method: "GET", endpoint: host, path: getPath, connectionManager: connectionManager) } func testPutHTTPRequest() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) - let response = try await sendHTTPRequest( + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let response = try await HTTPClientTestFixture.sendHTTPRequest( method: "PUT", endpoint: host, path: "/put", - body: TEST_DOC_LINE, + body: HTTPClientTestFixture.TEST_DOC_LINE, connectionManager: connectionManager) // Parse json body @@ -42,15 +42,15 @@ class HTTPTests: HTTPClientTestFixture { let data: String } let body: Response = try! JSONDecoder().decode(Response.self, from: response.body) - XCTAssertEqual(body.data, TEST_DOC_LINE) + XCTAssertEqual(body.data, HTTPClientTestFixture.TEST_DOC_LINE) } func testHTTPChunkTransferEncoding() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: host, alpnList: ["http/1.1"]) - let semaphore = DispatchSemaphore(value: 0) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, alpnList: ["http/1.1"]) + let semaphore = Semaphore(value: 0) var httpResponse = HTTPResponse() var onCompleteCalled = false - let httpRequestOptions = try getHTTPRequestOptions( + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions( method: "PUT", endpoint: host, path: "/put", @@ -67,7 +67,7 @@ class HTTPTests: HTTPClientTestFixture { let metrics = connectionManager.fetchMetrics() XCTAssertTrue(metrics.leasedConcurrency > 0) - let data = TEST_DOC_LINE.data(using: .utf8)! + let data = HTTPClientTestFixture.TEST_DOC_LINE.data(using: .utf8)! for chunk in data.chunked(into: 5) { try await streamBase.writeChunk(chunk: chunk, endOfStream: false) XCTAssertFalse(onCompleteCalled) @@ -78,7 +78,7 @@ class HTTPTests: HTTPClientTestFixture { try await Task.sleep(nanoseconds: 5_000_000_000) XCTAssertFalse(onCompleteCalled) try await streamBase.writeChunk(chunk: Data(), endOfStream: true) - semaphore.wait() + await semaphore.wait() XCTAssertTrue(onCompleteCalled) XCTAssertNil(httpResponse.error) XCTAssertEqual(httpResponse.statusCode, 200) @@ -89,15 +89,15 @@ class HTTPTests: HTTPClientTestFixture { } let body: Response = try! JSONDecoder().decode(Response.self, from: httpResponse.body) - XCTAssertEqual(body.data, TEST_DOC_LINE) + XCTAssertEqual(body.data, HTTPClientTestFixture.TEST_DOC_LINE) } func testHTTPChunkTransferEncodingWithDataInLastChunk() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: host, alpnList: ["http/1.1"]) - let semaphore = DispatchSemaphore(value: 0) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, alpnList: ["http/1.1"]) + let semaphore = Semaphore(value: 0) var httpResponse = HTTPResponse() var onCompleteCalled = false - let httpRequestOptions = try getHTTPRequestOptions( + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions( method: "PUT", endpoint: host, path: "/put", @@ -111,7 +111,7 @@ class HTTPTests: HTTPClientTestFixture { let streamBase = try connection.makeRequest(requestOptions: httpRequestOptions) try streamBase.activate() XCTAssertFalse(onCompleteCalled) - let data = TEST_DOC_LINE.data(using: .utf8)! + let data = HTTPClientTestFixture.TEST_DOC_LINE.data(using: .utf8)! for chunk in data.chunked(into: 5) { try await streamBase.writeChunk(chunk: chunk, endOfStream: false) XCTAssertFalse(onCompleteCalled) @@ -124,7 +124,7 @@ class HTTPTests: HTTPClientTestFixture { let lastChunkData = Data("last chunk data".utf8) try await streamBase.writeChunk(chunk: lastChunkData, endOfStream: true) - semaphore.wait() + await semaphore.wait() XCTAssertTrue(onCompleteCalled) XCTAssertNil(httpResponse.error) XCTAssertEqual(httpResponse.statusCode, 200) @@ -135,14 +135,14 @@ class HTTPTests: HTTPClientTestFixture { } let body: Response = try! JSONDecoder().decode(Response.self, from: httpResponse.body) - XCTAssertEqual(body.data, TEST_DOC_LINE + String(decoding: lastChunkData, as: UTF8.self)) + XCTAssertEqual(body.data, HTTPClientTestFixture.TEST_DOC_LINE + String(decoding: lastChunkData, as: UTF8.self)) } func testHTTPStreamIsReleasedIfNotActivated() async throws { do { - let httpRequestOptions = try getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath) - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) let connection = try await connectionManager.acquireConnection() _ = try connection.makeRequest(requestOptions: httpRequestOptions) } catch let err { @@ -151,70 +151,68 @@ class HTTPTests: HTTPClientTestFixture { } func testStreamLivesUntilComplete() async throws { - // let semaphore = DispatchSemaphore(value: 0) - await withCheckedContinuation { continuation in + let semaphore = Semaphore(value: 0) do { - let httpRequestOptions = try getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, continutaion: continuation) - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, semaphore: semaphore) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) let connection = try await connectionManager.acquireConnection() let stream = try connection.makeRequest(requestOptions: httpRequestOptions) try stream.activate() } - } - // semaphore.wait() + await semaphore.wait() } func testManagerLivesUntilComplete() async throws { var connection: HTTPClientConnection! = nil - let semaphore = DispatchSemaphore(value: 0) + let semaphore = Semaphore(value: 0) do { - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) connection = try await connectionManager.acquireConnection() } - let httpRequestOptions = try getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, semaphore: semaphore) + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, semaphore: semaphore) let stream = try connection.makeRequest(requestOptions: httpRequestOptions) try stream.activate() - semaphore.wait() + await semaphore.wait() } func testConnectionLivesUntilComplete() async throws { var stream: HTTPStream! = nil - let semaphore = DispatchSemaphore(value: 0) + let semaphore = Semaphore(value: 0) do { - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) let connection = try await connectionManager.acquireConnection() - let httpRequestOptions = try getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, semaphore: semaphore) + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, semaphore: semaphore) stream = try connection.makeRequest(requestOptions: httpRequestOptions) } try stream.activate() - semaphore.wait() + await semaphore.wait() } func testConnectionCloseThrow() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) let connection = try await connectionManager.acquireConnection() connection.close() - let httpRequestOptions = try getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath) + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath) XCTAssertThrowsError( _ = try connection.makeRequest(requestOptions: httpRequestOptions)) } func testConnectionCloseActivateThrow() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) let connection = try await connectionManager.acquireConnection() - let httpRequestOptions = try getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath) + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath) let stream = try connection.makeRequest(requestOptions: httpRequestOptions) connection.close() XCTAssertThrowsError(try stream.activate()) } func testConnectionCloseIsIdempotent() async throws { - let connectionManager = try await getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) let connection = try await connectionManager.acquireConnection() - let httpRequestOptions = try getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath) + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath) let stream = try connection.makeRequest(requestOptions: httpRequestOptions) connection.close() connection.close() diff --git a/Test/AwsCommonRuntimeKitTests/io/BootstrapTests.swift b/Test/AwsCommonRuntimeKitTests/io/BootstrapTests.swift index 3e9d22d01..9c578d87b 100644 --- a/Test/AwsCommonRuntimeKitTests/io/BootstrapTests.swift +++ b/Test/AwsCommonRuntimeKitTests/io/BootstrapTests.swift @@ -33,6 +33,6 @@ class BootstrapTests: XCBaseTestCase { hostResolver: resolver, shutdownCallback: shutdownCallback) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } } diff --git a/Test/AwsCommonRuntimeKitTests/io/EventLoopGroupTests.swift b/Test/AwsCommonRuntimeKitTests/io/EventLoopGroupTests.swift index c7d4cbcbd..426b438f4 100644 --- a/Test/AwsCommonRuntimeKitTests/io/EventLoopGroupTests.swift +++ b/Test/AwsCommonRuntimeKitTests/io/EventLoopGroupTests.swift @@ -11,7 +11,7 @@ class EventLoopGroupTests: XCBaseTestCase { _ = try EventLoopGroup() { shutdownWasCalled.fulfill() } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } func testCanCreateGroupWithThreads() throws { diff --git a/Test/AwsCommonRuntimeKitTests/io/HostResolverTests.swift b/Test/AwsCommonRuntimeKitTests/io/HostResolverTests.swift index 9ba7482dd..08544b6d0 100644 --- a/Test/AwsCommonRuntimeKitTests/io/HostResolverTests.swift +++ b/Test/AwsCommonRuntimeKitTests/io/HostResolverTests.swift @@ -61,6 +61,6 @@ class HostResolverTests: XCBaseTestCase { maxTTL: 5, shutdownCallback: shutdownCallback) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } } diff --git a/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift b/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift index c4280207d..5add73c92 100644 --- a/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift +++ b/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift @@ -37,7 +37,7 @@ class RetryerTests: XCBaseTestCase { XCTAssertNotNil(token) _ = try await retryer.scheduleRetry(token: token, errorType: RetryError.serverError) } - wait(for: [shutdownWasCalled], timeout: 15) + await fulfillment(of: [shutdownWasCalled], timeout: 15) } func testGenerateRandom() async throws { @@ -59,6 +59,6 @@ class RetryerTests: XCBaseTestCase { XCTAssertNotNil(token) _ = try await retryer.scheduleRetry(token: token, errorType: RetryError.serverError) } - await fulfilment(of: [generateRandomWasCalled, shutdownWasCalled], timeout: 15, enforceOrder: true) + await fulfillment(of: [generateRandomWasCalled, shutdownWasCalled], timeout: 15, enforceOrder: true) } } From b12eebdffccf866c9b48f9822c094dea7030820d Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 6 Jan 2025 09:26:55 -0800 Subject: [PATCH 06/18] more fixes --- .../auth/signing/Signer.swift | 3 +++ Source/AwsCommonRuntimeKit/crt/Allocator.swift | 3 +-- Source/AwsCommonRuntimeKit/crt/Logger.swift | 2 +- .../AwsCommonRuntimeKit/http/HTTP1Stream.swift | 2 ++ .../http/HTTP2ClientConnection.swift | 2 ++ .../AwsCommonRuntimeKit/http/HTTP2Stream.swift | 2 ++ .../http/HTTP2StreamManager.swift | 2 ++ .../http/HTTPClientConnection.swift | 2 ++ ...TTPClientConnectionManagerCallbackCore.swift | 2 +- .../AwsCommonRuntimeKit/http/HTTPStream.swift | 2 ++ Source/AwsCommonRuntimeKit/io/HostAddress.swift | 2 +- .../io/HostAddressType.swift | 2 +- .../AwsCommonRuntimeKit/io/HostResolver.swift | 2 ++ .../io/retryer/RetryToken.swift | 2 ++ Source/Elasticurl/CommandLine.swift | 5 +++-- Source/Elasticurl/Elasticurl.swift | 4 ++-- .../http/HTTPTests.swift | 17 ++++++++--------- 17 files changed, 37 insertions(+), 19 deletions(-) diff --git a/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift b/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift index 3c24c34b2..e35d4250f 100644 --- a/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift +++ b/Source/AwsCommonRuntimeKit/auth/signing/Signer.swift @@ -164,6 +164,8 @@ public class Signer { } } +// After signing, we mutate the request and resume the continuation, which may result in a thread change. +// We won't modify it after continuation.resume is called. So we can mark it @unchecked Sendable class SignRequestCore: @unchecked Sendable { let request: HTTPRequestBase let continuation: CheckedContinuation @@ -207,6 +209,7 @@ private func onRequestSigningComplete(signingResult: UnsafeMutablePointer?, diff --git a/Source/AwsCommonRuntimeKit/crt/Allocator.swift b/Source/AwsCommonRuntimeKit/crt/Allocator.swift index 1f293e5f8..d9a14986d 100644 --- a/Source/AwsCommonRuntimeKit/crt/Allocator.swift +++ b/Source/AwsCommonRuntimeKit/crt/Allocator.swift @@ -4,9 +4,8 @@ import AwsCCommon /* * The default allocator. - * You are probably looking to use `allocator` instead. * We need to declare `allocator` as mutable (`var`) instead of `let` because we override it with a tracing allocator in tests. This is not mutated anywhere else apart from the start of tests. - * Swift compiler doesn't let us compile this code due to global shared mutable state without locks, and complains that this is not safe. Disable the safety here since we know better than the compiler. + * Swift compiler doesn't let us compile this code due to global shared mutable state without locks, and complains that this is not safe. Disable the safety here since we won't modify it. */ nonisolated(unsafe) var allocator = aws_default_allocator()! diff --git a/Source/AwsCommonRuntimeKit/crt/Logger.swift b/Source/AwsCommonRuntimeKit/crt/Logger.swift index 1c3aa0992..1c25fd5af 100644 --- a/Source/AwsCommonRuntimeKit/crt/Logger.swift +++ b/Source/AwsCommonRuntimeKit/crt/Logger.swift @@ -55,7 +55,7 @@ public actor Logger { } } -public enum LogLevel { +public enum LogLevel: Sendable { case none case fatal case error diff --git a/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift b/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift index eec089372..36297d8f6 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift @@ -4,6 +4,8 @@ import AwsCHttp import Foundation /// An HTTP1Stream represents a single HTTP/1.1 specific Http Request/Response. +// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. +// So mark it as unchecked Sendable. public class HTTP1Stream: HTTPStream, @unchecked Sendable { /// Stream keeps a reference to HttpConnection to keep it alive private let httpConnection: HTTPClientConnection diff --git a/Source/AwsCommonRuntimeKit/http/HTTP2ClientConnection.swift b/Source/AwsCommonRuntimeKit/http/HTTP2ClientConnection.swift index c6ce6c715..01265d6f1 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP2ClientConnection.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP2ClientConnection.swift @@ -5,6 +5,8 @@ import AwsCHttp import AwsCIo import Foundation +// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. +// So mark it as unchecked Sendable. public class HTTP2ClientConnection: HTTPClientConnection, @unchecked Sendable { /// Creates a new http2 stream from the `HTTPRequestOptions` given. diff --git a/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift b/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift index 2a2c0cc04..527ec00b8 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift @@ -5,6 +5,8 @@ import AwsCHttp import Foundation /// An HTTP2Stream represents a single HTTP/2 specific HTTP Request/Response. +// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. +// So mark it as unchecked Sendable. public class HTTP2Stream: HTTPStream, @unchecked Sendable { private let httpConnection: HTTPClientConnection? diff --git a/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift b/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift index 903e5b81c..139f5f76f 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift @@ -3,6 +3,8 @@ import AwsCHttp /// Manages a Pool of HTTP/2 Streams. Creates and manages HTTP/2 connections under the hood. +// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. +// So mark it as unchecked Sendable. public class HTTP2StreamManager: @unchecked Sendable { let rawValue: UnsafeMutablePointer diff --git a/Source/AwsCommonRuntimeKit/http/HTTPClientConnection.swift b/Source/AwsCommonRuntimeKit/http/HTTPClientConnection.swift index b547c180c..0cff7721c 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTPClientConnection.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTPClientConnection.swift @@ -6,6 +6,8 @@ import AwsCIo import Foundation // swiftlint:disable force_try +// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. +// So mark it as unchecked Sendable. public class HTTPClientConnection: @unchecked Sendable { let rawValue: UnsafeMutablePointer /// This will keep the connection manager alive until connection is alive diff --git a/Source/AwsCommonRuntimeKit/http/HTTPClientConnectionManagerCallbackCore.swift b/Source/AwsCommonRuntimeKit/http/HTTPClientConnectionManagerCallbackCore.swift index 7658bca41..82b11a499 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTPClientConnectionManagerCallbackCore.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTPClientConnectionManagerCallbackCore.swift @@ -47,7 +47,7 @@ private func onConnectionSetup(connection: UnsafeMutablePointer var callbackData: HTTPStreamCallbackCore diff --git a/Source/AwsCommonRuntimeKit/io/HostAddress.swift b/Source/AwsCommonRuntimeKit/io/HostAddress.swift index 27cca3c32..907e072fa 100644 --- a/Source/AwsCommonRuntimeKit/io/HostAddress.swift +++ b/Source/AwsCommonRuntimeKit/io/HostAddress.swift @@ -4,7 +4,7 @@ import AwsCIo /// Represents a single HostAddress resolved by the Host Resolver -public struct HostAddress: CStruct, @unchecked Sendable { +public struct HostAddress: CStruct, Sendable { /// Address type is ipv4 or ipv6 public let addressType: HostAddressType diff --git a/Source/AwsCommonRuntimeKit/io/HostAddressType.swift b/Source/AwsCommonRuntimeKit/io/HostAddressType.swift index cc973853d..3140e6971 100644 --- a/Source/AwsCommonRuntimeKit/io/HostAddressType.swift +++ b/Source/AwsCommonRuntimeKit/io/HostAddressType.swift @@ -4,7 +4,7 @@ import AwsCIo /// Type of Host Address (ipv4 or ipv6) -public enum HostAddressType { +public enum HostAddressType: Sendable { case A case AAAA } diff --git a/Source/AwsCommonRuntimeKit/io/HostResolver.swift b/Source/AwsCommonRuntimeKit/io/HostResolver.swift index 2fe598b46..61fa8db72 100644 --- a/Source/AwsCommonRuntimeKit/io/HostResolver.swift +++ b/Source/AwsCommonRuntimeKit/io/HostResolver.swift @@ -24,6 +24,8 @@ public protocol HostResolverProtocol { } /// CRT Host Resolver which performs async DNS lookups +// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. +// So mark it as unchecked Sendable. public class HostResolver: HostResolverProtocol, @unchecked Sendable { let rawValue: UnsafeMutablePointer let maxTTL: Int diff --git a/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift b/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift index 424f33957..57574ec9d 100644 --- a/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift +++ b/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift @@ -4,6 +4,8 @@ import AwsCIo /// This is just a wrapper for aws_retry_token which user can not create themself but pass around once acquired. +// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. +// So mark it as unchecked Sendable. public class RetryToken: @unchecked Sendable { let rawValue: UnsafeMutablePointer diff --git a/Source/Elasticurl/CommandLine.swift b/Source/Elasticurl/CommandLine.swift index a26f9274f..84419faf0 100644 --- a/Source/Elasticurl/CommandLine.swift +++ b/Source/Elasticurl/CommandLine.swift @@ -4,8 +4,7 @@ import Foundation import AwsCCommon // swiftlint:disable trailing_whitespace -// TODO: what is swift parser? -struct CommandLineParser : @unchecked Sendable { +struct CommandLineParser { /// A function to parse command line arguments /// - Parameters: /// - argc: The number of arguments @@ -61,6 +60,8 @@ extension CLIHasArg: RawRepresentable, CaseIterable { } } +// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. +// So mark it as unchecked Sendable. class AWSCLIOption: @unchecked Sendable { let rawValue: aws_cli_option let name: UnsafeMutablePointer diff --git a/Source/Elasticurl/Elasticurl.swift b/Source/Elasticurl/Elasticurl.swift index 4ecfa2564..6ba7ade51 100644 --- a/Source/Elasticurl/Elasticurl.swift +++ b/Source/Elasticurl/Elasticurl.swift @@ -6,7 +6,7 @@ import AwsCommonRuntimeKit import Foundation // swiftlint:disable cyclomatic_complexity function_body_length -struct Context : @unchecked Sendable { +struct Context: Sendable { // args public var logLevel: LogLevel = .trace public var verb: String = "GET" @@ -27,7 +27,7 @@ struct Context : @unchecked Sendable { } @main -struct Elasticurl : @unchecked Sendable { +struct Elasticurl { private static let version = "0.1.0" static func parseArguments() -> Context { diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift index 1394ec1ee..d72603c53 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift @@ -152,15 +152,14 @@ class HTTPTests { func testStreamLivesUntilComplete() async throws { let semaphore = Semaphore(value: 0) - do { - let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, semaphore: semaphore) - let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) - let connection = try await connectionManager.acquireConnection() - let stream = try connection.makeRequest(requestOptions: httpRequestOptions) - try stream.activate() - } - - await semaphore.wait() + do { + let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, semaphore: semaphore) + let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) + let connection = try await connectionManager.acquireConnection() + let stream = try connection.makeRequest(requestOptions: httpRequestOptions) + try stream.activate() + } + await semaphore.wait() } func testManagerLivesUntilComplete() async throws { From 5b3f624b0455396489e92318a2bb0b692939db4a Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 6 Jan 2025 09:43:57 -0800 Subject: [PATCH 07/18] more fixes --- Source/Elasticurl/CommandLine.swift | 3 +-- Source/Elasticurl/Elasticurl.swift | 1 - .../http/HTTPClientTestFixture.swift | 16 ++++++++++------ .../http/HTTPTests.swift | 10 +++++----- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Source/Elasticurl/CommandLine.swift b/Source/Elasticurl/CommandLine.swift index 84419faf0..ebc45f703 100644 --- a/Source/Elasticurl/CommandLine.swift +++ b/Source/Elasticurl/CommandLine.swift @@ -3,7 +3,7 @@ import Foundation import AwsCCommon -// swiftlint:disable trailing_whitespace + struct CommandLineParser { /// A function to parse command line arguments /// - Parameters: @@ -15,7 +15,6 @@ struct CommandLineParser { /// - Returns: A dictionary of`[String: Any] ` with `String` as the name of the flag and `Any` as the /// value passed in public static func parseArguments(argc: Int32, - arguments: UnsafeMutablePointer?>, optionString: String, options: [aws_cli_option]) -> [String: Any] { diff --git a/Source/Elasticurl/Elasticurl.swift b/Source/Elasticurl/Elasticurl.swift index 6ba7ade51..a4db24ea8 100644 --- a/Source/Elasticurl/Elasticurl.swift +++ b/Source/Elasticurl/Elasticurl.swift @@ -62,7 +62,6 @@ struct Elasticurl { arguments: CommandLine.unsafeArgv, optionString: optionString, options: options) - var context = Context() if let caCert = argumentsDict["a"] as? String { context.caCert = caCert diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift index 942f3bcc6..d8238d3aa 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift @@ -12,7 +12,11 @@ struct HTTPResponse { var version: HTTPVersion? } -actor Semaphore { +/* + * Async Semaphore compatible with Swift's structured concurrency. Swift complains about the normal sync Semaphore since it's a blocking wait. + * https://forums.swift.org/t/semaphore-alternatives-for-structured-concurrency/59353 + */ +actor TestSemaphore { private var count: Int private var waiters: [CheckedContinuation] = [] @@ -59,7 +63,7 @@ class HTTPClientTestFixture: XCBaseTestCase { onComplete: HTTPRequestOptions.OnStreamComplete? = nil) async throws -> HTTPResponse { var httpResponse = HTTPResponse() - let semaphore = Semaphore(value: 0) + let semaphore = TestSemaphore(value: 0) let httpRequestOptions: HTTPRequestOptions if requestVersion == HTTPVersion.version_2 { @@ -116,7 +120,7 @@ class HTTPClientTestFixture: XCBaseTestCase { onComplete: HTTPRequestOptions.OnStreamComplete? = nil) async throws -> HTTPResponse { var httpResponse = HTTPResponse() - let semaphore = Semaphore(value: 0) + let semaphore = TestSemaphore(value: 0) let httpRequestOptions = try getHTTP2RequestOptions( method: method, @@ -172,7 +176,7 @@ class HTTPClientTestFixture: XCBaseTestCase { static func getRequestOptions(request: HTTPRequestBase, response: UnsafeMutablePointer? = nil, - semaphore: Semaphore? = nil, + semaphore: TestSemaphore? = nil, onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, onComplete: HTTPRequestOptions.OnStreamComplete? = nil, @@ -207,7 +211,7 @@ class HTTPClientTestFixture: XCBaseTestCase { path: String, body: String = "", response: UnsafeMutablePointer? = nil, - semaphore: Semaphore? = nil, + semaphore: TestSemaphore? = nil, headers: [HTTPHeader] = [HTTPHeader](), onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, @@ -239,7 +243,7 @@ class HTTPClientTestFixture: XCBaseTestCase { body: String = "", manualDataWrites: Bool = false, response: UnsafeMutablePointer? = nil, - semaphore: Semaphore? = nil, + semaphore: TestSemaphore? = nil, onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, onComplete: HTTPRequestOptions.OnStreamComplete? = nil, diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift index d72603c53..31f2e0f08 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift @@ -47,7 +47,7 @@ class HTTPTests { func testHTTPChunkTransferEncoding() async throws { let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, alpnList: ["http/1.1"]) - let semaphore = Semaphore(value: 0) + let semaphore = TestSemaphore(value: 0) var httpResponse = HTTPResponse() var onCompleteCalled = false let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions( @@ -94,7 +94,7 @@ class HTTPTests { func testHTTPChunkTransferEncodingWithDataInLastChunk() async throws { let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, alpnList: ["http/1.1"]) - let semaphore = Semaphore(value: 0) + let semaphore = TestSemaphore(value: 0) var httpResponse = HTTPResponse() var onCompleteCalled = false let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions( @@ -151,7 +151,7 @@ class HTTPTests { } func testStreamLivesUntilComplete() async throws { - let semaphore = Semaphore(value: 0) + let semaphore = TestSemaphore(value: 0) do { let httpRequestOptions = try HTTPClientTestFixture.getHTTPRequestOptions(method: "GET", endpoint: host, path: getPath, semaphore: semaphore) let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) @@ -164,7 +164,7 @@ class HTTPTests { func testManagerLivesUntilComplete() async throws { var connection: HTTPClientConnection! = nil - let semaphore = Semaphore(value: 0) + let semaphore = TestSemaphore(value: 0) do { let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) @@ -179,7 +179,7 @@ class HTTPTests { func testConnectionLivesUntilComplete() async throws { var stream: HTTPStream! = nil - let semaphore = Semaphore(value: 0) + let semaphore = TestSemaphore(value: 0) do { let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: host, ssh: true, port: 443) From 2f3aac0dd8dfdcb8c0fb70e5ddb39d80e10152b7 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 6 Jan 2025 09:45:33 -0800 Subject: [PATCH 08/18] update comment --- Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift index d8238d3aa..971ed81c7 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift @@ -14,7 +14,7 @@ struct HTTPResponse { /* * Async Semaphore compatible with Swift's structured concurrency. Swift complains about the normal sync Semaphore since it's a blocking wait. - * https://forums.swift.org/t/semaphore-alternatives-for-structured-concurrency/59353 + * See: https://forums.swift.org/t/semaphore-alternatives-for-structured-concurrency/59353 */ actor TestSemaphore { private var count: Int From 703b650ca93251d487fcff5bcb01dde1eef5b3e3 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 6 Jan 2025 09:58:35 -0800 Subject: [PATCH 09/18] fix test --- Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift | 2 +- Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift | 2 +- Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift | 2 +- Source/AwsCommonRuntimeKit/http/HTTPStream.swift | 4 ++-- Source/AwsCommonRuntimeKit/io/HostResolver.swift | 2 +- Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift | 2 +- .../http/HTTP2ClientConnectionTests.swift | 2 +- .../http/HTTP2StreamManagerTests.swift | 2 +- .../AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift | 2 +- Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift b/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift index 36297d8f6..5efca6efd 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift @@ -3,9 +3,9 @@ import AwsCHttp import Foundation -/// An HTTP1Stream represents a single HTTP/1.1 specific Http Request/Response. // Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. // So mark it as unchecked Sendable. +/// An HTTP1Stream represents a single HTTP/1.1 specific Http Request/Response. public class HTTP1Stream: HTTPStream, @unchecked Sendable { /// Stream keeps a reference to HttpConnection to keep it alive private let httpConnection: HTTPClientConnection diff --git a/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift b/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift index 527ec00b8..260c754b4 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift @@ -4,9 +4,9 @@ import AwsCHttp import Foundation -/// An HTTP2Stream represents a single HTTP/2 specific HTTP Request/Response. // Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. // So mark it as unchecked Sendable. +/// An HTTP2Stream represents a single HTTP/2 specific HTTP Request/Response. public class HTTP2Stream: HTTPStream, @unchecked Sendable { private let httpConnection: HTTPClientConnection? diff --git a/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift b/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift index 139f5f76f..c827e8492 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0. import AwsCHttp -/// Manages a Pool of HTTP/2 Streams. Creates and manages HTTP/2 connections under the hood. // Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. // So mark it as unchecked Sendable. +/// Manages a Pool of HTTP/2 Streams. Creates and manages HTTP/2 connections under the hood. public class HTTP2StreamManager: @unchecked Sendable { let rawValue: UnsafeMutablePointer diff --git a/Source/AwsCommonRuntimeKit/http/HTTPStream.swift b/Source/AwsCommonRuntimeKit/http/HTTPStream.swift index ae077511b..3c9fca30f 100644 --- a/Source/AwsCommonRuntimeKit/http/HTTPStream.swift +++ b/Source/AwsCommonRuntimeKit/http/HTTPStream.swift @@ -3,10 +3,10 @@ import AwsCHttp import Foundation -/// An base abstract class that represents a single Http Request/Response for both HTTP/1.1 and HTTP/2. -/// Can be used to update the Window size, and get status code. // Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. // So mark it as unchecked Sendable. +/// An base abstract class that represents a single Http Request/Response for both HTTP/1.1 and HTTP/2. +/// Can be used to update the Window size, and get status code. public class HTTPStream: @unchecked Sendable { let rawValue: UnsafeMutablePointer var callbackData: HTTPStreamCallbackCore diff --git a/Source/AwsCommonRuntimeKit/io/HostResolver.swift b/Source/AwsCommonRuntimeKit/io/HostResolver.swift index 61fa8db72..72dcb21e6 100644 --- a/Source/AwsCommonRuntimeKit/io/HostResolver.swift +++ b/Source/AwsCommonRuntimeKit/io/HostResolver.swift @@ -23,9 +23,9 @@ public protocol HostResolverProtocol { func purgeCache() async } -/// CRT Host Resolver which performs async DNS lookups // Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. // So mark it as unchecked Sendable. +/// CRT Host Resolver which performs async DNS lookups public class HostResolver: HostResolverProtocol, @unchecked Sendable { let rawValue: UnsafeMutablePointer let maxTTL: Int diff --git a/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift b/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift index 57574ec9d..32300ab80 100644 --- a/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift +++ b/Source/AwsCommonRuntimeKit/io/retryer/RetryToken.swift @@ -3,9 +3,9 @@ import AwsCIo -/// This is just a wrapper for aws_retry_token which user can not create themself but pass around once acquired. // Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer. // So mark it as unchecked Sendable. +/// This is just a wrapper for aws_retry_token which user can not create themself but pass around once acquired. public class RetryToken: @unchecked Sendable { let rawValue: UnsafeMutablePointer diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift index b2b0a6d67..e7bb7a17f 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift @@ -3,7 +3,7 @@ import XCTest @testable import AwsCommonRuntimeKit -class HTTP2ClientConnectionTests { +class HTTP2ClientConnectionTests: XCBaseTestCase { let expectedVersion = HTTPVersion.version_2 diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift index 165ad92b5..b6b1d1a8e 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift @@ -4,7 +4,7 @@ import XCTest @testable import AwsCommonRuntimeKit -class HTT2StreamManagerTests { +class HTT2StreamManagerTests: XCBaseTestCase { let endpoint = "d1cz66xoahf9cl.cloudfront.net"; // Use cloudfront for HTTP/2 let path = "/random_32_byte.data"; diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift index 971ed81c7..73bcabfc4 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPClientTestFixture.swift @@ -57,7 +57,7 @@ class HTTPClientTestFixture: XCBaseTestCase { connectionManager: HTTPClientConnectionManager, expectedVersion: HTTPVersion = HTTPVersion.version_1_1, requestVersion: HTTPVersion = HTTPVersion.version_1_1, - numRetries: UInt = 0, + numRetries: UInt = 2, onResponse: HTTPRequestOptions.OnResponse? = nil, onBody: HTTPRequestOptions.OnIncomingBody? = nil, onComplete: HTTPRequestOptions.OnStreamComplete? = nil) async throws -> HTTPResponse { diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift index 31f2e0f08..09e9eab37 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPTests.swift @@ -6,7 +6,7 @@ import XCTest import AwsCCommon import AwsCHttp -class HTTPTests { +class HTTPTests: XCBaseTestCase { let host = "postman-echo.com" let getPath = "/get" From 2478627b71c6e8136dc9ce23128f94e3d7c8df09 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 6 Jan 2025 10:16:51 -0800 Subject: [PATCH 10/18] more fixes --- .../event-stream/EventStreamTests.swift | 3 +-- .../http/HTTP2ClientConnectionTests.swift | 2 +- .../http/HTTP2StreamManagerTests.swift | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift b/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift index f89fbe62f..6411cabcc 100644 --- a/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift +++ b/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift @@ -6,8 +6,7 @@ import AwsCEventStream @testable import AwsCommonRuntimeKit class EventStreamTests: XCBaseTestCase { - let semaphore = DispatchSemaphore(value: 0) - + func testEncodeDecodeHeaders() async throws { let onCompleteWasCalled = XCTestExpectation(description: "OnComplete was called") diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift index e7bb7a17f..38c602e1a 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTP2ClientConnectionTests.swift @@ -137,7 +137,7 @@ class HTTP2ClientConnectionTests: XCBaseTestCase { func testHTTP2StreamUpload() async throws { let connectionManager = try await HTTPClientTestFixture.getHttpConnectionManager(endpoint: "nghttp2.org", alpnList: ["h2"]) - let semaphore = Semaphore(value: 0) + let semaphore = TestSemaphore(value: 0) var httpResponse = HTTPResponse() var onCompleteCalled = false let testBody = "testBody" diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift index b6b1d1a8e..b961ae369 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTP2StreamManagerTests.swift @@ -107,7 +107,7 @@ class HTT2StreamManagerTests: XCBaseTestCase { func testHTTP2StreamUpload() async throws { let streamManager = try makeStreamManger(host: "nghttp2.org") - let semaphore = Semaphore(value: 0) + let semaphore = TestSemaphore(value: 0) var httpResponse = HTTPResponse() var onCompleteCalled = false let testBody = "testBody" From 2aa220fb0c3a7927e1e41ca15cee5171b8cac753 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 6 Jan 2025 11:41:53 -0800 Subject: [PATCH 11/18] reset package.swift --- Package.swift | 2 +- aws-common-runtime/aws-c-cal | 2 +- aws-common-runtime/aws-c-common | 2 +- aws-common-runtime/s2n | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index b452e5b58..98535e612 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:6.0 +// swift-tools-version:5.7 import PackageDescription let excludesFromAll = ["tests", "cmake", "CONTRIBUTING.md", diff --git a/aws-common-runtime/aws-c-cal b/aws-common-runtime/aws-c-cal index 656762aef..fbbe2612a 160000 --- a/aws-common-runtime/aws-c-cal +++ b/aws-common-runtime/aws-c-cal @@ -1 +1 @@ -Subproject commit 656762aefbee2bc8f509cb23cd107abff20a72bb +Subproject commit fbbe2612a3385d1ded02a52d20ad7fd2da4501f4 diff --git a/aws-common-runtime/aws-c-common b/aws-common-runtime/aws-c-common index 63187b976..7a6f5df20 160000 --- a/aws-common-runtime/aws-c-common +++ b/aws-common-runtime/aws-c-common @@ -1 +1 @@ -Subproject commit 63187b976a482309e23296c5f967fc19c4131746 +Subproject commit 7a6f5df201cb4b1910932ea3221de83edaa39880 diff --git a/aws-common-runtime/s2n b/aws-common-runtime/s2n index 493b77167..2e79e7efe 160000 --- a/aws-common-runtime/s2n +++ b/aws-common-runtime/s2n @@ -1 +1 @@ -Subproject commit 493b77167dc367c394de23cfe78a029298e2a254 +Subproject commit 2e79e7efeb26f06eb59a1d4f3444ea63fc3e20c3 From 75aea3f17f07e665bdee7e21c8c5085af79a75f4 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 6 Jan 2025 11:55:05 -0800 Subject: [PATCH 12/18] fix stuff --- Source/AwsCommonRuntimeKit/crt/Allocator.swift | 6 +++++- Source/Elasticurl/CommandLine.swift | 4 ++-- aws-common-runtime/aws-c-common | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Source/AwsCommonRuntimeKit/crt/Allocator.swift b/Source/AwsCommonRuntimeKit/crt/Allocator.swift index d9a14986d..153477dcf 100644 --- a/Source/AwsCommonRuntimeKit/crt/Allocator.swift +++ b/Source/AwsCommonRuntimeKit/crt/Allocator.swift @@ -5,9 +5,13 @@ import AwsCCommon /* * The default allocator. * We need to declare `allocator` as mutable (`var`) instead of `let` because we override it with a tracing allocator in tests. This is not mutated anywhere else apart from the start of tests. - * Swift compiler doesn't let us compile this code due to global shared mutable state without locks, and complains that this is not safe. Disable the safety here since we won't modify it. + * Swift compiler doesn't let us compile this code in Swift 6 due to global shared mutable state without locks, and complains that this is not safe. Disable the safety here since we won't modify it. */ +#if swift(>=5.10) nonisolated(unsafe) var allocator = aws_default_allocator()! +#else +var allocator = aws_default_allocator()! +#endif /// An allocator is used to allocate memory on the heap. protocol Allocator { diff --git a/Source/Elasticurl/CommandLine.swift b/Source/Elasticurl/CommandLine.swift index ebc45f703..e5b666dab 100644 --- a/Source/Elasticurl/CommandLine.swift +++ b/Source/Elasticurl/CommandLine.swift @@ -26,8 +26,8 @@ struct CommandLineParser { break } if let char = UnicodeScalar(Int(opt)) { - if get_cli_optarg() != nil { - argumentsDict[String(char)] = String(cString: get_cli_optarg()) + if aws_get_cli_optarg() != nil { + argumentsDict[String(char)] = String(cString: aws_get_cli_optarg()) } else { // if argument doesnt have a value just mark it as present in the dictionary argumentsDict[String(char)] = true diff --git a/aws-common-runtime/aws-c-common b/aws-common-runtime/aws-c-common index 7a6f5df20..3334fee31 160000 --- a/aws-common-runtime/aws-c-common +++ b/aws-common-runtime/aws-c-common @@ -1 +1 @@ -Subproject commit 7a6f5df201cb4b1910932ea3221de83edaa39880 +Subproject commit 3334fee3131f53afcf9fd2cfe44b20964b9b9587 From e35ed112bfb599be0466600b2a2256dfe3984e8e Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Mon, 6 Jan 2025 13:13:09 -0800 Subject: [PATCH 13/18] unchecked --- Source/Elasticurl/Elasticurl.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Elasticurl/Elasticurl.swift b/Source/Elasticurl/Elasticurl.swift index a4db24ea8..3829dc7f4 100644 --- a/Source/Elasticurl/Elasticurl.swift +++ b/Source/Elasticurl/Elasticurl.swift @@ -6,7 +6,7 @@ import AwsCommonRuntimeKit import Foundation // swiftlint:disable cyclomatic_complexity function_body_length -struct Context: Sendable { +struct Context: @unchecked Sendable { // args public var logLevel: LogLevel = .trace public var verb: String = "GET" From 015d98c075aa3a02f1be970f45cb93e9005f5d52 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Tue, 7 Jan 2025 10:06:01 -0800 Subject: [PATCH 14/18] Some ifdef --- .../AwsCommonRuntimeKit/crt/Allocator.swift | 1 + .../XCBaseTestCase.swift | 11 +++++++++- .../auth/CredentialsProviderTests.swift | 22 +++++++++---------- .../crt/ShutDownCallbackOptionsTests.swift | 2 +- .../event-stream/EventStreamTests.swift | 12 +++++----- .../HTTPClientConnectionManagerTests.swift | 2 +- .../io/BootstrapTests.swift | 2 +- .../io/EventLoopGroupTests.swift | 2 +- .../io/HostResolverTests.swift | 6 ++--- .../io/RetryerTests.swift | 8 +++---- 10 files changed, 39 insertions(+), 29 deletions(-) diff --git a/Source/AwsCommonRuntimeKit/crt/Allocator.swift b/Source/AwsCommonRuntimeKit/crt/Allocator.swift index 153477dcf..63bc9cac6 100644 --- a/Source/AwsCommonRuntimeKit/crt/Allocator.swift +++ b/Source/AwsCommonRuntimeKit/crt/Allocator.swift @@ -6,6 +6,7 @@ import AwsCCommon * The default allocator. * We need to declare `allocator` as mutable (`var`) instead of `let` because we override it with a tracing allocator in tests. This is not mutated anywhere else apart from the start of tests. * Swift compiler doesn't let us compile this code in Swift 6 due to global shared mutable state without locks, and complains that this is not safe. Disable the safety here since we won't modify it. + * Remove the Ifdef once our minimum supported Swift version reaches 5.10 */ #if swift(>=5.10) nonisolated(unsafe) var allocator = aws_default_allocator()! diff --git a/Test/AwsCommonRuntimeKitTests/XCBaseTestCase.swift b/Test/AwsCommonRuntimeKitTests/XCBaseTestCase.swift index ed5c5ee15..c0d45567d 100644 --- a/Test/AwsCommonRuntimeKitTests/XCBaseTestCase.swift +++ b/Test/AwsCommonRuntimeKitTests/XCBaseTestCase.swift @@ -7,7 +7,7 @@ import AwsCCommon class XCBaseTestCase: XCTestCase { internal let tracingAllocator = TracingAllocator(tracingStacksOf: allocator) - + override func setUp() { super.setUp() // XCode currently lacks a way to enable logs exclusively for failed tests only. @@ -67,6 +67,15 @@ extension XCTestCase { #endif } + func awaitExpectation(_ expectations: [XCTestExpectation]) async { + // Remove the Ifdef once our minimum supported Swift version reaches 5.10 + #if swift(>=5.10) + await fulfillment(of: expectations, timeout: 5) + #else + wait(for: expectations, timeout: 5) + #endif + } + /// Return the environment variable value, or Skip the test if env var is not set. func getEnvironmentVarOrSkipTest(environmentVarName name: String) throws -> String { guard let result = ProcessInfo.processInfo.environment[name] else { diff --git a/Test/AwsCommonRuntimeKitTests/auth/CredentialsProviderTests.swift b/Test/AwsCommonRuntimeKitTests/auth/CredentialsProviderTests.swift index cb88b135d..14a1bbf78 100644 --- a/Test/AwsCommonRuntimeKitTests/auth/CredentialsProviderTests.swift +++ b/Test/AwsCommonRuntimeKitTests/auth/CredentialsProviderTests.swift @@ -66,7 +66,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertNotNil(credentials) assertCredentials(credentials: credentials) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } // TODO: change this test to not pass accountId separately once the source function handles it @@ -81,7 +81,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertNotNil(credentials) assertCredentials(credentials: credentials) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } func testCredentialsProviderEnvThrow() async { @@ -92,7 +92,7 @@ class CredentialsProviderTests: XCBaseTestCase { } catch { exceptionWasThrown.fulfill() } - await fulfillment(of: [exceptionWasThrown], timeout: 15) + await awaitExpectation([exceptionWasThrown]) } func withEnvironmentCredentialsClosure(closure: () async throws -> T) async rethrows -> T { @@ -129,7 +129,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertEqual("accessKey", credentials.getAccessKey()) XCTAssertEqual("secretKey", credentials.getSecret()) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } func testCreateCredentialsProviderProcess() async throws { @@ -145,7 +145,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertEqual("SecretAccessKey123", credentials.getSecret()) XCTAssertEqual("SessionToken123", credentials.getSessionToken()) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } func testCreateCredentialsProviderSSO() async throws { @@ -162,7 +162,7 @@ class CredentialsProviderTests: XCBaseTestCase { // get credentials will fail in CI due to expired token, so do not assert on credentials. _ = try? await provider.getCredentials() } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } func testCreateCredentialsProviderImds() async throws { @@ -170,7 +170,7 @@ class CredentialsProviderTests: XCBaseTestCase { _ = try CredentialsProvider(source: .imds(bootstrap: getClientBootstrap(), shutdownCallback: getShutdownCallback())) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } func testCreateCredentialsProviderCache() async throws { @@ -184,7 +184,7 @@ class CredentialsProviderTests: XCBaseTestCase { XCTAssertNotNil(credentials) assertCredentials(credentials: credentials) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } func testCreateAWSCredentialsProviderDefaultChain() async throws { @@ -202,7 +202,7 @@ class CredentialsProviderTests: XCBaseTestCase { assertCredentials(credentials: credentials) } } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } func testCreateDestroyStsWebIdentityInvalidEnv() async throws { @@ -212,7 +212,7 @@ class CredentialsProviderTests: XCBaseTestCase { fileBasedConfiguration: FileBasedConfiguration())) ) } - + func testCreateDestroyStsWebIdentity() async throws { _ = try! CredentialsProvider(source: .stsWebIdentity( bootstrap: getClientBootstrap(), @@ -250,6 +250,6 @@ class CredentialsProviderTests: XCBaseTestCase { } catch { exceptionWasThrown.fulfill() } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } } diff --git a/Test/AwsCommonRuntimeKitTests/crt/ShutDownCallbackOptionsTests.swift b/Test/AwsCommonRuntimeKitTests/crt/ShutDownCallbackOptionsTests.swift index 26de8e2d4..01fea4c96 100644 --- a/Test/AwsCommonRuntimeKitTests/crt/ShutDownCallbackOptionsTests.swift +++ b/Test/AwsCommonRuntimeKitTests/crt/ShutDownCallbackOptionsTests.swift @@ -13,6 +13,6 @@ class ShutdownCallbackOptionsTests: XCBaseTestCase { shutdownWasCalled.fulfill() } } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } } diff --git a/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift b/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift index 6411cabcc..b8ef55be4 100644 --- a/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift +++ b/Test/AwsCommonRuntimeKitTests/event-stream/EventStreamTests.swift @@ -6,7 +6,7 @@ import AwsCEventStream @testable import AwsCommonRuntimeKit class EventStreamTests: XCBaseTestCase { - + func testEncodeDecodeHeaders() async throws { let onCompleteWasCalled = XCTestExpectation(description: "OnComplete was called") @@ -47,7 +47,7 @@ class EventStreamTests: XCBaseTestCase { }) try decoder.decode(data: encoded) XCTAssertTrue(headers.elementsEqual(decodedHeaders)) - await fulfillment(of: [onCompleteWasCalled], timeout: 1) + await awaitExpectation([onCompleteWasCalled]) } func testEncodeDecodePayload() async throws { @@ -75,7 +75,7 @@ class EventStreamTests: XCBaseTestCase { }) try decoder.decode(data: encoded) XCTAssertEqual(payload, decodedPayload) - await fulfillment(of: [onCompleteWasCalled], timeout: 1) + await awaitExpectation([onCompleteWasCalled]) } func testEncodeOutOfScope() async throws { @@ -113,7 +113,7 @@ class EventStreamTests: XCBaseTestCase { let expectedHeaders = [EventStreamHeader(name: "int16", value: .int32(value: 16))] XCTAssertTrue(expectedHeaders.elementsEqual(decodedHeaders)) - await fulfillment(of: [onCompleteWasCalled], timeout: 1) + await awaitExpectation([onCompleteWasCalled]) } func testDecodeByteByByte() async throws { @@ -149,7 +149,7 @@ class EventStreamTests: XCBaseTestCase { XCTAssertEqual(payload, decodedPayload) XCTAssertTrue(headers.elementsEqual(decodedHeaders)) - await fulfillment(of: [onCompleteWasCalled], timeout: 1) + await awaitExpectation([onCompleteWasCalled]) } func testEmpty() async throws { @@ -174,6 +174,6 @@ class EventStreamTests: XCBaseTestCase { XCTFail("Error occurred. Code: \(code)\nMessage:\(message)") }) try decoder.decode(data: encoded) - await fulfillment(of: [onCompleteWasCalled], timeout: 1) + await awaitExpectation([onCompleteWasCalled]) } } diff --git a/Test/AwsCommonRuntimeKitTests/http/HTTPClientConnectionManagerTests.swift b/Test/AwsCommonRuntimeKitTests/http/HTTPClientConnectionManagerTests.swift index 8ff6d9128..8c87bca56 100644 --- a/Test/AwsCommonRuntimeKitTests/http/HTTPClientConnectionManagerTests.swift +++ b/Test/AwsCommonRuntimeKitTests/http/HTTPClientConnectionManagerTests.swift @@ -37,6 +37,6 @@ class HTTPClientConnectionManagerTests: XCBaseTestCase { } _ = try HTTPClientConnectionManager(options: httpClientOptions) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } } diff --git a/Test/AwsCommonRuntimeKitTests/io/BootstrapTests.swift b/Test/AwsCommonRuntimeKitTests/io/BootstrapTests.swift index 9c578d87b..9bc5f0db8 100644 --- a/Test/AwsCommonRuntimeKitTests/io/BootstrapTests.swift +++ b/Test/AwsCommonRuntimeKitTests/io/BootstrapTests.swift @@ -33,6 +33,6 @@ class BootstrapTests: XCBaseTestCase { hostResolver: resolver, shutdownCallback: shutdownCallback) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } } diff --git a/Test/AwsCommonRuntimeKitTests/io/EventLoopGroupTests.swift b/Test/AwsCommonRuntimeKitTests/io/EventLoopGroupTests.swift index 426b438f4..55ba8905e 100644 --- a/Test/AwsCommonRuntimeKitTests/io/EventLoopGroupTests.swift +++ b/Test/AwsCommonRuntimeKitTests/io/EventLoopGroupTests.swift @@ -11,7 +11,7 @@ class EventLoopGroupTests: XCBaseTestCase { _ = try EventLoopGroup() { shutdownWasCalled.fulfill() } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } func testCanCreateGroupWithThreads() throws { diff --git a/Test/AwsCommonRuntimeKitTests/io/HostResolverTests.swift b/Test/AwsCommonRuntimeKitTests/io/HostResolverTests.swift index 08544b6d0..fe97bd88d 100644 --- a/Test/AwsCommonRuntimeKitTests/io/HostResolverTests.swift +++ b/Test/AwsCommonRuntimeKitTests/io/HostResolverTests.swift @@ -4,13 +4,13 @@ import XCTest @testable import AwsCommonRuntimeKit class HostResolverTests: XCBaseTestCase { - + func testCanResolveHosts() async throws { let elg = try EventLoopGroup() let resolver = try HostResolver(eventLoopGroup: elg, maxHosts: 8, maxTTL: 5) - + let addresses = try await resolver.resolveAddress(args: HostResolverArguments(hostName: "localhost")) XCTAssertNoThrow(addresses) XCTAssertNotNil(addresses.count) @@ -61,6 +61,6 @@ class HostResolverTests: XCBaseTestCase { maxTTL: 5, shutdownCallback: shutdownCallback) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } } diff --git a/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift b/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift index 5add73c92..351143fe1 100644 --- a/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift +++ b/Test/AwsCommonRuntimeKitTests/io/RetryerTests.swift @@ -4,12 +4,12 @@ import XCTest @testable import AwsCommonRuntimeKit class RetryerTests: XCBaseTestCase { let expectation = XCTestExpectation(description: "Credentials callback was called") - + func testCreateAWSRetryer() throws { let elg = try EventLoopGroup(threadCount: 1) _ = try RetryStrategy(eventLoopGroup: elg) } - + func testAcquireToken() async throws { let elg = try EventLoopGroup(threadCount: 1) let retryer = try RetryStrategy(eventLoopGroup: elg) @@ -37,7 +37,7 @@ class RetryerTests: XCBaseTestCase { XCTAssertNotNil(token) _ = try await retryer.scheduleRetry(token: token, errorType: RetryError.serverError) } - await fulfillment(of: [shutdownWasCalled], timeout: 15) + await awaitExpectation([shutdownWasCalled]) } func testGenerateRandom() async throws { @@ -59,6 +59,6 @@ class RetryerTests: XCBaseTestCase { XCTAssertNotNil(token) _ = try await retryer.scheduleRetry(token: token, errorType: RetryError.serverError) } - await fulfillment(of: [generateRandomWasCalled, shutdownWasCalled], timeout: 15, enforceOrder: true) + await awaitExpectation([generateRandomWasCalled, shutdownWasCalled]) } } From 54d17c39b8acd529db314ae357148d26b2837aac Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Tue, 7 Jan 2025 12:00:22 -0800 Subject: [PATCH 15/18] try swift 6 --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f26edd08..93147235e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,6 +71,26 @@ jobs: chmod a+x builder ./builder build -p ${{ env.PACKAGE_NAME }} + macos-swift6: + runs-on: macos-14 + env: + DEVELOPER_DIR: /Applications/Xcode.app + XCODE_DESTINATION: 'OS X' + NSUnbufferedIO: YES + strategy: + fail-fast: false + steps: + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ env.CRT_CI_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: Build ${{ env.PACKAGE_NAME }} + consumers + run: | + sed -i '' '1s|// swift-tools-version:.*|// swift-tools-version:6.0|' Package.swift + python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')" + chmod a+x builder + ./builder build -p ${{ env.PACKAGE_NAME }} + devices: runs-on: ${{ matrix.runner }} env: From 82f02db6e342010cc22772a08045527bf4e9b0be Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Tue, 7 Jan 2025 12:05:50 -0800 Subject: [PATCH 16/18] try ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93147235e..047664199 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,7 +86,7 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | - sed -i '' '1s|// swift-tools-version:.*|// swift-tools-version:6.0|' Package.swift + sed -i '1s|// swift-tools-version:.*|// swift-tools-version:6.0|' Package.swift python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')" chmod a+x builder ./builder build -p ${{ env.PACKAGE_NAME }} From 28d5c831cc9ae3aae35b57edcf7a0229923b5d0e Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Tue, 7 Jan 2025 12:08:07 -0800 Subject: [PATCH 17/18] sed mac --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 047664199..93147235e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,7 +86,7 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | - sed -i '1s|// swift-tools-version:.*|// swift-tools-version:6.0|' Package.swift + sed -i '' '1s|// swift-tools-version:.*|// swift-tools-version:6.0|' Package.swift python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')" chmod a+x builder ./builder build -p ${{ env.PACKAGE_NAME }} From 2c7b1e30d0734c95171f78735b2054e7d21ac5ba Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Tue, 7 Jan 2025 12:11:05 -0800 Subject: [PATCH 18/18] remove it --- .github/workflows/ci.yml | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93147235e..1f26edd08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,26 +71,6 @@ jobs: chmod a+x builder ./builder build -p ${{ env.PACKAGE_NAME }} - macos-swift6: - runs-on: macos-14 - env: - DEVELOPER_DIR: /Applications/Xcode.app - XCODE_DESTINATION: 'OS X' - NSUnbufferedIO: YES - strategy: - fail-fast: false - steps: - - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ env.CRT_CI_ROLE }} - aws-region: ${{ env.AWS_DEFAULT_REGION }} - - name: Build ${{ env.PACKAGE_NAME }} + consumers - run: | - sed -i '' '1s|// swift-tools-version:.*|// swift-tools-version:6.0|' Package.swift - python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')" - chmod a+x builder - ./builder build -p ${{ env.PACKAGE_NAME }} - devices: runs-on: ${{ matrix.runner }} env: