Search in sources :

Example 1 with FeatureDecision

use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.

the class Optimizely method getFeatureVariableValueForType.

@VisibleForTesting
String getFeatureVariableValueForType(@Nonnull String featureKey, @Nonnull String variableKey, @Nonnull String userId, @Nonnull Map<String, String> attributes, @Nonnull LiveVariable.VariableType variableType) {
    if (featureKey == null) {
        logger.warn("The featureKey parameter must be nonnull.");
        return null;
    } else if (variableKey == null) {
        logger.warn("The variableKey parameter must be nonnull.");
        return null;
    } else if (userId == null) {
        logger.warn("The userId parameter must be nonnull.");
        return null;
    }
    FeatureFlag featureFlag = projectConfig.getFeatureKeyMapping().get(featureKey);
    if (featureFlag == null) {
        logger.info("No feature flag was found for key \"{}\".", featureKey);
        return null;
    }
    LiveVariable variable = featureFlag.getVariableKeyToLiveVariableMap().get(variableKey);
    if (variable == null) {
        logger.info("No feature variable was found for key \"{}\" in feature flag \"{}\".", variableKey, featureKey);
        return null;
    } else if (!variable.getType().equals(variableType)) {
        logger.info("The feature variable \"" + variableKey + "\" is actually of type \"" + variable.getType().toString() + "\" type. You tried to access it as type \"" + variableType.toString() + "\". Please use the appropriate feature variable accessor.");
        return null;
    }
    String variableValue = variable.getDefaultValue();
    FeatureDecision featureDecision = decisionService.getVariationForFeature(featureFlag, userId, attributes);
    if (featureDecision.variation != null) {
        LiveVariableUsageInstance liveVariableUsageInstance = featureDecision.variation.getVariableIdToLiveVariableUsageInstanceMap().get(variable.getId());
        if (liveVariableUsageInstance != null) {
            variableValue = liveVariableUsageInstance.getValue();
        } else {
            variableValue = variable.getDefaultValue();
        }
    } else {
        logger.info("User \"{}\" was not bucketed into any variation for feature flag \"{}\". " + "The default value \"{}\" for \"{}\" is being returned.", userId, featureKey, variableValue, variableKey);
    }
    return variableValue;
}
Also used : FeatureDecision(com.optimizely.ab.bucketing.FeatureDecision) LiveVariableUsageInstance(com.optimizely.ab.config.LiveVariableUsageInstance) FeatureFlag(com.optimizely.ab.config.FeatureFlag) LiveVariable(com.optimizely.ab.config.LiveVariable) VisibleForTesting(com.optimizely.ab.annotations.VisibleForTesting)

Example 2 with FeatureDecision

use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.

the class Optimizely method isFeatureEnabled.

@Nonnull
private Boolean isFeatureEnabled(@Nonnull ProjectConfig projectConfig, @Nonnull String featureKey, @Nonnull String userId, @Nonnull Map<String, ?> attributes) {
    if (featureKey == null) {
        logger.warn("The featureKey parameter must be nonnull.");
        return false;
    } else if (userId == null) {
        logger.warn("The userId parameter must be nonnull.");
        return false;
    }
    FeatureFlag featureFlag = projectConfig.getFeatureKeyMapping().get(featureKey);
    if (featureFlag == null) {
        logger.info("No feature flag was found for key \"{}\".", featureKey);
        return false;
    }
    Map<String, ?> copiedAttributes = copyAttributes(attributes);
    FeatureDecision.DecisionSource decisionSource = FeatureDecision.DecisionSource.ROLLOUT;
    FeatureDecision featureDecision = decisionService.getVariationForFeature(featureFlag, createUserContext(userId, copiedAttributes), projectConfig).getResult();
    Boolean featureEnabled = false;
    SourceInfo sourceInfo = new RolloutSourceInfo();
    if (featureDecision.decisionSource != null) {
        decisionSource = featureDecision.decisionSource;
    }
    if (featureDecision.variation != null) {
        // For rollouts experiments and variations are an implementation detail only.
        if (featureDecision.decisionSource.equals(FeatureDecision.DecisionSource.FEATURE_TEST)) {
            sourceInfo = new FeatureTestSourceInfo(featureDecision.experiment.getKey(), featureDecision.variation.getKey());
        } else {
            logger.info("The user \"{}\" is not included in an experiment for feature \"{}\".", userId, featureKey);
        }
        if (featureDecision.variation.getFeatureEnabled()) {
            featureEnabled = true;
        }
    }
    sendImpression(projectConfig, featureDecision.experiment, userId, copiedAttributes, featureDecision.variation, featureKey, decisionSource.toString(), featureEnabled);
    DecisionNotification decisionNotification = DecisionNotification.newFeatureDecisionNotificationBuilder().withUserId(userId).withAttributes(copiedAttributes).withFeatureKey(featureKey).withFeatureEnabled(featureEnabled).withSource(decisionSource).withSourceInfo(sourceInfo).build();
    notificationCenter.send(decisionNotification);
    logger.info("Feature \"{}\" is enabled for user \"{}\"? {}", featureKey, userId, featureEnabled);
    return featureEnabled;
}
Also used : FeatureDecision(com.optimizely.ab.bucketing.FeatureDecision) Nonnull(javax.annotation.Nonnull)

