From 40bf3cdc430f0bc24757bafe62fb2fa27f609e72 Mon Sep 17 00:00:00 2001 From: Pete Smith Date: Thu, 15 Aug 2024 15:22:27 +0200 Subject: [PATCH] PIR: Bump v3 Database Migration to 100% (#3102) Task/Issue URL: https://app.asana.com/0/1206488453854252/1207806240565841/f **Description**: Bumps v3 migration rollout by completely removing `DataBrokerProtectionMigrationsFeatureFlagger` and related tests. --- ...DataBrokerProtectionDatabaseProvider.swift | 9 +- ...erProtectionMigrationsFeatureFlagger.swift | 76 ------- ...rokerProtectionDatabaseProviderTests.swift | 24 --- ...tectionMigrationsFeatureFlaggerTests.swift | 189 ------------------ .../DataBrokerProtectionTests/Mocks.swift | 8 - 5 files changed, 1 insertion(+), 305 deletions(-) delete mode 100644 LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionMigrationsFeatureFlagger.swift delete mode 100644 LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerProtectionMigrationsFeatureFlaggerTests.swift diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionDatabaseProvider.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionDatabaseProvider.swift index 25eb07f181..039b97b692 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionDatabaseProvider.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionDatabaseProvider.swift @@ -78,7 +78,6 @@ protocol DataBrokerProtectionDatabaseProvider: SecureStorageDatabaseProvider { final class DefaultDataBrokerProtectionDatabaseProvider: GRDBSecureStorageDatabaseProvider, DataBrokerProtectionDatabaseProvider { - typealias FeatureFlagger = DataBrokerProtectionMigrationsFeatureFlagger typealias MigrationsProvider = DataBrokerProtectionDatabaseMigrationsProvider public static func defaultDatabaseURL() -> URL { @@ -94,14 +93,8 @@ final class DefaultDataBrokerProtectionDatabaseProvider: GRDBSecureStorageDataba /// - Returns: DefaultDataBrokerProtectionDatabaseProvider instance public static func create(file: URL = DefaultDataBrokerProtectionDatabaseProvider.defaultDatabaseURL(), key: Data, - featureFlagger: FeatureFlagger = DefaultDataBrokerProtectionMigrationsFeatureFlagger(), migrationProvider: T.Type = DefaultDataBrokerProtectionDatabaseMigrationsProvider.self) throws -> DefaultDataBrokerProtectionDatabaseProvider { - - if featureFlagger.isUserIn(percent: 10) { - return try DefaultDataBrokerProtectionDatabaseProvider(file: file, key: key, registerMigrationsHandler: migrationProvider.v3Migrations) - } else { - return try DefaultDataBrokerProtectionDatabaseProvider(file: file, key: key, registerMigrationsHandler: migrationProvider.v2Migrations) - } + try DefaultDataBrokerProtectionDatabaseProvider(file: file, key: key, registerMigrationsHandler: migrationProvider.v3Migrations) } public init(file: URL = DefaultDataBrokerProtectionDatabaseProvider.defaultDatabaseURL(), diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionMigrationsFeatureFlagger.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionMigrationsFeatureFlagger.swift deleted file mode 100644 index e95b007297..0000000000 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Storage/DataBrokerProtectionMigrationsFeatureFlagger.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// DataBrokerProtectionMigrationsFeatureFlagger.swift -// -// Copyright © 2024 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -/// Conforming types provide a `isUserIn` method to check if a user is part of the specified % feature rollout -protocol DataBrokerProtectionMigrationsFeatureFlagger { - func isUserIn(percent: Int) -> Bool -} - -final class DefaultDataBrokerProtectionMigrationsFeatureFlagger: DataBrokerProtectionMigrationsFeatureFlagger { - - enum Constants { - static let v3MigrationFeatureFlagValue = "macos.browser.data-broker-protection.v3MigrationFeatureFlagValue" - } - - private var userDefaults: UserDefaults - - init(userDefaults: UserDefaults = .dbp) { - self.userDefaults = userDefaults - } - - /// Checks if a user is part of the specified % feature rollout - /// - Parameter percent: Percentage - /// - Returns: True or false - func isUserIn(percent: Int) -> Bool { - - guard let storedNumber = storedRandomNumber else { - - let generatedNumber = Int.random(in: 1...100) - storedRandomNumber = generatedNumber - - return generatedNumber.isIn(percent: percent) - } - - return storedNumber.isIn(percent: percent) - } -} - -private extension DefaultDataBrokerProtectionMigrationsFeatureFlagger { - - /// Retrieves its value from, and stores it to, `UserDefaults` - var storedRandomNumber: Int? { - get { - userDefaults.object(forKey: Constants.v3MigrationFeatureFlagValue) as? Int - } - set { - userDefaults.set(newValue, forKey: Constants.v3MigrationFeatureFlagValue) - } - } -} - -private extension Int { - - /// Checks if a number is less than or equal to a % value - /// - Parameter percent: Percentage - /// - Returns: True or false - func isIn(percent: Int) -> Bool { - self <= percent - } -} diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerProtectionDatabaseProviderTests.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerProtectionDatabaseProviderTests.swift index 0545a9c8df..bbfe9f8de4 100644 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerProtectionDatabaseProviderTests.swift +++ b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerProtectionDatabaseProviderTests.swift @@ -216,30 +216,6 @@ final class DataBrokerProtectionDatabaseProviderTests: XCTestCase { XCTAssertNoThrow(try sut.deleteProfileData()) XCTAssertTrue(try sut.db.allTablesAreEmpty()) } - - func testCreationWithUserNotIn10PercentUsesV2Migrations() throws { - // Given - let mockFeatureFlagger = MockFeatureFlagger(isUserIn: false) - - // When - _ = try DefaultDataBrokerProtectionDatabaseProvider.create(file: vaultURL, key: key, featureFlagger: mockFeatureFlagger, migrationProvider: MockMigrationsProvider.self) - - // Then - XCTAssertTrue(MockMigrationsProvider.didCallV2Migrations) - XCTAssertFalse(MockMigrationsProvider.didCallV3Migrations) - } - - func testCreationWithUserIn10PercentUsesV3Migrations() throws { - // Given - let mockFeatureFlagger = MockFeatureFlagger(isUserIn: true) - - // When - _ = try DefaultDataBrokerProtectionDatabaseProvider.create(file: vaultURL, key: key, featureFlagger: mockFeatureFlagger, migrationProvider: MockMigrationsProvider.self) - - // Then - XCTAssertFalse(MockMigrationsProvider.didCallV2Migrations) - XCTAssertTrue(MockMigrationsProvider.didCallV3Migrations) - } } private extension DatabaseWriter { diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerProtectionMigrationsFeatureFlaggerTests.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerProtectionMigrationsFeatureFlaggerTests.swift deleted file mode 100644 index 4086947c56..0000000000 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/DataBrokerProtectionMigrationsFeatureFlaggerTests.swift +++ /dev/null @@ -1,189 +0,0 @@ -// -// DataBrokerProtectionMigrationsFeatureFlaggerTests.swift -// -// Copyright © 2024 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import XCTest -@testable import DataBrokerProtection - -final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase { - - private var userDefaults: UserDefaults! - private let key = DefaultDataBrokerProtectionMigrationsFeatureFlagger.Constants.v3MigrationFeatureFlagValue - - override func setUp() { - super.setUp() - userDefaults = UserDefaults(suiteName: "mockDefaults") - userDefaults.removePersistentDomain(forName: "mockDefaults") - } - - override func tearDown() { - userDefaults.removePersistentDomain(forName: "mockDefaults") - userDefaults = nil - super.tearDown() - } - - func testRandomNumberGeneration() { - // Given - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - XCTAssertNil(userDefaults.object(forKey: key)) - - // When - _ = sut.isUserIn(percent: 10) - - // Then - XCTAssertNotNil(userDefaults.object(forKey: key)) - } - - func testRandomNumberGenerationAndReuse() { - // Given - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - XCTAssertNil(userDefaults.object(forKey: key)) - - // When - let resultOne = sut.isUserIn(percent: 10) - - // Then - XCTAssertNotNil(userDefaults.object(forKey: key)) - - // When - let resultTwo = sut.isUserIn(percent: 10) - - // Then - XCTAssertEqual(resultOne, resultTwo) - } - - func testInPercentLogicForInputValue0AndPercent0() { - // Given - userDefaults.set(0, forKey: key) - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - - // When - let result = sut.isUserIn(percent: 0) - - // Then - XCTAssertEqual(userDefaults.object(forKey: key) as? Int, 0) - XCTAssertTrue(result) - } - - func testInPercentLogicForInputValue0AndPercent1() { - // Given - userDefaults.set(0, forKey: key) - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - - // When - let result = sut.isUserIn(percent: 1) - - // Then - XCTAssertEqual(userDefaults.object(forKey: key) as? Int, 0) - XCTAssertTrue(result) - } - - func testInPercentLogicForInputValue10AndPercent10() { - // Given - userDefaults.set(10, forKey: key) - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - - // When - let result = sut.isUserIn(percent: 10) - - // Then - XCTAssertEqual(userDefaults.object(forKey: key) as? Int, 10) - XCTAssertTrue(result) - } - - func testInPercentLogicForInputValue15AndPercent10() { - // Given - userDefaults.set(15, forKey: key) - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - - // When - let result = sut.isUserIn(percent: 10) - - // Then - XCTAssertEqual(userDefaults.object(forKey: key) as? Int, 15) - XCTAssertFalse(result) - } - - func testInPercentLogicForInputValue99AndPercent100() { - // Given - userDefaults.set(99, forKey: key) - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - - // When - let result = sut.isUserIn(percent: 100) - - // Then - XCTAssertEqual(userDefaults.object(forKey: key) as? Int, 99) - XCTAssertTrue(result) - } - - func testInPercentLogicForInputValue100AndPercent99() { - // Given - userDefaults.set(100, forKey: key) - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - - // When - let result = sut.isUserIn(percent: 99) - - // Then - XCTAssertEqual(userDefaults.object(forKey: key) as? Int, 100) - XCTAssertFalse(result) - } - - func testInPercentLogicForInputValue100AndPercent100() { - // Given - userDefaults.set(100, forKey: key) - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - - // When - let result = sut.isUserIn(percent: 100) - - // Then - XCTAssertEqual(userDefaults.object(forKey: key) as? Int, 100) - XCTAssertTrue(result) - } - - func testAverageCalculatedRandomNumberAssignmentIsBetween9And11Percent() { - // Given - var percentages: [Double] = [] - - // When - repeat { - var results: [Bool] = [] - - repeat { - userDefaults.set(nil, forKey: key) - let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults) - let result = sut.isUserIn(percent: 10) - results.append(result) - } while results.count < 100 - - let totalCount = Double(results.count) - let trueValueCount = Double(results.filter { $0 == true }.count) - - let percentage = trueValueCount/totalCount * 100 - - percentages.append(percentage) - - } while percentages.count < 100 - - // Then - let sum = percentages.reduce(0, +) - let average = sum / Double(percentages.count) - XCTAssert(average > 8.0 && average < 12.0) - } -} diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift index 8ba9b23818..803ea0cc87 100644 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift +++ b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift @@ -1744,11 +1744,3 @@ struct MockMigrationsProvider: DataBrokerProtectionDatabaseMigrationsProvider { return { _ in } } } - -struct MockFeatureFlagger: DataBrokerProtectionMigrationsFeatureFlagger { - var isUserIn = false - - func isUserIn(percent: Int) -> Bool { - isUserIn - } -}