Search in sources :

Example 66 with Variation

use of com.optimizely.ab.config.Variation in project java-sdk by optimizely.

the class DecisionService method getVariationForFeature.

/**
 * Get the variation the user is bucketed into for the FeatureFlag
 * @param featureFlag The feature flag the user wants to access.
 * @param userId User Identifier
 * @param filteredAttributes A map of filtered attributes.
 * @return {@link FeatureDecision}
 */
@Nonnull
public FeatureDecision getVariationForFeature(@Nonnull FeatureFlag featureFlag, @Nonnull String userId, @Nonnull Map<String, String> filteredAttributes) {
    if (!featureFlag.getExperimentIds().isEmpty()) {
        for (String experimentId : featureFlag.getExperimentIds()) {
            Experiment experiment = projectConfig.getExperimentIdMapping().get(experimentId);
            Variation variation = this.getVariation(experiment, userId, filteredAttributes);
            if (variation != null) {
                return new FeatureDecision(experiment, variation, FeatureDecision.DecisionSource.EXPERIMENT);
            }
        }
    } else {
        logger.info("The feature flag \"{}\" is not used in any experiments.", featureFlag.getKey());
    }
    FeatureDecision featureDecision = getVariationForFeatureInRollout(featureFlag, userId, filteredAttributes);
    if (featureDecision.variation == null) {
        logger.info("The user \"{}\" was not bucketed into a rollout for feature flag \"{}\".", userId, featureFlag.getKey());
    } else {
        logger.info("The user \"{}\" was bucketed into a rollout for feature flag \"{}\".", userId, featureFlag.getKey());
    }
    return featureDecision;
}
Also used : Experiment(com.optimizely.ab.config.Experiment) Variation(com.optimizely.ab.config.Variation) Nonnull(javax.annotation.Nonnull)

Example 67 with Variation

use of com.optimizely.ab.config.Variation in project java-sdk by optimizely.

the class DecisionService method getVariationForFeatureInRollout.

/**
 * Try to bucket the user into a rollout rule.
 * Evaluate the user for rules in priority order by seeing if the user satisfies the audience.
 * Fall back onto the everyone else rule if the user is ever excluded from a rule due to traffic allocation.
 * @param featureFlag The feature flag the user wants to access.
 * @param userId User Identifier
 * @param filteredAttributes A map of filtered attributes.
 * @return {@link FeatureDecision}
 */
@Nonnull
FeatureDecision getVariationForFeatureInRollout(@Nonnull FeatureFlag featureFlag, @Nonnull String userId, @Nonnull Map<String, String> filteredAttributes) {
    // use rollout to get variation for feature
    if (featureFlag.getRolloutId().isEmpty()) {
        logger.info("The feature flag \"{}\" is not used in a rollout.", featureFlag.getKey());
        return new FeatureDecision(null, null, null);
    }
    Rollout rollout = projectConfig.getRolloutIdMapping().get(featureFlag.getRolloutId());
    if (rollout == null) {
        logger.error("The rollout with id \"{}\" was not found in the datafile for feature flag \"{}\".", featureFlag.getRolloutId(), featureFlag.getKey());
        return new FeatureDecision(null, null, null);
    }
    // for all rules before the everyone else rule
    int rolloutRulesLength = rollout.getExperiments().size();
    String bucketingId = userId;
    if (filteredAttributes.containsKey(BUCKETING_ATTRIBUTE)) {
        bucketingId = filteredAttributes.get(BUCKETING_ATTRIBUTE);
    }
    Variation variation;
    for (int i = 0; i < rolloutRulesLength - 1; i++) {
        Experiment rolloutRule = rollout.getExperiments().get(i);
        Audience audience = projectConfig.getAudienceIdMapping().get(rolloutRule.getAudienceIds().get(0));
        if (ExperimentUtils.isUserInExperiment(projectConfig, rolloutRule, filteredAttributes)) {
            variation = bucketer.bucket(rolloutRule, bucketingId);
            if (variation == null) {
                break;
            }
            return new FeatureDecision(rolloutRule, variation, FeatureDecision.DecisionSource.ROLLOUT);
        } else {
            logger.debug("User \"{}\" did not meet the conditions to be in rollout rule for audience \"{}\".", userId, audience.getName());
        }
    }
    // get last rule which is the fall back rule
    Experiment finalRule = rollout.getExperiments().get(rolloutRulesLength - 1);
    if (ExperimentUtils.isUserInExperiment(projectConfig, finalRule, filteredAttributes)) {
        variation = bucketer.bucket(finalRule, bucketingId);
        if (variation != null) {
            return new FeatureDecision(finalRule, variation, FeatureDecision.DecisionSource.ROLLOUT);
        }
    }
    return new FeatureDecision(null, null, null);
}
Also used : Audience(com.optimizely.ab.config.audience.Audience) Experiment(com.optimizely.ab.config.Experiment) Rollout(com.optimizely.ab.config.Rollout) Variation(com.optimizely.ab.config.Variation) Nonnull(javax.annotation.Nonnull)

