From 0729519f5a0001fe3271e37193250bcdbbe15604 Mon Sep 17 00:00:00 2001 From: Jullian Mercier <31648126+jullianm@users.noreply.github.com> Date: Wed, 19 Feb 2025 12:20:30 +0100 Subject: [PATCH 1/8] fix mls logout error --- .../Source/MLS/MLSService.swift | 18 +++++++++++------- .../Source/MLS/SyncStatusProtocol.swift | 2 +- .../Tests/MLS/MockSyncStatus.swift | 2 +- .../Decoding/EventDecoder+MLS.swift | 12 ++++++------ .../Sources/SharingSession.swift | 2 +- .../Source/UserSession/SyncStatus.swift | 8 ++++++-- .../UserSession/ZMSyncStateDelegate.swift | 2 +- .../ZMUserSession/ZMUserSession.swift | 8 +++++--- .../TeamInvitationRequestStrategyTests.swift | 2 +- .../Synchronization/SynchronizationMocks.swift | 2 +- .../ZMUserSessionTests+PushNotifications.swift | 2 +- .../UserSession/ZMUserSessionTests.swift | 8 ++++---- .../DeveloperDebugActionsViewModel.swift | 2 +- 13 files changed, 40 insertions(+), 30 deletions(-) diff --git a/wire-ios-data-model/Source/MLS/MLSService.swift b/wire-ios-data-model/Source/MLS/MLSService.swift index bb408795a27..52de9d0806d 100644 --- a/wire-ios-data-model/Source/MLS/MLSService.swift +++ b/wire-ios-data-model/Source/MLS/MLSService.swift @@ -1316,7 +1316,7 @@ public final class MLSService: MLSServiceInterface { // In case of `WrongEpoch` error, local and remote epochs have diverged so we may have missed events. // This ensures we're on the latest state. - await syncStatus.performQuickSync() + await syncStatus.performQuickSync(isRecovering: true) guard let conversationInfo = fetchConversationInfo( with: groupID, @@ -1726,12 +1726,16 @@ public final class MLSService: MLSServiceInterface { } + private var task: Task? + public func commitPendingProposalsIfNeeded() { - guard let context else { - return - } + task?.cancel() + + task = Task { [self] in + guard !Task.isCancelled else { + return + } - WaitingGroupTask(context: context) { [self] in await commitPendingProposals() } } @@ -1886,13 +1890,13 @@ public final class MLSService: MLSServiceInterface { } catch CommitError.failedToSendCommit(recovery: .commitPendingProposalsAfterQuickSync, _) { logger.warn("failed to send commit, syncing then committing pending proposals...") - await syncStatus.performQuickSync() + await syncStatus.performQuickSync(isRecovering: true) logger.info("sync finished, committing pending proposals...") try await commitPendingProposals(in: groupID) } catch CommitError.failedToSendCommit(recovery: .retryAfterQuickSync, cause: let error) { logger.warn("failed to send commit, syncing then retrying operation...") - await syncStatus.performQuickSync() + await syncStatus.performQuickSync(isRecovering: true) logger.info("sync finished, retying operation...") guard retryCount <= maxRetryAttempts else { diff --git a/wire-ios-data-model/Source/MLS/SyncStatusProtocol.swift b/wire-ios-data-model/Source/MLS/SyncStatusProtocol.swift index aab6d07df6e..c138a6889da 100644 --- a/wire-ios-data-model/Source/MLS/SyncStatusProtocol.swift +++ b/wire-ios-data-model/Source/MLS/SyncStatusProtocol.swift @@ -21,7 +21,7 @@ import Foundation // sourcery: AutoMockable public protocol SyncStatusProtocol { - func performQuickSync() async + func performQuickSync(isRecovering: Bool) async func resyncResources() func forceSlowSync() diff --git a/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift b/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift index 30dfb21199e..afc6ddb5beb 100644 --- a/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift +++ b/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift @@ -30,7 +30,7 @@ class MockSyncStatus: SyncStatusProtocol { } var mockPerformQuickSync: (() async -> Void)? - func performQuickSync() async { + func performQuickSync(isRecovering: Bool) async { guard let mock = mockPerformQuickSync else { fatalError("no mock for `performQuickSync`") } diff --git a/wire-ios-request-strategy/Sources/Synchronization/Decoding/EventDecoder+MLS.swift b/wire-ios-request-strategy/Sources/Synchronization/Decoding/EventDecoder+MLS.swift index 6632c2dfd9f..44e8f267da7 100644 --- a/wire-ios-request-strategy/Sources/Synchronization/Decoding/EventDecoder+MLS.swift +++ b/wire-ios-request-strategy/Sources/Synchronization/Decoding/EventDecoder+MLS.swift @@ -123,17 +123,17 @@ extension EventDecoder { case let .proposal(commitDelay): let scheduledDate = (updateEvent.timestamp ?? Date()) + TimeInterval(commitDelay) - let mlsService = await context.perform { + await context.perform { conversation?.commitPendingProposalDate = scheduledDate - return context.mlsService - } - - if let mlsService, updateEvent.source == .webSocket { - mlsService.commitPendingProposalsIfNeeded() } } } + if let mlsService = await context.perform({ context.mlsService }), + updateEvent.source == .webSocket { + mlsService.commitPendingProposalsIfNeeded() + } + return events } diff --git a/wire-ios-share-engine/Sources/SharingSession.swift b/wire-ios-share-engine/Sources/SharingSession.swift index 97012f08791..d7047f67d8b 100644 --- a/wire-ios-share-engine/Sources/SharingSession.swift +++ b/wire-ios-share-engine/Sources/SharingSession.swift @@ -154,7 +154,7 @@ final class ApplicationStatusDirectory: ApplicationStatus { /// Required by `MLSService` initializer. /// No need to fill in the methods as we don't sync resources in the share engine. struct SyncStatus: SyncStatusProtocol { - func performQuickSync() async {} + func performQuickSync(isRecovering: Bool) async {} func resyncResources() {} func forceSlowSync() {} } diff --git a/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift b/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift index 06ceb80713f..54f7b241feb 100644 --- a/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift +++ b/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift @@ -63,6 +63,7 @@ public class SyncStatus: NSObject, SyncStatusProtocol, SyncProgress { } private var isForceQuickSync = false + private var isRecovering = false public var isSyncing: Bool { currentSyncPhase.isSyncing || !isPushChannelOpen @@ -140,7 +141,9 @@ public class SyncStatus: NSObject, SyncStatusProtocol, SyncProgress { syncStateDelegate?.didStartSlowSync() } - public func performQuickSync() async { + public func performQuickSync(isRecovering: Bool) async { + self.isRecovering = isRecovering + await withCheckedContinuation { [weak self] continuation in guard let self else { continuation.resume() @@ -155,9 +158,10 @@ public class SyncStatus: NSObject, SyncStatusProtocol, SyncProgress { } func notifyQuickSyncDidFinish() { - syncStateDelegate?.didFinishQuickSync() + syncStateDelegate?.didFinishQuickSync(isRecovering: isRecovering) quickSyncContinuation?.resume() quickSyncContinuation = nil + isRecovering = false } public func forceQuickSync() { diff --git a/wire-ios-sync-engine/Source/UserSession/ZMSyncStateDelegate.swift b/wire-ios-sync-engine/Source/UserSession/ZMSyncStateDelegate.swift index 898358d5f94..ea0b2f081c3 100644 --- a/wire-ios-sync-engine/Source/UserSession/ZMSyncStateDelegate.swift +++ b/wire-ios-sync-engine/Source/UserSession/ZMSyncStateDelegate.swift @@ -30,6 +30,6 @@ protocol ZMSyncStateDelegate: AnyObject { func didStartQuickSync() /// The session did finish the quick sync - func didFinishQuickSync() + func didFinishQuickSync(isRecovering: Bool) } diff --git a/wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSession.swift b/wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSession.swift index 7fb5838ef93..b94cfb013b6 100644 --- a/wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSession.swift +++ b/wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSession.swift @@ -955,7 +955,7 @@ extension ZMUserSession: ZMSyncStateDelegate { } } - public func didFinishQuickSync() { + public func didFinishQuickSync(isRecovering: Bool) { WireLogger.sync.debug("did finish quick sync") processEvents() @@ -984,8 +984,10 @@ extension ZMUserSession: ZMSyncStateDelegate { WireLogger.mls.warn("`qualifiedClientID` is missing for selfClient") } - if mlsFeature.isEnabled { - mlsService.commitPendingProposalsIfNeeded() + if !isRecovering, mlsFeature.isEnabled { + Task { + mlsService.commitPendingProposalsIfNeeded() + } } await calculateSelfSupportedProtocolsIfNeeded() diff --git a/wire-ios-sync-engine/Tests/Source/Synchronization/Strategies/TeamInvitationRequestStrategyTests.swift b/wire-ios-sync-engine/Tests/Source/Synchronization/Strategies/TeamInvitationRequestStrategyTests.swift index fc69a246bbd..4fe9068c42c 100644 --- a/wire-ios-sync-engine/Tests/Source/Synchronization/Strategies/TeamInvitationRequestStrategyTests.swift +++ b/wire-ios-sync-engine/Tests/Source/Synchronization/Strategies/TeamInvitationRequestStrategyTests.swift @@ -181,7 +181,7 @@ extension TeamInvitationRequestStrategyTests: ZMRequestCancellation, ZMSyncState func didStartQuickSync() {} - func didFinishQuickSync() {} + func didFinishQuickSync(isRecovering: Bool) {} func didRegisterSelfUserClient(_ userClient: UserClient) {} diff --git a/wire-ios-sync-engine/Tests/Source/Synchronization/SynchronizationMocks.swift b/wire-ios-sync-engine/Tests/Source/Synchronization/SynchronizationMocks.swift index fd91e9fbc72..bd2ca169511 100644 --- a/wire-ios-sync-engine/Tests/Source/Synchronization/SynchronizationMocks.swift +++ b/wire-ios-sync-engine/Tests/Source/Synchronization/SynchronizationMocks.swift @@ -230,7 +230,7 @@ public class MockSyncStateDelegate: NSObject, ZMSyncStateDelegate { didCallStartQuickSync = true } - public func didFinishQuickSync() { + public func didFinishQuickSync(isRecovering: Bool) { didCallFinishQuickSync = true } diff --git a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests+PushNotifications.swift b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests+PushNotifications.swift index 0c84ceca3dc..70f408bc75f 100644 --- a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests+PushNotifications.swift +++ b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests+PushNotifications.swift @@ -392,7 +392,7 @@ extension ZMUserSessionTests_PushNotifications { XCTAssertTrue(waitForAllGroupsToBeEmpty(withTimeout: 0.5), file: file, line: line) syncMOC.performAndWait { - sut.didFinishQuickSync() + sut.didFinishQuickSync(isRecovering: false) } XCTAssertTrue(waitForAllGroupsToBeEmpty(withTimeout: 0.5), file: file, line: line) } diff --git a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests.swift b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests.swift index e43f7fd93a1..e84743de6ac 100644 --- a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests.swift +++ b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests.swift @@ -311,7 +311,7 @@ final class ZMUserSessionTests: ZMUserSessionTestsBase { ) syncMOC.performAndWait { - sut.didFinishQuickSync() + sut.didFinishQuickSync(isRecovering: false) } XCTAssertTrue(waitForAllGroupsToBeEmpty(withTimeout: 1)) @@ -487,7 +487,7 @@ final class ZMUserSessionTests: ZMUserSessionTestsBase { syncMOC.saveOrRollback() // WHEN - sut.didFinishQuickSync() + sut.didFinishQuickSync(isRecovering: false) } XCTAssertTrue(waitForAllGroupsToBeEmpty(withTimeout: 0.5)) @@ -535,7 +535,7 @@ final class ZMUserSessionTests: ZMUserSessionTestsBase { let mls = Feature.MLS(status: .enabled, config: .init()) self.sut.featureRepository.storeMLS(mls) - sut.didFinishQuickSync() + sut.didFinishQuickSync(isRecovering: false) } XCTAssertTrue(waitForAllGroupsToBeEmpty(withTimeout: 0.5)) @@ -555,7 +555,7 @@ final class ZMUserSessionTests: ZMUserSessionTestsBase { ZMUser.selfUser(in: self.syncMOC).supportedProtocols = .init() // WHEN - sut.didFinishQuickSync() + sut.didFinishQuickSync(isRecovering: false) } XCTAssertTrue(waitForAllGroupsToBeEmpty(withTimeout: 0.5)) diff --git a/wire-ios/Wire-iOS/Sources/Developer/DeveloperTools/DebugActions/DeveloperDebugActionsViewModel.swift b/wire-ios/Wire-iOS/Sources/Developer/DeveloperTools/DebugActions/DeveloperDebugActionsViewModel.swift index 643edbbeae4..25a7d42fefd 100644 --- a/wire-ios/Wire-iOS/Sources/Developer/DeveloperTools/DebugActions/DeveloperDebugActionsViewModel.swift +++ b/wire-ios/Wire-iOS/Sources/Developer/DeveloperTools/DebugActions/DeveloperDebugActionsViewModel.swift @@ -89,7 +89,7 @@ final class DeveloperDebugActionsViewModel: ObservableObject { guard let userSession else { return } Task { - await userSession.syncStatus.performQuickSync() + await userSession.syncStatus.performQuickSync(isRecovering: false) } } From 226d55492a3aa682322e7eb5b797a604158b19df Mon Sep 17 00:00:00 2001 From: Jullian Mercier <31648126+jullianm@users.noreply.github.com> Date: Wed, 19 Feb 2025 12:47:29 +0100 Subject: [PATCH 2/8] fix compilation error --- wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift b/wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift index 9de018e9b2b..18be4965318 100644 --- a/wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift +++ b/wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift @@ -112,7 +112,7 @@ final class SyncAgent: NSObject { /// Perform an incremental sync. func performIncrementalSync() async throws { - await legacySyncStatus.performQuickSync() + await legacySyncStatus.performQuickSync(isRecovering: false) } } @@ -140,7 +140,7 @@ extension SyncAgent: ZMSyncStateDelegate { delegate?.syncAgentDidStartLegacyIncrementalSync(self) } - func didFinishQuickSync() { + func didFinishQuickSync(isRecovering: Bool) { WireLogger.sync.debug("did start finish incremental sync") delegate?.syncAgentDidFinishLegacyIncrementalSync(self) } From 2ea987f13860df7d6779ea0e1c58f841135a9b03 Mon Sep 17 00:00:00 2001 From: Jullian Mercier <31648126+jullianm@users.noreply.github.com> Date: Wed, 19 Feb 2025 12:58:14 +0100 Subject: [PATCH 3/8] fix UT compilation issues --- .../generated/AutoMockable.generated.swift | 14 ++++++------- .../Synchronization/SyncAgentTests.swift | 20 +++++++++---------- .../ZMUserSessionTests+RecurringActions.swift | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/wire-ios-data-model/Support/Sourcery/generated/AutoMockable.generated.swift b/wire-ios-data-model/Support/Sourcery/generated/AutoMockable.generated.swift index 21d0207a179..4f7ba5b614e 100644 --- a/wire-ios-data-model/Support/Sourcery/generated/AutoMockable.generated.swift +++ b/wire-ios-data-model/Support/Sourcery/generated/AutoMockable.generated.swift @@ -5489,17 +5489,17 @@ public class MockSyncStatusProtocol: SyncStatusProtocol { // MARK: - performQuickSync - public var performQuickSync_Invocations: [Void] = [] - public var performQuickSync_MockMethod: (() async -> Void)? + public var performQuickSyncIsRecovering_Invocations: [Bool] = [] + public var performQuickSyncIsRecovering_MockMethod: ((Bool) async -> Void)? - public func performQuickSync() async { - performQuickSync_Invocations.append(()) + public func performQuickSync(isRecovering: Bool) async { + performQuickSyncIsRecovering_Invocations.append(isRecovering) - guard let mock = performQuickSync_MockMethod else { - fatalError("no mock for `performQuickSync`") + guard let mock = performQuickSyncIsRecovering_MockMethod else { + fatalError("no mock for `performQuickSyncIsRecovering`") } - await mock() + await mock(isRecovering) } // MARK: - resyncResources diff --git a/wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift b/wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift index 919d4502a5c..2dcb2aa7abd 100644 --- a/wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift +++ b/wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift @@ -56,14 +56,14 @@ final class SyncAgentTests: XCTestCase { // Mock lastUpdateEventIDRepository.fetchLastEventID_MockValue = .some(nil) initialSync.performSkipPullingLastUpdateEventID_MockMethod = { _ in } - legacySyncStatus.performQuickSync_MockMethod = {} + legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } // When try await sut.performSyncIfNeeded() // Then XCTAssertEqual(initialSync.performSkipPullingLastUpdateEventID_Invocations, [false]) - XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) } func testPerformSyncIfNeeded_IncrementalSync() async throws { @@ -72,14 +72,14 @@ final class SyncAgentTests: XCTestCase { // Mock lastUpdateEventIDRepository.fetchLastEventID_MockValue = .some(UUID()) - legacySyncStatus.performQuickSync_MockMethod = {} + legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } // When try await sut.performSyncIfNeeded() // Then XCTAssertEqual(initialSync.performSkipPullingLastUpdateEventID_Invocations.count, 0) - XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) } func testPerformInitialSync() async throws { @@ -88,14 +88,14 @@ final class SyncAgentTests: XCTestCase { // Mock initialSync.performSkipPullingLastUpdateEventID_MockMethod = { _ in } - legacySyncStatus.performQuickSync_MockMethod = {} + legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } // When try await sut.performInitialSync() // Then XCTAssertEqual(initialSync.performSkipPullingLastUpdateEventID_Invocations, [false]) - XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) } func testPerformInitialSync_Legacy() async throws { @@ -118,14 +118,14 @@ final class SyncAgentTests: XCTestCase { // Mock initialSync.performSkipPullingLastUpdateEventID_MockMethod = { _ in } - legacySyncStatus.performQuickSync_MockMethod = {} + legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } // When try await sut.performResourceSync() // Then XCTAssertEqual(initialSync.performSkipPullingLastUpdateEventID_Invocations, [true]) - XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) } func testPerformResourceSync_Legacy() async throws { @@ -144,13 +144,13 @@ final class SyncAgentTests: XCTestCase { func testPerformIncrementalSync() async throws { // Mock - legacySyncStatus.performQuickSync_MockMethod = {} + legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } // When try await sut.performIncrementalSync() // Then - XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) } } diff --git a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests+RecurringActions.swift b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests+RecurringActions.swift index e9c15c784c9..13a9bf6f11e 100644 --- a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests+RecurringActions.swift +++ b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests+RecurringActions.swift @@ -51,7 +51,7 @@ final class ZMUserSessionTests_RecurringActions: ZMUserSessionTestsBase { // When XCTAssertTrue(mockRecurringActionService.performActionsIfNeeded_Invocations.isEmpty) syncMOC.performAndWait { - sut.didFinishQuickSync() + sut.didFinishQuickSync(isRecovering: false) } XCTAssertTrue(waitForAllGroupsToBeEmpty(withTimeout: 0.5)) From c52e83cd8d5b002adecd7ed023228c4e16087088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franc=CC=A7ois=20Benaiteau?= Date: Wed, 19 Feb 2025 13:29:05 +0100 Subject: [PATCH 4/8] fix: use another method --- .../Source/MLS/MLSService.swift | 6 ++-- .../Source/MLS/SyncStatusProtocol.swift | 3 +- .../generated/AutoMockable.generated.swift | 29 ++++++++++++++----- .../Tests/MLS/MockSyncStatus.swift | 11 ++++++- .../Sources/SharingSession.swift | 3 +- .../Source/Synchronization/SyncAgent.swift | 2 +- .../Source/UserSession/SyncStatus.swift | 14 ++++++--- .../DeveloperDebugActionsViewModel.swift | 2 +- 8 files changed, 51 insertions(+), 19 deletions(-) diff --git a/wire-ios-data-model/Source/MLS/MLSService.swift b/wire-ios-data-model/Source/MLS/MLSService.swift index 52de9d0806d..d2ec99e9aa8 100644 --- a/wire-ios-data-model/Source/MLS/MLSService.swift +++ b/wire-ios-data-model/Source/MLS/MLSService.swift @@ -1316,7 +1316,7 @@ public final class MLSService: MLSServiceInterface { // In case of `WrongEpoch` error, local and remote epochs have diverged so we may have missed events. // This ensures we're on the latest state. - await syncStatus.performQuickSync(isRecovering: true) + await syncStatus.recoverWithQuickSync() guard let conversationInfo = fetchConversationInfo( with: groupID, @@ -1890,13 +1890,13 @@ public final class MLSService: MLSServiceInterface { } catch CommitError.failedToSendCommit(recovery: .commitPendingProposalsAfterQuickSync, _) { logger.warn("failed to send commit, syncing then committing pending proposals...") - await syncStatus.performQuickSync(isRecovering: true) + await syncStatus.recoverWithQuickSync() logger.info("sync finished, committing pending proposals...") try await commitPendingProposals(in: groupID) } catch CommitError.failedToSendCommit(recovery: .retryAfterQuickSync, cause: let error) { logger.warn("failed to send commit, syncing then retrying operation...") - await syncStatus.performQuickSync(isRecovering: true) + await syncStatus.recoverWithQuickSync() logger.info("sync finished, retying operation...") guard retryCount <= maxRetryAttempts else { diff --git a/wire-ios-data-model/Source/MLS/SyncStatusProtocol.swift b/wire-ios-data-model/Source/MLS/SyncStatusProtocol.swift index c138a6889da..c1a30bb2f22 100644 --- a/wire-ios-data-model/Source/MLS/SyncStatusProtocol.swift +++ b/wire-ios-data-model/Source/MLS/SyncStatusProtocol.swift @@ -21,8 +21,9 @@ import Foundation // sourcery: AutoMockable public protocol SyncStatusProtocol { - func performQuickSync(isRecovering: Bool) async + func performQuickSync() async func resyncResources() func forceSlowSync() + func recoverWithQuickSync() async } diff --git a/wire-ios-data-model/Support/Sourcery/generated/AutoMockable.generated.swift b/wire-ios-data-model/Support/Sourcery/generated/AutoMockable.generated.swift index 4f7ba5b614e..0d31fb9a692 100644 --- a/wire-ios-data-model/Support/Sourcery/generated/AutoMockable.generated.swift +++ b/wire-ios-data-model/Support/Sourcery/generated/AutoMockable.generated.swift @@ -5489,17 +5489,17 @@ public class MockSyncStatusProtocol: SyncStatusProtocol { // MARK: - performQuickSync - public var performQuickSyncIsRecovering_Invocations: [Bool] = [] - public var performQuickSyncIsRecovering_MockMethod: ((Bool) async -> Void)? + public var performQuickSync_Invocations: [Void] = [] + public var performQuickSync_MockMethod: (() async -> Void)? - public func performQuickSync(isRecovering: Bool) async { - performQuickSyncIsRecovering_Invocations.append(isRecovering) + public func performQuickSync() async { + performQuickSync_Invocations.append(()) - guard let mock = performQuickSyncIsRecovering_MockMethod else { - fatalError("no mock for `performQuickSyncIsRecovering`") + guard let mock = performQuickSync_MockMethod else { + fatalError("no mock for `performQuickSync`") } - await mock(isRecovering) + await mock() } // MARK: - resyncResources @@ -5532,6 +5532,21 @@ public class MockSyncStatusProtocol: SyncStatusProtocol { mock() } + // MARK: - recoverWithQuickSync + + public var recoverWithQuickSync_Invocations: [Void] = [] + public var recoverWithQuickSync_MockMethod: (() async -> Void)? + + public func recoverWithQuickSync() async { + recoverWithQuickSync_Invocations.append(()) + + guard let mock = recoverWithQuickSync_MockMethod else { + fatalError("no mock for `recoverWithQuickSync`") + } + + await mock() + } + } public class MockUpdateMLSGroupVerificationStatusUseCaseProtocol: UpdateMLSGroupVerificationStatusUseCaseProtocol { diff --git a/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift b/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift index afc6ddb5beb..9a3f0dbcb71 100644 --- a/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift +++ b/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift @@ -30,7 +30,7 @@ class MockSyncStatus: SyncStatusProtocol { } var mockPerformQuickSync: (() async -> Void)? - func performQuickSync(isRecovering: Bool) async { + func performQuickSync() async { guard let mock = mockPerformQuickSync else { fatalError("no mock for `performQuickSync`") } @@ -46,5 +46,14 @@ class MockSyncStatus: SyncStatusProtocol { mock() } + + var mockRecoverWithQuickSync: (() -> Void)? + func recoverWithQuickSync() { + guard let mock = mockRecoverWithQuickSync else { + fatalError("no mock for `recoverWithQuickSync`") + } + + mock() + } } diff --git a/wire-ios-share-engine/Sources/SharingSession.swift b/wire-ios-share-engine/Sources/SharingSession.swift index d7047f67d8b..e7fa35e444a 100644 --- a/wire-ios-share-engine/Sources/SharingSession.swift +++ b/wire-ios-share-engine/Sources/SharingSession.swift @@ -154,9 +154,10 @@ final class ApplicationStatusDirectory: ApplicationStatus { /// Required by `MLSService` initializer. /// No need to fill in the methods as we don't sync resources in the share engine. struct SyncStatus: SyncStatusProtocol { - func performQuickSync(isRecovering: Bool) async {} + func performQuickSync() async {} func resyncResources() {} func forceSlowSync() {} + func recoverWithQuickSync() async {} } /// A Wire session to share content from a share extension diff --git a/wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift b/wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift index 18be4965318..de9c88a5912 100644 --- a/wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift +++ b/wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift @@ -112,7 +112,7 @@ final class SyncAgent: NSObject { /// Perform an incremental sync. func performIncrementalSync() async throws { - await legacySyncStatus.performQuickSync(isRecovering: false) + await legacySyncStatus.performQuickSync() } } diff --git a/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift b/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift index 54f7b241feb..3702a03716c 100644 --- a/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift +++ b/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift @@ -141,9 +141,16 @@ public class SyncStatus: NSObject, SyncStatusProtocol, SyncProgress { syncStateDelegate?.didStartSlowSync() } - public func performQuickSync(isRecovering: Bool) async { - self.isRecovering = isRecovering - + public func recoverWithQuickSync() async { + self.isRecovering = true + defer { + self.isRecovering = false + } + await performQuickSync() + } + + + public func performQuickSync() async { await withCheckedContinuation { [weak self] continuation in guard let self else { continuation.resume() @@ -161,7 +168,6 @@ public class SyncStatus: NSObject, SyncStatusProtocol, SyncProgress { syncStateDelegate?.didFinishQuickSync(isRecovering: isRecovering) quickSyncContinuation?.resume() quickSyncContinuation = nil - isRecovering = false } public func forceQuickSync() { diff --git a/wire-ios/Wire-iOS/Sources/Developer/DeveloperTools/DebugActions/DeveloperDebugActionsViewModel.swift b/wire-ios/Wire-iOS/Sources/Developer/DeveloperTools/DebugActions/DeveloperDebugActionsViewModel.swift index 25a7d42fefd..643edbbeae4 100644 --- a/wire-ios/Wire-iOS/Sources/Developer/DeveloperTools/DebugActions/DeveloperDebugActionsViewModel.swift +++ b/wire-ios/Wire-iOS/Sources/Developer/DeveloperTools/DebugActions/DeveloperDebugActionsViewModel.swift @@ -89,7 +89,7 @@ final class DeveloperDebugActionsViewModel: ObservableObject { guard let userSession else { return } Task { - await userSession.syncStatus.performQuickSync(isRecovering: false) + await userSession.syncStatus.performQuickSync() } } From 7426d03c7bcb0f50ce6527b509ba3ab8144e9f9b Mon Sep 17 00:00:00 2001 From: Jullian Mercier <31648126+jullianm@users.noreply.github.com> Date: Thu, 20 Feb 2025 10:17:08 +0100 Subject: [PATCH 5/8] add throttle mechanism on committing pending proposals, add various optimization --- .../Source/MLS/MLSService.swift | 24 ++++++++++++------- .../Decoding/EventDecoder.swift | 2 +- .../Synchronization/EventProcessor.swift | 4 ++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/wire-ios-data-model/Source/MLS/MLSService.swift b/wire-ios-data-model/Source/MLS/MLSService.swift index d2ec99e9aa8..df1de4cf637 100644 --- a/wire-ios-data-model/Source/MLS/MLSService.swift +++ b/wire-ios-data-model/Source/MLS/MLSService.swift @@ -1727,15 +1727,22 @@ public final class MLSService: MLSServiceInterface { } private var task: Task? + private var lastExecutionTime = Date.distantPast + private let throttleInterval: TimeInterval = 2.0 // 2 seconds throttle public func commitPendingProposalsIfNeeded() { - task?.cancel() + let now = Date() + + guard now.timeIntervalSince(lastExecutionTime) > throttleInterval else { + return // Ignore call if within the throttle period + } - task = Task { [self] in - guard !Task.isCancelled else { - return - } + lastExecutionTime = now + task?.cancel() + + task = Task { [self] in + guard !Task.isCancelled else { return } await commitPendingProposals() } } @@ -1753,6 +1760,7 @@ public final class MLSService: MLSServiceInterface { // Committing proposals for each group is independent and should not wait for // each other. + logger.info("TEST10: Entering task group") await withTaskGroup(of: Void.self) { taskGroup in for (groupID, timestamp) in groupsWithPendingCommits { taskGroup.addTask { [self] in @@ -1761,18 +1769,18 @@ public final class MLSService: MLSServiceInterface { logger.info("commit scheduled in the past, committing...") try await commitPendingProposals(in: groupID) } else { - logger.info("commit scheduled in the future, waiting...") + logger.info("TEST10: commit scheduled in the future, waiting...") let timeIntervalSinceNow = timestamp.timeIntervalSinceNow if timeIntervalSinceNow > 0 { try await Task.sleep(nanoseconds: timeIntervalSinceNow.nanoseconds) } - logger.info("scheduled commit is ready, committing...") + logger.info("TEST10: scheduled commit is ready, committing...") try await commitPendingProposals(in: groupID) } } catch { - logger.error("failed to commit pending proposals: \(String(describing: error))") + logger.error("TEST10: failed to commit pending proposals: \(String(describing: error))") } } } diff --git a/wire-ios-request-strategy/Sources/Synchronization/Decoding/EventDecoder.swift b/wire-ios-request-strategy/Sources/Synchronization/Decoding/EventDecoder.swift index c9cf097832c..ca57af353fb 100644 --- a/wire-ios-request-strategy/Sources/Synchronization/Decoding/EventDecoder.swift +++ b/wire-ios-request-strategy/Sources/Synchronization/Decoding/EventDecoder.swift @@ -102,7 +102,7 @@ extension EventDecoder { StoredUpdateEvent.highestIndex(self.eventMOC) } - guard proteusProvider.canPerform else { + guard proteusProvider.canPerform, !events.isEmpty else { WireLogger.proteus.warn("ignore decrypting events because it is not safe") return [] } diff --git a/wire-ios-sync-engine/Source/Synchronization/EventProcessor.swift b/wire-ios-sync-engine/Source/Synchronization/EventProcessor.swift index 22d2f30dd93..cec1733288e 100644 --- a/wire-ios-sync-engine/Source/Synchronization/EventProcessor.swift +++ b/wire-ios-sync-engine/Source/Synchronization/EventProcessor.swift @@ -97,7 +97,7 @@ actor EventProcessor: UpdateEventProcessor { guard !DeveloperFlag.ignoreIncomingEvents.isOn else { return } - let publicKeys = try? self.earService.fetchPublicKeys() + let publicKeys = try? await self.earService.fetchPublicKeys() let decryptedEvents = try await self.eventDecoder.decryptAndStoreEvents(events, publicKeys: publicKeys) await self.processBackgroundEvents(decryptedEvents) @@ -178,7 +178,7 @@ actor EventProcessor: UpdateEventProcessor { attributes: .safePublic ) - guard let self else { return } + guard let self, !decryptedUpdateEvents.isEmpty else { return } let date = Date() let fetchRequest = await prefetchRequest(updateEvents: decryptedUpdateEvents) From 660e96ceddf5c109a358ce44e4616758de8fbcfd Mon Sep 17 00:00:00 2001 From: Jullian Mercier <31648126+jullianm@users.noreply.github.com> Date: Fri, 21 Feb 2025 15:09:57 +0100 Subject: [PATCH 6/8] lint and format --- wire-ios-data-model/Source/MLS/MLSService.swift | 4 ++-- wire-ios-data-model/Tests/MLS/MockSyncStatus.swift | 2 +- wire-ios-sync-engine/Source/UserSession/SyncStatus.swift | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/wire-ios-data-model/Source/MLS/MLSService.swift b/wire-ios-data-model/Source/MLS/MLSService.swift index df1de4cf637..48ed4469226 100644 --- a/wire-ios-data-model/Source/MLS/MLSService.swift +++ b/wire-ios-data-model/Source/MLS/MLSService.swift @@ -1732,7 +1732,7 @@ public final class MLSService: MLSServiceInterface { public func commitPendingProposalsIfNeeded() { let now = Date() - + guard now.timeIntervalSince(lastExecutionTime) > throttleInterval else { return // Ignore call if within the throttle period } @@ -1740,7 +1740,7 @@ public final class MLSService: MLSServiceInterface { lastExecutionTime = now task?.cancel() - + task = Task { [self] in guard !Task.isCancelled else { return } await commitPendingProposals() diff --git a/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift b/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift index 9a3f0dbcb71..5c113673781 100644 --- a/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift +++ b/wire-ios-data-model/Tests/MLS/MockSyncStatus.swift @@ -46,7 +46,7 @@ class MockSyncStatus: SyncStatusProtocol { mock() } - + var mockRecoverWithQuickSync: (() -> Void)? func recoverWithQuickSync() { guard let mock = mockRecoverWithQuickSync else { diff --git a/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift b/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift index 3702a03716c..bcbcae8d4b8 100644 --- a/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift +++ b/wire-ios-sync-engine/Source/UserSession/SyncStatus.swift @@ -142,14 +142,13 @@ public class SyncStatus: NSObject, SyncStatusProtocol, SyncProgress { } public func recoverWithQuickSync() async { - self.isRecovering = true + isRecovering = true defer { self.isRecovering = false } await performQuickSync() } - - + public func performQuickSync() async { await withCheckedContinuation { [weak self] continuation in guard let self else { From 699462d3df6bfd46f09b535d245bae01e918b05d Mon Sep 17 00:00:00 2001 From: Jullian Mercier <31648126+jullianm@users.noreply.github.com> Date: Fri, 21 Feb 2025 15:35:41 +0100 Subject: [PATCH 7/8] fix UT compilation errors --- .../Synchronization/SyncAgentTests.swift | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift b/wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift index 2dcb2aa7abd..919d4502a5c 100644 --- a/wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift +++ b/wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift @@ -56,14 +56,14 @@ final class SyncAgentTests: XCTestCase { // Mock lastUpdateEventIDRepository.fetchLastEventID_MockValue = .some(nil) initialSync.performSkipPullingLastUpdateEventID_MockMethod = { _ in } - legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } + legacySyncStatus.performQuickSync_MockMethod = {} // When try await sut.performSyncIfNeeded() // Then XCTAssertEqual(initialSync.performSkipPullingLastUpdateEventID_Invocations, [false]) - XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) } func testPerformSyncIfNeeded_IncrementalSync() async throws { @@ -72,14 +72,14 @@ final class SyncAgentTests: XCTestCase { // Mock lastUpdateEventIDRepository.fetchLastEventID_MockValue = .some(UUID()) - legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } + legacySyncStatus.performQuickSync_MockMethod = {} // When try await sut.performSyncIfNeeded() // Then XCTAssertEqual(initialSync.performSkipPullingLastUpdateEventID_Invocations.count, 0) - XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) } func testPerformInitialSync() async throws { @@ -88,14 +88,14 @@ final class SyncAgentTests: XCTestCase { // Mock initialSync.performSkipPullingLastUpdateEventID_MockMethod = { _ in } - legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } + legacySyncStatus.performQuickSync_MockMethod = {} // When try await sut.performInitialSync() // Then XCTAssertEqual(initialSync.performSkipPullingLastUpdateEventID_Invocations, [false]) - XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) } func testPerformInitialSync_Legacy() async throws { @@ -118,14 +118,14 @@ final class SyncAgentTests: XCTestCase { // Mock initialSync.performSkipPullingLastUpdateEventID_MockMethod = { _ in } - legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } + legacySyncStatus.performQuickSync_MockMethod = {} // When try await sut.performResourceSync() // Then XCTAssertEqual(initialSync.performSkipPullingLastUpdateEventID_Invocations, [true]) - XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) } func testPerformResourceSync_Legacy() async throws { @@ -144,13 +144,13 @@ final class SyncAgentTests: XCTestCase { func testPerformIncrementalSync() async throws { // Mock - legacySyncStatus.performQuickSyncIsRecovering_MockMethod = { _ in } + legacySyncStatus.performQuickSync_MockMethod = {} // When try await sut.performIncrementalSync() // Then - XCTAssertEqual(legacySyncStatus.performQuickSyncIsRecovering_Invocations.count, 1) + XCTAssertEqual(legacySyncStatus.performQuickSync_Invocations.count, 1) } } From ef71844643cb550bbc3a11ff7638542078534b99 Mon Sep 17 00:00:00 2001 From: Jullian Mercier <31648126+jullianm@users.noreply.github.com> Date: Fri, 21 Feb 2025 17:00:32 +0100 Subject: [PATCH 8/8] fix UTs --- .../Tests/MLS/MLSServiceTests.swift | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/wire-ios-data-model/Tests/MLS/MLSServiceTests.swift b/wire-ios-data-model/Tests/MLS/MLSServiceTests.swift index ccba2647805..419bee152c4 100644 --- a/wire-ios-data-model/Tests/MLS/MLSServiceTests.swift +++ b/wire-ios-data-model/Tests/MLS/MLSServiceTests.swift @@ -327,7 +327,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { let message = "foo" let error = MLSDecryptionService.MLSMessageDecryptionError.wrongEpoch mockDecryptionService.decryptMessageForSubconversationType_MockError = error - mockSyncStatus.mockPerformQuickSync = {} + mockSyncStatus.mockRecoverWithQuickSync = {} let expectation = XCTestExpectation(description: "repaired conversation") await uiMOC.perform { @@ -1478,7 +1478,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { XCTFail("missing groupID") return } - mockSyncStatus.mockPerformQuickSync = {} + mockSyncStatus.mockRecoverWithQuickSync = {} let expectation = XCTestExpectation(description: "rejoined conversation") @@ -1510,7 +1510,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { return } - mockSyncStatus.mockPerformQuickSync = {} + mockSyncStatus.mockRecoverWithQuickSync = {} let expectation = XCTestExpectation(description: "didn't rejoin conversation") expectation.isInverted = true @@ -1974,9 +1974,10 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { } // Mock quick sync. - var mockPerformQuickSyncCount = 0 - mockSyncStatus.mockPerformQuickSync = { - mockPerformQuickSyncCount += 1 + var mockRecoverQuickSyncCount = 0 + + mockSyncStatus.mockRecoverWithQuickSync = { + mockRecoverQuickSyncCount += 1 } // When @@ -1986,7 +1987,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { XCTAssertEqual(mockUpdateKeyMaterialCount, 2) // Then it performed a quick sync once. - XCTAssertEqual(mockPerformQuickSyncCount, 1) + XCTAssertEqual(mockRecoverQuickSyncCount, 1) // Then processed the result once. XCTAssertEqual(mockConversationEventProcessor.processConversationEvents_Invocations, [[]]) @@ -2014,9 +2015,10 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { } // Mock quick sync. - var mockPerformQuickSyncCount = 0 - mockSyncStatus.mockPerformQuickSync = { - mockPerformQuickSyncCount += 1 + var mockRecoverQuickSyncCount = 0 + + mockSyncStatus.mockRecoverWithQuickSync = { + mockRecoverQuickSyncCount += 1 } // When @@ -2026,7 +2028,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { XCTAssertEqual(mockUpdateKeyMaterialCount, 4) // Then it performed a quick sync 3 times (for 3 failures). - XCTAssertEqual(mockPerformQuickSyncCount, 3) + XCTAssertEqual(mockRecoverQuickSyncCount, 3) // Then processed the result once. XCTAssertEqual(mockConversationEventProcessor.processConversationEvents_Invocations, [[]]) @@ -2048,7 +2050,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { } // Mock quick sync. - mockSyncStatus.mockPerformQuickSync = {} + mockSyncStatus.mockRecoverWithQuickSync = {} do { // When @@ -2075,7 +2077,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { } // Mock quick sync. - mockSyncStatus.mockPerformQuickSync = {} + mockSyncStatus.mockRecoverWithQuickSync = {} do { // When @@ -2115,9 +2117,10 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { } // Mock quick sync. - var mockPerformQuickSyncCount = 0 - mockSyncStatus.mockPerformQuickSync = { - mockPerformQuickSyncCount += 1 + var mockRecoverQuickSyncCount = 0 + + mockSyncStatus.mockRecoverWithQuickSync = { + mockRecoverQuickSyncCount += 1 } // When @@ -2130,7 +2133,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { XCTAssertEqual(mockUpdateKeyMaterialCount, 4) // Then it performed a quick sync 5 times (for 2 + 3 failures). - XCTAssertEqual(mockPerformQuickSyncCount, 5) + XCTAssertEqual(mockRecoverQuickSyncCount, 5) // Then processed the results twice (1 for each success). XCTAssertEqual(mockConversationEventProcessor.processConversationEvents_Invocations, [[], []]) @@ -2166,9 +2169,10 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { } // Mock quick sync. - var mockPerformQuickSyncCount = 0 - mockSyncStatus.mockPerformQuickSync = { - mockPerformQuickSyncCount += 1 + var mockRecoverQuickSyncCount = 0 + + mockSyncStatus.mockRecoverWithQuickSync = { + mockRecoverQuickSyncCount += 1 } // When @@ -2181,7 +2185,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { XCTAssertEqual(mockUpdateKeyMaterialCount, 1) // Then it performed a quick sync once. - XCTAssertEqual(mockPerformQuickSyncCount, 1) + XCTAssertEqual(mockRecoverQuickSyncCount, 1) // Then processed the result once. XCTAssertEqual(mockConversationEventProcessor.processConversationEvents_Invocations, [[]]) @@ -2204,9 +2208,10 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { } // Mock quick sync. - var mockPerformQuickSyncCount = 0 - mockSyncStatus.mockPerformQuickSync = { - mockPerformQuickSyncCount += 1 + var mockRecoverQuickSyncCount = 0 + + mockSyncStatus.mockRecoverWithQuickSync = { + mockRecoverQuickSyncCount += 1 } // Then @@ -2219,7 +2224,7 @@ final class MLSServiceTests: ZMConversationTestsBase, MLSServiceDelegate { XCTAssertEqual(mockUpdateKeyMaterialCount, 1) // Then it didn't perform a quick sync. - XCTAssertEqual(mockPerformQuickSyncCount, 0) + XCTAssertEqual(mockRecoverQuickSyncCount, 0) // Then it didn't process any result. XCTAssertEqual(mockConversationEventProcessor.processConversationEvents_Invocations, [])