diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionDebugMenu.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionDebugMenu.swift index e26c61ae15..749e95c02b 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionDebugMenu.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionDebugMenu.swift @@ -485,10 +485,7 @@ final class NetworkProtectionDebugMenu: NSMenu { @objc func resetNetworkProtectionRemoteMessages(_ sender: Any?) { DefaultSurveyRemoteMessagingStorage.surveys().removeStoredAndDismissedMessages() - DefaultSurveyRemoteMessaging( - subscriptionManager: Application.appDelegate.subscriptionManager, - minimumRefreshInterval: 0 - ).resetLastRefreshTimestamp() + DefaultSurveyRemoteMessaging(subscriptionManager: Application.appDelegate.subscriptionManager).resetLastRefreshTimestamp() } @objc func overrideNetworkProtectionActivationDateToNow(_ sender: Any?) { diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionRemoteMessaging/SurveyRemoteMessaging.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionRemoteMessaging/SurveyRemoteMessaging.swift index b07c5e9496..d25f3e5064 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionRemoteMessaging/SurveyRemoteMessaging.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionRemoteMessaging/SurveyRemoteMessaging.swift @@ -29,6 +29,12 @@ protocol SurveyRemoteMessaging { } +protocol SurveyRemoteMessageSubscriptionFetching { + + func getSubscription(accessToken: String) async -> Result + +} + final class DefaultSurveyRemoteMessaging: SurveyRemoteMessaging { enum Constants { @@ -37,23 +43,33 @@ final class DefaultSurveyRemoteMessaging: SurveyRemoteMessaging { private let messageRequest: HomePageRemoteMessagingRequest private let messageStorage: SurveyRemoteMessagingStorage - private let subscriptionManager: SubscriptionManaging + private let accountManager: AccountManaging + private let subscriptionFetcher: SurveyRemoteMessageSubscriptionFetching private let waitlistActivationDateStore: WaitlistActivationDateStore private let minimumRefreshInterval: TimeInterval private let userDefaults: UserDefaults convenience init(subscriptionManager: SubscriptionManaging) { #if DEBUG || REVIEW - self.init(subscriptionManager: subscriptionManager, minimumRefreshInterval: .seconds(30)) + self.init( + accountManager: subscriptionManager.accountManager, + subscriptionFetcher: subscriptionManager.subscriptionService, + minimumRefreshInterval: .seconds(30) + ) #else - self.init(subscriptionManager: subscriptionManager, minimumRefreshInterval: .hours(1)) + self.init( + accountManager: subscriptionManager.accountManager, + subscriptionFetcher: subscriptionManager.subscriptionService, + minimumRefreshInterval: .hours(1) + ) #endif } init( messageRequest: HomePageRemoteMessagingRequest = DefaultHomePageRemoteMessagingRequest.surveysRequest(), messageStorage: SurveyRemoteMessagingStorage = DefaultSurveyRemoteMessagingStorage.surveys(), - subscriptionManager: SubscriptionManaging, + accountManager: AccountManaging, + subscriptionFetcher: SurveyRemoteMessageSubscriptionFetching, waitlistActivationDateStore: WaitlistActivationDateStore = DefaultWaitlistActivationDateStore(source: .netP), networkProtectionVisibility: NetworkProtectionFeatureVisibility = DefaultNetworkProtectionVisibility(subscriptionManager: Application.appDelegate.subscriptionManager), minimumRefreshInterval: TimeInterval, @@ -61,7 +77,8 @@ final class DefaultSurveyRemoteMessaging: SurveyRemoteMessaging { ) { self.messageRequest = messageRequest self.messageStorage = messageStorage - self.subscriptionManager = subscriptionManager + self.accountManager = accountManager + self.subscriptionFetcher = subscriptionFetcher self.waitlistActivationDateStore = waitlistActivationDateStore self.minimumRefreshInterval = minimumRefreshInterval self.userDefaults = userDefaults @@ -98,11 +115,11 @@ final class DefaultSurveyRemoteMessaging: SurveyRemoteMessaging { /// Because the result of the message fetch is cached, it means that they won't be immediately updated if the user suddenly qualifies, but the refresh interval for remote messages is only 1 hour so it /// won't take long for the message to appear to the user. private func process(messages: [SurveyRemoteMessage]) async -> [SurveyRemoteMessage] { - guard let token = subscriptionManager.accountManager.accessToken else { + guard let token = accountManager.accessToken else { return [] } - guard case let .success(subscription) = await subscriptionManager.subscriptionService.getSubscription(accessToken: token) else { + guard case let .success(subscription) = await subscriptionFetcher.getSubscription(accessToken: token) else { return [] } @@ -201,3 +218,11 @@ final class DefaultSurveyRemoteMessaging: SurveyRemoteMessaging { } } + +extension SubscriptionService: SurveyRemoteMessageSubscriptionFetching { + + func getSubscription(accessToken: String) async -> Result { + return await self.getSubscription(accessToken: accessToken, cachePolicy: .returnCacheDataElseLoad) + } + +} diff --git a/UnitTests/HomePage/SurveyRemoteMessagingTests.swift b/UnitTests/HomePage/SurveyRemoteMessagingTests.swift index 9397754279..e4591c707d 100644 --- a/UnitTests/HomePage/SurveyRemoteMessagingTests.swift +++ b/UnitTests/HomePage/SurveyRemoteMessagingTests.swift @@ -17,8 +17,8 @@ // import XCTest -import Subscription import SubscriptionTestingUtilities +@testable import Subscription @testable import DuckDuckGo_Privacy_Browser @available(macOS 12.0, *) @@ -27,20 +27,15 @@ final class SurveyRemoteMessagingTests: XCTestCase { private var defaults: UserDefaults! private let testGroupName = "remote-messaging" - private var subscriptionManager: SubscriptionManaging! + private var accountManager: AccountManaging! + private var subscriptionFetcher: SurveyRemoteMessageSubscriptionFetching! override func setUp() { defaults = UserDefaults(suiteName: testGroupName)! defaults.removePersistentDomain(forName: testGroupName) - subscriptionManager = SubscriptionManagerMock( - accountManager: AccountManagerMock(isUserAuthenticated: true), - subscriptionService: SubscriptionService(currentServiceEnvironment: .staging), - authService: AuthService(currentServiceEnvironment: .staging), - storePurchaseManager: StorePurchaseManager(), - currentEnvironment: .default, - canPurchase: true - ) + accountManager = AccountManagerMock(isUserAuthenticated: true, accessToken: "mock-token") + subscriptionFetcher = MockSubscriptionFetcher() } func testWhenFetchingRemoteMessages_AndTheUserDidNotSignUpViaWaitlist_ThenMessagesAreFetched() async { @@ -52,7 +47,8 @@ final class SurveyRemoteMessagingTests: XCTestCase { let messaging = DefaultSurveyRemoteMessaging( messageRequest: request, messageStorage: storage, - subscriptionManager: subscriptionManager, + accountManager: accountManager, + subscriptionFetcher: subscriptionFetcher, waitlistActivationDateStore: activationDateStorage, minimumRefreshInterval: 0, userDefaults: defaults @@ -73,7 +69,8 @@ final class SurveyRemoteMessagingTests: XCTestCase { let messaging = DefaultSurveyRemoteMessaging( messageRequest: request, messageStorage: storage, - subscriptionManager: subscriptionManager, + accountManager: accountManager, + subscriptionFetcher: subscriptionFetcher, waitlistActivationDateStore: activationDateStorage, minimumRefreshInterval: 0, userDefaults: defaults @@ -99,7 +96,8 @@ final class SurveyRemoteMessagingTests: XCTestCase { let messaging = DefaultSurveyRemoteMessaging( messageRequest: request, messageStorage: storage, - subscriptionManager: subscriptionManager, + accountManager: accountManager, + subscriptionFetcher: subscriptionFetcher, waitlistActivationDateStore: activationDateStorage, minimumRefreshInterval: 0, userDefaults: defaults @@ -126,7 +124,8 @@ final class SurveyRemoteMessagingTests: XCTestCase { let messaging = DefaultSurveyRemoteMessaging( messageRequest: request, messageStorage: storage, - subscriptionManager: subscriptionManager, + accountManager: accountManager, + subscriptionFetcher: subscriptionFetcher, waitlistActivationDateStore: activationDateStorage, minimumRefreshInterval: .days(7), // Use a large number to hit the refresh check userDefaults: defaults @@ -153,7 +152,8 @@ final class SurveyRemoteMessagingTests: XCTestCase { let messaging = DefaultSurveyRemoteMessaging( messageRequest: request, messageStorage: storage, - subscriptionManager: subscriptionManager, + accountManager: accountManager, + subscriptionFetcher: subscriptionFetcher, waitlistActivationDateStore: activationDateStorage, minimumRefreshInterval: 0, userDefaults: defaults @@ -166,50 +166,6 @@ final class SurveyRemoteMessagingTests: XCTestCase { XCTAssertEqual(presentableMessagesAfter, [activeMessage]) } - func testWhenStoredMessagesExist_AndSomeMessagesRequireDaysActive_ThenPresentableMessagesDoNotIncludeInvalidMessages() { - let request = MockNetworkProtectionRemoteMessagingRequest() - let storage = MockSurveyRemoteMessagingStorage() - let activationDateStorage = MockWaitlistActivationDateStore() - - let hiddenMessage = mockMessage(id: "123", daysSinceVPNEnabled: 10) - let activeMessage = mockMessage(id: "456") - try? storage.store(messages: [hiddenMessage, activeMessage]) - activationDateStorage._daysSinceActivation = 5 - - let messaging = DefaultSurveyRemoteMessaging( - messageRequest: request, - messageStorage: storage, - subscriptionManager: subscriptionManager, - waitlistActivationDateStore: activationDateStorage, - minimumRefreshInterval: 0, - userDefaults: defaults - ) - - let presentableMessagesAfter = messaging.presentableRemoteMessages() - XCTAssertEqual(presentableMessagesAfter, [activeMessage]) - } - - func testWhenStoredMessagesExist_AndSomeMessagesNetPVisibility_ThenPresentableMessagesDoNotIncludeInvalidMessages() { - let request = MockNetworkProtectionRemoteMessagingRequest() - let storage = MockSurveyRemoteMessagingStorage() - let activationDateStorage = MockWaitlistActivationDateStore() - - let hiddenMessage = mockMessage(id: "123") - try? storage.store(messages: [hiddenMessage]) - - let messaging = DefaultSurveyRemoteMessaging( - messageRequest: request, - messageStorage: storage, - subscriptionManager: subscriptionManager, - waitlistActivationDateStore: activationDateStorage, - minimumRefreshInterval: 0, - userDefaults: defaults - ) - - let presentableMessages = messaging.presentableRemoteMessages() - XCTAssertEqual(presentableMessages, []) - } - func testWhenStoredMessagesExist_AndSomeMessagesRequireNetPUsage_ThenPresentableMessagesDoNotIncludeInvalidMessages() { let request = MockNetworkProtectionRemoteMessagingRequest() let storage = MockSurveyRemoteMessagingStorage() @@ -221,7 +177,8 @@ final class SurveyRemoteMessagingTests: XCTestCase { let messaging = DefaultSurveyRemoteMessaging( messageRequest: request, messageStorage: storage, - subscriptionManager: subscriptionManager, + accountManager: accountManager, + subscriptionFetcher: subscriptionFetcher, waitlistActivationDateStore: activationDateStorage, minimumRefreshInterval: 0, userDefaults: defaults @@ -232,7 +189,7 @@ final class SurveyRemoteMessagingTests: XCTestCase { } private func mockMessage(id: String, - subscriptionStatus: String = "", + subscriptionStatus: String = Subscription.Status.autoRenewable.rawValue, minimumDaysSinceSubscriptionStarted: Int = 0, maximumDaysUntilSubscriptionExpirationOrRenewal: Int = 0, daysSinceVPNEnabled: Int = 0, @@ -314,3 +271,20 @@ final class MockWaitlistActivationDateStore: WaitlistActivationDateStore { } } + +final class MockSubscriptionFetcher: SurveyRemoteMessageSubscriptionFetching { + + var subscription: Subscription = Subscription( + productId: "product", + name: "name", + billingPeriod: .monthly, + startedAt: Date(), + expiresOrRenewsAt: Date(), + platform: .apple, + status: .autoRenewable) + + func getSubscription(accessToken: String) async -> Result { + return .success(subscription) + } + +}