diff --git a/Split.xcodeproj/project.pbxproj b/Split.xcodeproj/project.pbxproj index 719ea7233..806ebf9b0 100644 --- a/Split.xcodeproj/project.pbxproj +++ b/Split.xcodeproj/project.pbxproj @@ -5286,7 +5286,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TVOS_DEPLOYMENT_TARGET = 15.4; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -5352,7 +5352,7 @@ SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TVOS_DEPLOYMENT_TARGET = 15.4; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -5397,7 +5397,7 @@ SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2,3,6"; TVOS_DEPLOYMENT_TARGET = 12.0; USER_HEADER_SEARCH_PATHS = ""; @@ -5440,7 +5440,7 @@ SWIFT_INCLUDE_PATHS = ""; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2,3,4"; TVOS_DEPLOYMENT_TARGET = 12.0; USER_HEADER_SEARCH_PATHS = ""; @@ -5471,7 +5471,7 @@ SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -5498,7 +5498,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -5583,7 +5583,7 @@ SUPPORTED_PLATFORMS = "watchsimulator watchos"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_INCLUDE_PATHS = ""; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 4; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 7.0; @@ -5626,7 +5626,7 @@ SUPPORTED_PLATFORMS = "watchsimulator watchos"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_INCLUDE_PATHS = ""; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 4; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 7.0; diff --git a/SplitTests/Fake/Network/HttpClientMock.swift b/SplitTests/Fake/Network/HttpClientMock.swift index 4a1fc62ab..ec38c5407 100644 --- a/SplitTests/Fake/Network/HttpClientMock.swift +++ b/SplitTests/Fake/Network/HttpClientMock.swift @@ -10,7 +10,7 @@ import Foundation @testable import Split import XCTest -class HttpClientMock: HttpClient { +class HttpClientMock: HttpClient, @unchecked Sendable { var throwOnSend = false var httpDataRequest: HttpDataRequest! diff --git a/SplitTests/Fake/Network/TelemetryProducerStub.swift b/SplitTests/Fake/Network/TelemetryProducerStub.swift index 1dae5d0a1..d0d549832 100644 --- a/SplitTests/Fake/Network/TelemetryProducerStub.swift +++ b/SplitTests/Fake/Network/TelemetryProducerStub.swift @@ -27,6 +27,8 @@ class TelemetryStorageStub: TelemetryStorage { var methodLatencies = [TelemetryMethod: Int]() var impressions = [TelemetryImpressionsDataType: Int]() var events = [TelemetryEventsDataType: Int]() + + var lock = NSLock() var isFactoryDataRecorded = Atomic(false) @@ -148,6 +150,8 @@ class TelemetryStorageStub: TelemetryStorage { } func popTags() -> [String] { + lock.lock() + defer { lock.unlock() } popTagsCallCount+=1 return [] } diff --git a/SplitTests/Fake/Service/NotificationHelperStub.swift b/SplitTests/Fake/Service/NotificationHelperStub.swift index 513f4ed24..4b503c85e 100644 --- a/SplitTests/Fake/Service/NotificationHelperStub.swift +++ b/SplitTests/Fake/Service/NotificationHelperStub.swift @@ -9,7 +9,7 @@ import Foundation @testable import Split -class NotificationHelperStub: NotificationHelper { +class NotificationHelperStub: NotificationHelper, @unchecked Sendable { private let queue = DispatchQueue(label: UUID.init().uuidString, attributes: .concurrent) private var actions = [String: [ObserverAction]]() diff --git a/SplitTests/Fake/Service/TlsPinCheckerMock.swift b/SplitTests/Fake/Service/TlsPinCheckerMock.swift index 13c869063..670ab3561 100644 --- a/SplitTests/Fake/Service/TlsPinCheckerMock.swift +++ b/SplitTests/Fake/Service/TlsPinCheckerMock.swift @@ -9,7 +9,7 @@ import Foundation @testable import Split -class PinCheckerMock: TlsPinChecker { +class PinCheckerMock: TlsPinChecker, @unchecked Sendable { var pinResults = [CredentialValidationResult]() private var respIndex = -1 diff --git a/SplitTests/Fake/Storage/IntegrationCoreDataHelper.swift b/SplitTests/Fake/Storage/IntegrationCoreDataHelper.swift index 2f82a395c..b76fb0ec1 100644 --- a/SplitTests/Fake/Storage/IntegrationCoreDataHelper.swift +++ b/SplitTests/Fake/Storage/IntegrationCoreDataHelper.swift @@ -140,7 +140,12 @@ class IntegrationCoreDataHelper { } } - private static var obsCrud = [String: DbRowNotification]() + #if swift(>=6.0) + nonisolated(unsafe) private static var obsCrud = [String: DbRowNotification]() + #else + private static var obsCrud = [String: DbRowNotification]() + #endif + static func getDbExp(count: Int, entity: CoreDataEntity, operation: String) -> XCTestExpectation { let row = DbRowNotification(expectation: XCTestExpectation(description: "\(operation)_count: \(count)"), triggerCount: count) diff --git a/SplitTests/Fake/Storage/MySegmentsStorageStub.swift b/SplitTests/Fake/Storage/MySegmentsStorageStub.swift index 072d466ba..7b5b403f9 100644 --- a/SplitTests/Fake/Storage/MySegmentsStorageStub.swift +++ b/SplitTests/Fake/Storage/MySegmentsStorageStub.swift @@ -20,6 +20,8 @@ class MySegmentsStorageStub: MySegmentsStorage { var getCountByKeyCalledCount = 0 var getCountCalledCount = 0 var changeNumber: Int64 = -1 + + var lock = NSLock() var keys: Set { return Set(segments.keys.map { $0 }) @@ -69,6 +71,8 @@ class MySegmentsStorageStub: MySegmentsStorage { } func getCount() -> Int { + lock.lock() + defer { lock.unlock() } getCountCalledCount+=1 var count = 0 for (_, value) in segments { diff --git a/SplitTests/Helpers/IntegrationHelper.swift b/SplitTests/Helpers/IntegrationHelper.swift index 746d13180..c591bf8b5 100644 --- a/SplitTests/Helpers/IntegrationHelper.swift +++ b/SplitTests/Helpers/IntegrationHelper.swift @@ -14,13 +14,13 @@ class IntegrationHelper { ServiceEndpoints.builder().set(sdkEndpoint: mockEndPoint).set(eventsEndpoint: mockEndPoint).build() } - static var dummyApiKey = "99049fd8653247c5ea42bc3c1ae2c6a42bc3" + static let dummyApiKey = "99049fd8653247c5ea42bc3c1ae2c6a42bc3" - static var dummyFolderName = "2a1099049fd8653247c5ea42bOIajMRhH0R0FcBwJZM4ca7zj6HAq1ZDS" + static let dummyFolderName = "2a1099049fd8653247c5ea42bOIajMRhH0R0FcBwJZM4ca7zj6HAq1ZDS" - static var dummyUserKey = "CUSTOMER_ID" + static let dummyUserKey = "CUSTOMER_ID" - static var mockEndPoint = "http://localhost:8080" + static let mockEndPoint = "http://localhost:8080" static var emptyMySegments: String { """ @@ -35,7 +35,7 @@ class IntegrationHelper { """ } - static var emptySplitChanges = "{\"ff\": {\"d\":[], \"s\": 9567456937865, \"t\": 9567456937869 }, \"rbs\": {\"d\":[], \"s\": -1, \"t\": -1 }}" + static let emptySplitChanges = "{\"ff\": {\"d\":[], \"s\": 9567456937865, \"t\": 9567456937869 }, \"rbs\": {\"d\":[], \"s\": -1, \"t\": -1 }}" static func emptySplitChanges(since: Int, till: Int) -> String { "{\"ff\": {\"d\":[], \"s\": \(since), \"t\": \(till) }, \"rbs\": {\"d\":[], \"s\": \(since), \"t\": \(till) }}" @@ -219,7 +219,7 @@ class IntegrationHelper { } } - static var dummyCipherKey = String("11F17550-01EA-45").dataBytes! + static let dummyCipherKey = String("11F17550-01EA-45").dataBytes! } // MARK: Simplest SDK Factory diff --git a/SplitTests/Helpers/SecurityHelper.swift b/SplitTests/Helpers/SecurityHelper.swift index 54c6a09f0..86dad8693 100644 --- a/SplitTests/Helpers/SecurityHelper.swift +++ b/SplitTests/Helpers/SecurityHelper.swift @@ -120,7 +120,7 @@ class SecurityHelper { } -class ChallengeSenderMock: NSObject, URLAuthenticationChallengeSender { +class ChallengeSenderMock: NSObject, URLAuthenticationChallengeSender, @unchecked Sendable { func use(_ credential: URLCredential, for challenge: URLAuthenticationChallenge) {} func continueWithoutCredential(for challenge: URLAuthenticationChallenge) {} func cancel(_ challenge: URLAuthenticationChallenge) {} diff --git a/SplitTests/HttpClient/CertPinning/HttpRequestManagerTests.swift b/SplitTests/HttpClient/CertPinning/HttpRequestManagerTests.swift index d9ced83e2..a2d5fdb1d 100644 --- a/SplitTests/HttpClient/CertPinning/HttpRequestManagerTests.swift +++ b/SplitTests/HttpClient/CertPinning/HttpRequestManagerTests.swift @@ -30,13 +30,16 @@ class HttpRequestManagerTests: XCTestCase { let manager = createRequestManager() var notifications = [String]() var results = [CredentialValidationResult: URLSession.AuthChallengeDisposition]() - + let notificationsQueue = DispatchQueue(label: "notifications.queue") + notificationHelper.addObserver(for: .pinnedCredentialValidationFail) { info in guard let info = info as? String else { XCTFail() return } - notifications.append(info) + notificationsQueue.sync { + notifications.append(info) + } } for result in CredentialValidationResult.allCases { diff --git a/SplitTests/Service/Telemetry/TelemetryStatsRecorderWorkerTests.swift b/SplitTests/Service/Telemetry/TelemetryStatsRecorderWorkerTests.swift index 0886aeaa8..7b771ec94 100644 --- a/SplitTests/Service/Telemetry/TelemetryStatsRecorderWorkerTests.swift +++ b/SplitTests/Service/Telemetry/TelemetryStatsRecorderWorkerTests.swift @@ -103,7 +103,8 @@ class TelemetryStatsRecorderWorkerTests: XCTestCase { } } - let semaphore = DispatchSemaphore(value: 0) + let exp = XCTestExpectation(description: "Waiting for all flushes") + group.notify(queue: queue) { XCTAssertEqual(6, self.statsRecorder.executeCallCount) XCTAssertNotNil(self.statsRecorder.statsSent) @@ -111,9 +112,9 @@ class TelemetryStatsRecorderWorkerTests: XCTestCase { XCTAssertEqual(6, self.mySegmentsStorage.getCountCalledCount) XCTAssertEqual(6, self.myLargeSegmentsStorage.getCountCalledCount) XCTAssertEqual(6, self.telemetryStorage.popTagsCallCount) - semaphore.signal() + exp.fulfill() } - semaphore.wait() + wait(for: [exp], timeout: 4) } } diff --git a/SplitTests/SplitEventsManagerTest.swift b/SplitTests/SplitEventsManagerTest.swift index 11d8603ae..2c4f330d0 100644 --- a/SplitTests/SplitEventsManagerTest.swift +++ b/SplitTests/SplitEventsManagerTest.swift @@ -306,7 +306,7 @@ class SplitEventsManagerTest: XCTestCase { } } -class TestTask: SplitEventTask { +class TestTask: SplitEventTask, @unchecked Sendable { var event: SplitEvent = .sdkReady diff --git a/SplitTests/Streaming/SyncManagerTest.swift b/SplitTests/Streaming/SyncManagerTest.swift index 756466696..0b6592b5a 100644 --- a/SplitTests/Streaming/SyncManagerTest.swift +++ b/SplitTests/Streaming/SyncManagerTest.swift @@ -216,21 +216,23 @@ class SyncManagerTest: XCTestCase { .set(telemetryServiceEndpoint: endpoints[3]) .set(eventsEndpoint: endpoints[4]) .build() - splitConfig.serviceEndpoints = epConfig + splitConfig.serviceEndpoints = epConfig splitConfig.streamingEnabled = true - var exp: XCTestExpectation? - let nHelper = DefaultNotificationHelper.instance - nHelper.addObserver(for: .pinnedCredentialValidationFail) { host in - exp?.fulfill() - } + for (oIndex, oEndpoint) in endpoints.enumerated() { - exp = XCTestExpectation() + let exp = XCTestExpectation(description: "Expectation for \(oEndpoint)") + + let nHelper = DefaultNotificationHelper.instance + nHelper.addObserver(for: .pinnedCredentialValidationFail) { host in + exp.fulfill() + } + synchronizer = SynchronizerStub() pushManager = PushNotificationManagerStub() syncManager = createSyncManager() syncManager.start() nHelper.post(notification: .pinnedCredentialValidationFail, info: oEndpoint as AnyObject) - wait(for: [exp!], timeout: 5.0) + wait(for: [exp], timeout: 5.0) print("Evaluating: \(oEndpoint)") switch oIndex {