Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core-api/src/main/java/com/optimizely/ab/Optimizely.java
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ <T extends Object> T getFeatureVariableValueForType(@Nonnull String featureKey,

Object convertedValue = convertStringToType(variableValue, variableType);

DecisionNotification decisionNotification = DecisionNotification.newFeatureVariableBuilder()
DecisionNotification decisionNotification = DecisionNotification.newFeatureVariableDecisionNotificationBuilder()
.withUserId(userId)
.withAttributes(copiedAttributes)
.withFeatureKey(featureKey)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.optimizely.ab.notification;


import com.optimizely.ab.OptimizelyRuntimeException;
import com.optimizely.ab.bucketing.FeatureDecision;
import com.optimizely.ab.config.FeatureVariable;
import com.optimizely.ab.config.Variation;
Expand All @@ -26,9 +27,20 @@
import java.util.HashMap;
import java.util.Map;

import static com.optimizely.ab.notification.DecisionNotification.ExperimentDecisionNotificationBuilder.EXPERIMENT_KEY;
import static com.optimizely.ab.notification.DecisionNotification.ExperimentDecisionNotificationBuilder.VARIATION_KEY;

/**
* DecisionNotification encapsulates the arguments and responses when using the following methods:
*
* activate {@link com.optimizely.ab.Optimizely#activate}
* getEnabledFeatures {@link com.optimizely.ab.Optimizely#getEnabledFeatures}
* getFeatureVariableBoolean {@link com.optimizely.ab.Optimizely#getFeatureVariableBoolean}
* getFeatureVariableDouble {@link com.optimizely.ab.Optimizely#getFeatureVariableDouble}
* getFeatureVariableInteger {@link com.optimizely.ab.Optimizely#getFeatureVariableInteger}
* getFeatureVariableString {@link com.optimizely.ab.Optimizely#getFeatureVariableString}
* getVariation {@link com.optimizely.ab.Optimizely#getVariation}
* isFeatureEnabled {@link com.optimizely.ab.Optimizely#isFeatureEnabled}
*
* @see <a href="https://docs.developers.optimizely.com/full-stack/docs/register-notification-listeners">Notification Listeners</a>
*/
public final class DecisionNotification {
protected String type;
protected String userId;
Expand Down Expand Up @@ -108,6 +120,14 @@ public ExperimentDecisionNotificationBuilder withVariation(Variation variation)
}

public DecisionNotification build() {
if (type == null) {
throw new OptimizelyRuntimeException("type not set");
}

if (experimentKey == null) {
throw new OptimizelyRuntimeException("experimentKey not set");
}

decisionInfo = new HashMap<>();
decisionInfo.put(EXPERIMENT_KEY, experimentKey);
decisionInfo.put(VARIATION_KEY, variation != null ? variation.getKey() : null);
Expand Down Expand Up @@ -169,11 +189,22 @@ public FeatureDecisionNotificationBuilder withFeatureEnabled(Boolean featureEnab
}

public DecisionNotification build() {
if (source == null) {
throw new OptimizelyRuntimeException("source not set");
}

if (featureKey == null) {
throw new OptimizelyRuntimeException("featureKey not set");
}

if (featureEnabled == null) {
throw new OptimizelyRuntimeException("featureEnabled not set");
}

decisionInfo = new HashMap<>();
decisionInfo.put(FEATURE_KEY, featureKey);
decisionInfo.put(FEATURE_ENABLED, featureEnabled);
decisionInfo.put(SOURCE, source.toString());

decisionInfo.put(SOURCE_INFO, sourceInfo.get());

return new DecisionNotification(
Expand All @@ -184,7 +215,7 @@ public DecisionNotification build() {
}
}

public static FeatureVariableDecisionNotificationBuilder newFeatureVariableBuilder() {
public static FeatureVariableDecisionNotificationBuilder newFeatureVariableDecisionNotificationBuilder() {
return new FeatureVariableDecisionNotificationBuilder();
}

Expand Down Expand Up @@ -252,6 +283,22 @@ public FeatureVariableDecisionNotificationBuilder withVariableValue(Object varia
}

public DecisionNotification build() {
if (featureKey == null) {
throw new OptimizelyRuntimeException("featureKey not set");
}

if (featureEnabled == null) {
throw new OptimizelyRuntimeException("featureEnabled not set");
}

if (variableKey == null) {
throw new OptimizelyRuntimeException("variableKey not set");
}

if (variableType == null) {
throw new OptimizelyRuntimeException("variableType not set");
}

decisionInfo = new HashMap<>();
decisionInfo.put(FEATURE_KEY, featureKey);
decisionInfo.put(FEATURE_ENABLED, featureEnabled);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/**
*
* Copyright 2019, Optimizely and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.optimizely.ab.notification;

import com.optimizely.ab.OptimizelyRuntimeException;
import com.optimizely.ab.bucketing.FeatureDecision;
import com.optimizely.ab.config.FeatureVariable;
import com.optimizely.ab.config.Variation;
import org.junit.Before;
import org.junit.Test;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;

public class DecisionNotificationTest {

private static final Boolean FEATURE_ENABLED = Boolean.FALSE;
private static final String EXPERIMENT_KEY = "experimentKey";
private static final String FEATURE_KEY = "featureKey";
private static final String FEATURE_VARIABLE_KEY = "featureVariableKey";
private static final String USER_ID = "userID";
private static final Map<String, String> USER_ATTRIBUTES = Collections.singletonMap("user", "attr");
private static final RolloutSourceInfo rolloutSourceInfo = mock(RolloutSourceInfo.class);
private static final Variation VARIATION = mock(Variation.class);

private DecisionNotification experimentDecisionNotification;
private DecisionNotification featureDecisionNotification;
private DecisionNotification featureVariableDecisionNotification;

@Before
public void setUp() {
experimentDecisionNotification = DecisionNotification.newExperimentDecisionNotificationBuilder()
.withUserId(USER_ID)
.withAttributes(USER_ATTRIBUTES)
.withExperimentKey(EXPERIMENT_KEY)
.withVariation(VARIATION)
.withType(NotificationCenter.DecisionNotificationType.AB_TEST.toString())
.build();
featureDecisionNotification = DecisionNotification.newFeatureDecisionNotificationBuilder()
.withUserId(USER_ID)
.withFeatureKey(FEATURE_KEY)
.withFeatureEnabled(FEATURE_ENABLED)
.withSource(FeatureDecision.DecisionSource.ROLLOUT)
.withAttributes(USER_ATTRIBUTES)
.withSourceInfo(rolloutSourceInfo)
.build();
featureVariableDecisionNotification = DecisionNotification.newFeatureVariableDecisionNotificationBuilder()
.withUserId(USER_ID)
.withFeatureKey(FEATURE_KEY)
.withFeatureEnabled(Boolean.TRUE)
.withVariableKey(FEATURE_VARIABLE_KEY)
.withVariableType(FeatureVariable.VariableType.STRING)
.withAttributes(USER_ATTRIBUTES)
.build();
}

@Test
public void testGetType() {
assertEquals(NotificationCenter.DecisionNotificationType.AB_TEST.toString(), experimentDecisionNotification.getType());
assertEquals(NotificationCenter.DecisionNotificationType.FEATURE.toString(), featureDecisionNotification.getType());
assertEquals(NotificationCenter.DecisionNotificationType.FEATURE_VARIABLE.toString(), featureVariableDecisionNotification.getType());
}

@Test
public void testGetUserId() {
assertEquals(USER_ID, experimentDecisionNotification.getUserId());
assertEquals(USER_ID, featureDecisionNotification.getUserId());
assertEquals(USER_ID, featureVariableDecisionNotification.getUserId());
}

@Test
public void testGetAttributes() {
assertEquals(USER_ATTRIBUTES, experimentDecisionNotification.getAttributes());
assertEquals(USER_ATTRIBUTES, featureDecisionNotification.getAttributes());
assertEquals(USER_ATTRIBUTES, featureVariableDecisionNotification.getAttributes());
}

@Test
public void testGetDecisionInfo() {
// Assert for Experiment's DecisionInfo
HashMap<String, String> expectedExperimentDecisionInfo = new HashMap<>();
expectedExperimentDecisionInfo.put(DecisionNotification.ExperimentDecisionNotificationBuilder.EXPERIMENT_KEY, EXPERIMENT_KEY);
expectedExperimentDecisionInfo.put(DecisionNotification.ExperimentDecisionNotificationBuilder.VARIATION_KEY, VARIATION.getKey());
assertEquals(expectedExperimentDecisionInfo, experimentDecisionNotification.getDecisionInfo());

// Assert for Feature's DecisionInfo
Map<String, ?> actualFeatureDecisionInfo = featureDecisionNotification.getDecisionInfo();
assertFalse((Boolean) actualFeatureDecisionInfo.get(DecisionNotification.FeatureDecisionNotificationBuilder.FEATURE_ENABLED));
assertEquals(FEATURE_KEY, actualFeatureDecisionInfo.get(DecisionNotification.FeatureDecisionNotificationBuilder.FEATURE_KEY));
assertEquals(FeatureDecision.DecisionSource.ROLLOUT.toString(), actualFeatureDecisionInfo.get(DecisionNotification.FeatureDecisionNotificationBuilder.SOURCE));
assertEquals(rolloutSourceInfo.get(), actualFeatureDecisionInfo.get(DecisionNotification.FeatureDecisionNotificationBuilder.SOURCE_INFO));

// Assert for Feature Variable's DecisionInfo
Map<String, ?> actualFeatureVariableDecisionInfo = featureVariableDecisionNotification.getDecisionInfo();
assertTrue((Boolean) actualFeatureVariableDecisionInfo.get(DecisionNotification.FeatureVariableDecisionNotificationBuilder.FEATURE_ENABLED));
assertEquals(FEATURE_KEY, actualFeatureVariableDecisionInfo.get(DecisionNotification.FeatureVariableDecisionNotificationBuilder.FEATURE_KEY));
assertEquals(FEATURE_VARIABLE_KEY, actualFeatureVariableDecisionInfo.get(DecisionNotification.FeatureVariableDecisionNotificationBuilder.VARIABLE_KEY));
assertEquals(FeatureVariable.VariableType.STRING, actualFeatureVariableDecisionInfo.get(DecisionNotification.FeatureVariableDecisionNotificationBuilder.VARIABLE_TYPE));
assertEquals(FeatureDecision.DecisionSource.ROLLOUT.toString(), actualFeatureVariableDecisionInfo.get(DecisionNotification.FeatureVariableDecisionNotificationBuilder.SOURCE));
assertEquals(rolloutSourceInfo.get(), actualFeatureVariableDecisionInfo.get(DecisionNotification.FeatureVariableDecisionNotificationBuilder.SOURCE_INFO));
}

@Test(expected = OptimizelyRuntimeException.class)
public void nullTypeFailsExperimentNotificationBuild() {
DecisionNotification.newExperimentDecisionNotificationBuilder()
.withExperimentKey(EXPERIMENT_KEY)
.build();
}

@Test(expected = OptimizelyRuntimeException.class)
public void nullExperimentKeyFailsExperimentNotificationBuild() {
DecisionNotification.newExperimentDecisionNotificationBuilder()
.withType(NotificationCenter.DecisionNotificationType.AB_TEST.toString())
.build();
}

@Test(expected = OptimizelyRuntimeException.class)
public void nullSourceFailsFeatureNotificationBuild() {
DecisionNotification.newFeatureDecisionNotificationBuilder()
.withFeatureKey(FEATURE_KEY)
.withFeatureEnabled(FEATURE_ENABLED)
.build();
}

@Test(expected = OptimizelyRuntimeException.class)
public void nullFeatureKeyFailsFeatureNotificationBuild() {
DecisionNotification.newFeatureDecisionNotificationBuilder()
.withFeatureEnabled(FEATURE_ENABLED)
.withSource(FeatureDecision.DecisionSource.ROLLOUT)
.build();
}

@Test(expected = OptimizelyRuntimeException.class)
public void nullFeatureEnabledFailsFeatureNotificationBuild() {
DecisionNotification.newFeatureDecisionNotificationBuilder()
.withFeatureKey(FEATURE_KEY)
.withSource(FeatureDecision.DecisionSource.ROLLOUT)
.build();
}

@Test(expected = OptimizelyRuntimeException.class)
public void nullFeatureKeyFailsFeatureVariableNotificationBuild() {
DecisionNotification.newFeatureVariableDecisionNotificationBuilder()
.withFeatureEnabled(Boolean.TRUE)
.withVariableKey(FEATURE_VARIABLE_KEY)
.withVariableType(FeatureVariable.VariableType.STRING)
.build();
}

@Test(expected = OptimizelyRuntimeException.class)
public void nullFeatureEnabledFailsFeatureVariableNotificationBuild() {
DecisionNotification.newFeatureVariableDecisionNotificationBuilder()
.withFeatureKey(FEATURE_KEY)
.withVariableKey(FEATURE_VARIABLE_KEY)
.withVariableType(FeatureVariable.VariableType.STRING)
.build();
}

@Test(expected = OptimizelyRuntimeException.class)
public void nullVariableKeyFailsFeatureVariableNotificationBuild() {
DecisionNotification.newFeatureVariableDecisionNotificationBuilder()
.withFeatureKey(FEATURE_KEY)
.withFeatureEnabled(Boolean.TRUE)
.withVariableType(FeatureVariable.VariableType.STRING)
.build();
}

@Test(expected = OptimizelyRuntimeException.class)
public void nullVariableTypeFailsFeatureVariableNotificationBuild() {
DecisionNotification.newFeatureVariableDecisionNotificationBuilder()
.withFeatureKey(FEATURE_KEY)
.withFeatureEnabled(Boolean.TRUE)
.withVariableKey(FEATURE_VARIABLE_KEY)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
*
* Copyright 2019, Optimizely and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.optimizely.ab.notification;

import org.junit.Before;
import org.junit.Test;

import java.util.HashMap;

import static org.junit.Assert.assertEquals;

public class FeatureTestSourceInfoTest {

private static final String EXPERIMENT_KEY = "featureTestKey";
private static final String VARIATION_KEY = "featureTestVariationKey";

private FeatureTestSourceInfo featureSourceInfo;

@Before
public void setUp() {
featureSourceInfo = new FeatureTestSourceInfo(EXPERIMENT_KEY, VARIATION_KEY);
}

@Test
public void testGet() {
HashMap<String, String> expectedSourceInfo = new HashMap<>();
expectedSourceInfo.put("experimentKey", EXPERIMENT_KEY);
expectedSourceInfo.put("variationKey", VARIATION_KEY);

assertEquals(expectedSourceInfo, featureSourceInfo.get());
}
}
Loading