Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FSSDK-9776] handle duplicate experiment key #523

Merged
merged 11 commits into from
Nov 30, 2023
7 changes: 6 additions & 1 deletion Sources/Optimizely/OptimizelyConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ struct OptimizelyConfigImp: OptimizelyConfig {
var attributes: [OptimizelyAttribute] = []
var audiences: [OptimizelyAudience] = []
var events: [OptimizelyEvent] = []

var logger = OPTLoggerFactory.getLogger()

init(projectConfig: ProjectConfig) {
guard let project = projectConfig.project else { return }

Expand Down Expand Up @@ -150,7 +151,11 @@ extension OptimizelyConfigImp {

func makeExperimentsMap(project: Project, experiments: [Experiment]) -> [String: Experiment] {
var map = [String: Experiment]()

experiments.forEach {
if map.keys.contains($0.key) {
logger.w("Duplicate experiment keys found in datafile: \($0.key)")
}
muzahidul-opti marked this conversation as resolved.
Show resolved Hide resolved
map[$0.key] = $0
}
return map
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class OptimizelyClientTests_OptimizelyConfig: XCTestCase {
let datafile = OTUtils.loadJSONDatafile("optimizely_config_datafile")!

self.optimizely = OptimizelyClient(sdkKey: "12345",
logger: TestLogger(),
userProfileService: OTUtils.createClearUserProfileService())
try! self.optimizely.start(datafile: datafile)
}
Expand Down Expand Up @@ -257,6 +258,67 @@ class OptimizelyClientTests_OptimizelyConfig: XCTestCase {
let result = try? self.optimizely.getOptimizelyConfig()
XCTAssertNil(result)
}

func testOptimizelyConfigWithDuplicateKeys() {
let exp0: [String : Any] = [
"id": "10001",
"key": "duplicate_key",
"status": "Running",
"layerId": "22222",
"variations": [],
"trafficAllocation": [],
"audienceIds": ["33333"],
"audienceConditions": [],
"forcedVariations": ["12345": "1234567890"]
]

let exp1: [String : Any] = [
"id": "10005",
"key": "duplicate_key",
"status": "Running",
"layerId": "22222",
"variations": [],
"trafficAllocation": [],
"audienceIds": ["33333"],
"audienceConditions": [],
"forcedVariations": ["12345": "1234567890"]
]

var projectData: [String: Any] = [
"version": "4",
"projectId": "11111",
"experiments": [],
"audiences": [],
"groups": [],
"attributes": [],
"accountId": "1234567890",
"events": [],
"revision": "5",
"anonymizeIP": true,
"rollouts": [],
"typedAudiences": [],
"integrations": [],
"featureFlags": [],
"botFiltering": false,
"sendFlagDecisions": true
]

projectData["experiments"] = [exp0, exp1]
let model: Project = try! OTUtils.model(from: projectData)
let projectConfig = ProjectConfig()
projectConfig.project = model

optimizely.config = projectConfig

let optiConfig = try! optimizely.getOptimizelyConfig()
let optimizelyExpMap: [String: OptimizelyExperiment] = optiConfig.experimentsMap

let logger = (optiConfig as! OptimizelyConfigImp).logger as! TestLogger
XCTAssertEqual(logger.getMessages(.warning), ["Duplicate experiment keys found in datafile: duplicate_key"])

XCTAssertEqual(optimizelyExpMap.count, 1)
XCTAssertEqual(optimizelyExpMap["duplicate_key"]?.id, "10005")
mikechu-optimizely marked this conversation as resolved.
Show resolved Hide resolved
}

}

Expand Down Expand Up @@ -365,3 +427,41 @@ extension OptimizelyEvent {
}
}

// MARK: - Mock Loggers

fileprivate class TestLogger: OPTLogger {
private static var _logLevel: OptimizelyLogLevel?
public static var logLevel: OptimizelyLogLevel {
get {
return _logLevel ?? .info
}
set (newLevel) {
_logLevel = newLevel
}
}

required public init() {
clearMessages()
}

func log(level: OptimizelyLogLevel, message: String) {
logMessages[level.rawValue].append(message)
}

// Utils

var logMessages = [[String]]()

var logCount: Int {
return logMessages.reduce(0) { $0 + $1.count }
}

func getMessages(_ level: OptimizelyLogLevel) -> [String] {
return logMessages[level.rawValue]
}

func clearMessages() {
logMessages = [[String]](repeating: [], count: OptimizelyLogLevel.debug.rawValue + 1)
}

}
2 changes: 1 addition & 1 deletion Tests/OptimizelyTests-DataModel/ProjectConfigTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class ProjectConfigTests: XCTestCase {
XCTAssertEqual(featureMap["1003"], ["2002"])
XCTAssertEqual(featureMap["1004"], ["2002"])
}
func testFlagVariations() {
let datafile = OTUtils.loadJSONDatafile("decide_datafile")!
let optimizely = OptimizelyClient(sdkKey: "12345",
Expand Down
Loading