Skip to content

Commit c2af8fe

Browse files
[FSSDK-9776] handle duplicate experiment key (#523)
Logged for Duplicate keys
1 parent 953db4e commit c2af8fe

File tree

3 files changed

+104
-5
lines changed

3 files changed

+104
-5
lines changed

Sources/Optimizely/OptimizelyClient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ open class OptimizelyClient: NSObject {
782782
public func getOptimizelyConfig() throws -> OptimizelyConfig {
783783
guard let config = self.config else { throw OptimizelyError.sdkNotReady }
784784

785-
return OptimizelyConfigImp(projectConfig: config)
785+
return OptimizelyConfigImp(projectConfig: config, logger: logger)
786786
}
787787

788788
}

Sources/Optimizely/OptimizelyConfig.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ struct OptimizelyConfigImp: OptimizelyConfig {
9595
var attributes: [OptimizelyAttribute] = []
9696
var audiences: [OptimizelyAudience] = []
9797
var events: [OptimizelyEvent] = []
98-
99-
init(projectConfig: ProjectConfig) {
98+
99+
init(projectConfig: ProjectConfig, logger: OPTLogger = DefaultLogger()) {
100100
guard let project = projectConfig.project else { return }
101101

102102
self.environmentKey = project.environmentKey ?? ""
@@ -139,7 +139,7 @@ struct OptimizelyConfigImp: OptimizelyConfig {
139139
return updatedRollout
140140
}
141141

142-
self.experimentsMap = makeExperimentsMap(project: project, experiments: updatedExperiments)
142+
self.experimentsMap = makeExperimentsMap(project: project, experiments: updatedExperiments, logger: logger)
143143
self.featuresMap = makeFeaturesMap(project: project, experiments: updatedExperiments, rollouts: updatedRollouts)
144144
}
145145
}
@@ -148,9 +148,12 @@ struct OptimizelyConfigImp: OptimizelyConfig {
148148

149149
extension OptimizelyConfigImp {
150150

151-
func makeExperimentsMap(project: Project, experiments: [Experiment]) -> [String: Experiment] {
151+
func makeExperimentsMap(project: Project, experiments: [Experiment], logger: OPTLogger) -> [String: Experiment] {
152152
var map = [String: Experiment]()
153153
experiments.forEach {
154+
if map.keys.contains($0.key) {
155+
logger.w("Duplicate experiment keys found in datafile: \($0.key)")
156+
}
154157
map[$0.key] = $0
155158
}
156159
return map

Tests/OptimizelyTests-APIs/OptimizelyClientTests_OptimizelyConfig.swift

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,64 @@ class OptimizelyClientTests_OptimizelyConfig: XCTestCase {
257257
let result = try? self.optimizely.getOptimizelyConfig()
258258
XCTAssertNil(result)
259259
}
260+
261+
func testOptimizelyConfigWithDuplicateKeys() {
262+
let exp0: [String : Any] = [
263+
"id": "10001",
264+
"key": "duplicate_key",
265+
"status": "Running",
266+
"layerId": "22222",
267+
"variations": [],
268+
"trafficAllocation": [],
269+
"audienceIds": ["33333"],
270+
"audienceConditions": [],
271+
"forcedVariations": ["12345": "1234567890"]
272+
]
273+
274+
let exp1: [String : Any] = [
275+
"id": "10005",
276+
"key": "duplicate_key",
277+
"status": "Running",
278+
"layerId": "22222",
279+
"variations": [],
280+
"trafficAllocation": [],
281+
"audienceIds": ["33333"],
282+
"audienceConditions": [],
283+
"forcedVariations": ["12345": "1234567890"]
284+
]
285+
286+
var projectData: [String: Any] = [
287+
"version": "4",
288+
"projectId": "11111",
289+
"experiments": [],
290+
"audiences": [],
291+
"groups": [],
292+
"attributes": [],
293+
"accountId": "1234567890",
294+
"events": [],
295+
"revision": "5",
296+
"anonymizeIP": true,
297+
"rollouts": [],
298+
"typedAudiences": [],
299+
"integrations": [],
300+
"featureFlags": [],
301+
"botFiltering": false,
302+
"sendFlagDecisions": true
303+
]
304+
305+
projectData["experiments"] = [exp0, exp1]
306+
let model: Project = try! OTUtils.model(from: projectData)
307+
let projectConfig = ProjectConfig()
308+
projectConfig.project = model
309+
310+
let logger = TestLogger()
311+
let optiConfigImpl = OptimizelyConfigImp(projectConfig: projectConfig, logger: logger)
312+
let optimizelyExpMap: [String: OptimizelyExperiment] = optiConfigImpl.experimentsMap
313+
XCTAssertEqual(logger.getMessages(.warning), ["Duplicate experiment keys found in datafile: duplicate_key"])
314+
315+
XCTAssertEqual(optimizelyExpMap.count, 1)
316+
XCTAssertEqual(optimizelyExpMap["duplicate_key"]?.id, "10005")
317+
}
260318

261319
}
262320

@@ -365,3 +423,41 @@ extension OptimizelyEvent {
365423
}
366424
}
367425

426+
// MARK: - Mock Loggers
427+
428+
fileprivate class TestLogger: OPTLogger {
429+
private static var _logLevel: OptimizelyLogLevel?
430+
public static var logLevel: OptimizelyLogLevel {
431+
get {
432+
return _logLevel ?? .info
433+
}
434+
set (newLevel) {
435+
_logLevel = newLevel
436+
}
437+
}
438+
439+
required public init() {
440+
clearMessages()
441+
}
442+
443+
func log(level: OptimizelyLogLevel, message: String) {
444+
logMessages[level.rawValue].append(message)
445+
}
446+
447+
// Utils
448+
449+
var logMessages = [[String]]()
450+
451+
var logCount: Int {
452+
return logMessages.reduce(0) { $0 + $1.count }
453+
}
454+
455+
func getMessages(_ level: OptimizelyLogLevel) -> [String] {
456+
return logMessages[level.rawValue]
457+
}
458+
459+
func clearMessages() {
460+
logMessages = [[String]](repeating: [], count: OptimizelyLogLevel.debug.rawValue + 1)
461+
}
462+
463+
}

0 commit comments

Comments
 (0)