use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.
the class Optimizely method decide.
OptimizelyDecision decide(@Nonnull OptimizelyUserContext user, @Nonnull String key, @Nonnull List<OptimizelyDecideOption> options) {
ProjectConfig projectConfig = getProjectConfig();
if (projectConfig == null) {
return OptimizelyDecision.newErrorDecision(key, user, DecisionMessage.SDK_NOT_READY.reason());
}
FeatureFlag flag = projectConfig.getFeatureKeyMapping().get(key);
if (flag == null) {
return OptimizelyDecision.newErrorDecision(key, user, DecisionMessage.FLAG_KEY_INVALID.reason(key));
}
String userId = user.getUserId();
Map<String, Object> attributes = user.getAttributes();
Boolean decisionEventDispatched = false;
List<OptimizelyDecideOption> allOptions = getAllOptions(options);
DecisionReasons decisionReasons = DefaultDecisionReasons.newInstance(allOptions);
Map<String, ?> copiedAttributes = new HashMap<>(attributes);
FeatureDecision flagDecision;
// Check Forced Decision
OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flag.getKey(), null);
DecisionResponse<Variation> forcedDecisionVariation = decisionService.validatedForcedDecision(optimizelyDecisionContext, projectConfig, user);
decisionReasons.merge(forcedDecisionVariation.getReasons());
if (forcedDecisionVariation.getResult() != null) {
flagDecision = new FeatureDecision(null, forcedDecisionVariation.getResult(), FeatureDecision.DecisionSource.FEATURE_TEST);
} else {
// Regular decision
DecisionResponse<FeatureDecision> decisionVariation = decisionService.getVariationForFeature(flag, user, projectConfig, allOptions);
flagDecision = decisionVariation.getResult();
decisionReasons.merge(decisionVariation.getReasons());
}
Boolean flagEnabled = false;
if (flagDecision.variation != null) {
if (flagDecision.variation.getFeatureEnabled()) {
flagEnabled = true;
}
}
logger.info("Feature \"{}\" is enabled for user \"{}\"? {}", key, userId, flagEnabled);
Map<String, Object> variableMap = new HashMap<>();
if (!allOptions.contains(OptimizelyDecideOption.EXCLUDE_VARIABLES)) {
DecisionResponse<Map<String, Object>> decisionVariables = getDecisionVariableMap(flag, flagDecision.variation, flagEnabled);
variableMap = decisionVariables.getResult();
decisionReasons.merge(decisionVariables.getReasons());
}
OptimizelyJSON optimizelyJSON = new OptimizelyJSON(variableMap);
FeatureDecision.DecisionSource decisionSource = FeatureDecision.DecisionSource.ROLLOUT;
if (flagDecision.decisionSource != null) {
decisionSource = flagDecision.decisionSource;
}
List<String> reasonsToReport = decisionReasons.toReport();
String variationKey = flagDecision.variation != null ? flagDecision.variation.getKey() : null;
// TODO: add ruleKey values when available later. use a copy of experimentKey until then.
// add to event metadata as well (currently set to experimentKey)
String ruleKey = flagDecision.experiment != null ? flagDecision.experiment.getKey() : null;
if (!allOptions.contains(OptimizelyDecideOption.DISABLE_DECISION_EVENT)) {
decisionEventDispatched = sendImpression(projectConfig, flagDecision.experiment, userId, copiedAttributes, flagDecision.variation, key, decisionSource.toString(), flagEnabled);
}
DecisionNotification decisionNotification = DecisionNotification.newFlagDecisionNotificationBuilder().withUserId(userId).withAttributes(copiedAttributes).withFlagKey(key).withEnabled(flagEnabled).withVariables(variableMap).withVariationKey(variationKey).withRuleKey(ruleKey).withReasons(reasonsToReport).withDecisionEventDispatched(decisionEventDispatched).build();
notificationCenter.send(decisionNotification);
return new OptimizelyDecision(variationKey, flagEnabled, optimizelyJSON, ruleKey, key, user, reasonsToReport);
}
use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.
the class OptimizelyTest method isFeatureEnabledTrueWhenFeatureEnabledOfVariationIsTrue.
/**
* Verify {@link Optimizely#isFeatureEnabled(String, String)} calls into
* {@link Optimizely#isFeatureEnabled(String, String, Map)} sending FeatureEnabled true and they both
* return True when the user is bucketed into a variation for the feature.
* An impression event should not be dispatched since the user was not bucketed into an Experiment.
*/
@Test
public void isFeatureEnabledTrueWhenFeatureEnabledOfVariationIsTrue() throws Exception {
assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString()));
String validFeatureKey = FEATURE_MULTI_VARIATE_FEATURE_KEY;
Optimizely optimizely = optimizelyBuilder.withDecisionService(mockDecisionService).build();
// Should be an experiment from the rollout associated with the feature, but for this test
// it doesn't matter. Just use any valid experiment.
Experiment experiment = validProjectConfig.getRolloutIdMapping().get(ROLLOUT_2_ID).getExperiments().get(0);
Variation variation = new Variation("variationId", "variationKey", true, null);
FeatureDecision featureDecision = new FeatureDecision(experiment, variation, FeatureDecision.DecisionSource.ROLLOUT);
doReturn(DecisionResponse.responseNoReasons(featureDecision)).when(mockDecisionService).getVariationForFeature(eq(FEATURE_FLAG_MULTI_VARIATE_FEATURE), eq(optimizely.createUserContext(genericUserId, Collections.emptyMap())), eq(validProjectConfig));
assertTrue(optimizely.isFeatureEnabled(validFeatureKey, genericUserId));
eventHandler.expectImpression("3421010877", "variationId", genericUserId);
}
use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.
the class OptimizelyTest method getEnabledFeatureWithMockDecisionService.
/**
* Verify {@link Optimizely#getEnabledFeatures(String, Map)} calls into
* {@link DecisionService#getVariationForFeature} to return feature
* disabled so {@link Optimizely#getEnabledFeatures(String, Map)} will
* return empty List of FeatureFlags.
*/
@Test
public void getEnabledFeatureWithMockDecisionService() throws Exception {
assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString()));
Optimizely optimizely = optimizelyBuilder.withDecisionService(mockDecisionService).build();
FeatureDecision featureDecision = new FeatureDecision(null, null, FeatureDecision.DecisionSource.ROLLOUT);
doReturn(DecisionResponse.responseNoReasons(featureDecision)).when(mockDecisionService).getVariationForFeature(any(FeatureFlag.class), any(OptimizelyUserContext.class), any(ProjectConfig.class));
List<String> featureFlags = optimizely.getEnabledFeatures(genericUserId, Collections.emptyMap());
assertTrue(featureFlags.isEmpty());
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
}
use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.
the class OptimizelyTest method getEnabledFeaturesWithNoFeatureEnabled.
/**
* Verify {@link Optimizely#getEnabledFeatures(String, Map)} calls into
* {@link DecisionService#getVariationForFeature} for each featureFlag sending
* userId and emptyMap and Mocked {@link Optimizely#isFeatureEnabled(String, String, Map)}
* to return feature disabled so {@link Optimizely#getEnabledFeatures(String, Map)} will
* return empty List of FeatureFlags and no notification listener will get called.
*/
@Test
public void getEnabledFeaturesWithNoFeatureEnabled() throws Exception {
assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString()));
isListenerCalled = false;
Optimizely optimizely = optimizelyBuilder.withDecisionService(mockDecisionService).build();
FeatureDecision featureDecision = new FeatureDecision(null, null, FeatureDecision.DecisionSource.ROLLOUT);
doReturn(DecisionResponse.responseNoReasons(featureDecision)).when(mockDecisionService).getVariationForFeature(any(FeatureFlag.class), any(OptimizelyUserContext.class), any(ProjectConfig.class));
int notificationId = optimizely.addDecisionNotificationHandler(decisionNotification -> {
});
List<String> featureFlags = optimizely.getEnabledFeatures(genericUserId, Collections.emptyMap());
assertTrue(featureFlags.isEmpty());
// Verify that listener not being called
assertFalse(isListenerCalled);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
eventHandler.expectImpression(null, "", genericUserId);
assertTrue(optimizely.notificationCenter.removeNotificationListener(notificationId));
}
use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.
the class OptimizelyTest method isFeatureEnabledFalseWhenFeatureEnabledOfVariationIsFalse.
/**
* Verify {@link Optimizely#isFeatureEnabled(String, String)} calls into
* {@link Optimizely#isFeatureEnabled(String, String, Map)} sending FeatureEnabled false because of which and they both
* return false even when the user is bucketed into a variation for the feature.
* An impression event should not be dispatched since the user was not bucketed into an Experiment.
*/
@Test
public void isFeatureEnabledFalseWhenFeatureEnabledOfVariationIsFalse() throws Exception {
assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString()));
Optimizely spyOptimizely = optimizelyBuilder.withDecisionService(mockDecisionService).build();
// Should be an experiment from the rollout associated with the feature, but for this test
// it doesn't matter. Just use any valid experiment.
Experiment experiment = validProjectConfig.getRolloutIdMapping().get(ROLLOUT_2_ID).getExperiments().get(0);
Variation variation = new Variation("variationId", "variationKey", false, null);
FeatureDecision featureDecision = new FeatureDecision(experiment, variation, FeatureDecision.DecisionSource.ROLLOUT);
doReturn(DecisionResponse.responseNoReasons(featureDecision)).when(mockDecisionService).getVariationForFeature(eq(FEATURE_FLAG_MULTI_VARIATE_FEATURE), eq(spyOptimizely.createUserContext(genericUserId, Collections.emptyMap())), eq(validProjectConfig));
assertFalse(spyOptimizely.isFeatureEnabled(FEATURE_MULTI_VARIATE_FEATURE_KEY, genericUserId));
eventHandler.expectImpression("3421010877", "variationId", genericUserId);
}
Aggregations