Skip to content

Commit 7298cf5

Browse files
move validate forced decision to decision service (#457)
* Moved validated forced decision to decision service and fixed tests * comment fix * Updated Header Co-authored-by: mnoman09 <[email protected]>
1 parent ca3690d commit 7298cf5

File tree

8 files changed

+112
-99
lines changed

8 files changed

+112
-99
lines changed

core-api/src/main/java/com/optimizely/ab/Optimizely.java

+2-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2016-2021, Optimizely, Inc. and contributors *
2+
* Copyright 2016-2022, 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. *
@@ -1185,7 +1185,7 @@ OptimizelyDecision decide(@Nonnull OptimizelyUserContext user,
11851185

11861186
// Check Forced Decision
11871187
OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flag.getKey(), null);
1188-
DecisionResponse<Variation> forcedDecisionVariation = user.findValidatedForcedDecision(optimizelyDecisionContext);
1188+
DecisionResponse<Variation> forcedDecisionVariation = decisionService.validatedForcedDecision(optimizelyDecisionContext, projectConfig, user);
11891189
decisionReasons.merge(forcedDecisionVariation.getReasons());
11901190
if (forcedDecisionVariation.getResult() != null) {
11911191
flagDecision = new FeatureDecision(null, forcedDecisionVariation.getResult(), FeatureDecision.DecisionSource.FEATURE_TEST);
@@ -1344,26 +1344,6 @@ private DecisionResponse<Map<String, Object>> getDecisionVariableMap(@Nonnull Fe
13441344
return new DecisionResponse(valuesMap, reasons);
13451345
}
13461346

1347-
/**
1348-
* Gets a variation based on flagKey and variationKey
1349-
*
1350-
* @param flagKey The flag key for the variation
1351-
* @param variationKey The variation key for the variation
1352-
* @return Returns a variation based on flagKey and variationKey, otherwise null
1353-
*/
1354-
public Variation getFlagVariationByKey(String flagKey, String variationKey) {
1355-
Map<String, List<Variation>> flagVariationsMap = getProjectConfig().getFlagVariationsMap();
1356-
if (flagVariationsMap.containsKey(flagKey)) {
1357-
List<Variation> variations = flagVariationsMap.get(flagKey);
1358-
for (Variation variation : variations) {
1359-
if (variation.getKey().equals(variationKey)) {
1360-
return variation;
1361-
}
1362-
}
1363-
}
1364-
return null;
1365-
}
1366-
13671347
/**
13681348
* Helper method which makes separate copy of attributesMap variable and returns it
13691349
*

core-api/src/main/java/com/optimizely/ab/OptimizelyUserContext.java

+2-30
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
*
3-
* Copyright 2020-2021, Optimizely and contributors
3+
* Copyright 2020-2022, Optimizely and contributors
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -265,35 +265,7 @@ public boolean removeAllForcedDecisions() {
265265
return true;
266266
}
267267

268-
/**
269-
* Find a validated forced decision
270-
*
271-
* @param optimizelyDecisionContext The OptimizelyDecisionContext containing flagKey and ruleKey
272-
* @return Returns a DecisionResponse structure of type Variation, otherwise null result with reasons
273-
*/
274-
public DecisionResponse<Variation> findValidatedForcedDecision(@Nonnull OptimizelyDecisionContext optimizelyDecisionContext) {
275-
DecisionReasons reasons = DefaultDecisionReasons.newInstance();
276-
OptimizelyForcedDecision optimizelyForcedDecision = findForcedDecision(optimizelyDecisionContext);
277-
String variationKey = optimizelyForcedDecision != null ? optimizelyForcedDecision.getVariationKey() : null;
278-
if (variationKey != null) {
279-
Variation variation = optimizely.getFlagVariationByKey(optimizelyDecisionContext.getFlagKey(), variationKey);
280-
String ruleKey = optimizelyDecisionContext.getRuleKey();
281-
String flagKey = optimizelyDecisionContext.getFlagKey();
282-
String info;
283-
String target = ruleKey != OptimizelyDecisionContext.OPTI_NULL_RULE_KEY ? String.format("flag (%s), rule (%s)", flagKey, ruleKey) : String.format("flag (%s)", flagKey);
284-
if (variation != null) {
285-
info = String.format("Variation (%s) is mapped to %s and user (%s) in the forced decision map.", variationKey, target, userId);
286-
logger.debug(info);
287-
reasons.addInfo(info);
288-
return new DecisionResponse(variation, reasons);
289-
} else {
290-
info = String.format("Invalid variation is mapped to %s and user (%s) in the forced decision map.", target, userId);
291-
logger.debug(info);
292-
reasons.addInfo(info);
293-
}
294-
}
295-
return new DecisionResponse<>(null, reasons);
296-
}
268+
297269

298270
// Utils
299271

core-api/src/main/java/com/optimizely/ab/bucketing/DecisionService.java

+37-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2017-2021, Optimizely, Inc. and contributors *
2+
* Copyright 2017-2022, 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. *
@@ -16,6 +16,7 @@
1616
package com.optimizely.ab.bucketing;
1717

1818
import com.optimizely.ab.OptimizelyDecisionContext;
19+
import com.optimizely.ab.OptimizelyForcedDecision;
1920
import com.optimizely.ab.OptimizelyRuntimeException;
2021
import com.optimizely.ab.OptimizelyUserContext;
2122
import com.optimizely.ab.config.*;
@@ -469,6 +470,39 @@ String getBucketingId(@Nonnull String userId,
469470
return bucketingId;
470471
}
471472

473+
/**
474+
* Find a validated forced decision
475+
*
476+
* @param optimizelyDecisionContext The OptimizelyDecisionContext containing flagKey and ruleKey
477+
* @param projectConfig The Project config
478+
* @param user The OptimizelyUserContext
479+
* @return Returns a DecisionResponse structure of type Variation, otherwise null result with reasons
480+
*/
481+
public DecisionResponse<Variation> validatedForcedDecision(@Nonnull OptimizelyDecisionContext optimizelyDecisionContext, @Nonnull ProjectConfig projectConfig, @Nonnull OptimizelyUserContext user) {
482+
DecisionReasons reasons = DefaultDecisionReasons.newInstance();
483+
String userId = user.getUserId();
484+
OptimizelyForcedDecision optimizelyForcedDecision = user.findForcedDecision(optimizelyDecisionContext);
485+
String variationKey = optimizelyForcedDecision != null ? optimizelyForcedDecision.getVariationKey() : null;
486+
if (projectConfig != null && variationKey != null) {
487+
Variation variation = projectConfig.getFlagVariationByKey(optimizelyDecisionContext.getFlagKey(), variationKey);
488+
String ruleKey = optimizelyDecisionContext.getRuleKey();
489+
String flagKey = optimizelyDecisionContext.getFlagKey();
490+
String info;
491+
String target = ruleKey != OptimizelyDecisionContext.OPTI_NULL_RULE_KEY ? String.format("flag (%s), rule (%s)", flagKey, ruleKey) : String.format("flag (%s)", flagKey);
492+
if (variation != null) {
493+
info = String.format("Variation (%s) is mapped to %s and user (%s) in the forced decision map.", variationKey, target, userId);
494+
logger.debug(info);
495+
reasons.addInfo(info);
496+
return new DecisionResponse(variation, reasons);
497+
} else {
498+
info = String.format("Invalid variation is mapped to %s and user (%s) in the forced decision map.", target, userId);
499+
logger.debug(info);
500+
reasons.addInfo(info);
501+
}
502+
}
503+
return new DecisionResponse<>(null, reasons);
504+
}
505+
472506
public ConcurrentHashMap<String, ConcurrentHashMap<String, String>> getForcedVariationMapping() {
473507
return forcedVariationMapping;
474508
}
@@ -591,7 +625,7 @@ public DecisionResponse<Variation> getVariationFromExperimentRule(@Nonnull Proje
591625
String ruleKey = rule != null ? rule.getKey() : null;
592626
// Check Forced-Decision
593627
OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flagKey, ruleKey);
594-
DecisionResponse<Variation> forcedDecisionResponse = user.findValidatedForcedDecision(optimizelyDecisionContext);
628+
DecisionResponse<Variation> forcedDecisionResponse = validatedForcedDecision(optimizelyDecisionContext, projectConfig, user);
595629

596630
reasons.merge(forcedDecisionResponse.getReasons());
597631

@@ -640,7 +674,7 @@ DecisionResponse<AbstractMap.SimpleEntry> getVariationFromDeliveryRule(@Nonnull
640674
// Check forced-decisions first
641675
Experiment rule = rules.get(ruleIndex);
642676
OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flagKey, rule.getKey());
643-
DecisionResponse<Variation> forcedDecisionResponse = user.findValidatedForcedDecision(optimizelyDecisionContext);
677+
DecisionResponse<Variation> forcedDecisionResponse = validatedForcedDecision(optimizelyDecisionContext, projectConfig, user);
644678
reasons.merge(forcedDecisionResponse.getReasons());
645679

646680
Variation variation = forcedDecisionResponse.getResult();

core-api/src/main/java/com/optimizely/ab/config/DatafileProjectConfig.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
*
3-
* Copyright 2016-2021, Optimizely and contributors
3+
* Copyright 2016-2022, Optimizely and contributors
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -503,6 +503,27 @@ public Map<String, List<Variation>> getFlagVariationsMap() {
503503
return flagVariationsMap;
504504
}
505505

506+
/**
507+
* Gets a variation based on flagKey and variationKey
508+
*
509+
* @param flagKey The flag key for the variation
510+
* @param variationKey The variation key for the variation
511+
* @return Returns a variation based on flagKey and variationKey, otherwise null
512+
*/
513+
@Override
514+
public Variation getFlagVariationByKey(String flagKey, String variationKey) {
515+
Map<String, List<Variation>> flagVariationsMap = getFlagVariationsMap();
516+
if (flagVariationsMap.containsKey(flagKey)) {
517+
List<Variation> variations = flagVariationsMap.get(flagKey);
518+
for (Variation variation : variations) {
519+
if (variation.getKey().equals(variationKey)) {
520+
return variation;
521+
}
522+
}
523+
}
524+
return null;
525+
}
526+
506527
@Override
507528
public String toString() {
508529
return "ProjectConfig{" +

core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
*
3-
* Copyright 2016-2021, Optimizely and contributors
3+
* Copyright 2016-2022, Optimizely and contributors
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -105,6 +105,8 @@ Experiment getExperimentForKey(@Nonnull String experimentKey,
105105

106106
Map<String, List<Variation>> getFlagVariationsMap();
107107

108+
Variation getFlagVariationByKey(String flagKey, String variationKey);
109+
108110
@Override
109111
String toString();
110112

core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2016-2020, Optimizely, Inc. and contributors *
2+
* Copyright 2016-2022, 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. *
@@ -4660,7 +4660,7 @@ public void getFlagVariationByKey() throws IOException {
46604660
String flagKey = "double_single_variable_feature";
46614661
String variationKey = "pi_variation";
46624662
Optimizely optimizely = Optimizely.builder().withDatafile(validConfigJsonV4()).build();
4663-
Variation variation = optimizely.getFlagVariationByKey(flagKey, variationKey);
4663+
Variation variation = optimizely.getProjectConfig().getFlagVariationByKey(flagKey, variationKey);
46644664

46654665
assertNotNull(variation);
46664666
assertEquals(variationKey, variation.getKey());

core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java

+1-39
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
*
3-
* Copyright 2021, Optimizely and contributors
3+
* Copyright 2021-2022, Optimizely and contributors
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -1442,44 +1442,6 @@ public void removeAllForcedDecisions() {
14421442
assertTrue(optimizelyUserContext.removeAllForcedDecisions());
14431443
}
14441444

1445-
1446-
@Test
1447-
public void findValidatedForcedDecisionWithRuleKey() {
1448-
String ruleKey = "77777";
1449-
String flagKey = "feature_2";
1450-
String variationKey = "variation_no_traffic";
1451-
OptimizelyUserContext optimizelyUserContext = new OptimizelyUserContext(
1452-
optimizely,
1453-
userId,
1454-
Collections.emptyMap());
1455-
1456-
OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flagKey, ruleKey);
1457-
OptimizelyForcedDecision optimizelyForcedDecision = new OptimizelyForcedDecision(variationKey);
1458-
1459-
optimizelyUserContext.setForcedDecision(optimizelyDecisionContext, optimizelyForcedDecision);
1460-
DecisionResponse<Variation> response = optimizelyUserContext.findValidatedForcedDecision(optimizelyDecisionContext);
1461-
Variation variation = response.getResult();
1462-
assertEquals(variationKey, variation.getKey());
1463-
}
1464-
1465-
@Test
1466-
public void findValidatedForcedDecisionWithoutRuleKey() {
1467-
String flagKey = "feature_2";
1468-
String variationKey = "variation_no_traffic";
1469-
OptimizelyUserContext optimizelyUserContext = new OptimizelyUserContext(
1470-
optimizely,
1471-
userId,
1472-
Collections.emptyMap());
1473-
1474-
OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flagKey, null);
1475-
OptimizelyForcedDecision optimizelyForcedDecision = new OptimizelyForcedDecision(variationKey);
1476-
1477-
optimizelyUserContext.setForcedDecision(optimizelyDecisionContext, optimizelyForcedDecision);
1478-
DecisionResponse<Variation> response = optimizelyUserContext.findValidatedForcedDecision(optimizelyDecisionContext);
1479-
Variation variation = response.getResult();
1480-
assertEquals(variationKey, variation.getKey());
1481-
}
1482-
14831445
@Test
14841446
public void setForcedDecisionsAndCallDecide() {
14851447
String flagKey = "feature_2";

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

+43-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2017-2020, Optimizely, Inc. and contributors *
2+
* Copyright 2017-2022, 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. *
@@ -17,6 +17,8 @@
1717

1818
import ch.qos.logback.classic.Level;
1919
import com.optimizely.ab.Optimizely;
20+
import com.optimizely.ab.OptimizelyDecisionContext;
21+
import com.optimizely.ab.OptimizelyForcedDecision;
2022
import com.optimizely.ab.OptimizelyUserContext;
2123
import com.optimizely.ab.config.*;
2224
import com.optimizely.ab.error.ErrorHandler;
@@ -35,6 +37,7 @@
3537

3638
import static com.optimizely.ab.config.DatafileProjectConfigTestUtils.*;
3739
import static com.optimizely.ab.config.ValidProjectConfigV4.*;
40+
import static junit.framework.TestCase.assertEquals;
3841
import static org.hamcrest.CoreMatchers.is;
3942
import static org.hamcrest.MatcherAssert.assertThat;
4043
import static org.junit.Assert.*;
@@ -761,6 +764,45 @@ public void getVariationFromExperimentRuleTest() {
761764
assertEquals(expectedVariation, decisionResponse.getResult());
762765
}
763766

767+
@Test
768+
public void validatedForcedDecisionWithRuleKey() {
769+
String userId = "testUser1";
770+
String ruleKey = "2637642575";
771+
String flagKey = "multi_variate_feature";
772+
String variationKey = "2346257680";
773+
OptimizelyUserContext optimizelyUserContext = new OptimizelyUserContext(
774+
optimizely,
775+
userId,
776+
Collections.emptyMap());
777+
778+
OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flagKey, ruleKey);
779+
OptimizelyForcedDecision optimizelyForcedDecision = new OptimizelyForcedDecision(variationKey);
780+
781+
optimizelyUserContext.setForcedDecision(optimizelyDecisionContext, optimizelyForcedDecision);
782+
DecisionResponse<Variation> response = decisionService.validatedForcedDecision(optimizelyDecisionContext, v4ProjectConfig, optimizelyUserContext);
783+
Variation variation = response.getResult();
784+
assertEquals(variationKey, variation.getKey());
785+
}
786+
787+
@Test
788+
public void validatedForcedDecisionWithoutRuleKey() {
789+
String userId = "testUser1";
790+
String flagKey = "multi_variate_feature";
791+
String variationKey = "521740985";
792+
OptimizelyUserContext optimizelyUserContext = new OptimizelyUserContext(
793+
optimizely,
794+
userId,
795+
Collections.emptyMap());
796+
797+
OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flagKey, null);
798+
OptimizelyForcedDecision optimizelyForcedDecision = new OptimizelyForcedDecision(variationKey);
799+
800+
optimizelyUserContext.setForcedDecision(optimizelyDecisionContext, optimizelyForcedDecision);
801+
DecisionResponse<Variation> response = decisionService.validatedForcedDecision(optimizelyDecisionContext, v4ProjectConfig, optimizelyUserContext);
802+
Variation variation = response.getResult();
803+
assertEquals(variationKey, variation.getKey());
804+
}
805+
764806
//========= white list tests ==========/
765807

766808
/**

0 commit comments

Comments
 (0)