diff --git a/wire-ios-data-model/Tests/OneOnOne/OneOnOneProtocolSelectorTests.swift b/wire-ios-data-model/Tests/OneOnOne/OneOnOneProtocolSelectorTests.swift index de049b04970..60ef2d6ca8f 100644 --- a/wire-ios-data-model/Tests/OneOnOne/OneOnOneProtocolSelectorTests.swift +++ b/wire-ios-data-model/Tests/OneOnOne/OneOnOneProtocolSelectorTests.swift @@ -123,4 +123,26 @@ final class OneOnOneProtocolSelectorTests: ZMBaseManagedObjectTest { XCTAssertEqual(result, .proteus) } + func test_GetProtocolForUser_IfNoProtocolForSelfReturnsNil() async throws { + // Given + let userID = QualifiedID.random() + + await uiMOC.perform { [self] in + let user = createUser(id: userID, in: uiMOC) + user.supportedProtocols = [.proteus] + + let selfUser = ZMUser.selfUser(in: uiMOC) + selfUser.supportedProtocols = [] + } + + // When + let result = try await sut.getProtocolForUser( + with: userID, + in: uiMOC + ) + + // Then + XCTAssertEqual(result, .none) + } + } diff --git a/wire-ios-request-strategy/Sources/Services/SupportedProtocolsService.swift b/wire-ios-request-strategy/Sources/Services/SupportedProtocolsService.swift index 9ef1cd48cc4..d9403ba6da3 100644 --- a/wire-ios-request-strategy/Sources/Services/SupportedProtocolsService.swift +++ b/wire-ios-request-strategy/Sources/Services/SupportedProtocolsService.swift @@ -1,6 +1,6 @@ -//// +// // Wire -// Copyright (C) 2023 Wire Swiss GmbH +// Copyright (C) 2024 Wire Swiss GmbH // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ public final class SupportedProtocolsService: SupportedProtocolsServiceInterface private let featureRepository: FeatureRepositoryInterface private let userRepository: UserRepositoryInterface - private let logger = WireLogger(tag: "supported-protocols") + private let logger = WireLogger.supportedProtocols // MARK: - Life cycle diff --git a/wire-ios-sync-engine/Source/Use cases/UseCaseFactory.swift b/wire-ios-sync-engine/Source/Use cases/UseCaseFactory.swift index 27ed9360f9f..529f6f2009e 100644 --- a/wire-ios-sync-engine/Source/Use cases/UseCaseFactory.swift +++ b/wire-ios-sync-engine/Source/Use cases/UseCaseFactory.swift @@ -38,5 +38,4 @@ struct UseCaseFactory: UseCaseFactoryProtocol { resolver: oneOnOneResolver ) } - } diff --git a/wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSession.swift b/wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSession.swift index 947a2b59a6b..9c1602bc2ca 100644 --- a/wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSession.swift +++ b/wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSession.swift @@ -950,6 +950,7 @@ extension ZMUserSession: ZMSyncStateDelegate { WaitingGroupTask(context: syncContext) { [self] in await fetchAndStoreFeatureConfig() + await calculateSelfSupportedProtocolsIfNeeded() await resolveOneOnOneConversationsIfNeeded() } @@ -962,6 +963,23 @@ extension ZMUserSession: ZMSyncStateDelegate { performPostQuickSyncE2EIActions() } + /// Calculate supported protocols for self user in case they are empty + /// - note: Supported protocols are calculated only during slow sync + /// or while resolving 1-1 conversations (MLS enabled). + /// It fixes users that updates to latest version without having a supported-protocol. + /// This could be removed once MLS is enabled. + private func calculateSelfSupportedProtocolsIfNeeded() async { + await syncContext.perform { [syncContext] in + let service = SupportedProtocolsService(context: syncContext) + let selfUser = ZMUser.selfUser(in: syncContext) + if selfUser.supportedProtocols.isEmpty { + WireLogger.supportedProtocols.warn("no supported protocols found") + selfUser.supportedProtocols = service.calculateSupportedProtocols() + syncContext.saveOrRollback() + } + } + } + private func resolveOneOnOneConversationsIfNeeded() async { guard DeveloperFlag.enableMLSSupport.isOn else { return } do { diff --git a/wire-ios-sync-engine/Tests/Source/Use cases/CreateTeamOneOnOneConversationUseCaseTests.swift b/wire-ios-sync-engine/Tests/Source/Use cases/CreateTeamOneOnOneConversationUseCaseTests.swift index 7ec46fce0e1..700a1aae792 100644 --- a/wire-ios-sync-engine/Tests/Source/Use cases/CreateTeamOneOnOneConversationUseCaseTests.swift +++ b/wire-ios-sync-engine/Tests/Source/Use cases/CreateTeamOneOnOneConversationUseCaseTests.swift @@ -96,6 +96,7 @@ final class CreateTeamOneOnOneConversationUseCaseTests: XCTestCase { do { // When _ = try await sut.invoke(with: otherUser, syncContext: syncContext) + XCTFail("should fail") } catch CreateTeamOneOnOneConversationError.userIsNotOnSameTeam { // Then } catch { @@ -113,6 +114,7 @@ final class CreateTeamOneOnOneConversationUseCaseTests: XCTestCase { do { // When _ = try await sut.invoke(with: otherUser, syncContext: syncContext) + XCTFail("should fail") } catch CreateTeamOneOnOneConversationError.noCommonProtocols { // Then } catch { diff --git a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests.swift b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests.swift index 9447614e2e0..3a017badc0d 100644 --- a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests.swift +++ b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests.swift @@ -566,6 +566,7 @@ final class ZMUserSessionTests: ZMUserSessionTestsBase { func test_itPerformsPeriodicMLSUpdates_AfterQuickSync() { // GIVEN + DeveloperFlag.enableMLSSupport.enable(true, storage: .temporary()) mockMLSService.performPendingJoins_MockMethod = {} mockMLSService.commitPendingProposalsIfNeeded_MockMethod = {} mockMLSService.uploadKeyPackagesIfNeeded_MockMethod = {} @@ -596,5 +597,12 @@ final class ZMUserSessionTests: ZMUserSessionTestsBase { XCTAssertFalse(mockMLSService.updateKeyMaterialForAllStaleGroupsIfNeeded_Invocations.isEmpty) XCTAssertFalse(mockMLSService.commitPendingProposalsIfNeeded_Invocations.isEmpty) } + + XCTAssertTrue(waitForAllGroupsToBeEmpty(withTimeout: 0.5)) + + // THEN + let supportedProtocols = syncMOC.performAndWait { ZMUser.selfUser(in: self.syncMOC).supportedProtocols } + + XCTAssertTrue(supportedProtocols.contains(.proteus)) } } diff --git a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTestsBase.swift b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTestsBase.swift index 48217e128d6..94a95cead18 100644 --- a/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTestsBase.swift +++ b/wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTestsBase.swift @@ -46,7 +46,6 @@ class ZMUserSessionTestsBase: MessagingTest { var thirdPartyServices: ThirdPartyServices! var mockSyncStateDelegate: MockSyncStateDelegate! var mockUseCaseFactory: MockUseCaseFactoryProtocol! - var mockResolveOneOnOneConversationUseCase: MockResolveOneOnOneConversationsUseCaseProtocol! var mockGetFeatureConfigsActionHandler: MockActionHandler! var sut: ZMUserSession! @@ -85,11 +84,11 @@ class ZMUserSessionTestsBase: MessagingTest { } mockUseCaseFactory = MockUseCaseFactoryProtocol() - mockResolveOneOnOneConversationUseCase = MockResolveOneOnOneConversationsUseCaseProtocol() - mockResolveOneOnOneConversationUseCase.invoke_MockMethod = { } mockUseCaseFactory.createResolveOneOnOneUseCase_MockMethod = { - return self.mockResolveOneOnOneConversationUseCase + let mockResolveOneOnOneConversationUseCase = MockResolveOneOnOneConversationsUseCaseProtocol() + mockResolveOneOnOneConversationUseCase.invoke_MockMethod = { } + return mockResolveOneOnOneConversationUseCase } sut = createSut() @@ -117,7 +116,6 @@ class ZMUserSessionTestsBase: MessagingTest { self.mediaManager = nil self.flowManagerMock = nil self.mockUseCaseFactory = nil - self.mockResolveOneOnOneConversationUseCase = nil self.mockEARService.delegate = nil self.mockEARService = nil let sut = self.sut diff --git a/wire-ios-system/Source/Logging/WireLogger.swift b/wire-ios-system/Source/Logging/WireLogger.swift index fba44000ce2..16ba677c40d 100644 --- a/wire-ios-system/Source/Logging/WireLogger.swift +++ b/wire-ios-system/Source/Logging/WireLogger.swift @@ -242,6 +242,7 @@ public extension WireLogger { static let eventProcessing = WireLogger(tag: "event-processing") static let safeFileContext = WireLogger(tag: "safe-file-context") static let messageProcessing = WireLogger(tag: "message-processing") + static let supportedProtocols = WireLogger(tag: "supported-protocols") } /// Class to proxy WireLogger methods to Objective-C