diff options
| author | Bug Magnet <marco.nikic@mullvad.net> | 2025-05-16 16:20:55 +0200 |
|---|---|---|
| committer | Bug Magnet <marco.nikic@mullvad.net> | 2025-05-27 14:53:21 +0200 |
| commit | bbf890b10bda837308c05a3de6ac67df5aa2e06e (patch) | |
| tree | 3cac8d83c8c28c2532d3649a5a13d2e54e351cc4 | |
| parent | 6c9f7ec18da5bd26ce5880e5dc8f5c8b83d5f77f (diff) | |
| download | mullvadvpn-bbf890b10bda837308c05a3de6ac67df5aa2e06e.tar.xz mullvadvpn-bbf890b10bda837308c05a3de6ac67df5aa2e06e.zip | |
Enable Swift 6 mode for the PacketTunnel and test Target
31 files changed, 106 insertions, 147 deletions
diff --git a/ios/MullvadRustRuntimeTests/EphemeralPeerExchangeActorTests.swift b/ios/MullvadRustRuntimeTests/EphemeralPeerExchangeActorTests.swift index efc8c0fe0d..82e0ebdb48 100644 --- a/ios/MullvadRustRuntimeTests/EphemeralPeerExchangeActorTests.swift +++ b/ios/MullvadRustRuntimeTests/EphemeralPeerExchangeActorTests.swift @@ -15,12 +15,10 @@ import NetworkExtension import XCTest class EphemeralPeerExchangeActorTests: XCTestCase { - var tcpConnection: NWTCPConnectionStub! var tunnelProvider: TunnelProviderStub! override func setUpWithError() throws { - tcpConnection = NWTCPConnectionStub() - tunnelProvider = TunnelProviderStub(tcpConnection: tcpConnection) + tunnelProvider = TunnelProviderStub() } func testKeyExchangeFailsWhenNegotiationCannotStart() { @@ -37,7 +35,6 @@ class EphemeralPeerExchangeActorTests: XCTestCase { let privateKey = PrivateKey() keyExchangeActor.startNegotiation(with: privateKey, enablePostQuantum: true, enableDaita: false) - tcpConnection.becomeViable() wait(for: [negotiationFailure]) } diff --git a/ios/MullvadRustRuntimeTests/MullvadPostQuantum+Stubs.swift b/ios/MullvadRustRuntimeTests/MullvadPostQuantum+Stubs.swift index 59805230be..a62771003e 100644 --- a/ios/MullvadRustRuntimeTests/MullvadPostQuantum+Stubs.swift +++ b/ios/MullvadRustRuntimeTests/MullvadPostQuantum+Stubs.swift @@ -12,19 +12,6 @@ import NetworkExtension @testable import PacketTunnelCore @testable import WireGuardKitTypes -class NWTCPConnectionStub: NWTCPConnection { - var _isViable = false - override var isViable: Bool { - _isViable - } - - func becomeViable() { - willChangeValue(for: \.isViable) - _isViable = true - didChangeValue(for: \.isViable) - } -} - class TunnelProviderStub: TunnelProvider { func tunnelHandle() throws -> Int32 { 0 @@ -38,21 +25,6 @@ class TunnelProviderStub: TunnelProvider { send: { _, _, _, _ in return 0 } ) } - - let tcpConnection: NWTCPConnectionStub - - init(tcpConnection: NWTCPConnectionStub) { - self.tcpConnection = tcpConnection - } - - func createTCPConnectionThroughTunnel( - to remoteEndpoint: NWEndpoint, - enableTLS: Bool, - tlsParameters TLSParameters: NWTLSParameters?, - delegate: Any? - ) -> NWTCPConnection { - tcpConnection - } } class FailedNegotiatorStub: EphemeralPeerNegotiating { diff --git a/ios/MullvadRustRuntimeTests/TCPConnection.swift b/ios/MullvadRustRuntimeTests/TCPConnection.swift index cffce29e4e..c4c74ce76a 100644 --- a/ios/MullvadRustRuntimeTests/TCPConnection.swift +++ b/ios/MullvadRustRuntimeTests/TCPConnection.swift @@ -11,7 +11,7 @@ import Network /// Minimal implementation of TCP connection capable of receiving data. /// > Warning: Do not use this implementation in production code. See the warning in `start()`. -class TCPConnection: Connection { +class TCPConnection: Connection, @unchecked Sendable { private let dispatchQueue = DispatchQueue(label: "TCPConnection") private let nwConnection: NWConnection diff --git a/ios/MullvadRustRuntimeTests/UDPConnection.swift b/ios/MullvadRustRuntimeTests/UDPConnection.swift index 66ef178d96..c4b3becc1d 100644 --- a/ios/MullvadRustRuntimeTests/UDPConnection.swift +++ b/ios/MullvadRustRuntimeTests/UDPConnection.swift @@ -16,7 +16,7 @@ protocol Connection { /// Minimal implementation of UDP connection capable of sending data. /// > Warning: Do not use this implementation in production code. See the warning in `start()`. -class UDPConnection: Connection { +class UDPConnection: Connection, @unchecked Sendable { private let dispatchQueue = DispatchQueue(label: "UDPConnection") private let nwConnection: NWConnection diff --git a/ios/MullvadTypes/Promise.swift b/ios/MullvadTypes/Promise.swift index b5f5a58873..3bf66e7ae3 100644 --- a/ios/MullvadTypes/Promise.swift +++ b/ios/MullvadTypes/Promise.swift @@ -52,7 +52,7 @@ public final class Promise<Success, Failure: Error>: @unchecked Sendable { // allows the waiter to wait to `receive()` from another operation // asynchronously. It is important not to forget to call `send`, otherwise this // operation will block indefinitely. -public struct OneshotChannel { +public struct OneshotChannel: Sendable { private var continuation: AsyncStream<Void>.Continuation? private var stream: AsyncStream<Void> diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index de1e60d6b1..eb7a32dcd8 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -7338,7 +7338,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -7358,7 +7358,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -7469,7 +7469,7 @@ SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -7509,7 +7509,7 @@ SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -7532,7 +7532,7 @@ SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -7553,7 +7553,7 @@ SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -7755,7 +7755,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_STRICT_CONCURRENCY = minimal; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; }; name = Debug; }; @@ -7775,7 +7775,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "$(APPLICATION_IDENTIFIER).PacketTunnel"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_STRICT_CONCURRENCY = minimal; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; }; name = Release; }; @@ -8230,7 +8230,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG MULLVAD_ENVIRONMENT_PRODUCTION $(inherited)"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/MullvadVPNUITests/BridgingHeader.h"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = MullvadVPN; }; @@ -8262,7 +8262,7 @@ SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/MullvadVPNUITests/BridgingHeader.h"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = MullvadVPN; }; @@ -8396,7 +8396,7 @@ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Packet Tunnel Development"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_STRICT_CONCURRENCY = minimal; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; }; name = Staging; }; @@ -8415,7 +8415,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Staging; @@ -8634,7 +8634,7 @@ SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -8657,7 +8657,7 @@ SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Staging; @@ -8789,7 +8789,7 @@ SUPPORTS_MACCATALYST = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG MULLVAD_ENVIRONMENT_STAGING"; SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/MullvadVPNUITests/BridgingHeader.h"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = MullvadVPN; }; @@ -8813,7 +8813,7 @@ SUPPORTS_MACCATALYST = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = MULLVAD_ENVIRONMENT_PRODUCTION; SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/MullvadVPNUITests/BridgingHeader.h"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = MullvadVPN; }; @@ -8864,7 +8864,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -8915,7 +8915,7 @@ SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -8966,7 +8966,7 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -9016,7 +9016,7 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -9044,7 +9044,7 @@ SUPPORTS_MACCATALYST = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -9069,7 +9069,7 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Staging; @@ -9094,7 +9094,7 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -9119,7 +9119,7 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = MockRelease; @@ -9242,7 +9242,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Packet Tunnel Development"; SWIFT_STRICT_CONCURRENCY = minimal; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; }; name = MockRelease; }; @@ -9261,7 +9261,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = MockRelease; @@ -9480,7 +9480,7 @@ SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -9503,7 +9503,7 @@ SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = MockRelease; diff --git a/ios/MullvadVPNTests/MullvadLogging/LogFileOutputStreamTests.swift b/ios/MullvadVPNTests/MullvadLogging/LogFileOutputStreamTests.swift index 87f215dd33..0ff1ab8df8 100644 --- a/ios/MullvadVPNTests/MullvadLogging/LogFileOutputStreamTests.swift +++ b/ios/MullvadVPNTests/MullvadLogging/LogFileOutputStreamTests.swift @@ -6,7 +6,7 @@ // Copyright © 2025 Mullvad VPN AB. All rights reserved. // -import Foundation +@preconcurrency import Foundation @testable import MullvadLogging import Testing diff --git a/ios/MullvadVPNTests/MullvadSettings/IPOverrideRepositoryStub.swift b/ios/MullvadVPNTests/MullvadSettings/IPOverrideRepositoryStub.swift index 6bd16f5432..36d60bf4f7 100644 --- a/ios/MullvadVPNTests/MullvadSettings/IPOverrideRepositoryStub.swift +++ b/ios/MullvadVPNTests/MullvadSettings/IPOverrideRepositoryStub.swift @@ -6,7 +6,7 @@ // Copyright © 2025 Mullvad VPN AB. All rights reserved. // -import Combine +@preconcurrency import Combine import MullvadSettings struct IPOverrideRepositoryStub: IPOverrideRepositoryProtocol { diff --git a/ios/MullvadVPNTests/MullvadSettings/MigrationManagerMultiProcessUpgradeTests.swift b/ios/MullvadVPNTests/MullvadSettings/MigrationManagerMultiProcessUpgradeTests.swift index 6e619256c5..d268171d99 100644 --- a/ios/MullvadVPNTests/MullvadSettings/MigrationManagerMultiProcessUpgradeTests.swift +++ b/ios/MullvadVPNTests/MullvadSettings/MigrationManagerMultiProcessUpgradeTests.swift @@ -26,8 +26,8 @@ extension MigrationManagerTests { let backgroundMigrationExpectation = expectation(description: "Migration from packet tunnel") let foregroundMigrationExpectation = expectation(description: "Migration from host") - var migrationHappenedInPacketTunnel = false - var migrationHappenedInHost = false + nonisolated(unsafe) var migrationHappenedInPacketTunnel = false + nonisolated(unsafe) var migrationHappenedInHost = false packetTunnelProcess.async { [unowned self] in manager.migrateSettings(store: MigrationManagerTests.store) { backgroundMigrationResult in diff --git a/ios/MullvadVPNTests/MullvadSettings/MigrationManagerTests.swift b/ios/MullvadVPNTests/MullvadSettings/MigrationManagerTests.swift index f62ca74403..ab93a2d37d 100644 --- a/ios/MullvadVPNTests/MullvadSettings/MigrationManagerTests.swift +++ b/ios/MullvadVPNTests/MullvadSettings/MigrationManagerTests.swift @@ -12,7 +12,7 @@ @testable import MullvadTypes import XCTest -final class MigrationManagerTests: XCTestCase { +final class MigrationManagerTests: XCTestCase, @unchecked Sendable { static let store = InMemorySettingsStore<SettingNotFound>() var manager: MigrationManager! diff --git a/ios/MullvadVPNTests/MullvadVPN/Classes/InputTextFormatterTests.swift b/ios/MullvadVPNTests/MullvadVPN/Classes/InputTextFormatterTests.swift index def507f6a7..fb77a6f5e9 100644 --- a/ios/MullvadVPNTests/MullvadVPN/Classes/InputTextFormatterTests.swift +++ b/ios/MullvadVPNTests/MullvadVPN/Classes/InputTextFormatterTests.swift @@ -8,6 +8,7 @@ import XCTest +@MainActor class InputTextFormatterTests: XCTestCase { private let accountNumber = "12345678" private var inputTextFormatter: InputTextFormatter! @@ -19,14 +20,14 @@ class InputTextFormatterTests: XCTestCase { maxGroups: 4 ) - override func setUp() { + override func setUp() async throws { inputTextFormatter = InputTextFormatter( string: accountNumber, configuration: configuration ) } - override func tearDown() { + override func tearDown() async throws { inputTextFormatter = nil } diff --git a/ios/MullvadVPNTests/MullvadVPN/PacketTunnel/DeviceCheck/DeviceCheckOperationTests.swift b/ios/MullvadVPNTests/MullvadVPN/PacketTunnel/DeviceCheck/DeviceCheckOperationTests.swift index fecc0f384b..8a5f95cb15 100644 --- a/ios/MullvadVPNTests/MullvadVPN/PacketTunnel/DeviceCheck/DeviceCheckOperationTests.swift +++ b/ios/MullvadVPNTests/MullvadVPN/PacketTunnel/DeviceCheck/DeviceCheckOperationTests.swift @@ -12,14 +12,14 @@ import MullvadSettings import MullvadTypes import Operations import PacketTunnelCore -import WireGuardKitTypes +@preconcurrency import WireGuardKitTypes import XCTest class DeviceCheckOperationTests: XCTestCase { private let operationQueue = AsyncOperationQueue() private let dispatchQueue = DispatchQueue(label: "TestQueue") - func testShouldReportExpiredAccount() { + func testShouldReportExpiredAccount() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -45,10 +45,10 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } - func testShouldNotRotateKeyForInvalidAccount() { + func testShouldNotRotateKeyForInvalidAccount() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -76,10 +76,10 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } - func testShouldNotRotateKeyForRevokedDevice() { + func testShouldNotRotateKeyForRevokedDevice() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -107,10 +107,10 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } - func testShouldRotateKeyOnMismatchImmediately() { + func testShouldRotateKeyOnMismatchImmediately() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -136,10 +136,10 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } - func testShouldRespectCooldownWhenAttemptingToRotateImmediately() { + func testShouldRespectCooldownWhenAttemptingToRotateImmediately() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -165,10 +165,10 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } - func testShouldNotRotateDeviceKeyWhenServerKeyIsIdentical() { + func testShouldNotRotateDeviceKeyWhenServerKeyIsIdentical() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -188,10 +188,10 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } - func testShouldNotRotateKeyBeforeRetryIntervalPassed() { + func testShouldNotRotateKeyBeforeRetryIntervalPassed() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -213,10 +213,10 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } - func testShouldRotateKeyOnceInTwentyFourHours() { + func testShouldRotateKeyOnceInTwentyFourHours() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -238,10 +238,10 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } - func testShouldReportFailedKeyRotationAttempt() { + func testShouldReportFailedKeyRotationAttempt() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -268,10 +268,10 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } - func testShouldFailOnKeyRotationRace() { + func testShouldFailOnKeyRotationRace() async { let expect = expectation(description: "Wait for operation to complete") let currentKey = PrivateKey() @@ -305,7 +305,7 @@ class DeviceCheckOperationTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: .UnitTest.timeout) + await fulfillment(of: [expect], timeout: .UnitTest.timeout) } private func startDeviceCheck( @@ -327,7 +327,7 @@ class DeviceCheckOperationTests: XCTestCase { } /// Mock implementation of a remote service used by `DeviceCheckOperation` to reach the API. -private class MockRemoteService: DeviceCheckRemoteServiceProtocol { +private class MockRemoteService: DeviceCheckRemoteServiceProtocol, @unchecked Sendable { typealias AccountDataHandler = (_ accountNumber: String) throws -> Account typealias DeviceDataHandler = (_ accountNumber: String, _ deviceIdentifier: String) throws -> Device typealias RotateDeviceKeyHandler = ( @@ -356,7 +356,7 @@ private class MockRemoteService: DeviceCheckRemoteServiceProtocol { func getAccountData( accountNumber: String, - completion: @escaping (Result<Account, Error>) -> Void + completion: @escaping @Sendable (Result<Account, Error>) -> Void ) -> Cancellable { DispatchQueue.main.async { [self] in let result: Result<Account, Error> = Result { @@ -374,7 +374,7 @@ private class MockRemoteService: DeviceCheckRemoteServiceProtocol { func getDevice( accountNumber: String, identifier: String, - completion: @escaping (Result<Device, Error>) -> Void + completion: @escaping @Sendable (Result<Device, Error>) -> Void ) -> Cancellable { DispatchQueue.main.async { [self] in let result: Result<Device, Error> = Result { @@ -395,7 +395,7 @@ private class MockRemoteService: DeviceCheckRemoteServiceProtocol { accountNumber: String, identifier: String, publicKey: PublicKey, - completion: @escaping (Result<Device, Error>) -> Void + completion: @escaping @Sendable (Result<Device, Error>) -> Void ) -> Cancellable { DispatchQueue.main.async { [self] in let result: Result<Device, Error> = Result { diff --git a/ios/PacketTunnel/DeviceCheck/DeviceCheckOperation.swift b/ios/PacketTunnel/DeviceCheck/DeviceCheckOperation.swift index 926b94a9e3..ab88b22167 100644 --- a/ios/PacketTunnel/DeviceCheck/DeviceCheckOperation.swift +++ b/ios/PacketTunnel/DeviceCheck/DeviceCheckOperation.swift @@ -66,7 +66,7 @@ final class DeviceCheckOperation: ResultOperation<DeviceCheck>, @unchecked Senda Begins the flow by fetching device state and then fetching account and device data. Calls `didReceiveData()` with the received data when done. */ - private func startFlow(completion: @escaping (Result<DeviceCheck, Error>) -> Void) { + private func startFlow(completion: @escaping @Sendable (Result<DeviceCheck, Error>) -> Void) { do { guard case let .loggedIn(accountData, deviceData) = try deviceStateAccessor.read() else { throw DeviceCheckError.invalidDeviceState @@ -90,7 +90,7 @@ final class DeviceCheckOperation: ResultOperation<DeviceCheck>, @unchecked Senda private func didReceiveData( accountResult: Result<Account, Error>, deviceResult: Result<Device, Error>, - completion: @escaping (Result<DeviceCheck, Error>) -> Void + completion: @escaping @Sendable (Result<DeviceCheck, Error>) -> Void ) { do { let accountVerdict = try accountVerdict(from: accountResult) @@ -158,7 +158,7 @@ final class DeviceCheckOperation: ResultOperation<DeviceCheck>, @unchecked Senda then it rotate device key by marking the beginning of key rotation, updating device state and persisting before proceeding to rotate the key. */ - private func rotateKeyIfNeeded(completion: @escaping (Result<KeyRotationStatus, Error>) -> Void) { + private func rotateKeyIfNeeded(completion: @escaping @Sendable (Result<KeyRotationStatus, Error>) -> Void) { let deviceState: DeviceState do { deviceState = try deviceStateAccessor.read() diff --git a/ios/PacketTunnel/PacketTunnelProvider/NEProviderStopReason+Debug.swift b/ios/PacketTunnel/PacketTunnelProvider/NEProviderStopReason+Debug.swift index cb749f68a5..a86bebbd54 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/NEProviderStopReason+Debug.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/NEProviderStopReason+Debug.swift @@ -46,6 +46,8 @@ extension NEProviderStopReason: CustomStringConvertible { return "sleep" case .appUpdate: return "app update" + case .internalError: + return "internal error" @unknown default: return "unknown value (\(rawValue))" } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+Extensions.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+Extensions.swift index 7ae35c4685..5345287b73 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+Extensions.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+Extensions.swift @@ -6,7 +6,7 @@ // Copyright © 2025 Mullvad VPN AB. All rights reserved. // -import Combine +@preconcurrency import Combine import Foundation extension PacketTunnelActor { diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift index 9cf3833bb8..c467ca270d 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift @@ -7,7 +7,7 @@ // import Foundation -import MullvadTypes +@preconcurrency import MullvadTypes import Network import WireGuardKitTypes diff --git a/ios/PacketTunnelCore/Pinger/PingerProtocol.swift b/ios/PacketTunnelCore/Pinger/PingerProtocol.swift index 1c06c634f9..0da7f7a3f0 100644 --- a/ios/PacketTunnelCore/Pinger/PingerProtocol.swift +++ b/ios/PacketTunnelCore/Pinger/PingerProtocol.swift @@ -29,7 +29,7 @@ public struct PingerSendResult { } /// A type capable of sending and receving ICMP traffic. -public protocol PingerProtocol { +public protocol PingerProtocol: Sendable { var onReply: ((PingerReply) -> Void)? { get set } func startPinging(destAddress: IPv4Address) throws diff --git a/ios/PacketTunnelCore/Pinger/TunnelPinger.swift b/ios/PacketTunnelCore/Pinger/TunnelPinger.swift index 10807e7362..20defd7a90 100644 --- a/ios/PacketTunnelCore/Pinger/TunnelPinger.swift +++ b/ios/PacketTunnelCore/Pinger/TunnelPinger.swift @@ -12,7 +12,7 @@ import Network import PacketTunnelCore import WireGuardKit -public final class TunnelPinger: PingerProtocol { +public final class TunnelPinger: PingerProtocol, @unchecked Sendable { private var sequenceNumber: UInt16 = 0 private let stateLock = NSLock() private let pingReceiveQueue: DispatchQueue diff --git a/ios/PacketTunnelCore/TunnelMonitor/TunnelDeviceInfoProtocol.swift b/ios/PacketTunnelCore/TunnelMonitor/TunnelDeviceInfoProtocol.swift index 664fd69ed9..d9a0a33250 100644 --- a/ios/PacketTunnelCore/TunnelMonitor/TunnelDeviceInfoProtocol.swift +++ b/ios/PacketTunnelCore/TunnelMonitor/TunnelDeviceInfoProtocol.swift @@ -9,7 +9,7 @@ import Foundation /// A type that can provide statistics and basic information about tunnel device. -public protocol TunnelDeviceInfoProtocol { +public protocol TunnelDeviceInfoProtocol: Sendable { /// Returns tunnel interface name (i.e utun0) if available. var interfaceName: String? { get } diff --git a/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitor.swift b/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitor.swift index c1160d25f2..9d20efcc01 100644 --- a/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitor.swift +++ b/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitor.swift @@ -13,7 +13,7 @@ import Network import NetworkExtension /// Tunnel monitor. -public final class TunnelMonitor: TunnelMonitorProtocol { +public final class TunnelMonitor: TunnelMonitorProtocol, @unchecked Sendable { private let tunnelDeviceInfo: TunnelDeviceInfoProtocol private let nslock = NSLock() @@ -22,7 +22,6 @@ public final class TunnelMonitor: TunnelMonitorProtocol { private let timings: TunnelMonitorTimings private var pinger: PingerProtocol - private var isObservingDefaultPath = false private var timer: DispatchSourceTimer? private var state: TunnelMonitorState diff --git a/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitorTimings.swift b/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitorTimings.swift index 7e925ec932..ee1836bb22 100644 --- a/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitorTimings.swift +++ b/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitorTimings.swift @@ -8,7 +8,7 @@ import MullvadTypes -public struct TunnelMonitorTimings { +public struct TunnelMonitorTimings: Sendable { /// Interval for periodic heartbeat ping issued when traffic is flowing. /// Should help to detect connectivity issues on networks that drop traffic in one of directions, /// regardless if tx/rx counters are being updated. diff --git a/ios/PacketTunnelCore/URLRequestProxy/ProxyURLRequest.swift b/ios/PacketTunnelCore/URLRequestProxy/ProxyURLRequest.swift index e40f9d78e5..82e33e8c03 100644 --- a/ios/PacketTunnelCore/URLRequestProxy/ProxyURLRequest.swift +++ b/ios/PacketTunnelCore/URLRequestProxy/ProxyURLRequest.swift @@ -9,7 +9,7 @@ import Foundation /// Struct describing serializable URLRequest data. -public struct ProxyURLRequest: Codable { +public struct ProxyURLRequest: Codable, Sendable { public let id: UUID public let url: URL public let method: String? diff --git a/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift b/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift index 85737b4bc9..d340974131 100644 --- a/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift +++ b/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift @@ -89,10 +89,7 @@ final class EphemeralPeerExchangingPipelineTests: XCTestCase { let connectionState = stubConnectionState(enableMultiHop: false, enablePostQuantum: true, enableDaita: false) await postQuantumKeyExchangingPipeline.startNegotiation(connectionState, privateKey: PrivateKey()) - wait( - for: [reconfigurationExpectation, negotiationSuccessful], - timeout: .UnitTest.invertedTimeout - ) + await fulfillment(of: [reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout) } func testSingleHopDaitaPeerExchange() async throws { @@ -123,10 +120,7 @@ final class EphemeralPeerExchangingPipelineTests: XCTestCase { let connectionState = stubConnectionState(enableMultiHop: false, enablePostQuantum: false, enableDaita: true) await postQuantumKeyExchangingPipeline.startNegotiation(connectionState, privateKey: PrivateKey()) - wait( - for: [reconfigurationExpectation, negotiationSuccessful], - timeout: .UnitTest.invertedTimeout - ) + await fulfillment(of: [reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout) } func testMultiHopPostQuantumKeyExchange() async throws { @@ -158,10 +152,7 @@ final class EphemeralPeerExchangingPipelineTests: XCTestCase { let connectionState = stubConnectionState(enableMultiHop: true, enablePostQuantum: true, enableDaita: false) await postQuantumKeyExchangingPipeline.startNegotiation(connectionState, privateKey: PrivateKey()) - wait( - for: [reconfigurationExpectation, negotiationSuccessful], - timeout: .UnitTest.invertedTimeout - ) + await fulfillment(of: [reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout) } func testMultiHopDaitaExchange() async throws { @@ -188,10 +179,7 @@ final class EphemeralPeerExchangingPipelineTests: XCTestCase { let connectionState = stubConnectionState(enableMultiHop: true, enablePostQuantum: false, enableDaita: true) await postQuantumKeyExchangingPipeline.startNegotiation(connectionState, privateKey: PrivateKey()) - wait( - for: [reconfigurationExpectation, negotiationSuccessful], - timeout: .UnitTest.invertedTimeout - ) + await fulfillment(of: [reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout) } func stubConnectionState( diff --git a/ios/PacketTunnelCoreTests/Mocks/EphemeralPeerExchangeActorStub.swift b/ios/PacketTunnelCoreTests/Mocks/EphemeralPeerExchangeActorStub.swift index 9766aac9ec..341e41eba6 100644 --- a/ios/PacketTunnelCoreTests/Mocks/EphemeralPeerExchangeActorStub.swift +++ b/ios/PacketTunnelCoreTests/Mocks/EphemeralPeerExchangeActorStub.swift @@ -12,7 +12,7 @@ import NetworkExtension @testable import PacketTunnelCore @testable import WireGuardKitTypes -final class EphemeralPeerExchangeActorStub: EphemeralPeerExchangeActorProtocol { +final class EphemeralPeerExchangeActorStub: EphemeralPeerExchangeActorProtocol, @unchecked Sendable { typealias KeyNegotiationResult = Result<(PreSharedKey, PrivateKey), EphemeralPeerExchangeErrorStub> var result: KeyNegotiationResult = .failure(.unknown) diff --git a/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActor+Mocks.swift b/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActor+Mocks.swift index bb8d94a806..135b2a3e1c 100644 --- a/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActor+Mocks.swift +++ b/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActor+Mocks.swift @@ -8,8 +8,8 @@ import Foundation import MullvadMockData -import MullvadREST -import PacketTunnelCore +@preconcurrency import MullvadREST +@preconcurrency import PacketTunnelCore extension PacketTunnelActorTimings { static var timingsForTests: PacketTunnelActorTimings { diff --git a/ios/PacketTunnelCoreTests/Mocks/PingerMock.swift b/ios/PacketTunnelCoreTests/Mocks/PingerMock.swift index 9c468fd45d..bab560267e 100644 --- a/ios/PacketTunnelCoreTests/Mocks/PingerMock.swift +++ b/ios/PacketTunnelCoreTests/Mocks/PingerMock.swift @@ -12,7 +12,7 @@ import Network @testable import PacketTunnelCore /// Ping client mock that can be used to simulate network transmission errors and delays. -class PingerMock: PingerProtocol { +class PingerMock: PingerProtocol, @unchecked Sendable { typealias OutcomeDecider = (IPv4Address, UInt16) -> Outcome private let decideOutcome: OutcomeDecider diff --git a/ios/PacketTunnelCoreTests/Mocks/TunnelDeviceInfoStub.swift b/ios/PacketTunnelCoreTests/Mocks/TunnelDeviceInfoStub.swift index 40aaafee73..e6cde648ba 100644 --- a/ios/PacketTunnelCoreTests/Mocks/TunnelDeviceInfoStub.swift +++ b/ios/PacketTunnelCoreTests/Mocks/TunnelDeviceInfoStub.swift @@ -10,7 +10,7 @@ import Foundation import PacketTunnelCore /// Tunnel device stub that returns fixed interface name and feeds network stats from the type implementing `NetworkStatsProviding` -struct TunnelDeviceInfoStub: TunnelDeviceInfoProtocol { +struct TunnelDeviceInfoStub: TunnelDeviceInfoProtocol, @unchecked Sendable { let networkStatsProviding: NetworkStatsProviding var interfaceName: String? { diff --git a/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift b/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift index 4e77a6b617..7221e72a55 100644 --- a/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift +++ b/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift @@ -90,8 +90,8 @@ final class MultiHopEphemeralPeerExchangerTests: XCTestCase { await multiHopExchanger.start() - wait( - for: [expectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], + await fulfillment( + of: [expectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout ) } @@ -133,8 +133,8 @@ final class MultiHopEphemeralPeerExchangerTests: XCTestCase { }) await multiHopPeerExchanger.start() - wait( - for: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], + await fulfillment( + of: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout ) } @@ -171,8 +171,8 @@ final class MultiHopEphemeralPeerExchangerTests: XCTestCase { }) await multiHopPeerExchanger.start() - wait( - for: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], + await fulfillment( + of: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout ) } @@ -213,8 +213,8 @@ final class MultiHopEphemeralPeerExchangerTests: XCTestCase { }) await multiHopPeerExchanger.start() - wait( - for: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], + await fulfillment( + of: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout ) } diff --git a/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift b/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift index 484e69ffe1..2c4e145b1c 100644 --- a/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift +++ b/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift @@ -6,7 +6,7 @@ // Copyright © 2025 Mullvad VPN AB. All rights reserved. // -import Combine +@preconcurrency import Combine @testable import MullvadMockData @testable import MullvadREST @testable import MullvadSettings diff --git a/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift b/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift index cba495a596..7707ffabf7 100644 --- a/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift +++ b/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift @@ -68,8 +68,8 @@ final class SingleHopEphemeralPeerExchangerTests: XCTestCase { await singleHopPostQuantumKeyExchanging.start() - wait( - for: [expectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], + await fulfillment( + of: [expectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout ) } @@ -110,8 +110,8 @@ final class SingleHopEphemeralPeerExchangerTests: XCTestCase { }) await singleHopPostQuantumKeyExchanging.start() - wait( - for: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], + await fulfillment( + of: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout ) } @@ -147,8 +147,8 @@ final class SingleHopEphemeralPeerExchangerTests: XCTestCase { }) await multiHopPeerExchanger.start() - wait( - for: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], + await fulfillment( + of: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], timeout: .UnitTest.invertedTimeout ) } diff --git a/ios/PacketTunnelCoreTests/TunnelMonitorTests.swift b/ios/PacketTunnelCoreTests/TunnelMonitorTests.swift index 5f15b7cf45..62d0fc057f 100644 --- a/ios/PacketTunnelCoreTests/TunnelMonitorTests.swift +++ b/ios/PacketTunnelCoreTests/TunnelMonitorTests.swift @@ -15,7 +15,7 @@ import XCTest final class TunnelMonitorTests: XCTestCase { let networkCounters = NetworkCounters() - func testShouldDetermineConnectionEstablished() throws { + func testShouldDetermineConnectionEstablished() async throws { let connectedExpectation = expectation(description: "Should report connected.") let connectionLostExpectation = expectation(description: "Should not report connection loss") connectionLostExpectation.isInverted = true @@ -38,10 +38,10 @@ final class TunnelMonitorTests: XCTestCase { tunnelMonitor.start(probeAddress: .loopback) - waitForExpectations(timeout: .UnitTest.invertedTimeout) + await fulfillment(of: [connectedExpectation, connectionLostExpectation], timeout: .UnitTest.invertedTimeout) } - func testInitialConnectionTimings() { + func testInitialConnectionTimings() async throws { // Setup pinger so that it never receives any replies. let pinger = PingerMock(networkStatsReporting: networkCounters) { _, _ in .ignore } @@ -108,7 +108,7 @@ final class TunnelMonitorTests: XCTestCase { // Start monitoring. tunnelMonitor.start(probeAddress: .loopback) - waitForExpectations(timeout: TimeInterval(timeout) / 1000) + await fulfillment(of: [expectation], timeout: TimeInterval(timeout) / 1000) } } |
