Skip to content

Commit fab0386

Browse files
Revert "(chore): cleanup" (#177)
* Revert "(chore): cleanup (#173)" This reverts commit 3a5a2e3. * just some cleanup from that we do want included * add better way of testing
1 parent b7a95a5 commit fab0386

File tree

11 files changed

+77
-95
lines changed

11 files changed

+77
-95
lines changed

DemoSwiftApp/AppDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
5151
// - initialize immediately with the given JSON datafile or its cached copy
5252
// - no network delay, but the local copy is not guaranteed to be in sync with the server experiment settings
5353

54-
initializeOptimizelySDKWithCustomization()
54+
initializeOptimizelySDKAsynchronous()
5555
}
5656

5757
// MARK: - Initialization Examples

OptimizelySDK/Data Model/Audience/Audience.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ struct Audience: Codable, Equatable {
6363
try container.encode(conditions, forKey: .conditions)
6464
}
6565

66-
func evaluate(project: Project?, attributes: OptimizelyAttributes?) throws -> Bool {
66+
func evaluate(project: ProjectProtocol?, attributes: OptimizelyAttributes?) throws -> Bool {
6767
return try conditions.evaluate(project: project, attributes: attributes)
6868
}
6969
}

OptimizelySDK/Data Model/Audience/ConditionHolder.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ enum ConditionHolder: Codable, Equatable {
6161
}
6262
}
6363

