diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 227df5155..e7d3a6c96 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: SwiftLint uses: docker://norionomura/swiftlint:0.54.0_swift-5.9.0 with: @@ -22,7 +22,7 @@ jobs: name: Run unit tests (macOS) - runs-on: macos-13-xlarge + runs-on: macos-14-xlarge timeout-minutes: 30 outputs: @@ -31,7 +31,7 @@ jobs: steps: - name: Check out the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive @@ -46,7 +46,7 @@ jobs: - name: Cache SPM if: env.cache_key_hash - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | .build/artifacts @@ -89,7 +89,7 @@ jobs: | xargs -L 1 ./scripts/report-failed-unit-test.sh -s ${{ vars.APPLE_CI_FAILING_TESTS_FAILED_TESTS_SECTION_ID }} - name: Upload logs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: build-log.txt @@ -109,13 +109,13 @@ jobs: name: Run unit tests (iOS) - runs-on: macos-13-xlarge + runs-on: macos-14-xlarge timeout-minutes: 30 steps: - name: Check out the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive @@ -130,7 +130,7 @@ jobs: - name: Cache SPM if: env.cache_key_hash - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: DerivedData/SourcePackages key: ${{ runner.os }}-spm-ios-${{ env.cache_key_hash }} @@ -144,7 +144,7 @@ jobs: run: | while xcodebuild -resolvePackageDependencies \ -scheme BrowserServicesKit-Package \ - -destination 'platform=iOS Simulator,name=iPhone 15' \ + -destination 'platform=iOS Simulator,name=iPhone 15,OS=17' \ -derivedDataPath DerivedData \ 2>&1 | grep Error; do :; done @@ -157,7 +157,7 @@ jobs: run: | set -o pipefail && xcodebuild test \ -scheme BrowserServicesKit \ - -destination 'platform=iOS Simulator,name=iPhone 15' \ + -destination 'platform=iOS Simulator,name=iPhone 15,OS=17' \ -derivedDataPath DerivedData \ -skipPackagePluginValidation \ -skipMacroValidation \ @@ -187,7 +187,7 @@ jobs: | xargs -L 1 ./scripts/report-failed-unit-test.sh -s ${{ vars.APPLE_CI_FAILING_TESTS_FAILED_TESTS_SECTION_ID }} - name: Upload logs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ios-build-log.txt @@ -203,7 +203,7 @@ jobs: steps: - name: Check out the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Create Asana Task uses: ./.github/actions/asana-failed-pr-checks with: @@ -222,7 +222,7 @@ jobs: steps: - name: Check out the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Close Asana Task uses: ./.github/actions/asana-failed-pr-checks with: diff --git a/.xcode-version b/.xcode-version index dafb659a6..232a7fc1a 100644 --- a/.xcode-version +++ b/.xcode-version @@ -1 +1 @@ -15.2 +15.4 diff --git a/Package.resolved b/Package.resolved index 75122a5f3..500b08f1b 100644 --- a/Package.resolved +++ b/Package.resolved @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/duckduckgo-autofill.git", "state" : { - "revision" : "2b81745565db09eee8c1cd44d38eefa1011a9f0a", - "version" : "12.0.1" + "revision" : "9fea1c6762db726328b14bb9ebfd6508849eae28", + "version" : "12.1.0" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/GRDB.swift.git", "state" : { - "revision" : "9f049d7b97b1e68ffd86744b500660d34a9e79b8", - "version" : "2.3.0" + "revision" : "4225b85c9a0c50544e413a1ea1e502c802b44b35", + "version" : "2.4.0" } }, { diff --git a/Package.swift b/Package.swift index abee6412f..a63ce1572 100644 --- a/Package.swift +++ b/Package.swift @@ -42,8 +42,8 @@ let package = Package( .library(name: "PixelKitTestingUtilities", targets: ["PixelKitTestingUtilities"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/duckduckgo-autofill.git", exact: "12.0.1"), - .package(url: "https://github.com/duckduckgo/GRDB.swift.git", exact: "2.3.0"), + .package(url: "https://github.com/duckduckgo/duckduckgo-autofill.git", exact: "12.1.0"), + .package(url: "https://github.com/duckduckgo/GRDB.swift.git", exact: "2.4.0"), .package(url: "https://github.com/duckduckgo/TrackerRadarKit", exact: "2.1.2"), .package(url: "https://github.com/duckduckgo/sync_crypto", exact: "0.2.0"), .package(url: "https://github.com/gumob/PunycodeSwift.git", exact: "2.1.0"), diff --git a/Sources/BrowserServicesKit/PrivacyConfig/Features/PrivacyFeature.swift b/Sources/BrowserServicesKit/PrivacyConfig/Features/PrivacyFeature.swift index 370867d6c..40eaad9da 100644 --- a/Sources/BrowserServicesKit/PrivacyConfig/Features/PrivacyFeature.swift +++ b/Sources/BrowserServicesKit/PrivacyConfig/Features/PrivacyFeature.swift @@ -30,6 +30,7 @@ public enum PrivacyFeature: String { case autoconsent case clickToLoad case autofill + case autofillBreakageReporter case ampLinks case trackingParameters case customUserAgent diff --git a/Sources/PrivacyDashboard/BrokenSiteReporting/BrokenSiteReportEntry.swift b/Sources/PrivacyDashboard/BrokenSiteReporting/BrokenSiteReportEntry.swift index 61e612465..9139ac32b 100644 --- a/Sources/PrivacyDashboard/BrokenSiteReporting/BrokenSiteReportEntry.swift +++ b/Sources/PrivacyDashboard/BrokenSiteReporting/BrokenSiteReportEntry.swift @@ -29,10 +29,10 @@ public struct BrokenSiteReportEntry { /// Object Creation + 30 days let expiryDate: Date? - public init?(report: BrokenSiteReport, currentDate: Date) { + public init?(report: BrokenSiteReport, currentDate: Date, daysToExpiry: Int) { guard let domainIdentifier = report.siteUrl.privacySafeDomainIdentifier, - let expiryDate = Calendar.current.date(byAdding: .day, value: 30, to: currentDate) else { + let expiryDate = Calendar.current.date(byAdding: .day, value: daysToExpiry, to: currentDate) else { return nil } self.identifier = domainIdentifier @@ -50,7 +50,7 @@ public struct BrokenSiteReportEntry { } -fileprivate extension URL { +public extension URL { /// A string containing the first 6 chars of the sha256 hash of the URL's domain part var privacySafeDomainIdentifier: String? { diff --git a/Sources/PrivacyDashboard/BrokenSiteReporting/BrokenSiteReporter.swift b/Sources/PrivacyDashboard/BrokenSiteReporting/BrokenSiteReporter.swift index 2ce4fc533..4af160149 100644 --- a/Sources/PrivacyDashboard/BrokenSiteReporting/BrokenSiteReporter.swift +++ b/Sources/PrivacyDashboard/BrokenSiteReporting/BrokenSiteReporter.swift @@ -42,15 +42,17 @@ public class BrokenSiteReporter { public typealias PixelHandler = (_ parameters: [String: String]) -> Void /// Pixels are sent by the main apps not by BSK, this is the closure called by the class when a pixel need to be sent let pixelHandler: PixelHandler - let persistencyManager: ExpiryStorage + public let persistencyManager: ExpiryStorage - public init(pixelHandler: @escaping PixelHandler, keyValueStoring: KeyValueStoringDictionaryRepresentable) { + public init(pixelHandler: @escaping PixelHandler, + keyValueStoring: KeyValueStoringDictionaryRepresentable, + storageConfiguration: ExpiryStorageConfiguration = .defaultConfig) { self.pixelHandler = pixelHandler - self.persistencyManager = ExpiryStorage(keyValueStoring: keyValueStoring) + self.persistencyManager = ExpiryStorage(keyValueStoring: keyValueStoring, configuration: storageConfiguration) } /// Report the site breakage - public func report(_ report: BrokenSiteReport, reportMode: BrokenSiteReport.Mode) throws { + public func report(_ report: BrokenSiteReport, reportMode: BrokenSiteReport.Mode, daysToExpiry: Int = 30) throws { let now = Date() let removedCount = persistencyManager.removeExpiredItems(currentDate: now) @@ -61,7 +63,7 @@ public class BrokenSiteReporter { var report = report // Create history entry - guard let entry = BrokenSiteReportEntry(report: report, currentDate: now) else { + guard let entry = BrokenSiteReportEntry(report: report, currentDate: now, daysToExpiry: daysToExpiry) else { os_log(.error, "Failed to create a history entry for broken site report") throw BrokenSiteReporterError.failedToGenerateHistoryEntry } diff --git a/Sources/PrivacyDashboard/BrokenSiteReporting/ExpiryStorage.swift b/Sources/PrivacyDashboard/BrokenSiteReporting/ExpiryStorage.swift index 39d5dfb7f..8cb9fb871 100644 --- a/Sources/PrivacyDashboard/BrokenSiteReporting/ExpiryStorage.swift +++ b/Sources/PrivacyDashboard/BrokenSiteReporting/ExpiryStorage.swift @@ -21,22 +21,37 @@ import Persistence public typealias KeyValueStoringDictionaryRepresentable = KeyValueStoring & DictionaryRepresentable +public struct ExpiryStorageConfiguration { + + var expiryDatesStorageKey: String + var valueExpiryDateKey: String + var valueDataKey: String + + public static let defaultConfig = ExpiryStorageConfiguration( + expiryDatesStorageKey: "com.duckduckgo.UserDefaultExpiryStorage", + valueExpiryDateKey: "com.duckduckgo.UserDefaultExpiryStorage.valueExpiryDate", + valueDataKey: "com.duckduckgo.UserDefaultExpiryStorage.valueData" + ) + + public static let autofillConfig = ExpiryStorageConfiguration( + expiryDatesStorageKey: "com.duckduckgo.AutofillUserDefaultExpiryStorage", + valueExpiryDateKey: "com.duckduckgo.AutofillUserDefaultExpiryStorage.valueExpiryDate", + valueDataKey: "com.duckduckgo.AutofillUserDefaultExpiryStorage.valueData" + ) +} + /// A storage solution were each entry has an expiry date and a function for removing all expired entries is provided. /// Any persistency solution implementing `KeyValueStoringDictionaryRepresentable` can be used. public class ExpiryStorage { - enum Keys: String { - case expiryDatesStorage = "com.duckduckgo.UserDefaultExpiryStorage" - case valueExpiryDate = "com.duckduckgo.UserDefaultExpiryStorage.valueExpiryDate" - case valueData = "com.duckduckgo.UserDefaultExpiryStorage.valueData" - } - let localStorage: KeyValueStoringDictionaryRepresentable + let config: ExpiryStorageConfiguration /// Default initialiser /// - Parameter keyValueStoring: An object managing the persistency of the key-value pairs that implements `KeyValueStoringDictionaryRepresentable` - public init(keyValueStoring: KeyValueStoringDictionaryRepresentable) { + public init(keyValueStoring: KeyValueStoringDictionaryRepresentable, configuration: ExpiryStorageConfiguration = .defaultConfig) { self.localStorage = keyValueStoring + self.config = configuration } /// Store a value and the desired expiry date (or removes the value if nil is passed as the value) for the provided key @@ -46,11 +61,11 @@ public class ExpiryStorage { /// - expiryDate: A date stored alongside the value, used by `removeExpiredItems(...)` for removing expired values. public func set(value: Any?, forKey key: String, expiryDate: Date) { - let valueDic = [Keys.valueExpiryDate.rawValue: expiryDate, Keys.valueData.rawValue: value] + let valueDic = [config.valueExpiryDateKey: expiryDate, config.valueDataKey: value] localStorage.set(valueDic, forKey: key) } - /// - Returns: The stored value assiciated to the key, nil if not existent + /// - Returns: The stored value associated to the key, nil if not existent public func value(forKey key: String) -> Any? { return entry(forKey: key)?.value @@ -59,8 +74,8 @@ public class ExpiryStorage { /// - Returns: The tuple expiryDate+value associated to the key, nil if they don't exist public func entry(forKey key: String) -> (expiryDate: Date, value: Any)? { guard let valueDic = localStorage.object(forKey: key) as? [String: Any], - let expiryDate = valueDic[Keys.valueExpiryDate.rawValue] as? Date, - let value = valueDic[Keys.valueData.rawValue] + let expiryDate = valueDic[config.valueExpiryDateKey] as? Date, + let value = valueDic[config.valueDataKey] else { return nil } diff --git a/Sources/RemoteMessaging/Matchers/UserAttributeMatcher.swift b/Sources/RemoteMessaging/Matchers/UserAttributeMatcher.swift index 973fcf7c5..94d1fc38c 100644 --- a/Sources/RemoteMessaging/Matchers/UserAttributeMatcher.swift +++ b/Sources/RemoteMessaging/Matchers/UserAttributeMatcher.swift @@ -54,6 +54,8 @@ public struct MobileUserAttributeMatcher: AttributeMatching { isPrivacyProSubscriptionActive: Bool, isPrivacyProSubscriptionExpiring: Bool, isPrivacyProSubscriptionExpired: Bool, + isDuckPlayerOnboarded: Bool, + isDuckPlayerEnabled: Bool, dismissedMessageIds: [String] ) { self.isWidgetInstalled = isWidgetInstalled @@ -74,6 +76,8 @@ public struct MobileUserAttributeMatcher: AttributeMatching { isPrivacyProSubscriptionActive: isPrivacyProSubscriptionActive, isPrivacyProSubscriptionExpiring: isPrivacyProSubscriptionExpiring, isPrivacyProSubscriptionExpired: isPrivacyProSubscriptionExpired, + isDuckPlayerOnboarded: isDuckPlayerOnboarded, + isDuckPlayerEnabled: isDuckPlayerEnabled, dismissedMessageIds: dismissedMessageIds ) } @@ -92,8 +96,6 @@ public struct MobileUserAttributeMatcher: AttributeMatching { public struct DesktopUserAttributeMatcher: AttributeMatching { private let pinnedTabsCount: Int private let hasCustomHomePage: Bool - private let isDuckPlayerOnboarded: Bool - private let isDuckPlayerEnabled: Bool private let dismissedDeprecatedMacRemoteMessageIds: [String] private let commonUserAttributeMatcher: CommonUserAttributeMatcher @@ -122,8 +124,6 @@ public struct DesktopUserAttributeMatcher: AttributeMatching { ) { self.pinnedTabsCount = pinnedTabsCount self.hasCustomHomePage = hasCustomHomePage - self.isDuckPlayerOnboarded = isDuckPlayerOnboarded - self.isDuckPlayerEnabled = isDuckPlayerEnabled self.dismissedDeprecatedMacRemoteMessageIds = dismissedDeprecatedMacRemoteMessageIds commonUserAttributeMatcher = .init( @@ -142,6 +142,8 @@ public struct DesktopUserAttributeMatcher: AttributeMatching { isPrivacyProSubscriptionActive: isPrivacyProSubscriptionActive, isPrivacyProSubscriptionExpiring: isPrivacyProSubscriptionExpiring, isPrivacyProSubscriptionExpired: isPrivacyProSubscriptionExpired, + isDuckPlayerOnboarded: isDuckPlayerOnboarded, + isDuckPlayerEnabled: isDuckPlayerEnabled, dismissedMessageIds: dismissedMessageIds ) } @@ -152,10 +154,6 @@ public struct DesktopUserAttributeMatcher: AttributeMatching { return matchingAttribute.evaluate(for: pinnedTabsCount) case let matchingAttribute as CustomHomePageMatchingAttribute: return matchingAttribute.evaluate(for: hasCustomHomePage) - case let matchingAttribute as DuckPlayerOnboardedMatchingAttribute: - return matchingAttribute.evaluate(for: isDuckPlayerOnboarded) - case let matchingAttribute as DuckPlayerEnabledMatchingAttribute: - return matchingAttribute.evaluate(for: isDuckPlayerEnabled) case let matchingAttribute as InteractedWithDeprecatedMacRemoteMessageMatchingAttribute: if dismissedDeprecatedMacRemoteMessageIds.contains(where: { messageId in StringArrayMatchingAttribute(matchingAttribute.value).matches(value: messageId) == .match @@ -193,6 +191,8 @@ public struct CommonUserAttributeMatcher: AttributeMatching { private let isPrivacyProSubscriptionActive: Bool private let isPrivacyProSubscriptionExpiring: Bool private let isPrivacyProSubscriptionExpired: Bool + private let isDuckPlayerOnboarded: Bool + private let isDuckPlayerEnabled: Bool private let dismissedMessageIds: [String] public init(statisticsStore: StatisticsStore, @@ -210,6 +210,8 @@ public struct CommonUserAttributeMatcher: AttributeMatching { isPrivacyProSubscriptionActive: Bool, isPrivacyProSubscriptionExpiring: Bool, isPrivacyProSubscriptionExpired: Bool, + isDuckPlayerOnboarded: Bool, + isDuckPlayerEnabled: Bool, dismissedMessageIds: [String] ) { self.statisticsStore = statisticsStore @@ -227,6 +229,8 @@ public struct CommonUserAttributeMatcher: AttributeMatching { self.isPrivacyProSubscriptionActive = isPrivacyProSubscriptionActive self.isPrivacyProSubscriptionExpiring = isPrivacyProSubscriptionExpiring self.isPrivacyProSubscriptionExpired = isPrivacyProSubscriptionExpired + self.isDuckPlayerOnboarded = isDuckPlayerOnboarded + self.isDuckPlayerEnabled = isDuckPlayerEnabled self.dismissedMessageIds = dismissedMessageIds } @@ -272,6 +276,10 @@ public struct CommonUserAttributeMatcher: AttributeMatching { } return .fail + case let matchingAttribute as DuckPlayerOnboardedMatchingAttribute: + return matchingAttribute.evaluate(for: isDuckPlayerOnboarded) + case let matchingAttribute as DuckPlayerEnabledMatchingAttribute: + return matchingAttribute.evaluate(for: isDuckPlayerEnabled) case let matchingAttribute as InteractedWithMessageMatchingAttribute: if dismissedMessageIds.contains(where: { messageId in StringArrayMatchingAttribute(matchingAttribute.value).matches(value: messageId) == .match diff --git a/Tests/PrivacyDashboardTests/BrokenSiteReportHistoryEntryTests.swift b/Tests/PrivacyDashboardTests/BrokenSiteReportHistoryEntryTests.swift index 3d428922a..41b2be6df 100644 --- a/Tests/PrivacyDashboardTests/BrokenSiteReportHistoryEntryTests.swift +++ b/Tests/PrivacyDashboardTests/BrokenSiteReportHistoryEntryTests.swift @@ -21,9 +21,11 @@ import XCTest final class BrokenSiteReportHistoryEntryTests: XCTestCase { + private let daysToExpiry: Int = 30 + func testDates() throws { let testDate = Date(timeIntervalSince1970: 1704795829) - let entry = BrokenSiteReportEntry(report: BrokenSiteReportMocks.report, currentDate: testDate) + let entry = BrokenSiteReportEntry(report: BrokenSiteReportMocks.report, currentDate: testDate, daysToExpiry: daysToExpiry) XCTAssertNotNil(entry) XCTAssertEqual("2024-01-09", entry?.lastSentDayString) @@ -32,11 +34,11 @@ final class BrokenSiteReportHistoryEntryTests: XCTestCase { func testUniqueIdentifier() throws { let testDate = Date(timeIntervalSince1970: 1704795829) - let entry = BrokenSiteReportEntry(report: BrokenSiteReportMocks.report, currentDate: testDate) - let entry2 = BrokenSiteReportEntry(report: BrokenSiteReportMocks.report2, currentDate: testDate) + let entry = BrokenSiteReportEntry(report: BrokenSiteReportMocks.report, currentDate: testDate, daysToExpiry: daysToExpiry) + let entry2 = BrokenSiteReportEntry(report: BrokenSiteReportMocks.report2, currentDate: testDate, daysToExpiry: daysToExpiry) XCTAssertNotEqual(entry?.identifier, entry2?.identifier) - let entry3 = BrokenSiteReportEntry(report: BrokenSiteReportMocks.report, currentDate: testDate) + let entry3 = BrokenSiteReportEntry(report: BrokenSiteReportMocks.report, currentDate: testDate, daysToExpiry: daysToExpiry) XCTAssertEqual(entry?.identifier, entry3?.identifier) } diff --git a/Tests/RemoteMessagingTests/Matchers/CommonUserAttributeMatcherTests.swift b/Tests/RemoteMessagingTests/Matchers/CommonUserAttributeMatcherTests.swift index 6de859c21..bcfb685fa 100644 --- a/Tests/RemoteMessagingTests/Matchers/CommonUserAttributeMatcherTests.swift +++ b/Tests/RemoteMessagingTests/Matchers/CommonUserAttributeMatcherTests.swift @@ -312,6 +312,8 @@ class CommonUserAttributeMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: true, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: dismissedMessageIds ) } diff --git a/Tests/RemoteMessagingTests/Matchers/MobileUserAttributeMatcherTests.swift b/Tests/RemoteMessagingTests/Matchers/MobileUserAttributeMatcherTests.swift index 3eedda82a..012c3c267 100644 --- a/Tests/RemoteMessagingTests/Matchers/MobileUserAttributeMatcherTests.swift +++ b/Tests/RemoteMessagingTests/Matchers/MobileUserAttributeMatcherTests.swift @@ -90,6 +90,8 @@ class MobileUserAttributeMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: true, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: dismissedMessageIds ) } diff --git a/Tests/RemoteMessagingTests/RemoteMessagingConfigMatcherTests.swift b/Tests/RemoteMessagingTests/RemoteMessagingConfigMatcherTests.swift index bfba9bab5..31b8a1610 100644 --- a/Tests/RemoteMessagingTests/RemoteMessagingConfigMatcherTests.swift +++ b/Tests/RemoteMessagingTests/RemoteMessagingConfigMatcherTests.swift @@ -54,6 +54,8 @@ class RemoteMessagingConfigMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: MockRemoteMessagePercentileStore(), @@ -149,6 +151,8 @@ class RemoteMessagingConfigMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: MockRemoteMessagePercentileStore(), @@ -254,6 +258,8 @@ class RemoteMessagingConfigMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: MockRemoteMessagePercentileStore(), @@ -302,6 +308,8 @@ class RemoteMessagingConfigMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: MockRemoteMessagePercentileStore(), @@ -346,6 +354,8 @@ class RemoteMessagingConfigMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: percentileStore, @@ -388,6 +398,8 @@ class RemoteMessagingConfigMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: percentileStore, @@ -430,6 +442,8 @@ class RemoteMessagingConfigMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: percentileStore, @@ -472,6 +486,8 @@ class RemoteMessagingConfigMatcherTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: percentileStore, diff --git a/Tests/RemoteMessagingTests/RemoteMessagingConfigProcessorTests.swift b/Tests/RemoteMessagingTests/RemoteMessagingConfigProcessorTests.swift index 76222d589..3ecf9c7e9 100644 --- a/Tests/RemoteMessagingTests/RemoteMessagingConfigProcessorTests.swift +++ b/Tests/RemoteMessagingTests/RemoteMessagingConfigProcessorTests.swift @@ -45,6 +45,8 @@ class RemoteMessagingConfigProcessorTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: MockRemoteMessagePercentileStore(), @@ -85,6 +87,8 @@ class RemoteMessagingConfigProcessorTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: MockRemoteMessagePercentileStore(), diff --git a/Tests/RemoteMessagingTests/RemoteMessagingProcessingTests.swift b/Tests/RemoteMessagingTests/RemoteMessagingProcessingTests.swift index 17e1e13c8..107a201fa 100644 --- a/Tests/RemoteMessagingTests/RemoteMessagingProcessingTests.swift +++ b/Tests/RemoteMessagingTests/RemoteMessagingProcessingTests.swift @@ -81,6 +81,8 @@ class RemoteMessagingProcessingTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: MockRemoteMessagePercentileStore(), diff --git a/Tests/RemoteMessagingTests/RemoteMessagingStoreTests.swift b/Tests/RemoteMessagingTests/RemoteMessagingStoreTests.swift index 327d748dc..b355470d9 100644 --- a/Tests/RemoteMessagingTests/RemoteMessagingStoreTests.swift +++ b/Tests/RemoteMessagingTests/RemoteMessagingStoreTests.swift @@ -429,6 +429,8 @@ class RemoteMessagingStoreTests: XCTestCase { isPrivacyProSubscriptionActive: false, isPrivacyProSubscriptionExpiring: false, isPrivacyProSubscriptionExpired: false, + isDuckPlayerOnboarded: false, + isDuckPlayerEnabled: false, dismissedMessageIds: [] ), percentileStore: RemoteMessagingPercentileUserDefaultsStore(keyValueStore: self.defaults),