Example 3 with FeatureDecision

use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.

the class Optimizely method getFeatureVariableValueForType.

@VisibleForTesting
<T> T getFeatureVariableValueForType(@Nonnull String featureKey, @Nonnull String variableKey, @Nonnull String userId, @Nonnull Map<String, ?> attributes, @Nonnull String variableType) {
    if (featureKey == null) {
        logger.warn("The featureKey parameter must be nonnull.");
        return null;
    } else if (variableKey == null) {
        logger.warn("The variableKey parameter must be nonnull.");
        return null;
    } else if (userId == null) {
        logger.warn("The userId parameter must be nonnull.");
        return null;
    }
    ProjectConfig projectConfig = getProjectConfig();
    if (projectConfig == null) {
        logger.error("Optimizely instance is not valid, failing getFeatureVariableValueForType call. type: {}", variableType);
        return null;
    }
    FeatureFlag featureFlag = projectConfig.getFeatureKeyMapping().get(featureKey);
    if (featureFlag == null) {
        logger.info("No feature flag was found for key \"{}\".", featureKey);
        return null;
    }
    FeatureVariable variable = featureFlag.getVariableKeyToFeatureVariableMap().get(variableKey);
    if (variable == null) {
        logger.info("No feature variable was found for key \"{}\" in feature flag \"{}\".", variableKey, featureKey);
        return null;
    } else if (!variable.getType().equals(variableType)) {
        logger.info("The feature variable \"" + variableKey + "\" is actually of type \"" + variable.getType().toString() + "\" type. You tried to access it as type \"" + variableType.toString() + "\". Please use the appropriate feature variable accessor.");
        return null;
    }
    String variableValue = variable.getDefaultValue();
    Map<String, ?> copiedAttributes = copyAttributes(attributes);
    FeatureDecision featureDecision = decisionService.getVariationForFeature(featureFlag, createUserContext(userId, copiedAttributes), projectConfig).getResult();
    Boolean featureEnabled = false;
    if (featureDecision.variation != null) {
        if (featureDecision.variation.getFeatureEnabled()) {
            FeatureVariableUsageInstance featureVariableUsageInstance = featureDecision.variation.getVariableIdToFeatureVariableUsageInstanceMap().get(variable.getId());
            if (featureVariableUsageInstance != null) {
                variableValue = featureVariableUsageInstance.getValue();
                logger.info("Got variable value \"{}\" for variable \"{}\" of feature flag \"{}\".", variableValue, variableKey, featureKey);
            } else {
                variableValue = variable.getDefaultValue();
                logger.info("Value is not defined for variable \"{}\". Returning default value \"{}\".", variableKey, variableValue);
            }
        } else {
            logger.info("Feature \"{}\" is not enabled for user \"{}\". " + "Returning the default variable value \"{}\".", featureKey, userId, variableValue);
        }
        featureEnabled = featureDecision.variation.getFeatureEnabled();
    } else {
        logger.info("User \"{}\" was not bucketed into any variation for feature flag \"{}\". " + "The default value \"{}\" for \"{}\" is being returned.", userId, featureKey, variableValue, variableKey);
    }
    Object convertedValue = convertStringToType(variableValue, variableType);
    Object notificationValue = convertedValue;
    if (convertedValue instanceof OptimizelyJSON) {
        notificationValue = ((OptimizelyJSON) convertedValue).toMap();
    }
    DecisionNotification decisionNotification = DecisionNotification.newFeatureVariableDecisionNotificationBuilder().withUserId(userId).withAttributes(copiedAttributes).withFeatureKey(featureKey).withFeatureEnabled(featureEnabled).withVariableKey(variableKey).withVariableType(variableType).withVariableValue(notificationValue).withFeatureDecision(featureDecision).build();
    notificationCenter.send(decisionNotification);
    return (T) convertedValue;
}
Also used : OptimizelyJSON(com.optimizely.ab.optimizelyjson.OptimizelyJSON) FeatureDecision(com.optimizely.ab.bucketing.FeatureDecision) VisibleForTesting(com.optimizely.ab.annotations.VisibleForTesting)

