Skip to content

Commit 44326f9

Browse files
yasirfolio3jaeopt
authored andcommitted
Additional tests added for multi rollout. (#326)
1 parent d9e14b1 commit 44326f9

File tree

3 files changed

+214
-18
lines changed

3 files changed

+214
-18
lines changed

Sources/Implementation/DefaultDecisionService.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ class DefaultDecisionService: OPTDecisionService {
188188
let rolloutRules = rollout.experiments
189189
if rolloutRules.isEmpty {
190190
logger.e(.rolloutHasNoExperiments(rolloutId))
191+
return nil
191192
}
192193

193194
// Evaluate all rollout rules except for last one

Tests/OptimizelyTests-APIs/OptimizelyClientTests_Variables.swift

Lines changed: 185 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
/****************************************************************************
2-
* Copyright 2019, Optimizely, Inc. and contributors *
3-
* *
4-
* Licensed under the Apache License, Version 2.0 (the "License"); *
5-
* you may not use this file except in compliance with the License. *
6-
* You may obtain a copy of the License at *
7-
* *
8-
* http://www.apache.org/licenses/LICENSE-2.0 *
9-
* *
10-
* Unless required by applicable law or agreed to in writing, software *
11-
* distributed under the License is distributed on an "AS IS" BASIS, *
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13-
* See the License for the specific language governing permissions and *
14-
* limitations under the License. *
15-
***************************************************************************/
2+
* Copyright 2019-2020, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
1616

1717
import XCTest
1818

@@ -24,6 +24,24 @@ class OptimizelyClientTests_Variables: XCTestCase {
2424

2525
let kUserId = "12345"
2626
let kExperimentId = "11111"
27+
var kRolloutId = "rollout11"
28+
var kRolloutExperimentId = "rolloutExp11"
29+
var kRolloutExperimentId2 = "rolloutExp12"
30+
var kRolloutExperimentId3 = "rolloutExp13"
31+
32+
let kRolloutVariableValueA = 40
33+
let kRolloutVariableValueB = 50
34+
let kRolloutVariableValueC = 60
35+
36+
var kRolloutAudienceIdAge1 = "30"
37+
var kRolloutAudienceIdAge2 = "40"
38+
var kAttributesRolloutAge1Match: [String: Any] = ["age": 20]
39+
var kAttributesRolloutAge2Match: [String: Any] = ["age": 30]
40+
var kAttributesRolloutNotMatch: [String: Any] = ["age": 40]
41+
42+
var kRolloutVariationKeyA = "rolloutA"
43+
var kRolloutVariationKeyB = "rolloutB"
44+
var kRolloutVariationKeyC = "rolloutC"
2745

2846
var sampleExperimentData: [String: Any] { return
2947
[
@@ -67,8 +85,100 @@ class OptimizelyClientTests_Variables: XCTestCase {
6785
]
6886
}
6987

88+
var sampleRolloutData: [String: Any] { return
89+
[
90+
"id": kRolloutId,
91+
"experiments": sampleRolloutExperimentData
92+
]
93+
}
94+
95+
var sampleRolloutExperimentData: [[String: Any]] { return
96+
[
97+
[
98+
"status": "Running",
99+
"id": kRolloutExperimentId,
100+
"key": "rolloutExp",
101+
"layerId": "10420273888",
102+
"trafficAllocation": [
103+
[
104+
"entityId": "10389700000",
105+
"endOfRange": 10000
106+
]
107+
],
108+
"audienceIds": [kRolloutAudienceIdAge1],
109+
"variations": [
110+
[
111+
"variables": [["id": kVariableId, "value": String(kRolloutVariableValueA)]],
112+
"id": "10389700000",
113+
"key": kRolloutVariationKeyA,
114+
"featureEnabled": true
115+
]
116+
],
117+
"forcedVariations": [:]
118+
],
119+
[
120+
"status": "Running",
121+
"id": kRolloutExperimentId2,
122+
"key": "rolloutExp1",
123+
"layerId": "10420273889",
124+
"trafficAllocation": [
125+
[
126+
"entityId": "10389700000",
127+
"endOfRange": 10000
128+
]
129+
],
130+
"audienceIds": [kRolloutAudienceIdAge2],
131+
"variations": [
132+
[
133+
"variables": [["id": kVariableId, "value": String(kRolloutVariableValueB)]],
134+
"id": "10389700000",
135+
"key": kRolloutVariationKeyB,
136+
"featureEnabled": true
137+
]
138+
],
139+
"forcedVariations": [:]
140+
],
141+
[
142+
"status": "Running",
143+
"id": kRolloutExperimentId3,
144+
"key": "rolloutExp2",
145+
"layerId": "10420273890",
146+
"trafficAllocation": [
147+
[
148+
"entityId": "10389700000",
149+
"endOfRange": 10000
150+
]
151+
],
152+
"audienceIds": [],
153+
"variations": [
154+
[
155+
"variables": [["id": kVariableId, "value": String(kRolloutVariableValueC)]],
156+
"id": "10389700000",
157+
"key": kRolloutVariationKeyC,
158+
"featureEnabled": true
159+
]
160+
],
161+
"forcedVariations": [:]
162+
]
163+
]
164+
}
165+
166+
var sampleRolloutTypedAudiencesData: [[String: Any]] { return
167+
[
168+
[
169+
"id": kRolloutAudienceIdAge1,
170+
"conditions": [ "type": "custom_attribute", "name": "age", "match": "lt", "value": 30 ],
171+
"name": "age"
172+
],
173+
[
174+
"id": kRolloutAudienceIdAge2,
175+
"conditions": [ "type": "custom_attribute", "name": "age", "match": "lt", "value": 40 ],
176+
"name": "age"
177+
]
178+
]
179+
}
180+
70181
var optimizely: OptimizelyClient!
71-
var experiment: Experiment!
72182
var featureFlag: FeatureFlag!
73183

74184
override func setUp() {
@@ -77,10 +187,10 @@ class OptimizelyClientTests_Variables: XCTestCase {
77187
optimizely = OTUtils.createOptimizely(datafileName: "empty_datafile",
78188
clearUserProfileService: true)!
79189

80-
let featureFlag: FeatureFlag = try! OTUtils.model(from: sampleFeatureFlagData)
190+
featureFlag = try! OTUtils.model(from: sampleFeatureFlagData)
81191
optimizely.config!.project.featureFlags = [featureFlag]
82192
}
83-
193+
84194
func testFeatureVariableWhenFeatureEnabled() {
85195
var experiment: Experiment = try! OTUtils.model(from: sampleExperimentData)
86196
experiment.variations[0].featureEnabled = true
@@ -100,7 +210,7 @@ class OptimizelyClientTests_Variables: XCTestCase {
100210

101211
XCTAssertEqual(value, kVariableDefaultValue)
102212
}
103-
213+
104214
func testFeatureVariableWhenFeatureEnabledNil() {
105215
var experiment: Experiment = try! OTUtils.model(from: sampleExperimentData)
106216
experiment.variations[0].featureEnabled = nil
@@ -110,5 +220,62 @@ class OptimizelyClientTests_Variables: XCTestCase {
110220

111221
XCTAssertEqual(value, kVariableDefaultValue)
112222
}
223+
}
224+
225+
// MARK: - Test getFeatureVariableForFeatureRollout()
113226

227+
extension OptimizelyClientTests_Variables {
228+
229+
func testFeatureVariableWhenBucketedToRollout() {
230+
optimizely.config!.project.rollouts = [try! OTUtils.model(from: sampleRolloutData)]
231+
optimizely.config!.project.typedAudiences = try! OTUtils.model(from: sampleRolloutTypedAudiencesData)
232+
featureFlag.rolloutId = kRolloutId
233+
optimizely.config!.project.featureFlags = [featureFlag]
234+
235+
let value = try! optimizely.getFeatureVariableInteger(featureKey: "house", variableKey: "window", userId: kUserId, attributes: kAttributesRolloutAge1Match)
236+
XCTAssert(value == kRolloutVariableValueA)
237+
}
238+
239+
func testFeatureVariableWhenBucketedToRolloutUsingSecondRule() {
240+
optimizely.config!.project.rollouts = [try! OTUtils.model(from: sampleRolloutData)]
241+
optimizely.config!.project.typedAudiences = try! OTUtils.model(from: sampleRolloutTypedAudiencesData)
242+
featureFlag.rolloutId = kRolloutId
243+
optimizely.config!.project.featureFlags = [featureFlag]
244+
245+
let value = try! optimizely.getFeatureVariableInteger(featureKey: "house", variableKey: "window", userId: kUserId, attributes: kAttributesRolloutAge2Match)
246+
XCTAssert(value == kRolloutVariableValueB)
247+
}
248+
249+
func testFeatureVariableWhenBucketedToRolloutUsingFallbackRule() {
250+
optimizely.config!.project.rollouts = [try! OTUtils.model(from: sampleRolloutData)]
251+
optimizely.config!.project.typedAudiences = try! OTUtils.model(from: sampleRolloutTypedAudiencesData)
252+
featureFlag.rolloutId = kRolloutId
253+
optimizely.config!.project.featureFlags = [featureFlag]
254+
optimizely.config!.project.rollouts[0].experiments[0].trafficAllocation[0].endOfRange = 0
255+
256+
let value = try! optimizely.getFeatureVariableInteger(featureKey: "house", variableKey: "window", userId: kUserId, attributes: kAttributesRolloutAge1Match)
257+
XCTAssert(value == kRolloutVariableValueC)
258+
}
259+
260+
func testFeatureVariableReturnsDefaultValueWhenFeatureDisabled() {
261+
optimizely.config!.project.rollouts = [try! OTUtils.model(from: sampleRolloutData)]
262+
optimizely.config!.project.typedAudiences = try! OTUtils.model(from: sampleRolloutTypedAudiencesData)
263+
featureFlag.rolloutId = kRolloutId
264+
optimizely.config!.project.featureFlags = [featureFlag]
265+
optimizely.config!.project.rollouts[0].experiments[0].variations[0].featureEnabled = false
266+
267+
let value = try! optimizely.getFeatureVariableInteger(featureKey: "house", variableKey: "window", userId: kUserId, attributes: kAttributesRolloutAge1Match)
268+
XCTAssert(value == kVariableDefaultValue)
269+
}
270+
271+
func testFeatureVariableReturnsDefaultValueWhenRolloutBucketingReturnsNil() {
272+
optimizely.config!.project.rollouts = [try! OTUtils.model(from: sampleRolloutData)]
273+
optimizely.config!.project.typedAudiences = try! OTUtils.model(from: sampleRolloutTypedAudiencesData)
274+
featureFlag.rolloutId = kRolloutId
275+
optimizely.config!.project.featureFlags = [featureFlag]
276+
optimizely.config!.project.rollouts[0].experiments = []
277+
278+
let value = try! optimizely.getFeatureVariableInteger(featureKey: "house", variableKey: "window", userId: kUserId, attributes: kAttributesRolloutAge1Match)
279+
XCTAssert(value == kVariableDefaultValue)
280+
}
114281
}

Tests/OptimizelyTests-Common/DecisionServiceTests_Features.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,20 @@ extension DecisionServiceTests_Features {
327327
XCTAssertNil(variation)
328328
}
329329

330+
func testGetVariationForFeatureRolloutEmptyRules() {
331+
self.config.project.rollouts = [try! OTUtils.model(from: sampleRolloutData)]
332+
self.config.project.rollouts[0].experiments = []
333+
self.config.project.typedAudiences = try! OTUtils.model(from: sampleRolloutTypedAudiencesData)
334+
featureFlag.rolloutId = kRolloutId
335+
self.config.project.featureFlags = [featureFlag]
336+
337+
let variation = self.decisionService.getVariationForFeatureRollout(config: config,
338+
featureFlag: featureFlag,
339+
userId: kUserId,
340+
attributes: kAttributesRolloutAge1Match)
341+
XCTAssertNil(variation)
342+
}
343+
330344
func testGetVariationForFeatureRolloutFallbackRule() {
331345
self.config.project.rollouts = [try! OTUtils.model(from: sampleRolloutData)]
332346
self.config.project.typedAudiences = try! OTUtils.model(from: sampleRolloutTypedAudiencesData)
@@ -354,6 +368,20 @@ extension DecisionServiceTests_Features {
354368
XCTAssert(variation!.key == kRolloutVariationKeyB)
355369
}
356370

371+
func testGetVariationForFeatureRolloutWithSameAudiencesReturnsFirstVariation() {
372+
self.config.project.rollouts = [try! OTUtils.model(from: sampleRolloutData)]
373+
self.config.project.rollouts[0].experiments[1].audienceIds = [kRolloutAudienceIdAge1]
374+
self.config.project.typedAudiences = try! OTUtils.model(from: sampleRolloutTypedAudiencesData)
375+
featureFlag.rolloutId = kRolloutId
376+
self.config.project.featureFlags = [featureFlag]
377+
378+
let variation = self.decisionService.getVariationForFeatureRollout(config: config,
379+
featureFlag: featureFlag,
380+
userId: kUserId,
381+
attributes: kAttributesRolloutAge1Match)
382+
XCTAssert(variation!.key == kRolloutVariationKeyA)
383+
}
384+
357385
func testGetVariationForFeatureRolloutReturnsNilIfAudienceEvaluationFailsForFallback() {
358386
self.config.project.rollouts = [try! OTUtils.model(from: sampleRolloutData)]
359387
self.config.project.typedAudiences = try! OTUtils.model(from: sampleRolloutTypedAudiencesData)

0 commit comments

Comments
 (0)