Skip to content

Commit e876960

Browse files
wip: fix holdout config tests
1 parent c868c29 commit e876960

File tree

3 files changed

+41
-21
lines changed

3 files changed

+41
-21
lines changed

Sources/Data Model/HoldoutConfig.swift

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//
2-
// Copyright 2022, Optimizely, Inc. and contributors
3-
//
4-
// Licensed under the Apache License, Version 2.0 (the "License");
2+
// Copyright 2022, Optimizely, Inc. and contributors
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
6-
// You may obtain a copy of the License at
7-
//
6+
// You may obtain a copy of the License at
7+
//
88
// http://www.apache.org/licenses/LICENSE-2.0
99
//
1010
// Unless required by applicable law or agreed to in writing, software
@@ -24,11 +24,12 @@ struct HoldoutConfig {
2424
}
2525
private(set) var holdoutIdMap: [String: Holdout] = [:]
2626
private(set) var global: [Holdout] = []
27-
private(set) var others: [Holdout] = []
2827
private(set) var includedHoldouts: [String: [Holdout]] = [:]
2928
private(set) var excludedHoldouts: [String: [Holdout]] = [:]
3029
private(set) var flagHoldoutsMap: [String: [Holdout]] = [:]
3130

31+
let logger = OPTLoggerFactory.getLogger()
32+
3233
init(allholdouts: [Holdout] = []) {
3334
self.allHoldouts = allholdouts
3435
updateHoldoutProperties()
@@ -42,15 +43,19 @@ struct HoldoutConfig {
4243
}()
4344
flagHoldoutsMap = [:]
4445
global = []
45-
others = []
46+
4647
includedHoldouts = [:]
4748
excludedHoldouts = [:]
4849

4950
for holdout in allHoldouts {
5051
switch (holdout.includedFlags.isEmpty, holdout.excludedFlags.isEmpty) {
5152
case (true, true):
5253
global.append(holdout)
53-
case (false, _):
54+
55+
case (false, false):
56+
logger.e(.holdoutToFlagMappingError)
57+
58+
case (false, true):
5459
holdout.includedFlags.forEach { flagId in
5560
if var existing = includedHoldouts[flagId] {
5661
existing.append(holdout)
@@ -59,8 +64,10 @@ struct HoldoutConfig {
5964
includedHoldouts[flagId] = [holdout]
6065
}
6166
}
62-
case (_, false):
63-
others.append(holdout)
67+
68+
case (true, false):
69+
global.append(holdout)
70+
6471
holdout.excludedFlags.forEach { flagId in
6572
if var existing = excludedHoldouts[flagId] {
6673
existing.append(holdout)
@@ -76,19 +83,29 @@ struct HoldoutConfig {
7683
mutating func getHoldoutForFlag(id: String) -> [Holdout] {
7784
guard !allHoldouts.isEmpty else { return [] }
7885

86+
// Check cache and return if persist holdouts
7987
if let holdouts = flagHoldoutsMap[id] {
8088
return holdouts
8189
}
8290

83-
if let included = includedHoldouts[id], !included.isEmpty {
84-
flagHoldoutsMap[id] = global + included
85-
} else {
86-
let excluded = excludedHoldouts[id] ?? []
87-
let filteredHoldouts = others.filter { holdout in
91+
var activeHoldouts: [Holdout] = []
92+
93+
let excluded = excludedHoldouts[id] ?? []
94+
95+
if !excluded.isEmpty {
96+
activeHoldouts = global.filter { holdout in
8897
return !excluded.contains(holdout)
8998
}
90-
flagHoldoutsMap[id] = global + filteredHoldouts
99+
} else {
100+
activeHoldouts = global
91101
}
102+
103+
let includedHoldouts = includedHoldouts[id] ?? []
104+
105+
activeHoldouts += includedHoldouts
106+
107+
flagHoldoutsMap[id] = activeHoldouts
108+
92109
return flagHoldoutsMap[id] ?? []
93110
}
94111

Sources/Utils/LogMessage.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ enum LogMessage {
6868
case failedToAssignValue
6969
case valueForKeyNotFound(_ key: String)
7070
case lowPeriodicDownloadInterval
71+
case holdoutToFlagMappingError
7172
}
7273

7374
extension LogMessage: CustomStringConvertible {
@@ -130,6 +131,7 @@ extension LogMessage: CustomStringConvertible {
130131
case .failedToAssignValue: message = "Value for path could not be assigned to provided type."
131132
case .valueForKeyNotFound(let key): message = "Value for JSON key (\(key)) not found."
132133
case .lowPeriodicDownloadInterval: message = "Polling intervals below 30 seconds are not recommended."
134+
case .holdoutToFlagMappingError: message = "A holdout cannot have include and exclude flags at the same time."
133135
}
134136

135137
return message

Tests/OptimizelyTests-DataModel/HoldoutConfigTests.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ class HoldoutConfigTests: XCTestCase {
3838
XCTAssertEqual(holdoutConfig.holdoutIdMap["3333"]?.excludedFlags, ["8888", "9999"])
3939

4040

41-
XCTAssertEqual(holdoutConfig.global, [holdout0])
42-
XCTAssertEqual(holdoutConfig.others, [holdout2])
41+
XCTAssertEqual(holdoutConfig.global, [holdout0, holdout2])
4342

4443
XCTAssertEqual(holdoutConfig.includedHoldouts["4444"], [holdout1])
4544
XCTAssertEqual(holdoutConfig.excludedHoldouts["8888"], [holdout2])
@@ -99,10 +98,12 @@ class HoldoutConfigTests: XCTestCase {
9998
var holdoutConfig = HoldoutConfig(allholdouts: allHoldouts)
10099

101100
// Should maintain order. Global first then lcoal
102-
XCTAssertEqual(holdoutConfig.getHoldoutForFlag(id: flag1), [holdout3, holdout4, holdout1])
101+
102+
XCTAssertEqual(holdoutConfig.getHoldoutForFlag(id: flag1), [holdout2, holdout3, holdout4, holdout1])
103103
XCTAssertEqual(holdoutConfig.getHoldoutForFlag(id: flag2), [holdout3, holdout4])
104-
XCTAssertEqual(holdoutConfig.getHoldoutForFlag(id: flag3), [holdout3, holdout4, holdout2])
105-
XCTAssertEqual(holdoutConfig.getHoldoutForFlag(id: flag4), [holdout3, holdout4, holdout2])
104+
105+
XCTAssertEqual(holdoutConfig.getHoldoutForFlag(id: flag3), [holdout2, holdout3, holdout4])
106+
XCTAssertEqual(holdoutConfig.getHoldoutForFlag(id: flag4), [holdout2, holdout3, holdout4])
106107

107108
}
108109

0 commit comments

Comments
 (0)