Skip to content

Commit 8f831f1

Browse files
test: add tests for holdout feature in DecisionServiceTest
- Create test for checking if a user is in a variation for holdout feature when included in flags - Implement test to verify exclusion of user from variation for holdout when specified as excluded from flags - Add assertions to validate decision source, experiment, and variation for holdout feature
1 parent d8068e2 commit 8f831f1

File tree

1 file changed

+122
-20
lines changed

1 file changed

+122
-20
lines changed

core-api/src/test/java/com/optimizely/ab/bucketing/DecisionServiceTest.java

Lines changed: 122 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,86 @@
1515
***************************************************************************/
1616
package com.optimizely.ab.bucketing;
1717

18-
import ch.qos.logback.classic.Level;
18+
import java.util.AbstractMap;
19+
import java.util.ArrayList;
20+
import java.util.Arrays;
21+
import java.util.Collections;
22+
import java.util.HashMap;
23+
import java.util.List;
24+
import java.util.Map;
25+
26+
import static org.hamcrest.CoreMatchers.is;
27+
import static org.hamcrest.MatcherAssert.assertThat;
28+
import static org.junit.Assert.assertFalse;
29+
import static org.junit.Assert.assertNotEquals;
30+
import static org.junit.Assert.assertNotNull;
31+
import static org.junit.Assert.assertNull;
32+
import static org.junit.Assert.assertTrue;
33+
import org.junit.Before;
34+
import org.junit.Rule;
35+
import org.junit.Test;
36+
import static org.mockito.Matchers.any;
37+
import static org.mockito.Matchers.anyMapOf;
38+
import static org.mockito.Matchers.anyObject;
39+
import static org.mockito.Matchers.anyString;
40+
import static org.mockito.Matchers.eq;
41+
import org.mockito.Mock;
42+
import static org.mockito.Mockito.atMost;
43+
import static org.mockito.Mockito.doReturn;
44+
import static org.mockito.Mockito.doThrow;
45+
import static org.mockito.Mockito.mock;
46+
import static org.mockito.Mockito.never;
47+
import static org.mockito.Mockito.spy;
48+
import static org.mockito.Mockito.times;
49+
import static org.mockito.Mockito.verify;
50+
import static org.mockito.Mockito.when;
51+
import org.mockito.junit.MockitoJUnit;
52+
import org.mockito.junit.MockitoRule;
53+
54+
import com.fasterxml.jackson.annotation.JsonFormat;
1955
import com.optimizely.ab.Optimizely;
2056
import com.optimizely.ab.OptimizelyDecisionContext;
2157
import com.optimizely.ab.OptimizelyForcedDecision;
2258
import com.optimizely.ab.OptimizelyUserContext;
23-
import com.optimizely.ab.config.*;
59+
import com.optimizely.ab.config.DatafileProjectConfigTestUtils;
60+
import static com.optimizely.ab.config.DatafileProjectConfigTestUtils.noAudienceProjectConfigV3;
61+
import static com.optimizely.ab.config.DatafileProjectConfigTestUtils.validProjectConfigV3;
62+
import static com.optimizely.ab.config.DatafileProjectConfigTestUtils.validProjectConfigV4;
63+
import com.optimizely.ab.config.Experiment;
64+
import com.optimizely.ab.config.FeatureFlag;
65+
import com.optimizely.ab.config.ProjectConfig;
66+
import com.optimizely.ab.config.Rollout;
67+
import com.optimizely.ab.config.TrafficAllocation;
68+
import com.optimizely.ab.config.ValidProjectConfigV4;
69+
import static com.optimizely.ab.config.ValidProjectConfigV4.ATTRIBUTE_HOUSE_KEY;
70+
import static com.optimizely.ab.config.ValidProjectConfigV4.ATTRIBUTE_NATIONALITY_KEY;
71+
import static com.optimizely.ab.config.ValidProjectConfigV4.AUDIENCE_ENGLISH_CITIZENS_VALUE;
72+
import static com.optimizely.ab.config.ValidProjectConfigV4.AUDIENCE_GRYFFINDOR_VALUE;
73+
import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_FLAG_BOOLEAN_FEATURE;
74+
import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_FLAG_MULTI_VARIATE_FEATURE;
75+
import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_FLAG_MULTI_VARIATE_FUTURE_FEATURE;
76+
import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_FLAG_MUTEX_GROUP_FEATURE;
77+
import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_FLAG_SINGLE_VARIABLE_BOOLEAN;
78+
import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_FLAG_SINGLE_VARIABLE_INTEGER;
79+
import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_MULTI_VARIATE_FEATURE_KEY;
80+
import static com.optimizely.ab.config.ValidProjectConfigV4.HOLDOUT_BASIC_HOLDOUT;
81+
import static com.optimizely.ab.config.ValidProjectConfigV4.HOLDOUT_EXCLUDED_FLAGS_HOLDOUT;
82+
import static com.optimizely.ab.config.ValidProjectConfigV4.HOLDOUT_INCLUDED_FLAGS_HOLDOUT;
83+
import static com.optimizely.ab.config.ValidProjectConfigV4.ROLLOUT_2;
84+
import static com.optimizely.ab.config.ValidProjectConfigV4.ROLLOUT_3_EVERYONE_ELSE_RULE;
85+
import static com.optimizely.ab.config.ValidProjectConfigV4.ROLLOUT_3_EVERYONE_ELSE_RULE_ENABLED_VARIATION;
86+
import static com.optimizely.ab.config.ValidProjectConfigV4.VARIATION_HOLDOUT_VARIATION_OFF;
87+
import static com.optimizely.ab.config.ValidProjectConfigV4.generateValidProjectConfigV4_holdout;
88+
import com.optimizely.ab.config.Variation;
2489
import com.optimizely.ab.error.ErrorHandler;
2590
import com.optimizely.ab.internal.ControlAttribute;
2691
import com.optimizely.ab.internal.LogbackVerifier;
2792
import com.optimizely.ab.optimizelydecision.DecisionReasons;
2893
import com.optimizely.ab.optimizelydecision.DecisionResponse;
29-
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
30-
import org.junit.Before;
31-
import org.junit.Rule;
32-
import org.junit.Test;
33-
import org.mockito.Mock;
34-
import org.mockito.junit.MockitoJUnit;
35-
import org.mockito.junit.MockitoRule;
36-
37-
import java.util.*;
3894