Example 4 with FeatureDecision

use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.

the class OptimizelyTest method isFeatureEnabledReturnsFalseAndDispatchesWhenUserIsBucketedIntoAnExperimentVariationToggleOff.

/**
 * Verify {@link Optimizely#isFeatureEnabled(String, String)} calls into
 * {@link Optimizely#isFeatureEnabled(String, String, Map)} and they both
 * return False
 * when the user is bucketed an feature test variation that is turned off.
 */
@Test
public void isFeatureEnabledReturnsFalseAndDispatchesWhenUserIsBucketedIntoAnExperimentVariationToggleOff() throws Exception {
    assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString()));
    String validFeatureKey = FEATURE_MULTI_VARIATE_FEATURE_KEY;
    Optimizely spyOptimizely = optimizelyBuilder.withDecisionService(mockDecisionService).build();
    Experiment activatedExperiment = validProjectConfig.getExperimentKeyMapping().get(EXPERIMENT_MULTIVARIATE_EXPERIMENT_KEY);
    Variation variation = new Variation("2", "variation_toggled_off", false, null);
    FeatureDecision featureDecision = new FeatureDecision(activatedExperiment, variation, FeatureDecision.DecisionSource.FEATURE_TEST);
    doReturn(DecisionResponse.responseNoReasons(featureDecision)).when(mockDecisionService).getVariationForFeature(any(FeatureFlag.class), any(OptimizelyUserContext.class), any(ProjectConfig.class));
    assertFalse(spyOptimizely.isFeatureEnabled(validFeatureKey, genericUserId));
    eventHandler.expectImpression(activatedExperiment.getId(), variation.getId(), genericUserId);
    logbackVerifier.expectMessage(Level.INFO, "Feature \"" + validFeatureKey + "\" is enabled for user \"" + genericUserId + "\"? false");
}
Also used : FeatureDecision(com.optimizely.ab.bucketing.FeatureDecision) Test(org.junit.Test)

Example 5 with FeatureDecision

use of com.optimizely.ab.bucketing.FeatureDecision in project java-sdk by optimizely.

the class OptimizelyTest method isFeatureEnabledReturnsTrueButDoesNotSendWhenUserIsBucketedIntoVariationWithoutExperiment.

/**
 * Verify {@link Optimizely#isFeatureEnabled(String, String)} calls into
 * {@link Optimizely#isFeatureEnabled(String, String, Map)} 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 isFeatureEnabledReturnsTrueButDoesNotSendWhenUserIsBucketedIntoVariationWithoutExperiment() 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));
    logbackVerifier.expectMessage(Level.INFO, "The user \"" + genericUserId + "\" is not included in an experiment for feature \"" + validFeatureKey + "\".");
    logbackVerifier.expectMessage(Level.INFO, "Feature \"" + validFeatureKey + "\" is enabled for user \"" + genericUserId + "\"? true");
    eventHandler.expectImpression("3421010877", "variationId", genericUserId);
    verify(mockDecisionService).getVariationForFeature(eq(FEATURE_FLAG_MULTI_VARIATE_FEATURE), eq(optimizely.createUserContext(genericUserId, Collections.emptyMap())), eq(validProjectConfig));
}
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