Example 68 with Variation

use of com.optimizely.ab.config.Variation in project java-sdk by optimizely.

the class DecisionService method getWhitelistedVariation.

/**
 * Get the variation the user has been whitelisted into.
 * @param experiment {@link Experiment} in which user is to be bucketed.
 * @param userId User Identifier
 * @return null if the user is not whitelisted into any variation
 *      {@link Variation} the user is bucketed into if the user has a specified whitelisted variation.
 */
@Nullable
Variation getWhitelistedVariation(@Nonnull Experiment experiment, @Nonnull String userId) {
    // if a user has a forced variation mapping, return the respective variation
    Map<String, String> userIdToVariationKeyMap = experiment.getUserIdToVariationKeyMap();
    if (userIdToVariationKeyMap.containsKey(userId)) {
        String forcedVariationKey = userIdToVariationKeyMap.get(userId);
        Variation forcedVariation = experiment.getVariationKeyToVariationMap().get(forcedVariationKey);
        if (forcedVariation != null) {
            logger.info("User \"{}\" is forced in variation \"{}\".", userId, forcedVariationKey);
        } else {
            logger.error("Variation \"{}\" is not in the datafile. Not activating user \"{}\".", forcedVariationKey, userId);
        }
        return forcedVariation;
    }
    return null;
}
Also used : Variation(com.optimizely.ab.config.Variation) Nullable(javax.annotation.Nullable)

Example 69 with Variation

use of com.optimizely.ab.config.Variation in project java-sdk by optimizely.

the class JsonConfigParser method parseExperiments.

private List<Experiment> parseExperiments(JSONArray experimentJson, String groupId) {
    List<Experiment> experiments = new ArrayList<Experiment>(experimentJson.length());
    for (Object obj : experimentJson) {
        JSONObject experimentObject = (JSONObject) obj;
        String id = experimentObject.getString("id");
        String key = experimentObject.getString("key");
        String status = experimentObject.isNull("status") ? ExperimentStatus.NOT_STARTED.toString() : experimentObject.getString("status");
        String layerId = experimentObject.has("layerId") ? experimentObject.getString("layerId") : null;
        JSONArray audienceIdsJson = experimentObject.getJSONArray("audienceIds");
        List<String> audienceIds = new ArrayList<String>(audienceIdsJson.length());
        for (Object audienceIdObj : audienceIdsJson) {
            audienceIds.add((String) audienceIdObj);
        }
        // parse the child objects
        List<Variation> variations = parseVariations(experimentObject.getJSONArray("variations"));
        Map<String, String> userIdToVariationKeyMap = parseForcedVariations(experimentObject.getJSONObject("forcedVariations"));
        List<TrafficAllocation> trafficAllocations = parseTrafficAllocation(experimentObject.getJSONArray("trafficAllocation"));
        experiments.add(new Experiment(id, key, status, layerId, audienceIds, variations, userIdToVariationKeyMap, trafficAllocations, groupId));
    }
    return experiments;
}
Also used : Experiment(com.optimizely.ab.config.Experiment) ArrayList(java.util.ArrayList) JSONArray(org.json.JSONArray) JSONObject(org.json.JSONObject) TrafficAllocation(com.optimizely.ab.config.TrafficAllocation) JSONObject(org.json.JSONObject) Variation(com.optimizely.ab.config.Variation)

Example 70 with Variation

use of com.optimizely.ab.config.Variation in project java-sdk by optimizely.

the class OptimizelyTest method removeNotificationListenerNotificationCenter.

/**
 * Verify that {@link com.optimizely.ab.notification.NotificationCenter} properly
 * calls and the listener is removed and no longer notified when an experiment is activated.
 */
