Skip to content

Commit e59c595

Browse files
authored
[FSSDK-9785] handle duplicate experiment keys with a warning (#535)
When duplicate experiment keys are found in a datafile, SDK returns a correct experimentMap in OptimizelyConfig: - the experimentMap will contain the experiment later in the datafile experiments list. - add a warning log about "Duplicate experiment keys found in datafile: {key-name}"
1 parent ca2a894 commit e59c595

File tree

3 files changed

+47
-5
lines changed

3 files changed

+47
-5
lines changed

Diff for: core-api/src/main/java/com/optimizely/ab/optimizelyconfig/OptimizelyConfigService.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2020-2021, Optimizely, Inc. and contributors *
2+
* Copyright 2020-2021, 2023, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -18,6 +18,8 @@
1818
import com.optimizely.ab.annotations.VisibleForTesting;
1919
import com.optimizely.ab.config.*;
2020
import com.optimizely.ab.config.audience.Audience;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
2123

2224
import java.util.*;
2325

@@ -31,6 +33,8 @@ public class OptimizelyConfigService {
3133
private Map<String, List<FeatureVariable>> featureIdToVariablesMap = new HashMap<>();
3234
private Map<String, OptimizelyExperiment> experimentMapByExperimentId = new HashMap<>();
3335

36+
private static final Logger logger = LoggerFactory.getLogger(OptimizelyConfigService.class);
37+
3438
public OptimizelyConfigService(ProjectConfig projectConfig) {
3539
this.projectConfig = projectConfig;
3640
this.audiences = getAudiencesList(projectConfig.getTypedAudiences(), projectConfig.getAudiences());
@@ -125,6 +129,11 @@ Map<String, OptimizelyExperiment> getExperimentsMap() {
125129
experiment.serializeConditions(this.audiencesMap)
126130
);
127131

132+
if (featureExperimentMap.containsKey(experiment.getKey())) {
133+
// continue with this warning, so the later experiment will be used.
134+
logger.warn("Duplicate experiment keys found in datafile: {}", experiment.getKey());
135+
}
136+
128137
featureExperimentMap.put(experiment.getKey(), optimizelyExperiment);
129138
experimentMapByExperimentId.put(experiment.getId(), optimizelyExperiment);
130139
}

Diff for: core-api/src/test/java/com/optimizely/ab/optimizelyconfig/OptimizelyConfigServiceTest.java

+36-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2020-2021, Optimizely, Inc. and contributors *
2+
* Copyright 2020-2021, 2023, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -15,23 +15,29 @@
1515
***************************************************************************/
1616
package com.optimizely.ab.optimizelyconfig;
1717

18+
import ch.qos.logback.classic.Level;
1819
import com.optimizely.ab.config.*;
1920
import com.optimizely.ab.config.audience.Audience;
21+
import com.optimizely.ab.internal.LogbackVerifier;
2022
import org.junit.Before;
23+
import org.junit.Rule;
2124
import org.junit.Test;
22-
import org.junit.runner.RunWith;
23-
import org.mockito.runners.MockitoJUnitRunner;
2425

2526
import java.util.*;
2627
import static java.util.Arrays.asList;
2728
import static org.junit.Assert.*;
29+
import static org.mockito.Mockito.mock;
30+
import static org.mockito.Mockito.when;
2831

2932
public class OptimizelyConfigServiceTest {
3033

3134
private ProjectConfig projectConfig;
3235
private OptimizelyConfigService optimizelyConfigService;
3336
private OptimizelyConfig expectedConfig;
3437

38+
@Rule
39+
public LogbackVerifier logbackVerifier = new LogbackVerifier();
40+
3541
@Before
3642
public void initialize() {
3743
projectConfig = generateOptimizelyConfig();
@@ -46,6 +52,33 @@ public void testGetExperimentsMap() {
4652
assertEquals(expectedConfig.getExperimentsMap(), optimizelyExperimentMap);
4753
}
4854

55+
@Test
56+
public void testGetExperimentsMapWithDuplicateKeys() {
57+
List<Experiment> experiments = Arrays.asList(
58+
new Experiment(
59+
"first",
60+
"duplicate_key",
61+
null, null, Collections.<String>emptyList(), null,
62+
Collections.<Variation>emptyList(), Collections.<String, String>emptyMap(), Collections.<TrafficAllocation>emptyList()
63+
),
64+
new Experiment(
65+
"second",
66+
"duplicate_key",
67+
null, null, Collections.<String>emptyList(), null,
68+
Collections.<Variation>emptyList(), Collections.<String, String>emptyMap(), Collections.<TrafficAllocation>emptyList()
69+
)
70+
);
71+
72+
ProjectConfig projectConfig = mock(ProjectConfig.class);
73+
OptimizelyConfigService optimizelyConfigService = new OptimizelyConfigService(projectConfig);
74+
when(projectConfig.getExperiments()).thenReturn(experiments);
75+
76+
Map<String, OptimizelyExperiment> optimizelyExperimentMap = optimizelyConfigService.getExperimentsMap();
77+
assertEquals("Duplicate keys should be overwritten", optimizelyExperimentMap.size(), 1);
78+
assertEquals("Duplicate keys should be overwritten", optimizelyExperimentMap.get("duplicate_key").getId(), "second");
79+
logbackVerifier.expectMessage(Level.WARN, "Duplicate experiment keys found in datafile: duplicate_key");
80+
}
81+
4982
@Test
5083
public void testRevision() {
5184
String revision = optimizelyConfigService.getConfig().getRevision();

Diff for: java-quickstart/src/main/java/com/optimizely/Example.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private void processVisitor(String userId, Map<String, Object> attributes) {
5656

5757
public static void main(String[] args) throws InterruptedException {
5858
Optimizely optimizely = OptimizelyFactory.newDefaultInstance("BX9Y3bTa4YErpHZEMpAwHm");
59-
59+
6060
Example example = new Example(optimizely);
6161
Random random = new Random();
6262

0 commit comments

Comments
 (0)