From e82a088b28277eca6b21c3f6a3e5b2fad9a78224 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Wed, 27 Mar 2024 04:08:10 +0100 Subject: [PATCH] VPN visibility fixes (#2507) Task/Issue URL: https://app.asana.com/0/0/1206886385075835/f Description Changes: VPN shortcut is still available when the VPN is visible. VPN settings now visible when the VPN is installed. VPN can be uninstalled when the login item is enabled. VPN has a flag to prevent multiple uninstallations of the VPN. --- .../Tests/UnitTestsAppStore.xcconfig | 2 +- DuckDuckGo/Menus/MainMenu.swift | 20 +++---- .../NavigationBar/View/MoreOptionsMenu.swift | 2 +- .../View/NavigationBarViewController.swift | 8 +-- .../NetworkProtectionNavBarButtonModel.swift | 2 +- ...etworkProtectionNavBarPopoverManager.swift | 2 +- ...NetworkProtectionIPCTunnelController.swift | 2 +- .../NetworkProtectionRemoteMessaging.swift | 2 +- .../Model/PreferencesSidebarModel.swift | 16 +----- .../Model/VPNPreferencesModel.swift | 2 +- .../NetworkProtectionFeatureDisabler.swift | 27 +++------- .../NetworkProtectionFeatureVisibility.swift | 32 ++++++++--- DuckDuckGoVPN/NetworkProtectionBouncer.swift | 18 +------ UnitTests/Menus/MoreOptionsMenuTests.swift | 53 ++++++++++++++----- ...etworkProtectionRemoteMessagingTests.swift | 16 +++--- 15 files changed, 105 insertions(+), 99 deletions(-) diff --git a/Configuration/Tests/UnitTestsAppStore.xcconfig b/Configuration/Tests/UnitTestsAppStore.xcconfig index a885a868ed..b31177d987 100644 --- a/Configuration/Tests/UnitTestsAppStore.xcconfig +++ b/Configuration/Tests/UnitTestsAppStore.xcconfig @@ -16,7 +16,7 @@ #include "UnitTests.xcconfig" #include "../AppStore.xcconfig" -FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION DBP +FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION DBP SUBSCRIPTION PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.mobile.ios.DuckDuckGoTests diff --git a/DuckDuckGo/Menus/MainMenu.swift b/DuckDuckGo/Menus/MainMenu.swift index 835f52a061..2df71c787b 100644 --- a/DuckDuckGo/Menus/MainMenu.swift +++ b/DuckDuckGo/Menus/MainMenu.swift @@ -544,18 +544,20 @@ import SubscriptionUI } private func updateShortcutMenuItems() { - toggleAutofillShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .autofill) - toggleBookmarksShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .bookmarks) - toggleDownloadsShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .downloads) + Task { @MainActor in + toggleAutofillShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .autofill) + toggleBookmarksShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .bookmarks) + toggleDownloadsShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .downloads) #if NETWORK_PROTECTION - if NetworkProtectionKeychainTokenStore().isFeatureActivated { - toggleNetworkProtectionShortcutMenuItem.isHidden = false - toggleNetworkProtectionShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .networkProtection) - } else { - toggleNetworkProtectionShortcutMenuItem.isHidden = true - } + if await DefaultNetworkProtectionVisibility().isVPNVisible() { + toggleNetworkProtectionShortcutMenuItem.isHidden = false + toggleNetworkProtectionShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .networkProtection) + } else { + toggleNetworkProtectionShortcutMenuItem.isHidden = true + } #endif + } } // MARK: - Debug diff --git a/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift b/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift index 3ae0a5ab01..05868109ac 100644 --- a/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift +++ b/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift @@ -341,7 +341,7 @@ final class MoreOptionsMenu: NSMenu { #endif #if NETWORK_PROTECTION - if networkProtectionFeatureVisibility.isNetworkProtectionVisible() { + if networkProtectionFeatureVisibility.isNetworkProtectionBetaVisible() { let networkProtectionItem: NSMenuItem networkProtectionItem = makeNetworkProtectionItem() diff --git a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift index d392da9c79..9f8bb87ab1 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift @@ -320,7 +320,7 @@ final class NavigationBarViewController: NSViewController { private func toggleNetworkProtectionPopover() { let featureVisibility = DefaultNetworkProtectionVisibility() - guard featureVisibility.isNetworkProtectionVisible() else { + guard featureVisibility.isNetworkProtectionBetaVisible() else { featureVisibility.disableForWaitlistUsers() LocalPinningManager.shared.unpin(.networkProtection) return @@ -405,7 +405,7 @@ final class NavigationBarViewController: NSViewController { self.updateHomeButton() #if NETWORK_PROTECTION case .networkProtection: - networkProtectionButtonModel.updateVisibility() + self.networkProtectionButtonModel.updateVisibility() #endif } } else { @@ -945,7 +945,7 @@ extension NavigationBarViewController: NSMenuDelegate { #if NETWORK_PROTECTION let isPopUpWindow = view.window?.isPopUpWindow ?? false - if !isPopUpWindow && networkProtectionFeatureActivation.isFeatureActivated { + if !isPopUpWindow && DefaultNetworkProtectionVisibility().isVPNVisible() { let networkProtectionTitle = LocalPinningManager.shared.shortcutTitle(for: .networkProtection) menu.addItem(withTitle: networkProtectionTitle, action: #selector(toggleNetworkProtectionPanelPinning), keyEquivalent: "N") } @@ -980,7 +980,7 @@ extension NavigationBarViewController: NSMenuDelegate { func showNetworkProtectionStatus() { let featureVisibility = DefaultNetworkProtectionVisibility() - if featureVisibility.isNetworkProtectionVisible() { + if featureVisibility.isNetworkProtectionBetaVisible() { popovers.showNetworkProtectionPopover(positionedBelow: networkProtectionButton, withDelegate: networkProtectionButtonModel) } else { diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarButtonModel.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarButtonModel.swift index b31c8f007f..5ee8f863a0 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarButtonModel.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarButtonModel.swift @@ -178,7 +178,7 @@ final class NetworkProtectionNavBarButtonModel: NSObject, ObservableObject { func updateVisibility() { // The button is visible in the case where NetP has not been activated, but the user has been invited and they haven't accepted T&Cs. let networkProtectionVisibility = DefaultNetworkProtectionVisibility() - if networkProtectionVisibility.isNetworkProtectionVisible() { + if networkProtectionVisibility.isNetworkProtectionBetaVisible() { if NetworkProtectionWaitlist().readyToAcceptTermsAndConditions { DailyPixel.fire(pixel: .networkProtectionWaitlistEntryPointToolbarButtonDisplayed, frequency: .dailyOnly, diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index 331892d0f5..089a82f3f1 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -144,7 +144,7 @@ final class NetworkProtectionNavBarPopoverManager: NetPPopoverManager { } else { let featureVisibility = DefaultNetworkProtectionVisibility() - if featureVisibility.isNetworkProtectionVisible() { + if featureVisibility.isNetworkProtectionBetaVisible() { show(positionedBelow: view, withDelegate: delegate) } else { featureVisibility.disableForWaitlistUsers() diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionIPCTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionIPCTunnelController.swift index 9c27855554..1b03bfb3f8 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionIPCTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionIPCTunnelController.swift @@ -83,7 +83,7 @@ final class NetworkProtectionIPCTunnelController: TunnelController { // MARK: - Login Items Manager private func enableLoginItems() async throws -> Bool { - guard try await featureVisibility.isFeatureEnabled() else { + guard try await featureVisibility.canStartVPN() else { // We shouldn't enable the menu app is the VPN feature is disabled. return false } diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionRemoteMessaging/NetworkProtectionRemoteMessaging.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionRemoteMessaging/NetworkProtectionRemoteMessaging.swift index 2a4a2d3f36..382a4f1bd8 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionRemoteMessaging/NetworkProtectionRemoteMessaging.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionRemoteMessaging/NetworkProtectionRemoteMessaging.swift @@ -133,7 +133,7 @@ final class DefaultNetworkProtectionRemoteMessaging: NetworkProtectionRemoteMess } // Next, check if the message requires access to NetP but it's not visible: - if message.requiresNetworkProtectionAccess, !networkProtectionVisibility.isNetworkProtectionVisible() { + if message.requiresNetworkProtectionAccess, !networkProtectionVisibility.isNetworkProtectionBetaVisible() { return false } diff --git a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift index 7078235c82..b5ba825f14 100644 --- a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift +++ b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift @@ -108,26 +108,12 @@ final class PreferencesSidebarModel: ObservableObject { private func setupVPNPaneVisibility() { DefaultNetworkProtectionVisibility().onboardStatusPublisher .receive(on: DispatchQueue.main) - .sink { [weak self] onboardingStatus in + .sink { [weak self] _ in guard let self else { return } - if onboardingStatus != .completed && self.selectedPane == .vpn { - self.selectedPane = .general - } - self.refreshSections() } .store(in: &cancellables) - - UserDefaults.netP.publisher(for: \.networkProtectionEntitlementsExpired) - .receive(on: DispatchQueue.main) - .sink { [weak self] entitlementsExpired in - guard let self else { return } - if !entitlementsExpired && self.selectedPane == .vpn { - self.selectedPane = .general - } - self.refreshSections() - }.store(in: &cancellables) } #endif diff --git a/DuckDuckGo/Preferences/Model/VPNPreferencesModel.swift b/DuckDuckGo/Preferences/Model/VPNPreferencesModel.swift index 8e062d7e27..54ead02220 100644 --- a/DuckDuckGo/Preferences/Model/VPNPreferencesModel.swift +++ b/DuckDuckGo/Preferences/Model/VPNPreferencesModel.swift @@ -61,7 +61,7 @@ final class VPNPreferencesModel: ObservableObject { private var onboardingStatus: OnboardingStatus { didSet { - showUninstallVPN = onboardingStatus != .default + showUninstallVPN = DefaultNetworkProtectionVisibility().isInstalled } } diff --git a/DuckDuckGo/Waitlist/NetworkProtectionFeatureDisabler.swift b/DuckDuckGo/Waitlist/NetworkProtectionFeatureDisabler.swift index c15bb6568e..ba12c9cdd2 100644 --- a/DuckDuckGo/Waitlist/NetworkProtectionFeatureDisabler.swift +++ b/DuckDuckGo/Waitlist/NetworkProtectionFeatureDisabler.swift @@ -62,24 +62,9 @@ final class NetworkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling self.ipcClient = ipcClient } - private var isSystemExtensionInstalled: Bool { -#if NETP_SYSTEM_EXTENSION - userDefaults.networkProtectionOnboardingStatus != .isOnboarding(step: .userNeedsToAllowExtension) -#else - return false -#endif - } - - private var isVPNConfigurationInstalled: Bool { - userDefaults.networkProtectionOnboardingStatus == .completed - } - @MainActor private func canUninstall(includingSystemExtension: Bool) -> Bool { - !isDisabling - && LoginItem.vpnMenu.status.isInstalled - && ((includingSystemExtension && isSystemExtensionInstalled) - || isVPNConfigurationInstalled) + !isDisabling && LoginItem.vpnMenu.status.isInstalled } /// This method disables the VPN and clear all of its state. @@ -93,17 +78,17 @@ final class NetworkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling func disable(keepAuthToken: Bool, uninstallSystemExtension: Bool) async -> Bool { // To disable NetP we need the login item to be running // This should be fine though as we'll disable them further down below + guard canUninstall(includingSystemExtension: uninstallSystemExtension) else { + return true + } + + isDisabling = true defer { unpinNetworkProtection() resetUserDefaults(uninstallSystemExtension: uninstallSystemExtension) } - guard canUninstall(includingSystemExtension: uninstallSystemExtension) else { - return true - } - - isDisabling = true enableLoginItems() // Allow some time for the login items to fully launch diff --git a/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift b/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift index db7eb7c5a5..28f9299290 100644 --- a/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift +++ b/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift @@ -33,9 +33,11 @@ import Subscription protocol NetworkProtectionFeatureVisibility { var isEligibleForThankYouMessage: Bool { get } + var isInstalled: Bool { get } - func isFeatureEnabled() async throws -> Bool - func isNetworkProtectionVisible() -> Bool + func canStartVPN() async throws -> Bool + func isVPNVisible() -> Bool + func isNetworkProtectionBetaVisible() -> Bool func shouldUninstallAutomatically() -> Bool func disableForAllUsers() async func disableForWaitlistUsers() @@ -77,19 +79,22 @@ struct DefaultNetworkProtectionVisibility: NetworkProtectionFeatureVisibility { /// 2. If no auth token is found, the feature is visible if the waitlist feature flag is enabled /// /// Once the waitlist beta has ended, we can trigger a remote change that removes the user's auth token and turn off the waitlist flag, hiding the VPN from the user. - func isNetworkProtectionVisible() -> Bool { + func isNetworkProtectionBetaVisible() -> Bool { return isEasterEggUser || waitlistIsOngoing } var isInstalled: Bool { - LoginItem.vpnMenu.status.isInstalled && isOnboarded + LoginItem.vpnMenu.status.isInstalled } - /// Replaces `isNetworkProtectionVisible` to add subscriptions support + /// Whether the user can start the VPN. /// - func isFeatureEnabled() async throws -> Bool { + /// For beta users this means they have an auth token. + /// For subscription users this means they have entitlements. + /// + func canStartVPN() async throws -> Bool { guard subscriptionFeatureAvailability.isFeatureAvailable else { - return isNetworkProtectionVisible() + return isNetworkProtectionBetaVisible() } switch await AccountManager().hasEntitlement(for: .networkProtection) { @@ -100,6 +105,19 @@ struct DefaultNetworkProtectionVisibility: NetworkProtectionFeatureVisibility { } } + /// Whether the user can see the VPN entry points in the UI. + /// + /// For beta users this means they have an auth token. + /// For subscription users this means they are authenticated. + /// + func isVPNVisible() -> Bool { + guard subscriptionFeatureAvailability.isFeatureAvailable else { + return isNetworkProtectionBetaVisible() + } + + return AccountManager().isUserAuthenticated + } + /// We've had to add this method because accessing the singleton in app delegate is crashing the integration tests. /// var subscriptionFeatureAvailability: DefaultSubscriptionFeatureAvailability { diff --git a/DuckDuckGoVPN/NetworkProtectionBouncer.swift b/DuckDuckGoVPN/NetworkProtectionBouncer.swift index 3ab9ee5e6b..f50152e122 100644 --- a/DuckDuckGoVPN/NetworkProtectionBouncer.swift +++ b/DuckDuckGoVPN/NetworkProtectionBouncer.swift @@ -36,23 +36,9 @@ final class NetworkProtectionBouncer { func requireAuthTokenOrKillApp(controller: TunnelController) async { #if SUBSCRIPTION let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) - let result = await accountManager.hasEntitlement(for: .networkProtection, cachePolicy: .reloadIgnoringLocalCacheData) - switch result { - case .success(true): - return - case .failure: - guard accountManager.accessToken == nil else { - return - } - case .success(false): - os_log(.error, log: .networkProtection, "🔴 Stopping: DuckDuckGo VPN not authorized. Missing entitlement.") - await controller.stop() - // EXIT_SUCCESS ensures the login item won't relaunch - // Ref: https://developer.apple.com/documentation/servicemanagement/smappservice/register() - // See where it mentions: - // "If the helper crashes or exits with a non-zero status, the system relaunches it" - exit(EXIT_SUCCESS) + guard !accountManager.isUserAuthenticated else { + return } #endif let keychainStore = NetworkProtectionKeychainTokenStore(keychainType: .default, diff --git a/UnitTests/Menus/MoreOptionsMenuTests.swift b/UnitTests/Menus/MoreOptionsMenuTests.swift index 7cf4b36222..05b355614a 100644 --- a/UnitTests/Menus/MoreOptionsMenuTests.swift +++ b/UnitTests/Menus/MoreOptionsMenuTests.swift @@ -18,6 +18,10 @@ import XCTest +#if SUBSCRIPTION +import Subscription +#endif + #if NETWORK_PROTECTION import NetworkProtection #endif @@ -62,7 +66,7 @@ final class MoreOptionsMenuTests: XCTestCase { internalUserDecider = InternalUserDeciderMock() #if NETWORK_PROTECTION - networkProtectionVisibilityMock = NetworkProtectionVisibilityMock(visible: false) + networkProtectionVisibilityMock = NetworkProtectionVisibilityMock(isInstalled: false, visible: false) #endif } @@ -80,7 +84,7 @@ final class MoreOptionsMenuTests: XCTestCase { #if NETWORK_PROTECTION moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, passwordManagerCoordinator: passwordManagerCoordinator, - networkProtectionFeatureVisibility: NetworkProtectionVisibilityMock(visible: true), + networkProtectionFeatureVisibility: NetworkProtectionVisibilityMock(isInstalled: false, visible: true), sharingMenu: NSMenu(), internalUserDecider: internalUserDecider) #else @@ -105,10 +109,18 @@ final class MoreOptionsMenuTests: XCTestCase { XCTAssertEqual(moreOptionMenu.items[12].title, UserText.emailOptionsMenuItem) #if NETWORK_PROTECTION - XCTAssertTrue(moreOptionMenu.items[13].isSeparatorItem) - XCTAssertTrue(moreOptionMenu.items[14].title.hasPrefix(UserText.networkProtection)) - XCTAssertTrue(moreOptionMenu.items[15].isSeparatorItem) - XCTAssertEqual(moreOptionMenu.items[16].title, UserText.settings) + if AccountManager().isUserAuthenticated { + XCTAssertTrue(moreOptionMenu.items[13].isSeparatorItem) + XCTAssertTrue(moreOptionMenu.items[14].title.hasPrefix(UserText.networkProtection)) + XCTAssertTrue(moreOptionMenu.items[15].title.hasPrefix(UserText.identityTheftRestorationOptionsMenuItem)) + XCTAssertTrue(moreOptionMenu.items[16].isSeparatorItem) + XCTAssertEqual(moreOptionMenu.items[17].title, UserText.settings) + } else { + XCTAssertTrue(moreOptionMenu.items[13].isSeparatorItem) + XCTAssertTrue(moreOptionMenu.items[14].title.hasPrefix(UserText.networkProtection)) + XCTAssertTrue(moreOptionMenu.items[15].isSeparatorItem) + XCTAssertEqual(moreOptionMenu.items[16].title, UserText.settings) + } #else XCTAssertTrue(moreOptionMenu.items[13].isSeparatorItem) XCTAssertEqual(moreOptionMenu.items[14].title, UserText.settings) @@ -120,7 +132,7 @@ final class MoreOptionsMenuTests: XCTestCase { #if NETWORK_PROTECTION moreOptionMenu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel, passwordManagerCoordinator: passwordManagerCoordinator, - networkProtectionFeatureVisibility: NetworkProtectionVisibilityMock(visible: false), + networkProtectionFeatureVisibility: NetworkProtectionVisibilityMock(isInstalled: false, visible: false), sharingMenu: NSMenu(), internalUserDecider: internalUserDecider) #else @@ -143,8 +155,20 @@ final class MoreOptionsMenuTests: XCTestCase { XCTAssertEqual(moreOptionMenu.items[10].title, UserText.passwordManagement) XCTAssertTrue(moreOptionMenu.items[11].isSeparatorItem) XCTAssertEqual(moreOptionMenu.items[12].title, UserText.emailOptionsMenuItem) +#if SUBSCRIPTION + XCTAssertTrue(moreOptionMenu.items[13].isSeparatorItem) + + if AccountManager().isUserAuthenticated { + XCTAssertTrue(moreOptionMenu.items[14].title.hasPrefix(UserText.identityTheftRestorationOptionsMenuItem)) + XCTAssertTrue(moreOptionMenu.items[15].isSeparatorItem) + XCTAssertEqual(moreOptionMenu.items[16].title, UserText.settings) + } else { + XCTAssertEqual(moreOptionMenu.items[14].title, UserText.settings) + } +#else XCTAssertTrue(moreOptionMenu.items[13].isSeparatorItem) XCTAssertEqual(moreOptionMenu.items[14].title, UserText.settings) +#endif } // MARK: Zoom @@ -166,8 +190,7 @@ final class MoreOptionsMenuTests: XCTestCase { @MainActor func testWhenClickingOnPreferenceMenuItemThenTheActionDelegateIsAlerted() { - moreOptionMenu.performActionForItem(at: 14) - + moreOptionMenu.performActionForItem(at: moreOptionMenu.items.count - 1) XCTAssertTrue(capturingActionDelegate.optionsButtonMenuRequestedPreferencesCalled) } @@ -176,21 +199,27 @@ final class MoreOptionsMenuTests: XCTestCase { #if NETWORK_PROTECTION final class NetworkProtectionVisibilityMock: NetworkProtectionFeatureVisibility { + var isInstalled: Bool var visible: Bool - init(visible: Bool) { + init(isInstalled: Bool, visible: Bool) { + self.isInstalled = isInstalled self.visible = visible } + func isVPNVisible() -> Bool { + return visible + } + func shouldUninstallAutomatically() -> Bool { return !visible } - func isNetworkProtectionVisible() -> Bool { + func isNetworkProtectionBetaVisible() -> Bool { return visible } - func isFeatureEnabled() async throws -> Bool { + func canStartVPN() async throws -> Bool { return false } diff --git a/UnitTests/NetworkProtection/NetworkProtectionRemoteMessagingTests.swift b/UnitTests/NetworkProtection/NetworkProtectionRemoteMessagingTests.swift index 33eec679ee..761f184335 100644 --- a/UnitTests/NetworkProtection/NetworkProtectionRemoteMessagingTests.swift +++ b/UnitTests/NetworkProtection/NetworkProtectionRemoteMessagingTests.swift @@ -37,7 +37,7 @@ final class NetworkProtectionRemoteMessagingTests: XCTestCase { let storage = MockNetworkProtectionRemoteMessagingStorage() let waitlistStorage = MockWaitlistStorage() let activationDateStorage = MockWaitlistActivationDateStore() - let visibility = NetworkProtectionVisibilityMock(visible: true) + let visibility = NetworkProtectionVisibilityMock(isInstalled: false, visible: true) let messaging = DefaultNetworkProtectionRemoteMessaging( messageRequest: request, @@ -67,7 +67,7 @@ final class NetworkProtectionRemoteMessagingTests: XCTestCase { let storage = MockNetworkProtectionRemoteMessagingStorage() let waitlistStorage = MockWaitlistStorage() let activationDateStorage = MockWaitlistActivationDateStore() - let visibility = NetworkProtectionVisibilityMock(visible: true) + let visibility = NetworkProtectionVisibilityMock(isInstalled: false, visible: true) request.result = .success([]) waitlistStorage.store(waitlistToken: "token") @@ -103,7 +103,7 @@ final class NetworkProtectionRemoteMessagingTests: XCTestCase { let storage = MockNetworkProtectionRemoteMessagingStorage() let waitlistStorage = MockWaitlistStorage() let activationDateStorage = MockWaitlistActivationDateStore() - let visibility = NetworkProtectionVisibilityMock(visible: true) + let visibility = NetworkProtectionVisibilityMock(isInstalled: false, visible: true) let messages = [mockMessage(id: "123")] @@ -144,7 +144,7 @@ final class NetworkProtectionRemoteMessagingTests: XCTestCase { let storage = MockNetworkProtectionRemoteMessagingStorage() let waitlistStorage = MockWaitlistStorage() let activationDateStorage = MockWaitlistActivationDateStore() - let visibility = NetworkProtectionVisibilityMock(visible: true) + let visibility = NetworkProtectionVisibilityMock(isInstalled: false, visible: true) waitlistStorage.store(waitlistToken: "token") waitlistStorage.store(waitlistTimestamp: 123) @@ -183,7 +183,7 @@ final class NetworkProtectionRemoteMessagingTests: XCTestCase { let storage = MockNetworkProtectionRemoteMessagingStorage() let waitlistStorage = MockWaitlistStorage() let activationDateStorage = MockWaitlistActivationDateStore() - let visibility = NetworkProtectionVisibilityMock(visible: true) + let visibility = NetworkProtectionVisibilityMock(isInstalled: false, visible: true) let dismissedMessage = mockMessage(id: "123") let activeMessage = mockMessage(id: "456") @@ -212,7 +212,7 @@ final class NetworkProtectionRemoteMessagingTests: XCTestCase { let storage = MockNetworkProtectionRemoteMessagingStorage() let waitlistStorage = MockWaitlistStorage() let activationDateStorage = MockWaitlistActivationDateStore() - let visibility = NetworkProtectionVisibilityMock(visible: true) + let visibility = NetworkProtectionVisibilityMock(isInstalled: false, visible: true) let hiddenMessage = mockMessage(id: "123", daysSinceNetworkProtectionEnabled: 10) let activeMessage = mockMessage(id: "456") @@ -238,7 +238,7 @@ final class NetworkProtectionRemoteMessagingTests: XCTestCase { let storage = MockNetworkProtectionRemoteMessagingStorage() let waitlistStorage = MockWaitlistStorage() let activationDateStorage = MockWaitlistActivationDateStore() - let visibility = NetworkProtectionVisibilityMock(visible: false) + let visibility = NetworkProtectionVisibilityMock(isInstalled: false, visible: false) let hiddenMessage = mockMessage(id: "123", requiresNetPAccess: true) try? storage.store(messages: [hiddenMessage]) @@ -262,7 +262,7 @@ final class NetworkProtectionRemoteMessagingTests: XCTestCase { let storage = MockNetworkProtectionRemoteMessagingStorage() let waitlistStorage = MockWaitlistStorage() let activationDateStorage = MockWaitlistActivationDateStore() - let visibility = NetworkProtectionVisibilityMock(visible: true) + let visibility = NetworkProtectionVisibilityMock(isInstalled: false, visible: true) let message = mockMessage(id: "123", requiresNetPUsage: false, requiresNetPAccess: true) try? storage.store(messages: [message])