@Test
public void removeNotificationListenerNotificationCenter() throws Exception {
    Experiment activatedExperiment = validProjectConfig.getExperiments().get(0);
    Variation bucketedVariation = activatedExperiment.getVariations().get(0);
    EventBuilder mockEventBuilder = mock(EventBuilder.class);
    Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler).withBucketing(mockBucketer).withEventBuilder(mockEventBuilder).withConfig(validProjectConfig).withErrorHandler(mockErrorHandler).build();
    Map<String, String> attributes = new HashMap<String, String>();
    attributes.put(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE);
    Map<String, String> testParams = new HashMap<String, String>();
    testParams.put("test", "params");
    LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, "");
    when(mockEventBuilder.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, genericUserId, attributes)).thenReturn(logEventToDispatch);
    when(mockBucketer.bucket(activatedExperiment, genericUserId)).thenReturn(bucketedVariation);
    when(mockEventBuilder.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, genericUserId, attributes)).thenReturn(logEventToDispatch);
    // Add and remove listener
    ActivateNotificationListener activateNotification = mock(ActivateNotificationListener.class);
    int notificationId = optimizely.notificationCenter.addNotificationListener(NotificationCenter.NotificationType.Activate, activateNotification);
    assertTrue(optimizely.notificationCenter.removeNotificationListener(notificationId));
    TrackNotificationListener trackNotification = mock(TrackNotificationListener.class);
    notificationId = optimizely.notificationCenter.addNotificationListener(NotificationCenter.NotificationType.Track, trackNotification);
    assertTrue(optimizely.notificationCenter.removeNotificationListener(notificationId));
    // Check if listener is notified after an experiment is activated
    Variation actualVariation = optimizely.activate(activatedExperiment, genericUserId, attributes);
    verify(activateNotification, never()).onActivate(activatedExperiment, genericUserId, attributes, actualVariation, logEventToDispatch);
    // Check if listener is notified after a live variable is accessed
    boolean activateExperiment = true;
    verify(activateNotification, never()).onActivate(activatedExperiment, genericUserId, attributes, actualVariation, logEventToDispatch);
    // Check if listener is notified after an event is tracked
    EventType eventType = validProjectConfig.getEventTypes().get(0);
    String eventKey = eventType.getKey();
    Map<Experiment, Variation> experimentVariationMap = createExperimentVariationMap(validProjectConfig, mockDecisionService, eventType.getKey(), genericUserId, attributes);
    when(mockEventBuilder.createConversionEvent(eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), eq(eventType.getId()), eq(eventKey), eq(attributes), anyMapOf(String.class, Object.class))).thenReturn(logEventToDispatch);
    optimizely.track(eventKey, genericUserId, attributes);
    verify(trackNotification, never()).onTrack(eventKey, genericUserId, attributes, Collections.EMPTY_MAP, logEventToDispatch);
}
Also used : HashMap(java.util.HashMap) LogEvent(com.optimizely.ab.event.LogEvent) EventType(com.optimizely.ab.config.EventType) Experiment(com.optimizely.ab.config.Experiment) Matchers.anyString(org.mockito.Matchers.anyString) EventBuilder(com.optimizely.ab.event.internal.EventBuilder) TrackNotificationListener(com.optimizely.ab.notification.TrackNotificationListener) ActivateNotificationListener(com.optimizely.ab.notification.ActivateNotificationListener) Variation(com.optimizely.ab.config.Variation) Test(org.junit.Test)

Aggregations

Variation (com.optimizely.ab.config.Variation)99 Experiment (com.optimizely.ab.config.Experiment)91 Test (org.junit.Test)81 Matchers.anyString (org.mockito.Matchers.anyString)50 LogEvent (com.optimizely.ab.event.LogEvent)44 HashMap (java.util.HashMap)42 EventBuilder (com.optimizely.ab.event.internal.EventBuilder)25 EventType (com.optimizely.ab.config.EventType)22 Map (java.util.Map)18 ImmutableMap (com.google.common.collect.ImmutableMap)15 EventBuilderTest.createExperimentVariationMap (com.optimizely.ab.event.internal.EventBuilderTest.createExperimentVariationMap)15 Attribute (com.optimizely.ab.config.Attribute)13 EventBatch (com.optimizely.ab.event.internal.payload.EventBatch)12 ArrayList (java.util.ArrayList)10 Bucketer (com.optimizely.ab.bucketing.Bucketer)9 ProjectConfig (com.optimizely.ab.config.ProjectConfig)9 TrafficAllocation (com.optimizely.ab.config.TrafficAllocation)8 Rollout (com.optimizely.ab.config.Rollout)7 NoOpErrorHandler (com.optimizely.ab.error.NoOpErrorHandler)7 SuppressFBWarnings (edu.umd.cs.findbugs.annotations.SuppressFBWarnings)7