diff --git a/core-api/src/main/java/com/optimizely/ab/Optimizely.java b/core-api/src/main/java/com/optimizely/ab/Optimizely.java index 0e260072e..4f942ff69 100644 --- a/core-api/src/main/java/com/optimizely/ab/Optimizely.java +++ b/core-api/src/main/java/com/optimizely/ab/Optimizely.java @@ -20,44 +20,80 @@ import com.optimizely.ab.bucketing.DecisionService; import com.optimizely.ab.bucketing.FeatureDecision; import com.optimizely.ab.bucketing.UserProfileService; -import com.optimizely.ab.config.*; +import com.optimizely.ab.config.AtomicProjectConfigManager; +import com.optimizely.ab.config.DatafileProjectConfig; +import com.optimizely.ab.config.EventType; +import com.optimizely.ab.config.Experiment; +import com.optimizely.ab.config.FeatureFlag; +import com.optimizely.ab.config.FeatureVariable; +import com.optimizely.ab.config.FeatureVariableUsageInstance; +import com.optimizely.ab.config.ProjectConfig; +import com.optimizely.ab.config.ProjectConfigManager; +import com.optimizely.ab.config.Variation; import com.optimizely.ab.config.parser.ConfigParseException; import com.optimizely.ab.error.ErrorHandler; import com.optimizely.ab.error.NoOpErrorHandler; -import com.optimizely.ab.event.*; -import com.optimizely.ab.event.internal.*; +import com.optimizely.ab.event.EventHandler; +import com.optimizely.ab.event.EventProcessor; +import com.optimizely.ab.event.ForwardingEventProcessor; +import com.optimizely.ab.event.LogEvent; +import com.optimizely.ab.event.NoopEventHandler; +import com.optimizely.ab.event.internal.BuildVersionInfo; +import com.optimizely.ab.event.internal.ClientEngineInfo; +import com.optimizely.ab.event.internal.EventFactory; +import com.optimizely.ab.event.internal.UserEvent; +import com.optimizely.ab.event.internal.UserEventFactory; import com.optimizely.ab.event.internal.payload.EventBatch; import com.optimizely.ab.internal.NotificationRegistry; -import com.optimizely.ab.notification.*; -import com.optimizely.ab.odp.*; +import com.optimizely.ab.notification.ActivateNotification; +import com.optimizely.ab.notification.DecisionNotification; +import com.optimizely.ab.notification.FeatureTestSourceInfo; +import com.optimizely.ab.notification.NotificationCenter; +import com.optimizely.ab.notification.NotificationHandler; +import com.optimizely.ab.notification.RolloutSourceInfo; +import com.optimizely.ab.notification.SourceInfo; +import com.optimizely.ab.notification.TrackNotification; +import com.optimizely.ab.notification.UpdateConfigNotification; +import com.optimizely.ab.odp.ODPEvent; +import com.optimizely.ab.odp.ODPManager; +import com.optimizely.ab.odp.ODPSegmentManager; +import com.optimizely.ab.odp.ODPSegmentOption; import com.optimizely.ab.optimizelyconfig.OptimizelyConfig; import com.optimizely.ab.optimizelyconfig.OptimizelyConfigManager; import com.optimizely.ab.optimizelyconfig.OptimizelyConfigService; -import com.optimizely.ab.optimizelydecision.*; +import com.optimizely.ab.optimizelydecision.DecisionMessage; +import com.optimizely.ab.optimizelydecision.DecisionReasons; +import com.optimizely.ab.optimizelydecision.DecisionResponse; +import com.optimizely.ab.optimizelydecision.DefaultDecisionReasons; +import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption; +import com.optimizely.ab.optimizelydecision.OptimizelyDecision; import com.optimizely.ab.optimizelyjson.OptimizelyJSON; -import java.util.concurrent.locks.ReentrantLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; - import java.io.Closeable; -import java.util.*; -import java.util.stream.Collectors; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; import static com.optimizely.ab.internal.SafetyUtils.tryClose; /** * Top-level container class for Optimizely functionality. * Thread-safe, so can be created as a singleton and safely passed around. - * + *
* Example instantiation: *
* Optimizely optimizely = Optimizely.builder(projectWatcher, eventHandler).build(); *- * + *
* To activate an experiment and perform variation specific processing: *
* Variation variation = optimizely.activate(experimentKey, userId, attributes);
@@ -136,7 +172,9 @@ private Optimizely(@Nonnull EventHandler eventHandler,
if (projectConfigManager.getSDKKey() != null) {
NotificationRegistry.getInternalNotificationCenter(projectConfigManager.getSDKKey()).
addNotificationHandler(UpdateConfigNotification.class,
- configNotification -> { updateODPSettings(); });
+ configNotification -> {
+ updateODPSettings();
+ });
}
}
@@ -634,6 +672,53 @@ public Integer getFeatureVariableInteger(@Nonnull String featureKey,
return variableValue;
}
+ /**
+ * Get the Long value of the specified variable in the feature.
+ *
+ * @param featureKey The unique key of the feature.
+ * @param variableKey The unique key of the variable.
+ * @param userId The ID of the user.
+ * @return The Integer value of the integer single variable feature.
+ * Null if the feature or variable could not be found.
+ */
+ @Nullable
+ public Long getFeatureVariableLong(@Nonnull String featureKey,
+ @Nonnull String variableKey,
+ @Nonnull String userId) {
+ return getFeatureVariableLong(featureKey, variableKey, userId, Collections.emptyMap());
+ }
+
+ /**
+ * Get the Integer value of the specified variable in the feature.
+ *
+ * @param featureKey The unique key of the feature.
+ * @param variableKey The unique key of the variable.
+ * @param userId The ID of the user.
+ * @param attributes The user's attributes.
+ * @return The Integer value of the integer single variable feature.
+ * Null if the feature or variable could not be found.
+ */
+ @Nullable
+ public Long getFeatureVariableLong(@Nonnull String featureKey,
+ @Nonnull String variableKey,
+ @Nonnull String userId,
+ @Nonnull Map attributes) {
+ try {
+ return getFeatureVariableValueForType(
+ featureKey,
+ variableKey,
+ userId,
+ attributes,
+ FeatureVariable.INTEGER_TYPE
+ );
+
+ } catch (Exception exception) {
+ logger.error("NumberFormatException while trying to parse value as Long. {}", String.valueOf(exception));
+ }
+
+ return null;
+ }
+
/**
* Get the String value of the specified variable in the feature.
*
@@ -828,8 +913,13 @@ Object convertStringToType(String variableValue, String type) {
try {
return Integer.parseInt(variableValue);
} catch (NumberFormatException exception) {
- logger.error("NumberFormatException while trying to parse \"" + variableValue +
- "\" as Integer. " + exception.toString());
+ try {
+ return Long.parseLong(variableValue);
+ } catch (NumberFormatException longException) {
+ logger.error("NumberFormatException while trying to parse \"{}\" as Integer. {}",
+ variableValue,
+ exception.toString());
+ }
}
break;
case FeatureVariable.JSON_TYPE:
@@ -845,11 +935,10 @@ Object convertStringToType(String variableValue, String type) {
/**
* Get the values of all variables in the feature.
*
- * @param featureKey The unique key of the feature.
- * @param userId The ID of the user.
+ * @param featureKey The unique key of the feature.
+ * @param userId The ID of the user.
* @return An OptimizelyJSON instance for all variable values.
* Null if the feature could not be found.
- *
*/
@Nullable
public OptimizelyJSON getAllFeatureVariables(@Nonnull String featureKey,
@@ -860,12 +949,11 @@ public OptimizelyJSON getAllFeatureVariables(@Nonnull String featureKey,
/**
* Get the values of all variables in the feature.
*
- * @param featureKey The unique key of the feature.
- * @param userId The ID of the user.
- * @param attributes The user's attributes.
+ * @param featureKey The unique key of the feature.
+ * @param userId The ID of the user.
+ * @param attributes The user's attributes.
* @return An OptimizelyJSON instance for all variable values.
* Null if the feature could not be found.
- *
*/
@Nullable
public OptimizelyJSON getAllFeatureVariables(@Nonnull String featureKey,
@@ -949,7 +1037,6 @@ public OptimizelyJSON getAllFeatureVariables(@Nonnull String featureKey,
* @param attributes The user's attributes.
* @return List of the feature keys that are enabled for the user if the userId is empty it will
* return Empty List.
- *
*/
public List getEnabledFeatures(@Nonnull String userId, @Nonnull Map attributes) {
List enabledFeaturesList = new ArrayList();
@@ -1164,10 +1251,10 @@ public OptimizelyConfig getOptimizelyConfig() {
/**
* Create a context of the user for which decision APIs will be called.
- *
+ *
* A user context will be created successfully even when the SDK is not fully configured yet.
*
- * @param userId The user ID to be used for bucketing.
+ * @param userId The user ID to be used for bucketing.
* @param attributes: A map of attribute names to current user attribute values.
* @return An OptimizelyUserContext associated with this OptimizelyClient.
*/
@@ -1289,15 +1376,15 @@ private OptimizelyDecision createOptimizelyDecision(
}
Map decideForKeys(@Nonnull OptimizelyUserContext user,
- @Nonnull List keys,
- @Nonnull List options) {
+ @Nonnull List keys,
+ @Nonnull List options) {
return decideForKeys(user, keys, options, false);
}
private Map decideForKeys(@Nonnull OptimizelyUserContext user,
- @Nonnull List keys,
- @Nonnull List options,
- boolean ignoreDefaultOptions) {
+ @Nonnull List keys,
+ @Nonnull List options,
+ boolean ignoreDefaultOptions) {
Map decisionMap = new HashMap<>();
ProjectConfig projectConfig = getProjectConfig();
@@ -1308,7 +1395,7 @@ private Map decideForKeys(@Nonnull OptimizelyUserCon
if (keys.isEmpty()) return decisionMap;
- List allOptions = ignoreDefaultOptions ? options: getAllOptions(options);
+ List allOptions = ignoreDefaultOptions ? options : getAllOptions(options);
Map flagDecisions = new HashMap<>();
Map decisionReasonsMap = new HashMap<>();
@@ -1351,7 +1438,7 @@ private Map decideForKeys(@Nonnull OptimizelyUserCon
decisionReasonsMap.get(flagKey).merge(decision.getReasons());
}
- for (String key: validKeys) {
+ for (String key : validKeys) {
FeatureDecision flagDecision = flagDecisions.get(key);
DecisionReasons decisionReasons = decisionReasonsMap.get((key));
@@ -1484,9 +1571,9 @@ public int addLogEventNotificationHandler(NotificationHandler handler)
/**
* Convenience method for adding NotificationHandlers
*
- * @param clazz The class of NotificationHandler
+ * @param clazz The class of NotificationHandler
* @param handler NotificationHandler handler
- * @param This is the type parameter
+ * @param This is the type parameter
* @return A handler Id (greater than 0 if succeeded)
*/
public int addNotificationHandler(Class clazz, NotificationHandler handler) {
@@ -1535,10 +1622,10 @@ public ODPManager getODPManager() {
/**
* Send an event to the ODP server.
*
- * @param type the event type (default = "fullstack").
- * @param action the event action name.
+ * @param type the event type (default = "fullstack").
+ * @param action the event action name.
* @param identifiers a dictionary for identifiers. The caller must provide at least one key-value pair unless non-empty common identifiers have been set already with {@link ODPManager.Builder#withUserCommonIdentifiers(Map) }.
- * @param data a dictionary for associated data. The default event data will be added to this data before sending to the ODP server.
+ * @param data a dictionary for associated data. The default event data will be added to this data before sending to the ODP server.
*/
public void sendODPEvent(@Nullable String type, @Nonnull String action, @Nullable Map identifiers, @Nullable Map data) {
ProjectConfig projectConfig = getProjectConfig();
@@ -1586,7 +1673,7 @@ private void updateODPSettings() {
* {@link Builder#withDatafile(java.lang.String)} and
* {@link Builder#withEventHandler(com.optimizely.ab.event.EventHandler)}
* respectively.
- *
+ *
* Example:
*
* Optimizely optimizely = Optimizely.builder()
@@ -1595,7 +1682,7 @@ private void updateODPSettings() {
* .build();
*
*
- * @param datafile A datafile
+ * @param datafile A datafile
* @param eventHandler An EventHandler
* @return An Optimizely builder
*/
@@ -1644,7 +1731,8 @@ public Builder(@Nonnull String datafile,
this.datafile = datafile;
}
- public Builder() { }
+ public Builder() {
+ }
public Builder withErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
@@ -1686,7 +1774,7 @@ public Builder withUserProfileService(UserProfileService userProfileService) {
* Override the SDK name and version (for client SDKs like android-sdk wrapping the core java-sdk) to be included in events.
*
* @param clientEngineName the client engine name ("java-sdk", "android-sdk", "flutter-sdk", etc.).
- * @param clientVersion the client SDK version.
+ * @param clientVersion the client SDK version.
* @return An Optimizely builder
*/
public Builder withClientInfo(String clientEngineName, String clientVersion) {
diff --git a/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java b/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java
index 260de9945..b444dbc26 100644
--- a/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java
+++ b/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java
@@ -1101,7 +1101,7 @@ public void trackEventWithNullAttributeValues() throws Exception {
* (i.e., not in the config) is passed through.
*
* In this case, the track event call should not remove the unknown attribute from the given map but should go on and track the event successfully.
- *
+ *
* TODO: Is this a dupe?? Also not sure the intent of the test since the attributes are stripped by the EventFactory
*/
@Test
@@ -1569,8 +1569,7 @@ private NotificationHandler getDecisionListener(
final String testType,
final String testUserId,
final Map testUserAttributes,
- final Map testDecisionInfo)
- {
+ final Map testDecisionInfo) {
return decisionNotification -> {
assertEquals(decisionNotification.getType(), testType);
assertEquals(decisionNotification.getUserId(), testUserId);
@@ -1609,10 +1608,10 @@ public void activateEndToEndWithDecisionListener() throws Exception {
int notificationId = optimizely.notificationCenter.getNotificationManager(DecisionNotification.class)
.addHandler(
- getDecisionListener(NotificationCenter.DecisionNotificationType.FEATURE_TEST.toString(),
- userId,
- testUserAttributes,
- testDecisionInfoMap));
+ getDecisionListener(NotificationCenter.DecisionNotificationType.FEATURE_TEST.toString(),
+ userId,
+ testUserAttributes,
+ testDecisionInfoMap));
// activate the experiment
Variation actualVariation = optimizely.activate(activatedExperiment.getKey(), userId, null);
@@ -1752,7 +1751,8 @@ public void getEnabledFeaturesWithNoFeatureEnabled() throws Exception {
any(OptimizelyUserContext.class),
any(ProjectConfig.class)
);
- int notificationId = optimizely.addDecisionNotificationHandler( decisionNotification -> { });
+ int notificationId = optimizely.addDecisionNotificationHandler(decisionNotification -> {
+ });
List featureFlags = optimizely.getEnabledFeatures(genericUserId, Collections.emptyMap());
assertTrue(featureFlags.isEmpty());
@@ -2012,10 +2012,10 @@ public void getFeatureVariableWithListenerUserInExperimentFeatureOn() throws Exc
testDecisionInfoMap));
assertEquals(optimizely.getFeatureVariableString(
- validFeatureKey,
- validVariableKey,
- testUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
+ validFeatureKey,
+ validVariableKey,
+ testUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
expectedValue);
// Verify that listener being called
@@ -2062,10 +2062,10 @@ public void getFeatureVariableWithListenerUserInExperimentFeatureOff() {
testDecisionInfoMap));
assertEquals(optimizely.getFeatureVariableString(
- validFeatureKey,
- validVariableKey,
- userID,
- null),
+ validFeatureKey,
+ validVariableKey,
+ userID,
+ null),
expectedValue);
// Verify that listener being called
@@ -2109,10 +2109,10 @@ public void getFeatureVariableWithListenerUserInRollOutFeatureOn() throws Except
testDecisionInfoMap));
assertEquals(optimizely.getFeatureVariableString(
- validFeatureKey,
- validVariableKey,
- genericUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
+ validFeatureKey,
+ validVariableKey,
+ genericUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
expectedValue);
// Verify that listener being called
@@ -2156,10 +2156,10 @@ public void getFeatureVariableWithListenerUserNotInRollOutFeatureOff() {
testDecisionInfoMap));
assertEquals(optimizely.getFeatureVariableBoolean(
- validFeatureKey,
- validVariableKey,
- genericUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
+ validFeatureKey,
+ validVariableKey,
+ genericUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
expectedValue);
// Verify that listener being called
@@ -2201,12 +2201,14 @@ public void getFeatureVariableIntegerWithListenerUserInRollOutFeatureOn() {
testUserAttributes,
testDecisionInfoMap));
- assertEquals((long) optimizely.getFeatureVariableInteger(
- validFeatureKey,
- validVariableKey,
- genericUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
- (long) expectedValue);
+ assertEquals(
+ expectedValue,
+ (long) optimizely.getFeatureVariableInteger(
+ validFeatureKey,
+ validVariableKey,
+ genericUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE))
+ );
// Verify that listener being called
assertTrue(isListenerCalled);
@@ -2251,10 +2253,10 @@ public void getFeatureVariableDoubleWithListenerUserInExperimentFeatureOn() thro
testDecisionInfoMap));
assertEquals(optimizely.getFeatureVariableDouble(
- validFeatureKey,
- validVariableKey,
- genericUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_SLYTHERIN_VALUE)),
+ validFeatureKey,
+ validVariableKey,
+ genericUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_SLYTHERIN_VALUE)),
Math.PI, 2);
// Verify that listener being called
@@ -2453,7 +2455,7 @@ public void getAllFeatureVariablesWithListenerUserInExperimentFeatureOff() {
assertTrue(isListenerCalled);
assertTrue(optimizely.notificationCenter.removeNotificationListener(notificationId));
}
-
+
/**
* Verify that the {@link Optimizely#activate(String, String, Map)} call
* correctly builds an endpoint url and request params
@@ -2526,7 +2528,7 @@ public void activateWithListenerNullAttributes() throws Exception {
* com.optimizely.ab.notification.NotificationListener)} properly used
* and the listener is
* added and notified when an experiment is activated.
- *
+ *
* Feels redundant with the above tests
*/
@SuppressWarnings("unchecked")
@@ -2572,7 +2574,7 @@ public void addNotificationListenerFromNotificationCenter() throws Exception {
/**
* Verify that {@link com.optimizely.ab.notification.NotificationCenter} properly
* calls and the listener is removed and no longer notified when an experiment is activated.
- *
+ *
* TODO move this to NotificationCenter.
*/
@SuppressWarnings("unchecked")
@@ -2619,7 +2621,7 @@ public void removeNotificationListenerNotificationCenter() throws Exception {
* Verify that {@link com.optimizely.ab.notification.NotificationCenter}
* clearAllListerners removes all listeners
* and no longer notified when an experiment is activated.
- *
+ *
* TODO Should be part of NotificationCenter tests.
*/
@SuppressWarnings("unchecked")
@@ -2741,7 +2743,7 @@ public void trackEventWithListenerNullAttributes() throws Exception {
//======== Feature Accessor Tests ========//
/**
- * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, FeatureVariable.VariableType)}
+ * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, String)}
* returns null and logs a message
* when it is called with a feature key that has no corresponding feature in the datafile.
*/
@@ -2770,7 +2772,7 @@ public void getFeatureVariableValueForTypeReturnsNullWhenFeatureNotFound() throw
}
/**
- * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, FeatureVariable.VariableType)}
+ * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, String)}
* returns null and logs a message
* when the feature key is valid, but no variable could be found for the variable key in the feature.
*/
@@ -2796,7 +2798,7 @@ public void getFeatureVariableValueForTypeReturnsNullWhenVariableNotFoundInValid
}
/**
- * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, FeatureVariable.VariableType)}
+ * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, String)}
* returns null when the variable's type does not match the type with which it was attempted to be accessed.
*/
@Test
@@ -2825,7 +2827,7 @@ public void getFeatureVariableValueReturnsNullWhenVariableTypeDoesNotMatch() thr
}
/**
- * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, FeatureVariable.VariableType)}
+ * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, String)}
* returns the String default value of a feature variable
* when the feature is not attached to an experiment or a rollout.
*/
@@ -2866,7 +2868,7 @@ public void getFeatureVariableValueForTypeReturnsDefaultValueWhenFeatureIsNotAtt
}
/**
- * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, FeatureVariable.VariableType)}
+ * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, String)}
* returns the String default value for a feature variable
* when the feature is attached to an experiment and no rollout, but the user is excluded from the experiment.
*/
@@ -2910,7 +2912,7 @@ public void getFeatureVariableValueReturnsDefaultValueWhenFeatureIsAttachedToOne
}
/**
- * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, FeatureVariable.VariableType)}
+ * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, String)}
* is called when the variation is not null and feature enabled is false
* returns the default variable value
*/
@@ -2964,10 +2966,10 @@ public void getFeatureVariableUserInExperimentFeatureOn() throws Exception {
Optimizely optimizely = optimizelyBuilder.build();
assertEquals(optimizely.getFeatureVariableString(
- validFeatureKey,
- validVariableKey,
- testUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
+ validFeatureKey,
+ validVariableKey,
+ testUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
expectedValue);
logbackVerifier.expectMessage(
@@ -2994,10 +2996,10 @@ public void getFeatureVariableUserInExperimentFeatureOff() {
Optimizely optimizely = optimizelyBuilder.build();
assertEquals(optimizely.getFeatureVariableString(
- validFeatureKey,
- validVariableKey,
- userID,
- null),
+ validFeatureKey,
+ validVariableKey,
+ userID,
+ null),
expectedValue);
}
@@ -3017,10 +3019,10 @@ public void getFeatureVariableUserInRollOutFeatureOn() throws Exception {
Optimizely optimizely = optimizelyBuilder.build();
assertEquals(optimizely.getFeatureVariableString(
- validFeatureKey,
- validVariableKey,
- genericUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
+ validFeatureKey,
+ validVariableKey,
+ genericUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
expectedValue);
}
@@ -3040,10 +3042,10 @@ public void getFeatureVariableUserNotInRollOutFeatureOff() {
Optimizely optimizely = optimizelyBuilder.build();
assertEquals(optimizely.getFeatureVariableBoolean(
- validFeatureKey,
- validVariableKey,
- genericUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
+ validFeatureKey,
+ validVariableKey,
+ genericUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
expectedValue);
}
@@ -3062,12 +3064,39 @@ public void getFeatureVariableIntegerUserInRollOutFeatureOn() {
Optimizely optimizely = optimizelyBuilder.build();
- assertEquals((long) optimizely.getFeatureVariableInteger(
- validFeatureKey,
- validVariableKey,
- genericUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE)),
- (long) expectedValue);
+ assertEquals(
+ expectedValue,
+ (int) optimizely.getFeatureVariableInteger(
+ validFeatureKey,
+ validVariableKey,
+ genericUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE))
+ );
+ }
+
+ /**
+ * Verify that the {@link Optimizely#getFeatureVariableInteger(String, String, String, Map)}
+ * is called when feature is in rollout and feature enabled is true
+ * return rollout variable value
+ */
+ @Test
+ public void getFeatureVariableLongUserInRollOutFeatureOn() {
+ assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString()));
+
+ final String validFeatureKey = FEATURE_SINGLE_VARIABLE_INTEGER_KEY;
+ String validVariableKey = VARIABLE_INTEGER_VARIABLE_KEY;
+ int expectedValue = 7;
+
+ Optimizely optimizely = optimizelyBuilder.build();
+
+ assertEquals(
+ expectedValue,
+ (int) optimizely.getFeatureVariableInteger(
+ validFeatureKey,
+ validVariableKey,
+ genericUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_GRYFFINDOR_VALUE))
+ );
}
/**
@@ -3085,15 +3114,15 @@ public void getFeatureVariableDoubleUserInExperimentFeatureOn() throws Exception
Optimizely optimizely = optimizelyBuilder.build();
assertEquals(optimizely.getFeatureVariableDouble(
- validFeatureKey,
- validVariableKey,
- genericUserId,
- Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_SLYTHERIN_VALUE)),
+ validFeatureKey,
+ validVariableKey,
+ genericUserId,
+ Collections.singletonMap(ATTRIBUTE_HOUSE_KEY, AUDIENCE_SLYTHERIN_VALUE)),
Math.PI, 2);
}
/**
- * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, FeatureVariable.VariableType)}
+ * Verify {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, String)}
* returns the default value for the feature variable
* when there is no variable usage present for the variation the user is bucketed into.
*/
@@ -4160,6 +4189,18 @@ public void convertStringToTypeIntegerCatchesExceptionFromParsing() throws Numbe
);
}
+ /**
+ * Verify that {@link Optimizely#convertStringToType(String, String)}
+ * is able to parse Long.
+ */
+ @Test
+ public void convertStringToTypeIntegerReturnsLongCorrectly() throws NumberFormatException {
+ String longValue = "8949425362117";
+
+ Optimizely optimizely = optimizelyBuilder.build();
+ assertEquals(Long.valueOf(longValue), optimizely.convertStringToType(longValue, FeatureVariable.INTEGER_TYPE));
+ }
+
/**
* Verify {@link Optimizely#getFeatureVariableInteger(String, String, String)}
* calls through to {@link Optimizely#getFeatureVariableInteger(String, String, String, Map)}
@@ -4234,7 +4275,7 @@ public void getFeatureVariableIntegerReturnsNullWhenUserIdIsNull() throws Except
* Verify {@link Optimizely#getFeatureVariableInteger(String, String, String)}
* calls through to {@link Optimizely#getFeatureVariableInteger(String, String, String, Map)}
* and both return the parsed Integer value from the value returned from
- * {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, FeatureVariable.VariableType)}.
+ * {@link Optimizely#getFeatureVariableValueForType(String, String, String, Map, String)}.
*/
@Test
public void getFeatureVariableIntegerReturnsWhatInternalReturns() throws Exception {
@@ -4333,8 +4374,8 @@ public void getFeatureVariableJSONUserInExperimentFeatureOn() throws Exception {
assertEquals(json.toMap().get("k1"), "s1");
assertEquals(json.toMap().get("k2"), 103.5);
assertEquals(json.toMap().get("k3"), false);
- assertEquals(((Map)json.toMap().get("k4")).get("kk1"), "ss1");
- assertEquals(((Map)json.toMap().get("k4")).get("kk2"), true);
+ assertEquals(((Map) json.toMap().get("k4")).get("kk1"), "ss1");
+ assertEquals(((Map) json.toMap().get("k4")).get("kk2"), true);
assertEquals(json.getValue("k1", String.class), "s1");
assertEquals(json.getValue("k4.kk2", Boolean.class), true);
@@ -4368,15 +4409,15 @@ public void getFeatureVariableJSONUserInExperimentFeatureOff() throws Exception
assertEquals(json.toMap().get("k1"), "v1");
assertEquals(json.toMap().get("k2"), 3.5);
assertEquals(json.toMap().get("k3"), true);
- assertEquals(((Map)json.toMap().get("k4")).get("kk1"), "vv1");
- assertEquals(((Map)json.toMap().get("k4")).get("kk2"), false);
+ assertEquals(((Map) json.toMap().get("k4")).get("kk1"), "vv1");
+ assertEquals(((Map) json.toMap().get("k4")).get("kk2"), false);
assertEquals(json.getValue("k1", String.class), "v1");
assertEquals(json.getValue("k4.kk2", Boolean.class), false);
}
/**
- * Verify that the {@link Optimizely#getAllFeatureVariables(String,String, Map)}
+ * Verify that the {@link Optimizely#getAllFeatureVariables(String, String, Map)}
* is called when feature is in experiment and feature enabled is true
* returns variable value
*/
@@ -4398,12 +4439,12 @@ public void getAllFeatureVariablesUserInExperimentFeatureOn() throws Exception {
assertEquals(json.toMap().get("first_letter"), "F");
assertEquals(json.toMap().get("rest_of_name"), "red");
- Map subMap = (Map)json.toMap().get("json_patched");
+ Map subMap = (Map) json.toMap().get("json_patched");
assertEquals(subMap.get("k1"), "s1");
assertEquals(subMap.get("k2"), 103.5);
assertEquals(subMap.get("k3"), false);
- assertEquals(((Map)subMap.get("k4")).get("kk1"), "ss1");
- assertEquals(((Map)subMap.get("k4")).get("kk2"), true);
+ assertEquals(((Map) subMap.get("k4")).get("kk1"), "ss1");
+ assertEquals(((Map) subMap.get("k4")).get("kk2"), true);
assertEquals(json.getValue("first_letter", String.class), "F");
assertEquals(json.getValue("json_patched.k1", String.class), "s1");
@@ -4435,12 +4476,12 @@ public void getAllFeatureVariablesUserInExperimentFeatureOff() throws Exception
assertEquals(json.toMap().get("first_letter"), "H");
assertEquals(json.toMap().get("rest_of_name"), "arry");
- Map subMap = (Map)json.toMap().get("json_patched");
+ Map subMap = (Map) json.toMap().get("json_patched");
assertEquals(subMap.get("k1"), "v1");
assertEquals(subMap.get("k2"), 3.5);
assertEquals(subMap.get("k3"), true);
- assertEquals(((Map)subMap.get("k4")).get("kk1"), "vv1");
- assertEquals(((Map)subMap.get("k4")).get("kk2"), false);
+ assertEquals(((Map) subMap.get("k4")).get("kk1"), "vv1");
+ assertEquals(((Map) subMap.get("k4")).get("kk2"), false);
assertEquals(json.getValue("first_letter", String.class), "H");
assertEquals(json.getValue("json_patched.k1", String.class), "v1");
@@ -4448,7 +4489,7 @@ public void getAllFeatureVariablesUserInExperimentFeatureOff() throws Exception
}
/**
- * Verify {@link Optimizely#getAllFeatureVariables(String,String, Map)} with invalid parameters
+ * Verify {@link Optimizely#getAllFeatureVariables(String, String, Map)} with invalid parameters
*/
@SuppressFBWarnings("NP_NONNULL_PARAM_VIOLATION")
@Test
@@ -4532,7 +4573,8 @@ public void testAddTrackNotificationHandler() {
NotificationManager manager = optimizely.getNotificationCenter()
.getNotificationManager(TrackNotification.class);
- int notificationId = optimizely.addTrackNotificationHandler(message -> {});
+ int notificationId = optimizely.addTrackNotificationHandler(message -> {
+ });
assertTrue(manager.remove(notificationId));
}
@@ -4542,7 +4584,8 @@ public void testAddDecisionNotificationHandler() {
NotificationManager manager = optimizely.getNotificationCenter()
.getNotificationManager(DecisionNotification.class);
- int notificationId = optimizely.addDecisionNotificationHandler(message -> {});
+ int notificationId = optimizely.addDecisionNotificationHandler(message -> {
+ });
assertTrue(manager.remove(notificationId));
}
@@ -4552,7 +4595,8 @@ public void testAddUpdateConfigNotificationHandler() {
NotificationManager manager = optimizely.getNotificationCenter()
.getNotificationManager(UpdateConfigNotification.class);
- int notificationId = optimizely.addUpdateConfigNotificationHandler(message -> {});
+ int notificationId = optimizely.addUpdateConfigNotificationHandler(message -> {
+ });
assertTrue(manager.remove(notificationId));
}
@@ -4562,7 +4606,8 @@ public void testAddLogEventNotificationHandler() {
NotificationManager manager = optimizely.getNotificationCenter()
.getNotificationManager(LogEvent.class);
- int notificationId = optimizely.addLogEventNotificationHandler(message -> {});
+ int notificationId = optimizely.addLogEventNotificationHandler(message -> {
+ });
assertTrue(manager.remove(notificationId));
}
diff --git a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java
index 0ed8d5945..faacfda76 100644
--- a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java
+++ b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java
@@ -266,6 +266,19 @@ public class ValidProjectConfigV4 {
FeatureVariable.INTEGER_TYPE,
null
);
+ private static final String FEATURE_SINGLE_VARIABLE_LONG_ID = "964006971";
+ public static final String FEATURE_SINGLE_VARIABLE_LONG_KEY = "long_single_variable_feature";
+ private static final String VARIABLE_LONG_VARIABLE_ID = "4339640697";
+ public static final String VARIABLE_LONG_VARIABLE_KEY = "long_variable";
+ private static final String VARIABLE_LONG_DEFAULT_VALUE = "379993881340";
+ private static final FeatureVariable VARIABLE_LONG_VARIABLE = new FeatureVariable(
+ VARIABLE_LONG_VARIABLE_ID,
+ VARIABLE_LONG_VARIABLE_KEY,
+ VARIABLE_LONG_DEFAULT_VALUE,
+ null,
+ FeatureVariable.INTEGER_TYPE,
+ null
+ );
private static final String FEATURE_SINGLE_VARIABLE_BOOLEAN_ID = "2591051011";
public static final String FEATURE_SINGLE_VARIABLE_BOOLEAN_KEY = "boolean_single_variable_feature";
private static final String VARIABLE_BOOLEAN_VARIABLE_ID = "3974680341";