64-
func evaluate(project: Project?, attributes: OptimizelyAttributes?) throws -> Bool {
64+
func evaluate(project: ProjectProtocol?, attributes: OptimizelyAttributes?) throws -> Bool {
6565
switch self {
6666
case .logicalOp:
6767
throw OptimizelyError.conditionInvalidFormat("Logical operation not evaluated")
@@ -77,7 +77,7 @@ enum ConditionHolder: Codable, Equatable {
7777

7878
extension Array where Element == ConditionHolder {
7979

80-
func evaluate(project: Project?, attributes: OptimizelyAttributes?) throws -> Bool {
80+
func evaluate(project: ProjectProtocol?, attributes: OptimizelyAttributes?) throws -> Bool {
8181
guard let firstItem = self.first else {
8282
throw OptimizelyError.conditionInvalidFormat("Empty condition array")
8383
}
@@ -94,7 +94,7 @@ extension Array where Element == ConditionHolder {
9494
}
9595
}
9696

97-
func evaluate(op: LogicalOp, project: Project?, attributes: OptimizelyAttributes?) throws -> Bool {
97+
func evaluate(op: LogicalOp, project: ProjectProtocol?, attributes: OptimizelyAttributes?) throws -> Bool {
9898
guard self.count > 0 else {
9999
throw OptimizelyError.conditionInvalidFormat("Empty condition array")
100100
}

OptimizelySDK/Data Model/Audience/ConditionLeaf.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ enum ConditionLeaf: Codable, Equatable {
5050
}
5151
}
5252

53-
func evaluate(project: Project?, attributes: OptimizelyAttributes?) throws -> Bool {
53+
func evaluate(project: ProjectProtocol?, attributes: OptimizelyAttributes?) throws -> Bool {
5454
switch self {
5555
case .audienceId(let id):
56-
guard var project = project else {
56+
guard let project = project else {
5757
throw OptimizelyError.conditionCannotBeEvaluated("audienceId: \(id)")
5858
}
5959

60-
return try project.getAudience(id: id)?.evaluate(project: project, attributes: attributes) ?? false
60+
return try project.evaluateAudience(audienceId: id, attributes: attributes)
6161
case .attribute(let userAttribute):
6262
return try userAttribute.evaluate(attributes: attributes)
6363
}

OptimizelySDK/Data Model/Group.swift

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,14 @@ struct Group: Codable, Equatable {
2626
var policy: Policy
2727
var trafficAllocation: [TrafficAllocation]
2828
var experiments: [Experiment]
29-
30-
private enum CodingKeys: String, CodingKey {
31-
case id
32-
case policy
33-
case trafficAllocation
34-
case experiments
35-
}
36-
37-
lazy var experimentMap:[String:Experiment] = {
38-
var map:[String:Experiment] = [:]
39-
experiments.forEach({map[$0.id] = $0 })
40-
return map
41-
}()
4229
}
4330

4431
// MARK: - Utils
4532

4633
extension Group {
4734

48-
mutating func getExperiment(id: String) -> Experiment? {
49-
return self.experimentMap[id]
35+
func getExperiemnt(id: String) -> Experiment? {
36+
return experiments.filter { $0.id == id }.first
5037
}
5138

5239
}

OptimizelySDK/Data Model/Project.swift

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
import Foundation
1818

19+
protocol ProjectProtocol {
20+
func evaluateAudience(audienceId: String, attributes: OptimizelyAttributes?) throws -> Bool
21+
}
22+
1923
//[REF]: datafile schema
2024
// https://github.com/optimizely/optimizely/blob/43454b726a2a8aab7dcd953999cf8e1902b09d4d/src/www/services/datafile_generator/schema.json
2125

@@ -38,40 +42,27 @@ struct Project: Codable, Equatable {
3842
var typedAudiences: [Audience]?
3943
var featureFlags: [FeatureFlag]
4044
var botFiltering: Bool?
45+
}
46+
47+
extension Project: ProjectProtocol {
4148

42-
private enum CodingKeys: String, CodingKey {
43-
case version
44-
case projectId
45-
case experiments
46-
case audiences
47-
case groups
48-
case attributes
49-
case accountId
50-
case events
51-
case revision
52-
case anonymizeIP
53-
case rollouts
54-
case typedAudiences
55-
case featureFlags
56-
case botFiltering
49+
func evaluateAudience(audienceId: String, attributes: OptimizelyAttributes?) throws -> Bool {
50+
guard let audience = getAudience(id: audienceId) else {
51+
throw OptimizelyError.conditionNoMatchingAudience(audienceId)
52+
}
53+
54+
return try audience.evaluate(project: self, attributes: attributes)
5755
}
5856

59-
lazy var audienceMap:[String:Audience] = {
60-
var map:[String:Audience] = [:]
61-
audiences.forEach({map[$0.id] = $0 })
62-
typedAudiences?.forEach({map[$0.id] = $0})
63-
return map
64-
}()
65-
66-
6757
}
6858

6959
// MARK: - Utils
7060

7161
extension Project {
7262

73-
mutating func getAudience(id: String) -> Audience? {
74-
return audienceMap[id]
63+
func getAudience(id: String) -> Audience? {
64+
return typedAudiences?.filter{ $0.id == id }.first ??
65+
audiences.filter{ $0.id == id }.first
7566
}
7667

7768
}

OptimizelySDK/Implementation/DefaultBucketer.swift

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,7 @@ class DefaultBucketer : OPTBucketer {
3333

3434
// check for mutex
3535

36-
let group = config.project.groups.filter({
37-
var g = $0
38-
guard let _ = g.experimentMap[experiment.id] else {
39-
return false
40-
}
41-
return true
42-
}).first
36+
let group = config.project.groups.filter{ $0.getExperiemnt(id: experiment.id) != nil }.first
4337

4438
if let group = group {
4539
switch group.policy {
@@ -85,12 +79,17 @@ class DefaultBucketer : OPTBucketer {
8579
return nil;
8680
}
8781

88-
for trafficAllocation in group.trafficAllocation where bucketValue <= trafficAllocation.endOfRange {
89-
if let experiment = config.getExperiment(id: trafficAllocation.entityId) {
90-
return experiment
91-
} else {
92-
logger?.e(.userBucketedIntoInvalidExperiment(trafficAllocation.entityId))
93-
return nil
82+
for trafficAllocation in group.trafficAllocation {
83+
if bucketValue <= trafficAllocation.endOfRange {
84+
let experimentId = trafficAllocation.entityId;
85+
86+
// propagate errors and logs for unknown experiment
87+
if let experiment = config.getExperiment(id: experimentId) {
88+
return experiment
89+
} else {
90+
logger?.e(.userBucketedIntoInvalidExperiment(experimentId))
91+
return nil
92+
}
9493
}
9594
}
9695

@@ -107,14 +106,18 @@ class DefaultBucketer : OPTBucketer {
107106
return nil
108107
}
109108

110-
for trafficAllocation in experiment.trafficAllocation where (bucketValue <= trafficAllocation.endOfRange) {
109+
for trafficAllocation in experiment.trafficAllocation {
110+
if (bucketValue <= trafficAllocation.endOfRange) {
111+
let variationId = trafficAllocation.entityId;
112+
111113
// propagate errors and logs for unknown variation
112-
if let variation = experiment.getVariation(id: trafficAllocation.entityId) {
114+
if let variation = experiment.getVariation(id: variationId) {
113115
return variation
114116
} else {
115-
logger?.e(.userBucketedIntoInvalidVariation(trafficAllocation.entityId))
117+
logger?.e(.userBucketedIntoInvalidVariation(variationId))
116118
return nil
117119
}
120+
}
118121
}
119122

120123
return nil;

OptimizelySDK/Implementation/DefaultDecisionService.swift

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -63,50 +63,50 @@ class DefaultDecisionService : OPTDecisionService {
6363
return variation
6464
}
6565

66+
var bucketedVariation:Variation?
6667
// ---- check if the user passes audience targeting before bucketing ----
67-
if isInExperiment(config: config, experiment:experiment, userId:userId, attributes:attributes), let bucketedVariation = bucketer.bucketExperiment(config: config, experiment: experiment, bucketingId: bucketingId) {
68+
if isInExperiment(config: config, experiment:experiment, userId:userId, attributes:attributes) {
69+
// bucket user into a variation
70+
bucketedVariation = bucketer.bucketExperiment(config: config, experiment: experiment, bucketingId: bucketingId)
71+
72+
if let bucketedVariation = bucketedVariation {
6873
// save to user profile
69-
self.saveProfile(userId: userId, experimentId: experimentId, variationId: bucketedVariation.id)
70-
return bucketedVariation
74+
self.saveProfile(userId: userId, experimentId: experimentId, variationId: bucketedVariation.id)
75+
}
7176
} else {
7277
logger?.i(.userNotInExperiment(userId, experiment.key))
7378
}
7479

75-
return nil
80+
return bucketedVariation;
7681
}
7782

7883
func isInExperiment(config:ProjectConfig, experiment:Experiment, userId:String, attributes: OptimizelyAttributes) -> Bool {
79-
80-
func innerEvaluate(conditions:ConditionHolder) throws -> Bool {
81-
var result = false
82-
switch conditions {
83-
case .array(let arrConditions):
84-
if arrConditions.count > 0 {
85-
result = try conditions.evaluate(project: config.project, attributes: attributes)
86-
} else {
87-
// empty conditions (backward compatibility with "audienceIds" is ignored if exists even though empty
88-
result = true
89-
}
90-
case .leaf:
91-
result = try conditions.evaluate(project: config.project, attributes: attributes)
92-
default:
93-
result = true
94-
}
95-
return result
96-
}
84+
9785
var result = true // success as default (no condition, etc)
9886

9987
do {
10088
if let conditions = experiment.audienceConditions {
101-
result = try innerEvaluate(conditions: conditions)
89+
switch conditions {
90+
case .array(let arrConditions):
91+
if arrConditions.count > 0 {
92+
result = try conditions.evaluate(project: config.project, attributes: attributes)
93+
} else {
94+
// empty conditions (backward compatibility with "audienceIds" is ignored if exists even though empty
95+
result = true
96+
}
97+
case .leaf:
98+
result = try conditions.evaluate(project: config.project, attributes: attributes)
99+
default:
100+
result = true
101+
}
102102
}
103103
// backward compatibility with audiencIds list
104104
else if experiment.audienceIds.count > 0 {
105105
var holder = [ConditionHolder]()
106106
holder.append(.logicalOp(.or))
107-
experiment.audienceIds.forEach({
108-
holder.append(.leaf(.audienceId($0)))
109-
})
107+
for id in experiment.audienceIds {
108+
holder.append(.leaf(.audienceId(id)))
109+
}
110110

111111
result = try holder.evaluate(project: config.project, attributes: attributes)
112112
}

OptimizelySDK/OptimizelySwiftSDK.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
0B05901A2209DC180007F4A2 /* HandlerRegistryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B0590172209DC180007F4A2 /* HandlerRegistryService.swift */; };
1616
0B05901B2209DC180007F4A2 /* HandlerRegistryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B0590172209DC180007F4A2 /* HandlerRegistryService.swift */; };
1717
0B11272E2242D817002A9C20 /* Optimizely.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6EBAEB6C21E3FEF800D13AA9 /* Optimizely.framework */; };
18-
0B272F83227CB217002B302D /* ConditionHolderTests_Evaluate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E95C8B12217C92E00B6EE06 /* ConditionHolderTests_Evaluate.swift */; };
19-
0B272F84227CB219002B302D /* ConditionHolderTests_Evaluate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E95C8B12217C92E00B6EE06 /* ConditionHolderTests_Evaluate.swift */; };
2018
0B4AE9FA22289CD90047B75D /* BatchEventBuilderTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B4AE9F922289CD90047B75D /* BatchEventBuilderTest.swift */; };
2119
0B4AE9FB22289CD90047B75D /* BatchEventBuilderTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B4AE9F922289CD90047B75D /* BatchEventBuilderTest.swift */; };
2220
0B4AEA112228A6430047B75D /* bucketing_id.json in Resources */ = {isa = PBXBuildFile; fileRef = 0B4AE9FC2228A6410047B75D /* bucketing_id.json */; };
@@ -616,6 +614,7 @@
616614
6EA4258C2218E6A000B074B5 /* OTUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E7FC6A222121D27009A171F /* OTUtils.swift */; };
617615
6EA4258D2218E6A100B074B5 /* OTUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E7FC6A222121D27009A171F /* OTUtils.swift */; };
618616
6EA4258E2218E6A200B074B5 /* OTUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E7FC6A222121D27009A171F /* OTUtils.swift */; };
617+
6EA4258F2218E6AD00B074B5 /* ConditionHolderTests_Evaluate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E95C8B12217C92E00B6EE06 /* ConditionHolderTests_Evaluate.swift */; };
619618
6EA425902218E6AD00B074B5 /* ConditionHolderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E95C8AA2217736000B6EE06 /* ConditionHolderTests.swift */; };
620619
6EA425912218E6AD00B074B5 /* RolloutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E4F0D94221393A500DD13A5 /* RolloutTests.swift */; };
621620
6EA425922218E6AD00B074B5 /* AttributeValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E4F0D7D2213536F00DD13A5 /* AttributeValueTests.swift */; };
@@ -630,6 +629,7 @@
630629
6EA4259B2218E6AD00B074B5 /* FeatureVariableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E7D3EE8220BAB0800410FDE /* FeatureVariableTests.swift */; };
631630
6EA4259C2218E6AD00B074B5 /* VariableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E7D3EE6220BA39000410FDE /* VariableTests.swift */; };
632631
6EA4259D2218E6AD00B074B5 /* AttributeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E65E55A220B8B0C0048081D /* AttributeTests.swift */; };
632+
6EA4259E2218E6AE00B074B5 /* ConditionHolderTests_Evaluate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E95C8B12217C92E00B6EE06 /* ConditionHolderTests_Evaluate.swift */; };
633633
6EA4259F2218E6AE00B074B5 /* ConditionHolderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E95C8AA2217736000B6EE06 /* ConditionHolderTests.swift */; };
634634
6EA425A02218E6AE00B074B5 /* RolloutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E4F0D94221393A500DD13A5 /* RolloutTests.swift */; };
635635
6EA425A12218E6AE00B074B5 /* AttributeValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E4F0D7D2213536F00DD13A5 /* AttributeValueTests.swift */; };
@@ -2950,6 +2950,7 @@
29502950
6EA426342218E74F00B074B5 /* UserAttribute.swift in Sources */,
29512951
6EA426482218E74F00B074B5 /* HandlerRegistryService.swift in Sources */,
29522952
6EA425A12218E6AE00B074B5 /* AttributeValueTests.swift in Sources */,
2953+
6EA4259E2218E6AE00B074B5 /* ConditionHolderTests_Evaluate.swift in Sources */,
29532954
6EA4261E2218E74F00B074B5 /* OPTUserProfileService.swift in Sources */,
29542955
6EA4261F2218E74F00B074B5 /* DataStoreUserDefaults.swift in Sources */,
29552956
6EA4262E2218E74F00B074B5 /* OPTDataStore.swift in Sources */,
@@ -2991,7 +2992,6 @@
29912992
6EA426382218E74F00B074B5 /* Attribute.swift in Sources */,
29922993
6EA425A72218E6AE00B074B5 /* VariationTests.swift in Sources */,
29932994
0B7B188E2232DB8700A1F85D /* DataStoreMemory.swift in Sources */,
2994-
0B272F84227CB219002B302D /* ConditionHolderTests_Evaluate.swift in Sources */,
29952995
6E8B6A4C221CC2D6006EA8A6 /* ProjectTests.swift in Sources */,
29962996
);
29972997
runOnlyForDeploymentPostprocessing = 0;
@@ -3123,6 +3123,7 @@
31233123
6EA426002218E74E00B074B5 /* UserAttribute.swift in Sources */,
31243124
6EA426142218E74E00B074B5 /* HandlerRegistryService.swift in Sources */,
31253125
6EA425922218E6AD00B074B5 /* AttributeValueTests.swift in Sources */,
3126+
6EA4258F2218E6AD00B074B5 /* ConditionHolderTests_Evaluate.swift in Sources */,
31263127
6EA425EA2218E74E00B074B5 /* OPTUserProfileService.swift in Sources */,
31273128
6EA425EB2218E74E00B074B5 /* DataStoreUserDefaults.swift in Sources */,
31283129
6EA425FA2218E74E00B074B5 /* OPTDataStore.swift in Sources */,
@@ -3164,7 +3165,6 @@
31643165
6EA426042218E74E00B074B5 /* Attribute.swift in Sources */,
31653166
6EA425982218E6AD00B074B5 /* VariationTests.swift in Sources */,
31663167
0B7B188A2232DB8500A1F85D /* DataStoreMemory.swift in Sources */,
3167-
0B272F83227CB217002B302D /* ConditionHolderTests_Evaluate.swift in Sources */,
31683168
6E8B6A4B221CC2D6006EA8A6 /* ProjectTests.swift in Sources */,
31693169
);
31703170
runOnlyForDeploymentPostprocessing = 0;

OptimizelySDK/OptimizelyTests/OptimizelyTests-APIs/OptimizelyClientTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class OptimizelyClientTests: XCTestCase {
4444

4545
func testTypedAudienceThroughProject() {
4646
// let variation = try? optimizely?.activate(experimentKey: "typed_audience_experiment", userId: "userId", attributes: ["doubleKey":5])
47-
let answer = try? optimizely?.config?.project.getAudience(id: "3468206643")?.evaluate( project: optimizely?.config?.project, attributes: ["booleanKey":true])
47+
let answer = try? optimizely?.config?.project.evaluateAudience(audienceId: "3468206643", attributes: ["booleanKey":true])
4848
XCTAssertTrue(answer!!)
4949

5050
}

0 commit comments

Comments
 (0)