39-
import static com.optimizely.ab.config.DatafileProjectConfigTestUtils.*;
40-
import static com.optimizely.ab.config.ValidProjectConfigV4.*;
95+
import ch.qos.logback.classic.Level;
96+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
4197
import static junit.framework.TestCase.assertEquals;
42-
import static org.hamcrest.CoreMatchers.is;
43-
import static org.hamcrest.MatcherAssert.assertThat;
44-
import static org.junit.Assert.*;
45-
import static org.mockito.Matchers.*;
46-
import static org.mockito.Mockito.*;
4798

4899
public class DecisionServiceTest {
49100

@@ -1243,14 +1294,65 @@ public void getVariationForFeatureReturnHoldoutDecisionForGlobalHoldout() {
12431294
optimizely.createUserContext("user123", attributes),
12441295
holdoutProjectConfig
12451296
).getResult();
1246-
1297+
1298+
assertEquals(HOLDOUT_BASIC_HOLDOUT, featureDecision.experiment);
12471299
assertEquals(VARIATION_HOLDOUT_VARIATION_OFF, featureDecision.variation);
12481300
assertEquals(FeatureDecision.DecisionSource.HOLDOUT, featureDecision.decisionSource);
12491301

12501302
logbackVerifier.expectMessage(Level.INFO, "User (user123) is in variation (ho_off_key) of holdout (basic_holdout).");
12511303
}
1252-
12531304

1305+
@Test
1306+
public void includedFlagsHoldoutOnlyAppliestoSpecificFlags() {
1307+
ProjectConfig holdoutProjectConfig = generateValidProjectConfigV4_holdout();
12541308

1309+
Bucketer mockBucketer = new Bucketer();
12551310

1311+
DecisionService decisionService = new DecisionService(mockBucketer, mockErrorHandler, null);
1312+
1313+
Map<String, Object> attributes = new HashMap<>();
1314+
attributes.put("$opt_bucketing_id", "ppid120000");
1315+
FeatureDecision featureDecision = decisionService.getVariationForFeature(
1316+
FEATURE_FLAG_BOOLEAN_FEATURE,
1317+
optimizely.createUserContext("user123", attributes),
1318+
holdoutProjectConfig
1319+
).getResult();
1320+
1321+
assertEquals(HOLDOUT_INCLUDED_FLAGS_HOLDOUT, featureDecision.experiment);
1322+
assertEquals(VARIATION_HOLDOUT_VARIATION_OFF, featureDecision.variation);
1323+
assertEquals(FeatureDecision.DecisionSource.HOLDOUT, featureDecision.decisionSource);
1324+
1325+
logbackVerifier.expectMessage(Level.INFO, "User (user123) is in variation (ho_off_key) of holdout (holdout_included_flags).");
1326+
}
1327+
1328+
@Test
1329+
public void excludedFlagsHoldoutAppliesToAllExceptSpecified() {
1330+
ProjectConfig holdoutProjectConfig = generateValidProjectConfigV4_holdout();
1331+
1332+
Bucketer mockBucketer = new Bucketer();
1333+
1334+
DecisionService decisionService = new DecisionService(mockBucketer, mockErrorHandler, null);
1335+
1336+
Map<String, Object> attributes = new HashMap<>();
1337+
attributes.put("$opt_bucketing_id", "ppid300002");
1338+
FeatureDecision excludedDecision = decisionService.getVariationForFeature(
1339+
FEATURE_FLAG_SINGLE_VARIABLE_BOOLEAN, // excluded from ho (holdout_excluded_flags)
1340+
optimizely.createUserContext("user123", attributes),
1341+
holdoutProjectConfig
1342+
).getResult();
1343+
1344+
assertNotEquals(FeatureDecision.DecisionSource.HOLDOUT, excludedDecision.decisionSource);
1345+
1346+
FeatureDecision featureDecision = decisionService.getVariationForFeature(
1347+
FEATURE_FLAG_SINGLE_VARIABLE_INTEGER, // excluded from ho (holdout_excluded_flags)
1348+
optimizely.createUserContext("user123", attributes),
1349+
holdoutProjectConfig
1350+
).getResult();
1351+
1352+
assertEquals(HOLDOUT_EXCLUDED_FLAGS_HOLDOUT, featureDecision.experiment);
1353+
assertEquals(VARIATION_HOLDOUT_VARIATION_OFF, featureDecision.variation);
1354+
assertEquals(FeatureDecision.DecisionSource.HOLDOUT, featureDecision.decisionSource);
1355+
1356+
logbackVerifier.expectMessage(Level.INFO, "User (user123) is in variation (ho_off_key) of holdout (holdout_excluded_flags).");
1357+
}
12561358
}

0 commit comments

Comments
 (0)