Skip to content

Commit dcd7cd1

Browse files
committed
refactor: evaluation user defaults key management
Introduced EvaluationUserDefaultsKey enum to centralize user defaults keys and updated references throughout the codebase. Added UserDefaults.removeAllEvaluationData() helper for test cleanup. Updated tests and mocks to use new key management and helper method, improving maintainability and reducing duplication.
1 parent 6aecf11 commit dcd7cd1

11 files changed

+53
-46
lines changed

Bucketeer/Sources/Internal/Evaluation/EvaluationStorageImpl.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ final class EvaluationStorageImpl: EvaluationStorage {
4848
evaluationMemCacheDao.get(key: userId) ?? []
4949
}
5050

51+
/// Deletes all evaluations and inserts new evaluations in storage.
52+
/// - Note: Caller must ensure this is called from the SDK queue. Not thread-safe
5153
func deleteAllAndInsert(
5254
evaluationId: String,
5355
evaluations: [Evaluation],
@@ -63,6 +65,8 @@ final class EvaluationStorageImpl: EvaluationStorage {
6365
evaluationMemCacheDao.set(key: userId, value: evaluations)
6466
}
6567

68+
/// Updates evaluations in storage.
69+
/// - Note: Caller must ensure this is called from the SDK queue. Not thread-safe for concurrent writes.
6670
func update(
6771
evaluationId: String ,
6872
evaluations: [Evaluation],
Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import Foundation
22

33
class EvaluationUserDefaultDaoImpl: EvaluationUserDefaultsDao {
4-
private static let userEvaluationsIdKey = "bucketeer_user_evaluations_id"
5-
private static let featureTagKey = "bucketeer_feature_tag"
6-
private static let evaluatedAtKey = "bucketeer_evaluated_at"
7-
private static let userAttributesUpdatedKey = "bucketeer_user_attributes_updated"
4+
85
private let defs: Defaults
96

107
init(defaults: Defaults) {
@@ -13,34 +10,34 @@ class EvaluationUserDefaultDaoImpl: EvaluationUserDefaultsDao {
1310

1411
var userAttributesUpdated: Bool {
1512
get {
16-
return defs.bool(forKey: Self.userAttributesUpdatedKey)
13+
return defs.bool(forKey: EvaluationUserDefaultsKey.userAttributesUpdated.rawValue)
1714
}
1815
set {
19-
defs.set(newValue, forKey: Self.userAttributesUpdatedKey)
16+
defs.set(newValue, forKey: EvaluationUserDefaultsKey.userAttributesUpdated.rawValue)
2017
}
2118
}
2219
var currentEvaluationsId: String {
2320
get {
24-
return defs.string(forKey: Self.userEvaluationsIdKey) ?? ""
21+
return defs.string(forKey: EvaluationUserDefaultsKey.userEvaluationsId.rawValue) ?? ""
2522
}
2623
set {
27-
defs.set(newValue, forKey: Self.userEvaluationsIdKey)
24+
defs.set(newValue, forKey: EvaluationUserDefaultsKey.userEvaluationsId.rawValue)
2825
}
2926
}
3027
var featureTag: String {
3128
get {
32-
return defs.string(forKey: Self.featureTagKey) ?? ""
29+
return defs.string(forKey: EvaluationUserDefaultsKey.featureTag.rawValue) ?? ""
3330
}
3431
set {
35-
defs.set(newValue, forKey: Self.featureTagKey)
32+
defs.set(newValue, forKey: EvaluationUserDefaultsKey.featureTag.rawValue)
3633
}
3734
}
3835
var evaluatedAt: String {
3936
get {
40-
return defs.string(forKey: Self.evaluatedAtKey) ?? "0"
37+
return defs.string(forKey: EvaluationUserDefaultsKey.evaluatedAt.rawValue) ?? "0"
4138
}
4239
set {
43-
defs.set(newValue, forKey: Self.evaluatedAtKey)
40+
defs.set(newValue, forKey: EvaluationUserDefaultsKey.evaluatedAt.rawValue)
4441
}
4542
}
4643

@@ -59,12 +56,4 @@ class EvaluationUserDefaultDaoImpl: EvaluationUserDefaultsDao {
5956
func setUserAttributesUpdated(value: Bool) {
6057
userAttributesUpdated = value
6158
}
62-
63-
// Delete all related data for testing purposes
64-
func deleteAll() {
65-
defs.removeObject(forKey: Self.userEvaluationsIdKey)
66-
defs.removeObject(forKey: Self.featureTagKey)
67-
defs.removeObject(forKey: Self.evaluatedAtKey)
68-
defs.removeObject(forKey: Self.userAttributesUpdatedKey)
69-
}
7059
}

Bucketeer/Sources/Internal/Evaluation/EvaluationUserDefaultsDao.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,10 @@ protocol EvaluationUserDefaultsDao {
1111
func setEvaluatedAt(value: String)
1212
func setUserAttributesUpdated(value: Bool)
1313
}
14+
15+
enum EvaluationUserDefaultsKey: String {
16+
case userEvaluationsId = "bucketeer_user_evaluations_id"
17+
case featureTag = "bucketeer_feature_tag"
18+
case evaluatedAt = "bucketeer_evaluated_at"
19+
case userAttributesUpdated = "bucketeer_user_attributes_updated"
20+
}

BucketeerTests/E2E/E2EBKTClientForceUpdateTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ final class E2EBKTClientForceUpdateTests: XCTestCase {
99

1010
override func setUp() async throws {
1111
try await super.setUp()
12-
EvaluationUserDefaultDaoImpl(defaults: UserDefaults.standard).deleteAll()
12+
UserDefaults.removeAllEvaluationData()
1313
}
1414

1515
@MainActor
@@ -18,7 +18,7 @@ final class E2EBKTClientForceUpdateTests: XCTestCase {
1818

1919
try await BKTClient.shared.flush()
2020
try BKTClient.destroy()
21-
EvaluationUserDefaultDaoImpl(defaults: UserDefaults.standard).deleteAll()
21+
UserDefaults.removeAllEvaluationData()
2222
try FileManager.default.removeItem(at: .database)
2323
}
2424

BucketeerTests/E2E/E2EEvaluationTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ final class E2EEvaluationTests: XCTestCase {
1010
override func setUp() async throws {
1111
try await super.setUp()
1212

13-
EvaluationUserDefaultDaoImpl(defaults: UserDefaults.standard).deleteAll()
13+
UserDefaults.removeAllEvaluationData()
1414

1515
let config = try BKTConfig.e2e()
1616
let user = try BKTUser.Builder().with(id: USER_ID).build()
@@ -26,7 +26,7 @@ final class E2EEvaluationTests: XCTestCase {
2626

2727
try await BKTClient.shared.flush()
2828
try BKTClient.destroy()
29-
EvaluationUserDefaultDaoImpl(defaults: UserDefaults.standard).deleteAll()
29+
UserDefaults.removeAllEvaluationData()
3030
try FileManager.default.removeItem(at: .database)
3131
}
3232

BucketeerTests/E2E/E2EEventTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ final class E2EEventTests: XCTestCase {
99

1010
override func setUp() async throws {
1111
try await super.setUp()
12-
EvaluationUserDefaultDaoImpl(defaults: UserDefaults.standard).deleteAll()
12+
UserDefaults.removeAllEvaluationData()
1313

1414
let config = try BKTConfig.e2e()
1515
let user = try BKTUser.Builder().with(id: USER_ID).build()
@@ -24,7 +24,7 @@ final class E2EEventTests: XCTestCase {
2424

2525
try await BKTClient.shared.flush()
2626
try BKTClient.destroy()
27-
EvaluationUserDefaultDaoImpl(defaults: UserDefaults.standard).deleteAll()
27+
UserDefaults.removeAllEvaluationData()
2828
try FileManager.default.removeItem(at: .database)
2929
}
3030

BucketeerTests/E2E/E2EMetricsEventTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ final class E2EMetricsEventTests: XCTestCase {
1010
override func tearDown() async throws {
1111
try await super.tearDown()
1212
try BKTClient.destroy()
13-
EvaluationUserDefaultDaoImpl(defaults: UserDefaults.standard).deleteAll()
13+
UserDefaults.removeAllEvaluationData()
1414
try? FileManager.default.removeItem(at: .database)
1515
}
1616

BucketeerTests/E2E/E2ETestHelpers.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,13 @@ final class MockAsyncEventUpdateListener: EvaluationUpdateListener {
196196
mockContinuation?.resume(returning: true)
197197
}
198198
}
199+
200+
extension UserDefaults {
201+
static func removeAllEvaluationData() {
202+
let userDefs = UserDefaults.standard
203+
userDefs.removeObject(forKey: EvaluationUserDefaultsKey.userEvaluationsId.rawValue)
204+
userDefs.removeObject(forKey: EvaluationUserDefaultsKey.featureTag.rawValue)
205+
userDefs.removeObject(forKey: EvaluationUserDefaultsKey.evaluatedAt.rawValue)
206+
userDefs.removeObject(forKey: EvaluationUserDefaultsKey.userAttributesUpdated.rawValue)
207+
}
208+
}

BucketeerTests/EvaluationInteractorTests.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ final class EvaluationInteractorTests: XCTestCase {
8383
"currentEvaluationsId should be empty string"
8484
)
8585
XCTAssertEqual(
86-
storage.userAttributesUpdated,
86+
storage.userAttributesState.isUpdated,
8787
false,
8888
"userAttributesUpdated should be false"
8989
)
@@ -119,7 +119,7 @@ final class EvaluationInteractorTests: XCTestCase {
119119
"currentEvaluationsId should not be a empty string after fetch evaluation success"
120120
)
121121
XCTAssertEqual(
122-
storage.userAttributesUpdated,
122+
storage.userAttributesState.isUpdated,
123123
false,
124124
"userAttributesUpdated should be false"
125125
)
@@ -455,11 +455,10 @@ final class EvaluationInteractorTests: XCTestCase {
455455
storage.currentEvaluationsId = baseUserEvaluationsId
456456
storage.featureTag = config.featureTag
457457
storage.evaluatedAt = evaluationCreatedAt
458-
storage.userAttributesUpdated = false
459458
XCTAssertEqual(storage.currentEvaluationsId, baseUserEvaluationsId)
460459
XCTAssertEqual(storage.featureTag, config.featureTag)
461460
XCTAssertEqual(storage.evaluatedAt, evaluationCreatedAt)
462-
XCTAssertEqual(storage.userAttributesUpdated, false)
461+
XCTAssertEqual(storage.userAttributesState.isUpdated, false)
463462
let api = MockApiClient(
464463
getEvaluationsHandler: { user, userEvaluationsId, _, condition, completion in
465464
XCTAssertEqual(user, .mock1)
@@ -485,13 +484,13 @@ final class EvaluationInteractorTests: XCTestCase {
485484
XCTAssertEqual(storage.currentEvaluationsId, baseUserEvaluationsId)
486485
XCTAssertEqual(storage.featureTag, config.featureTag)
487486
XCTAssertEqual(storage.evaluatedAt, evaluationCreatedAt)
488-
XCTAssertEqual(storage.userAttributesUpdated, false)
487+
XCTAssertEqual(storage.userAttributesState.isUpdated, false)
489488

490489
interactor.setUserAttributesUpdated()
491490
XCTAssertEqual(storage.currentEvaluationsId, baseUserEvaluationsId)
492491
XCTAssertEqual(storage.featureTag, config.featureTag)
493492
XCTAssertEqual(storage.evaluatedAt, evaluationCreatedAt)
494-
XCTAssertEqual(storage.userAttributesUpdated, true)
493+
XCTAssertEqual(storage.userAttributesState.isUpdated, true)
495494

496495
interactor.fetch(user: .mock1) { result in
497496
switch result {
@@ -508,7 +507,7 @@ final class EvaluationInteractorTests: XCTestCase {
508507
XCTAssertEqual(storage.featureTag, config.featureTag)
509508
XCTAssertEqual(storage.evaluatedAt, UserEvaluations.mock1.createdAt)
510509
// because `userAttributesUpdated` == true before fetch new evaluations, now it should be `false`
511-
XCTAssertEqual(storage.userAttributesUpdated, false, "userAttributesUpdated should be `false`")
510+
XCTAssertEqual(storage.userAttributesState.isUpdated, false, "userAttributesUpdated should be `false`")
512511

513512
wait(for: [expectation], timeout: 1)
514513
}
@@ -605,7 +604,7 @@ final class EvaluationInteractorTests: XCTestCase {
605604
XCTAssertEqual(storage.featureTag, config.featureTag)
606605
XCTAssertEqual(storage.evaluatedAt, UserEvaluations.mock1ForceUpdate.createdAt)
607606
// because `userAttributesUpdated` == true before fetch new evaluations, now it should be `false`
608-
XCTAssertEqual(storage.userAttributesUpdated, false, "userAttributesUpdated should be `false`")
607+
XCTAssertEqual(storage.userAttributesState.isUpdated, false, "userAttributesUpdated should be `false`")
609608

610609
wait(for: [expectation], timeout: 0.1)
611610
}
@@ -676,7 +675,7 @@ final class EvaluationInteractorTests: XCTestCase {
676675
XCTAssertEqual(storage.featureTag, config.featureTag)
677676
XCTAssertEqual(storage.evaluatedAt, UserEvaluations.mock1UpsertAndArchivedFeature.createdAt)
678677
// because `userAttributesUpdated` == true before fetch new evaluations, now it should be `false`
679-
XCTAssertEqual(storage.userAttributesUpdated, false, "userAttributesUpdated should be `false`")
678+
XCTAssertEqual(storage.userAttributesState.isUpdated, false, "userAttributesUpdated should be `false`")
680679

681680
wait(for: [expectation], timeout: 0.1)
682681
}

BucketeerTests/EvaluationStorageTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ final class EvaluationStorageTests: XCTestCase {
227227
storage.setUserAttributesUpdated()
228228

229229
let userAttributesState = storage.userAttributesState
230-
let updatedVersion = userAttributesState.version
231230
storage.setFeatureTag(value: "featureTagForTest")
232231

233232
let result = try storage.update(

0 commit comments

Comments
 (0)