Search in sources :

Example 11 with FeatureDecision

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);
}
Also used : FeatureDecision(com.optimizely.ab.bucketing.FeatureDecision) OptimizelyJSON(com.optimizely.ab.optimizelyjson.OptimizelyJSON)

Example 12 with FeatureDecision

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);
}
Also used : FeatureDecision(com.optimizely.ab.bucketing.FeatureDecision) Test(org.junit.Test)

Example 13 with FeatureDecision

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);
}
Also used : FeatureDecision(com.optimizely.ab.bucketing.FeatureDecision) Test(org.junit.Test)

Example 14 with FeatureDecision

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));
}
Also used : FeatureDecision(com.optimizely.ab.bucketing.FeatureDecision) Test(org.junit.Test)

Example 15 with FeatureDecision

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);
}
Also used : FeatureDecision(com.optimizely.ab.bucketing.FeatureDecision) Test(org.junit.Test)

Aggregations

FeatureDecision (com.optimizely.ab.bucketing.FeatureDecision)16 Test (org.junit.Test)10 OptimizelyJSON (com.optimizely.ab.optimizelyjson.OptimizelyJSON)3 VisibleForTesting (com.optimizely.ab.annotations.VisibleForTesting)2 FeatureFlag (com.optimizely.ab.config.FeatureFlag)2 LiveVariable (com.optimizely.ab.config.LiveVariable)2 Nonnull (javax.annotation.Nonnull)2 Experiment (com.optimizely.ab.config.Experiment)1 LiveVariableUsageInstance (com.optimizely.ab.config.LiveVariableUsageInstance)1 Nullable (javax.annotation.Nullable)1 Matchers.anyString (org.mockito.Matchers.anyString)1