17
17
import XCTest
18
18
19
19
class HoldoutConfigTests : XCTestCase {
20
+ func testEmptyHoldouts_shouldHaveEmptyMaps( ) {
21
+ let config = HoldoutConfig ( allholdouts: [ ] )
22
+
23
+ XCTAssertTrue ( config. holdoutIdMap. isEmpty)
24
+ XCTAssertTrue ( config. global. isEmpty)
25
+ XCTAssertTrue ( config. includedHoldouts. isEmpty)
26
+ XCTAssertTrue ( config. excludedHoldouts. isEmpty)
27
+ }
20
28
21
29
func testHoldoutMap( ) {
22
30
let holdout0 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
23
31
let holdout1 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleDataWithIncludedFlags)
24
32
let holdout2 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleDataWithExcludedFlags)
25
33
26
34
let allHoldouts = [ holdout0, holdout1, holdout2]
27
-
28
-
29
35
let holdoutConfig = HoldoutConfig ( allholdouts: allHoldouts)
30
36
31
37
XCTAssertEqual ( holdoutConfig. holdoutIdMap [ " 11111 " ] ? . includedFlags, [ ] )
@@ -37,7 +43,6 @@ class HoldoutConfigTests: XCTestCase {
37
43
XCTAssertEqual ( holdoutConfig. holdoutIdMap [ " 3333 " ] ? . includedFlags, [ ] )
38
44
XCTAssertEqual ( holdoutConfig. holdoutIdMap [ " 3333 " ] ? . excludedFlags, [ " 8888 " , " 9999 " ] )
39
45
40
-
41
46
XCTAssertEqual ( holdoutConfig. global, [ holdout0, holdout2] )
42
47
43
48
XCTAssertEqual ( holdoutConfig. includedHoldouts [ " 4444 " ] , [ holdout1] )
@@ -48,16 +53,12 @@ class HoldoutConfigTests: XCTestCase {
48
53
func testGetHoldoutById( ) {
49
54
var holdout0 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
50
55
holdout0. id = " 00000 "
51
-
52
56
var holdout1 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleDataWithIncludedFlags)
53
57
holdout1. id = " 11111 "
54
-
55
58
var holdout2 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleDataWithExcludedFlags)
56
59
holdout2. id = " 22222 "
57
60
58
61
let allHoldouts = [ holdout0, holdout1, holdout2]
59
-
60
-
61
62
let holdoutConfig = HoldoutConfig ( allholdouts: allHoldouts)
62
63
63
64
XCTAssertEqual ( holdoutConfig. getHoldout ( id: " 00000 " ) , holdout0)
@@ -66,47 +67,118 @@ class HoldoutConfigTests: XCTestCase {
66
67
67
68
}
68
69
69
- func testGetHoldoutForFlag( ) {
70
+ func testHoldoutOrdering_globalThenIncluded( ) {
71
+ var global1 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
72
+ global1. id = " g1 "
73
+
74
+ var global2 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
75
+ global2. id = " g2 "
70
76
77
+ var included : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
78
+ included. id = " i1 "
79
+ included. includedFlags = [ " f " ]
80
+
81
+ var config = HoldoutConfig ( allholdouts: [ included, global1, global2] )
82
+
83
+ let result = config. getHoldoutForFlag ( id: " f " ) . map ( \. id)
84
+ XCTAssertEqual ( result, [ " g1 " , " g2 " , " i1 " ] )
85
+ }
86
+
87
+ func testHoldoutOrdering_with_Both_IncludedAndExcludedFlags( ) {
71
88
let flag1 = " 11111 "
72
89
let flag2 = " 22222 "
73
90
let flag3 = " 33333 "
74
91
let flag4 = " 44444 "
75
92
76
- var holdout1 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
77
- holdout1. id = " 11 "
78
- holdout1. includedFlags = [ flag1]
79
- holdout1. excludedFlags = [ ]
93
+ var inc : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
94
+ inc. id = " i1 "
95
+ inc. includedFlags = [ flag1]
80
96
81
- var holdout2 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
82
- holdout2. id = " 22 "
83
- holdout2. includedFlags = [ ]
84
- holdout2. excludedFlags = [ flag2]
97
+ var exc : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
98
+ exc. id = " e1 "
99
+ exc. excludedFlags = [ flag2]
85
100
86
- var holdout3 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
87
- holdout3 . id = " 33 "
88
- holdout3 . includedFlags = [ ]
89
- holdout3 . excludedFlags = [ ]
101
+ var gh1 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
102
+ gh1 . id = " gh1 "
103
+ gh1 . includedFlags = [ ]
104
+ gh1 . excludedFlags = [ ]
90
105
91
- var holdout4 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
92
- holdout4 . id = " 44 "
93
- holdout4 . includedFlags = [ ]
94
- holdout4 . excludedFlags = [ ]
106
+ var gh2 : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
107
+ gh2 . id = " gh2 "
108
+ gh2 . includedFlags = [ ]
109
+ gh2 . excludedFlags = [ ]
95
110
96
111
97
- let allHoldouts = [ holdout1 , holdout2 , holdout3 , holdout4 ]
112
+ let allHoldouts = [ inc , exc , gh1 , gh2 ]
98
113
var holdoutConfig = HoldoutConfig ( allholdouts: allHoldouts)
99
114
100
- // Should maintain order. Global first then lcoal
115
+ XCTAssertEqual ( holdoutConfig. getHoldoutForFlag ( id: flag1) , [ exc, gh1, gh2, inc] )
116
+ XCTAssertEqual ( holdoutConfig. getHoldoutForFlag ( id: flag2) , [ gh1, gh2] )
101
117
102
- XCTAssertEqual ( holdoutConfig. getHoldoutForFlag ( id: flag1 ) , [ holdout2 , holdout3 , holdout4 , holdout1 ] )
103
- XCTAssertEqual ( holdoutConfig. getHoldoutForFlag ( id: flag2 ) , [ holdout3 , holdout4 ] )
118
+ XCTAssertEqual ( holdoutConfig. getHoldoutForFlag ( id: flag3 ) , [ exc , gh1 , gh2 ] )
119
+ XCTAssertEqual ( holdoutConfig. getHoldoutForFlag ( id: flag4 ) , [ exc , gh1 , gh2 ] )
104
120
105
- XCTAssertEqual ( holdoutConfig. getHoldoutForFlag ( id: flag3) , [ holdout2, holdout3, holdout4] )
106
- XCTAssertEqual ( holdoutConfig. getHoldoutForFlag ( id: flag4) , [ holdout2, holdout3, holdout4] )
107
-
108
121
}
109
122
123
+ func testExcludedHoldout_shouldNotAppearInGlobalForFlag( ) {
124
+ var global : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
125
+ global. id = " global "
126
+
127
+ var excluded : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
128
+ excluded. id = " excluded "
129
+ excluded. excludedFlags = [ " f " ]
130
+
131
+ var config = HoldoutConfig ( allholdouts: [ global, excluded] )
132
+
133
+ let result = config. getHoldoutForFlag ( id: " f " ) . map ( \. id)
134
+ XCTAssertEqual ( result, [ " global " ] ) // excluded should not appear
135
+ }
110
136
137
+ func testGetHoldoutForFlag_shouldUseCacheOnSecondCall( ) {
138
+ var holdout : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
139
+ holdout. id = " 1 "
140
+ holdout. excludedFlags = [ " f1 " ]
141
+
142
+ var config = HoldoutConfig ( allholdouts: [ holdout] )
143
+
144
+ _ = config. getHoldoutForFlag ( id: " f1 " )
145
+ let writeCountAfterFirst = config. cacheWriteCount
146
+
147
+ _ = config. getHoldoutForFlag ( id: " f1 " )
148
+ let writeCountAfterSecond = config. cacheWriteCount
149
+
150
+ XCTAssertEqual ( writeCountAfterFirst, 1 )
151
+ XCTAssertEqual ( writeCountAfterSecond, 1 , " Second call should not increase cache write count " )
152
+ }
111
153
154
+ func testHoldoutWithBothIncludedAndExcludedFlags_shouldLogError( ) {
155
+ class ConfigMockLogger : OPTLogger {
156
+ static var logLevel : OptimizelyLogLevel = . info
157
+ var expectedLog : String = " "
158
+ var logFound = false
159
+
160
+ required init ( ) { }
161
+
162
+ func log( level: OptimizelyLogLevel , message: String ) {
163
+ if ( message == expectedLog) {
164
+ logFound = true
165
+ }
166
+ }
167
+ }
168
+
169
+ var holdout : Holdout = try ! OTUtils . model ( from: HoldoutTests . sampleData)
170
+ holdout. id = " invalid "
171
+ holdout. includedFlags = [ " f1 " ]
172
+ holdout. excludedFlags = [ " f2 " ]
173
+
174
+ let mockLogger = ConfigMockLogger ( )
175
+ mockLogger. expectedLog = LogMessage . holdoutToFlagMappingError. description
176
+
177
+ var config = HoldoutConfig ( allholdouts: [ ] )
178
+ config. logger = mockLogger
179
+
180
+ config. allHoldouts = [ holdout]
181
+
182
+ XCTAssertTrue ( mockLogger. logFound)
183
+ }
112
184
}
0 commit comments