|
99 | 99 | import static com.optimizely.ab.config.ValidProjectConfigV4.VARIABLE_INTEGER_VARIABLE_KEY;
|
100 | 100 | import static com.optimizely.ab.config.ValidProjectConfigV4.VARIATION_MULTIVARIATE_EXPERIMENT_GRED;
|
101 | 101 | import static com.optimizely.ab.config.ValidProjectConfigV4.VARIATION_MULTIVARIATE_EXPERIMENT_GRED_KEY;
|
| 102 | +import static com.optimizely.ab.config.ValidProjectConfigV4.EXPERIMENT_DOUBLE_FEATURE_EXPERIMENT_KEY; |
102 | 103 | import static com.optimizely.ab.event.LogEvent.RequestMethod;
|
103 | 104 | import static com.optimizely.ab.event.internal.EventBuilderTest.createExperimentVariationMap;
|
104 | 105 | import static java.util.Arrays.asList;
|
@@ -3439,7 +3440,7 @@ public void isFeatureEnabledReturnsTrueButDoesNotSendWhenUserIsBucketedIntoVaria
|
3439 | 3440 | // Should be an experiment from the rollout associated with the feature, but for this test
|
3440 | 3441 | // it doesn't matter. Just use any valid experiment.
|
3441 | 3442 | Experiment experiment = validProjectConfig.getRolloutIdMapping().get(ROLLOUT_2_ID).getExperiments().get(0);
|
3442 |
| - Variation variation = new Variation("variationId", "variationKey"); |
| 3443 | + Variation variation = new Variation("variationId", "variationKey", true, null); |
3443 | 3444 | FeatureDecision featureDecision = new FeatureDecision(experiment, variation, FeatureDecision.DecisionSource.ROLLOUT);
|
3444 | 3445 | doReturn(featureDecision).when(mockDecisionService).getVariationForFeature(
|
3445 | 3446 | eq(FEATURE_FLAG_MULTI_VARIATE_FEATURE),
|
@@ -3472,6 +3473,117 @@ public void isFeatureEnabledReturnsTrueButDoesNotSendWhenUserIsBucketedIntoVaria
|
3472 | 3473 | verify(mockEventHandler, never()).dispatchEvent(any(LogEvent.class));
|
3473 | 3474 | }
|
3474 | 3475 |
|
| 3476 | + /** |
| 3477 | + * Verify that the {@link Optimizely#activate(String, String, Map<String, String>)} call |
| 3478 | + * uses forced variation to force the user into the third variation in which FeatureEnabled is set to |
| 3479 | + * false so feature enabled will return false |
| 3480 | + */ |
| 3481 | + @Test |
| 3482 | + public void isFeatureEnabledWithExperimentKeyForcedOfFeatureEnabledFalse() throws Exception { |
| 3483 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 3484 | + Experiment activatedExperiment = validProjectConfig.getExperimentKeyMapping().get(EXPERIMENT_MULTIVARIATE_EXPERIMENT_KEY); |
| 3485 | + Variation forcedVariation = activatedExperiment.getVariations().get(2); |
| 3486 | + EventBuilder mockEventBuilder = mock(EventBuilder.class); |
| 3487 | + |
| 3488 | + Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) |
| 3489 | + .withBucketing(mockBucketer) |
| 3490 | + .withEventBuilder(mockEventBuilder) |
| 3491 | + .withConfig(validProjectConfig) |
| 3492 | + .withErrorHandler(mockErrorHandler) |
| 3493 | + .build(); |
| 3494 | + |
| 3495 | + optimizely.setForcedVariation(activatedExperiment.getKey(), testUserId, forcedVariation.getKey() ); |
| 3496 | + assertFalse(optimizely.isFeatureEnabled(FEATURE_FLAG_MULTI_VARIATE_FEATURE.getKey(), testUserId)); |
| 3497 | + } |
| 3498 | + |
| 3499 | + /** |
| 3500 | + * Verify that the {@link Optimizely#activate(String, String, Map<String, String>)} call |
| 3501 | + * uses forced variation to force the user into the second variation in which FeatureEnabled is not set |
| 3502 | + * feature enabled will return false by default |
| 3503 | + */ |
| 3504 | + @Test |
| 3505 | + public void isFeatureEnabledWithExperimentKeyForcedWithNoFeatureEnabledSet() throws Exception { |
| 3506 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 3507 | + Experiment activatedExperiment = validProjectConfig.getExperimentKeyMapping().get(EXPERIMENT_DOUBLE_FEATURE_EXPERIMENT_KEY); |
| 3508 | + Variation forcedVariation = activatedExperiment.getVariations().get(1); |
| 3509 | + EventBuilder mockEventBuilder = mock(EventBuilder.class); |
| 3510 | + |
| 3511 | + Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) |
| 3512 | + .withBucketing(mockBucketer) |
| 3513 | + .withEventBuilder(mockEventBuilder) |
| 3514 | + .withConfig(validProjectConfig) |
| 3515 | + .withErrorHandler(mockErrorHandler) |
| 3516 | + .build(); |
| 3517 | + |
| 3518 | + optimizely.setForcedVariation(activatedExperiment.getKey(), testUserId, forcedVariation.getKey() ); |
| 3519 | + assertFalse(optimizely.isFeatureEnabled(FEATURE_SINGLE_VARIABLE_DOUBLE_KEY, testUserId)); |
| 3520 | + } |
| 3521 | + |
| 3522 | + /** |
| 3523 | + * Verify {@link Optimizely#isFeatureEnabled(String, String)} calls into |
| 3524 | + * {@link Optimizely#isFeatureEnabled(String, String, Map)} sending FeatureEnabled true and they both |
| 3525 | + * return True when the user is bucketed into a variation for the feature. |
| 3526 | + * An impression event should not be dispatched since the user was not bucketed into an Experiment. |
| 3527 | + * @throws Exception |
| 3528 | + */ |
| 3529 | + @Test |
| 3530 | + public void isFeatureEnabledTrueWhenFeatureEnabledOfVariationIsTrue() throws Exception{ |
| 3531 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 3532 | + |
| 3533 | + String validFeatureKey = FEATURE_MULTI_VARIATE_FEATURE_KEY; |
| 3534 | + |
| 3535 | + Optimizely spyOptimizely = spy(Optimizely.builder(validDatafile, mockEventHandler) |
| 3536 | + .withConfig(validProjectConfig) |
| 3537 | + .withDecisionService(mockDecisionService) |
| 3538 | + .build()); |
| 3539 | + // Should be an experiment from the rollout associated with the feature, but for this test |
| 3540 | + // it doesn't matter. Just use any valid experiment. |
| 3541 | + Experiment experiment = validProjectConfig.getRolloutIdMapping().get(ROLLOUT_2_ID).getExperiments().get(0); |
| 3542 | + Variation variation = new Variation("variationId", "variationKey", true, null); |
| 3543 | + FeatureDecision featureDecision = new FeatureDecision(experiment, variation, FeatureDecision.DecisionSource.ROLLOUT); |
| 3544 | + doReturn(featureDecision).when(mockDecisionService).getVariationForFeature( |
| 3545 | + eq(FEATURE_FLAG_MULTI_VARIATE_FEATURE), |
| 3546 | + eq(genericUserId), |
| 3547 | + eq(Collections.<String, String>emptyMap()) |
| 3548 | + ); |
| 3549 | + |
| 3550 | + assertTrue(spyOptimizely.isFeatureEnabled(validFeatureKey, genericUserId)); |
| 3551 | + |
| 3552 | + } |
| 3553 | + |
| 3554 | + |
| 3555 | + /** |
| 3556 | + * Verify {@link Optimizely#isFeatureEnabled(String, String)} calls into |
| 3557 | + * {@link Optimizely#isFeatureEnabled(String, String, Map)} sending FeatureEnabled false because of which and they both |
| 3558 | + * return false even when the user is bucketed into a variation for the feature. |
| 3559 | + * An impression event should not be dispatched since the user was not bucketed into an Experiment. |
| 3560 | + * @throws Exception |
| 3561 | + */ |
| 3562 | + @Test |
| 3563 | + public void isFeatureEnabledFalseWhenFeatureEnabledOfVariationIsFalse() throws Exception{ |
| 3564 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 3565 | + |
| 3566 | + String validFeatureKey = FEATURE_MULTI_VARIATE_FEATURE_KEY; |
| 3567 | + |
| 3568 | + Optimizely spyOptimizely = spy(Optimizely.builder(validDatafile, mockEventHandler) |
| 3569 | + .withConfig(validProjectConfig) |
| 3570 | + .withDecisionService(mockDecisionService) |
| 3571 | + .build()); |
| 3572 | + // Should be an experiment from the rollout associated with the feature, but for this test |
| 3573 | + // it doesn't matter. Just use any valid experiment. |
| 3574 | + Experiment experiment = validProjectConfig.getRolloutIdMapping().get(ROLLOUT_2_ID).getExperiments().get(0); |
| 3575 | + Variation variation = new Variation("variationId", "variationKey", false, null); |
| 3576 | + FeatureDecision featureDecision = new FeatureDecision(experiment, variation, FeatureDecision.DecisionSource.ROLLOUT); |
| 3577 | + doReturn(featureDecision).when(mockDecisionService).getVariationForFeature( |
| 3578 | + eq(FEATURE_FLAG_MULTI_VARIATE_FEATURE), |
| 3579 | + eq(genericUserId), |
| 3580 | + eq(Collections.<String, String>emptyMap()) |
| 3581 | + ); |
| 3582 | + |
| 3583 | + assertFalse(spyOptimizely.isFeatureEnabled(validFeatureKey, genericUserId)); |
| 3584 | + |
| 3585 | + } |
| 3586 | + |
3475 | 3587 | /** Integration Test
|
3476 | 3588 | * Verify {@link Optimizely#isFeatureEnabled(String, String, Map)}
|
3477 | 3589 | * returns True
|
@@ -3503,6 +3615,69 @@ public void isFeatureEnabledReturnsTrueAndDispatchesEventWhenUserIsBucketedIntoA
|
3503 | 3615 | verify(mockEventHandler, times(1)).dispatchEvent(any(LogEvent.class));
|
3504 | 3616 | }
|
3505 | 3617 |
|
| 3618 | + /** |
| 3619 | + * Verify {@link Optimizely#getEnabledFeatures(String, Map)} calls into |
| 3620 | + * {@link Optimizely#isFeatureEnabled(String, String, Map)} for each featureFlag |
| 3621 | + * return List of FeatureFlags that are enabled |
| 3622 | + */ |
| 3623 | + @Test |
| 3624 | + public void getEnabledFeatureWithValidUserId() throws ConfigParseException{ |
| 3625 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 3626 | + |
| 3627 | + Optimizely spyOptimizely = spy(Optimizely.builder(validDatafile, mockEventHandler) |
| 3628 | + .withConfig(validProjectConfig) |
| 3629 | + .build()); |
| 3630 | + ArrayList<String> featureFlags = (ArrayList<String>) spyOptimizely.getEnabledFeatures(genericUserId, |
| 3631 | + new HashMap<String, String>()); |
| 3632 | + assertFalse(featureFlags.isEmpty()); |
| 3633 | + |
| 3634 | + } |
| 3635 | + |
| 3636 | + |
| 3637 | + /** |
| 3638 | + * Verify {@link Optimizely#getEnabledFeatures(String, Map)} calls into |
| 3639 | + * {@link Optimizely#isFeatureEnabled(String, String, Map)} for each featureFlag sending |
| 3640 | + * userId as empty string |
| 3641 | + * return empty List of FeatureFlags without checking further. |
| 3642 | + */ |
| 3643 | + @Test |
| 3644 | + public void getEnabledFeatureWithEmptyUserId() throws ConfigParseException{ |
| 3645 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 3646 | + |
| 3647 | + Optimizely spyOptimizely = spy(Optimizely.builder(validDatafile, mockEventHandler) |
| 3648 | + .withConfig(validProjectConfig) |
| 3649 | + .build()); |
| 3650 | + ArrayList<String> featureFlags = (ArrayList<String>) spyOptimizely.getEnabledFeatures("", |
| 3651 | + new HashMap<String, String>()); |
| 3652 | + logbackVerifier.expectMessage(Level.ERROR, "Non-empty user ID required"); |
| 3653 | + assertTrue(featureFlags.isEmpty()); |
| 3654 | + |
| 3655 | + } |
| 3656 | + |
| 3657 | + /** |
| 3658 | + * Verify {@link Optimizely#getEnabledFeatures(String, Map)} calls into |
| 3659 | + * {@link Optimizely#isFeatureEnabled(String, String, Map)} for each featureFlag sending |
| 3660 | + * userId and emptyMap and Mocked {@link Optimizely#isFeatureEnabled(String, String, Map)} |
| 3661 | + * to return false so {@link Optimizely#getEnabledFeatures(String, Map)} will |
| 3662 | + * return empty List of FeatureFlags. |
| 3663 | + */ |
| 3664 | + @Test |
| 3665 | + public void getEnabledFeatureWithMockIsFeatureEnabledToReturnFalse() throws ConfigParseException{ |
| 3666 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 3667 | + |
| 3668 | + Optimizely spyOptimizely = spy(Optimizely.builder(validDatafile, mockEventHandler) |
| 3669 | + .withConfig(validProjectConfig) |
| 3670 | + .build()); |
| 3671 | + doReturn(false).when(spyOptimizely).isFeatureEnabled( |
| 3672 | + any(String.class), |
| 3673 | + eq(genericUserId), |
| 3674 | + eq(Collections.<String, String>emptyMap()) |
| 3675 | + ); |
| 3676 | + ArrayList<String> featureFlags = (ArrayList<String>) spyOptimizely.getEnabledFeatures(genericUserId, |
| 3677 | + Collections.<String, String>emptyMap()); |
| 3678 | + assertTrue(featureFlags.isEmpty()); |
| 3679 | + } |
| 3680 | + |
3506 | 3681 | /**
|
3507 | 3682 | * Verify {@link Optimizely#getFeatureVariableString(String, String, String)}
|
3508 | 3683 | * calls through to {@link Optimizely#getFeatureVariableString(String, String, String, Map)}
|
|
0 commit comments