Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIR Database Migrations to Address Integrity Issues & Related Feature Flagger #2997

Merged
merged 17 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,34 @@

import Foundation

protocol DateRangeChecker {
func isWithinRange(date: Date) -> Bool
}

struct DefaultDateRangeChecker: DateRangeChecker {
THISISDINOSAUR marked this conversation as resolved.
Show resolved Hide resolved

func isWithinRange(date: Date) -> Bool {
let calendar = Calendar.current

var startDateComponents = DateComponents()
startDateComponents.year = 2024
startDateComponents.month = 7
startDateComponents.day = 25

var endDateComponents = DateComponents()
endDateComponents.year = 2024
endDateComponents.month = 8
endDateComponents.day = 2

guard let startDate = calendar.date(from: startDateComponents),
let endDate = calendar.date(from: endDateComponents) else {
return false
}

return (startDate...endDate).contains(date)
}
}

/// 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
Expand All @@ -30,16 +58,33 @@ final class DefaultDataBrokerProtectionMigrationsFeatureFlagger: DataBrokerProte
}

private var userDefaults: UserDefaults
private var dateRangeChecker: DateRangeChecker

init(userDefaults: UserDefaults = .dbp) {
init(userDefaults: UserDefaults = .dbp,
dateRangeChecker: DateRangeChecker = DefaultDateRangeChecker()) {
self.userDefaults = userDefaults
self.dateRangeChecker = dateRangeChecker
}

/// Checks if a user is part of the specified % feature rollout
/// - Parameter percent: Percentage
/// - Returns: True or false
func isUserIn(percent: Int) -> Bool {

/*
START
Note: The following is temporary code intended to enable the feature flag for all users
prior to public release. This is to enable internal testing.

Asana to Remove this code: https://app.asana.com/0/1206488453854252/1207876679488680/f
*/
if dateRangeChecker.isWithinRange(date: Date()) {
return true
}
/*
END
*/

guard let storedNumber = storedRandomNumber else {

let generatedNumber = Int.random(in: 1...100)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,45 @@
import XCTest
@testable import DataBrokerProtection

private final class MockDateRangeChecker: DateRangeChecker {

private let startDateComponents: DateComponents
private let endDateComponents: DateComponents

init(startDateComponents: DateComponents, endDateComponents: DateComponents) {
self.startDateComponents = startDateComponents
self.endDateComponents = endDateComponents
}

func isWithinRange(date: Date) -> Bool {
let calendar = Calendar.current

guard let startDate = calendar.date(from: startDateComponents),
let endDate = calendar.date(from: endDateComponents) else {
return false
}

return (startDate...endDate).contains(date)
}
}

extension MockDateRangeChecker {
static var inthePast: MockDateRangeChecker {

var startDateComponents = DateComponents()
startDateComponents.year = 2020
startDateComponents.month = 7
startDateComponents.day = 25

var endDateComponents = DateComponents()
endDateComponents.year = 2020
endDateComponents.month = 8
endDateComponents.day = 2

return MockDateRangeChecker(startDateComponents: startDateComponents, endDateComponents: endDateComponents)
}
}

final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {

private var userDefaults: UserDefaults!
Expand All @@ -38,7 +77,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {

func testRandomNumberGeneration() {
// Given
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)
XCTAssertNil(userDefaults.object(forKey: key))

// When
Expand All @@ -50,7 +90,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {

func testRandomNumberGenerationAndReuse() {
// Given
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)
XCTAssertNil(userDefaults.object(forKey: key))

// When
Expand All @@ -69,7 +110,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {
func testInPercentLogicForInputValue0AndPercent0() {
// Given
userDefaults.set(0, forKey: key)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)

// When
let result = sut.isUserIn(percent: 0)
Expand All @@ -82,7 +124,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {
func testInPercentLogicForInputValue0AndPercent1() {
// Given
userDefaults.set(0, forKey: key)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)

// When
let result = sut.isUserIn(percent: 1)
Expand All @@ -95,7 +138,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {
func testInPercentLogicForInputValue10AndPercent10() {
// Given
userDefaults.set(10, forKey: key)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)

// When
let result = sut.isUserIn(percent: 10)
Expand All @@ -108,7 +152,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {
func testInPercentLogicForInputValue15AndPercent10() {
// Given
userDefaults.set(15, forKey: key)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)

// When
let result = sut.isUserIn(percent: 10)
Expand All @@ -121,7 +166,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {
func testInPercentLogicForInputValue99AndPercent100() {
// Given
userDefaults.set(99, forKey: key)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)

// When
let result = sut.isUserIn(percent: 100)
Expand All @@ -134,7 +180,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {
func testInPercentLogicForInputValue100AndPercent99() {
// Given
userDefaults.set(100, forKey: key)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)

// When
let result = sut.isUserIn(percent: 99)
Expand All @@ -147,7 +194,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {
func testInPercentLogicForInputValue100AndPercent100() {
// Given
userDefaults.set(100, forKey: key)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)

// When
let result = sut.isUserIn(percent: 100)
Expand All @@ -167,7 +215,8 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {

repeat {
userDefaults.set(nil, forKey: key)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)
let result = sut.isUserIn(percent: 10)
results.append(result)
} while results.count < 100
Expand All @@ -186,4 +235,31 @@ final class DataBrokerProtectionMigrationsFeatureFlaggerTests: XCTestCase {
let average = sum / Double(percentages.count)
XCTAssert(average > 9.0 && average < 11.0)
aataraxiaa marked this conversation as resolved.
Show resolved Hide resolved
}

func testDateWithinDefaultTemporaryWindowReturnsTrue() {
// 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)
XCTAssertTrue(result)
}

func testDateWithinPastWindowReturnsFalse() {
// Given
userDefaults.set(100, forKey: key)
let sut = DefaultDataBrokerProtectionMigrationsFeatureFlagger(userDefaults: userDefaults,
dateRangeChecker: MockDateRangeChecker.inthePast)

// When
let result = sut.isUserIn(percent: 99)

// Then
XCTAssertEqual(userDefaults.object(forKey: key) as? Int, 100)
XCTAssertFalse(result)
}
}
Loading