Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added GetFeatureVariableJSON. #216

Merged
merged 29 commits into from
May 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a129e3a
Added Optimizely Json
mnoman09 Apr 29, 2020
18857e6
Added unit tests
mnoman09 Apr 29, 2020
c988dd0
indentation fixes and small other fixes
mnoman09 Apr 30, 2020
581d95f
Merge branch 'master' into mnoman/optimizelyJson
mnoman09 Apr 30, 2020
cb48427
Added GetFeatureVariableJson support and unit test function
mnoman09 Apr 30, 2020
5735882
Added Unit tests
mnoman09 May 4, 2020
0f2e63c
default literal was not supported so Updated it to default(T)
mnoman09 May 4, 2020
439d5fa
comments resolved
mnoman09 May 5, 2020
4c316f4
Converted all Jobjects to dict and Jarray object to List
mnoman09 May 6, 2020
8e84f43
Added invalid cast exception class in optizelyException
mnoman09 May 6, 2020
96cfd82
Added addition unit tests and added support of casting dictionary to …
mnoman09 May 7, 2020
7efb98f
indentation fix
mnoman09 May 7, 2020
31a7dca
changed IsNullOrWhiteSpace into IsNullOrEmpty
mnoman09 May 7, 2020
348acf1
added a unit test
msohailhussain May 7, 2020
a6d1ddd
Refact
mnoman09 May 7, 2020
d18df1d
Merge branch 'mnoman/optimizelyJson' into mnoman/GetFeatureVariableJson
mnoman09 May 7, 2020
aa6de6b
updated header
mnoman09 May 7, 2020
a800616
Merge branch 'mnoman/optimizelyJson' into mnoman/GetFeatureVariableJson
mnoman09 May 7, 2020
8355cde
if notification value is optimizelyJson
mnoman09 May 7, 2020
a8aec1b
added errorhandler mock verifier
mnoman09 May 7, 2020
3db6dbf
Added additonal comments to explain functions further
mnoman09 May 7, 2020
2bf7ff1
Merge branch 'mnoman/optimizelyJson' into mnoman/GetFeatureVariableJson
mnoman09 May 8, 2020
beee956
setting type = subtype while parsing if its json
mnoman09 May 8, 2020
8e087b4
refact
mnoman09 May 11, 2020
fa0370c
Merge branch 'master' into mnoman/GetFeatureVariableJson
mnoman09 May 11, 2020
34765fc
Added additional tests
mnoman09 May 12, 2020
618f6ba
Added getFeatureVariableJsonListener Test
mnoman09 May 13, 2020
8508a44
changed unsupported type json to regex as we are now supporting json
mnoman09 May 14, 2020
4758fbd
Added Test and set type = json instead of subtype
mnoman09 May 18, 2020
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: 2 additions & 0 deletions OptimizelySDK.Tests/EntityTests/FeatureVariableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public void TestFeatureVariableTypeName()
Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.DOUBLE_TYPE), "GetFeatureVariableDouble");
Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.INTEGER_TYPE), "GetFeatureVariableInteger");
Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.STRING_TYPE), "GetFeatureVariableString");
Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.JSON_TYPE), "GetFeatureVariableJSON");
}

[Test]
Expand All @@ -39,6 +40,7 @@ public void TestConstantValues()
Assert.AreEqual(FeatureVariable.DOUBLE_TYPE, "double");
Assert.AreEqual(FeatureVariable.INTEGER_TYPE, "integer");
Assert.AreEqual(FeatureVariable.STRING_TYPE, "string");
Assert.AreEqual(FeatureVariable.JSON_TYPE, "json");
}
}
}
220 changes: 218 additions & 2 deletions OptimizelySDK.Tests/OptimizelyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class OptimizelyTest
const string FEATUREVARIABLE_INTEGERTYPE = "integer";
const string FEATUREVARIABLE_DOUBLETYPE = "double";
const string FEATUREVARIABLE_STRINGTYPE = "string";
const string FEATUREVARIABLE_JSONTYPE = "json";

#region Test Life Cycle
[SetUp]
Expand Down Expand Up @@ -197,6 +198,7 @@ public void TestInvalidInstanceLogMessages()
Assert.IsNull(optimizely.GetFeatureVariableString(string.Empty, string.Empty, string.Empty));
Assert.IsNull(optimizely.GetFeatureVariableDouble(string.Empty, string.Empty, string.Empty));
Assert.IsNull(optimizely.GetFeatureVariableInteger(string.Empty, string.Empty, string.Empty));
Assert.IsNull(optimizely.GetFeatureVariableJSON(string.Empty, string.Empty, string.Empty));

LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Provided 'datafile' has invalid schema."), Times.Once);
LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetVariation'."), Times.Once);
Expand All @@ -208,6 +210,7 @@ public void TestInvalidInstanceLogMessages()
LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetFeatureVariableString'."), Times.Once);
LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetFeatureVariableDouble'."), Times.Once);
LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetFeatureVariableInteger'."), Times.Once);
LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetFeatureVariableJSON'."), Times.Once);

}
[Test]
Expand Down Expand Up @@ -1245,6 +1248,36 @@ public void TestGetFeatureVariableStringFRCulture()
Assert.AreEqual(stringValueFR, "cta_1");
}

[Test]
public void TestGetFeatureVariableJSONFRCulture()
{
var fallbackConfigManager = new FallbackProjectConfigManager(Config);

var expectedDict = new Dictionary<string, object>()
{
{ "int_var", 1 },
{ "boolean_key", false}
};

SetCulture("en-US");
var optimizely = new Optimizely(fallbackConfigManager);

var optimizelyJsonValue = optimizely.GetFeatureVariableJSON("string_single_variable_feature", "json_var", "testUser1");

Assert.IsTrue(TestData.CompareObjects(optimizelyJsonValue.ToDictionary(), expectedDict));
Assert.AreEqual(optimizelyJsonValue.GetValue<long>("int_var"), 1);
mnoman09 marked this conversation as resolved.
Show resolved Hide resolved
Assert.AreEqual(optimizelyJsonValue.GetValue<bool>("boolean_key"), false);
Assert.IsTrue(TestData.CompareObjects(optimizelyJsonValue.GetValue<object>(""), expectedDict));

SetCulture("fr-FR");
var optimizelyJsonValueFR = optimizely.GetFeatureVariableJSON("string_single_variable_feature", "json_var", "testUser1");

Assert.IsTrue(TestData.CompareObjects(optimizelyJsonValue.ToDictionary(), expectedDict));
Assert.AreEqual(optimizelyJsonValueFR.GetValue<long>("int_var"), 1);
Assert.AreEqual(optimizelyJsonValueFR.GetValue<bool>("boolean_key"), false);
Assert.IsTrue(TestData.CompareObjects(optimizelyJsonValue.GetValue<object>(""), expectedDict));
}

[Test]
public void TestGetFeatureVariableDoubleReturnsCorrectValue()
{
Expand Down Expand Up @@ -1316,6 +1349,74 @@ public void TestGetFeatureVariableStringReturnsCorrectValue()
Assert.Null(OptimizelyMock.Object.GetFeatureVariableString(featureKey, variableKeyNull, TestUserId, null));
}

[Test]
public void TestGetFeatureVariableJSONReturnsCorrectValue()
{
var featureKey = "featureKey";
var variableKeyString = "varJSONString1";
var variableKeyIntString = "varJSONString2";
var variableKeyDouble = "varJSONDouble";
var variableKeyNull = "varNull";
var featureVariableType = "json";

OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType<OptimizelyJson>(It.IsAny<string>(), variableKeyString, It.IsAny<string>(),
It.IsAny<UserAttributes>(), featureVariableType)).Returns(new OptimizelyJson("{\"string\": \"Test String\"}", ErrorHandlerMock.Object, LoggerMock.Object));
mnoman09 marked this conversation as resolved.
Show resolved Hide resolved
Assert.AreEqual("Test String", OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyString, TestUserId, null).GetValue<string>("string"));

OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType<OptimizelyJson>(It.IsAny<string>(), variableKeyIntString, It.IsAny<string>(),
It.IsAny<UserAttributes>(), featureVariableType)).Returns(new OptimizelyJson("{ \"integer\": 123 }", ErrorHandlerMock.Object, LoggerMock.Object));
Assert.AreEqual(123, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyIntString, TestUserId, null).GetValue<long>("integer"));

OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType<OptimizelyJson>(It.IsAny<string>(), variableKeyDouble, It.IsAny<string>(),
It.IsAny<UserAttributes>(), featureVariableType)).Returns(new OptimizelyJson("{ \"double\": 123.28 }", ErrorHandlerMock.Object, LoggerMock.Object));
Assert.AreEqual(123.28, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyDouble, TestUserId, null).GetValue<double>("double"));

OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType<OptimizelyJson>(It.IsAny<string>(), variableKeyNull, It.IsAny<string>(),
It.IsAny<UserAttributes>(), featureVariableType)).Returns<OptimizelyJson>(null);
Assert.Null(OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyNull, TestUserId, null));
}

[Test]
public void TestGetFeatureVariableJSONReturnsCorrectValueWhenInitializedUsingDictionary()
{
var featureKey = "featureKey";
var variableKeyString = "varJSONString1";
var variableKeyIntString = "varJSONString2";
var variableKeyDouble = "varJSONDouble";
var variableKeyBoolean = "varJSONBoolean";
var variableKeyNull = "varNull";
var featureVariableType = "json";

var expectedStringDict = new Dictionary<string, object>() { { "string", "Test String" } };
var expectedIntegerDict = new Dictionary<string, object>() { { "integer", 123 } };
var expectedDoubleDict = new Dictionary<string, object>() { { "double", 123.28 } };
var expectedBooleanDict = new Dictionary<string, object>() { { "boolean", true } };

OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType<OptimizelyJson>(It.IsAny<string>(), variableKeyString, It.IsAny<string>(),
It.IsAny<UserAttributes>(), featureVariableType)).Returns(new OptimizelyJson(expectedStringDict, ErrorHandlerMock.Object, LoggerMock.Object));
Assert.IsTrue(TestData.CompareObjects(expectedStringDict, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyString, TestUserId, null).ToDictionary()));
Assert.AreEqual("Test String", OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyString, TestUserId, null).GetValue<string>("string"));

OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType<OptimizelyJson>(It.IsAny<string>(), variableKeyIntString, It.IsAny<string>(),
It.IsAny<UserAttributes>(), featureVariableType)).Returns(new OptimizelyJson(expectedIntegerDict, ErrorHandlerMock.Object, LoggerMock.Object));
Assert.IsTrue(TestData.CompareObjects(expectedIntegerDict, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyIntString, TestUserId, null).ToDictionary()));
Assert.AreEqual(123, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyIntString, TestUserId, null).GetValue<long>("integer"));

OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType<OptimizelyJson>(It.IsAny<string>(), variableKeyDouble, It.IsAny<string>(),
It.IsAny<UserAttributes>(), featureVariableType)).Returns(new OptimizelyJson(expectedDoubleDict, ErrorHandlerMock.Object, LoggerMock.Object));
Assert.IsTrue(TestData.CompareObjects(expectedDoubleDict, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyDouble, TestUserId, null).ToDictionary()));
Assert.AreEqual(123.28, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyDouble, TestUserId, null).GetValue<double>("double"));

OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType<OptimizelyJson>(It.IsAny<string>(), variableKeyBoolean, It.IsAny<string>(),
It.IsAny<UserAttributes>(), featureVariableType)).Returns(new OptimizelyJson(expectedBooleanDict, ErrorHandlerMock.Object, LoggerMock.Object));
Assert.IsTrue(TestData.CompareObjects(expectedBooleanDict, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyBoolean, TestUserId, null).ToDictionary()));
Assert.AreEqual(true, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyBoolean, TestUserId, null).GetValue<bool>("boolean"));

OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType<OptimizelyJson>(It.IsAny<string>(), variableKeyNull, It.IsAny<string>(),
It.IsAny<UserAttributes>(), featureVariableType)).Returns<OptimizelyJson>(null);
Assert.Null(OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyNull, TestUserId, null));
}

#region Feature Toggle Tests

[Test]
Expand Down Expand Up @@ -1444,6 +1545,70 @@ public void TestGetFeatureVariableBooleanReturnsRightValueWhenUserBuckedIntoRoll
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""true"" for variation ""{variation.Key}"" of feature flag ""{featureKey}""."));
}

[Test]
public void TestGetFeatureVariableJSONReturnsRightValueWhenUserBucketIntoRolloutAndVariationIsToggleOn()
{
var featureKey = "string_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "json_var";
var expectedStringValue = "cta_4";
var expectedIntValue = 4;
var experiment = Config.GetRolloutFromId("166661").Experiments[0];
var variation = Config.GetVariationFromKey(experiment.Key, "177775");
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT);
var userAttributes = new UserAttributes
{
{ "device_type", "iPhone" },
{ "company", "Optimizely" },
{ "location", "San Francisco" }
};

DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, Config, userAttributes)).Returns(decision);

var optly = Helper.CreatePrivateOptimizely();

optly.SetFieldOrProperty("ProjectConfigManager", ConfigManager);
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (OptimizelyJson)optly.Invoke("GetFeatureVariableJSON", featureKey, variableKey, TestUserId, userAttributes);
Assert.AreEqual(expectedIntValue, variableValue.GetValue<long>("int_var"));
Assert.AreEqual(expectedStringValue, variableValue.GetValue<string>("string_var"));

LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureKey}""."));
}

[Test]
public void TestGetFeatureVariableJSONReturnsRightValueWhenUserBucketIntoRolloutAndVariationIsToggleOnTypeIsJson()
{
var featureKey = "string_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "true_json_var";
var expectedStringValue = "cta_5";
var expectedIntValue = 5;
var experiment = Config.GetRolloutFromId("166661").Experiments[0];
var variation = Config.GetVariationFromKey(experiment.Key, "177775");
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT);
var userAttributes = new UserAttributes
{
{ "device_type", "iPhone" },
{ "company", "Optimizely" },
{ "location", "San Francisco" }
};

DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, Config, userAttributes)).Returns(decision);

var optly = Helper.CreatePrivateOptimizely();

optly.SetFieldOrProperty("ProjectConfigManager", ConfigManager);
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (OptimizelyJson)optly.Invoke("GetFeatureVariableJSON", featureKey, variableKey, TestUserId, userAttributes);
Assert.AreEqual(expectedIntValue, variableValue.GetValue<long>("int_var"));
Assert.AreEqual(expectedStringValue, variableValue.GetValue<string>("string_var"));

LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureKey}""."));
}

[Test]
public void TestGetFeatureVariableStringReturnsRightValueWhenUserBuckedIntoRolloutAndVariationIsToggleOn()
{
Expand Down Expand Up @@ -1606,6 +1771,7 @@ public void TestGetFeatureVariableValueForTypeGivenInvalidVariableType()
Assert.IsNull(Optimizely.GetFeatureVariableValueForType<bool?>("boolean_single_variable_feature", "boolean_variable", TestUserId, null, variableTypeDouble));
Assert.IsNull(Optimizely.GetFeatureVariableValueForType<int?>("integer_single_variable_feature", "integer_variable", TestUserId, null, variableTypeString));
Assert.IsNull(Optimizely.GetFeatureVariableValueForType<string>("string_single_variable_feature", "string_variable", TestUserId, null, variableTypeInt));
Assert.IsNull(Optimizely.GetFeatureVariableValueForType<OptimizelyJson>("string_single_variable_feature", "json_var", TestUserId, null, variableTypeInt));

LoggerMock.Verify(l => l.Log(LogLevel.ERROR,
$@"Variable is of type ""double"", but you requested it as type ""{variableTypeBool}""."));
Expand All @@ -1623,8 +1789,9 @@ public void TestUnsupportedVariableType()
var featureVariableStringRandomType = Optimizely.GetFeatureVariableString("", "any_key", TestUserId);
Assert.IsNull(featureVariableStringRandomType);

var featureVariableStringJsonType = Optimizely.GetFeatureVariableString("unsupported_variabletype", "string_json_key", TestUserId);
Assert.AreEqual(featureVariableStringJsonType, "{\"myvalue\": \"jsonValue\"}");
// This is to test that only json subtype is parsing and all other will subtype will be stringify
var featureVariableStringRegexSubType = Optimizely.GetFeatureVariableString("unsupported_variabletype", "string_regex_key", TestUserId);
Assert.AreEqual(featureVariableStringRegexSubType, "^\\d+(\\.\\d+)?");
}

// Should return default value and log message when feature is not enabled for the user.
Expand Down Expand Up @@ -2632,6 +2799,55 @@ public void TestGetFeatureVariableDoubleSendsNotificationWhenUserBuckedIntoFeatu
NotificationCallbackMock.Verify(nc => nc.TestDecisionCallback(DecisionNotificationTypes.FEATURE_VARIABLE, TestUserId, new UserAttributes(), It.Is<Dictionary<string, object>>(info => TestData.CompareObjects(info, decisionInfo))), Times.Once);
}

[Test]
public void TestGetFeatureVariableJsonSendsNotificationWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOn()
{
var featureKey = "string_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "json_var";
var expectedDict = new Dictionary<string, object>()
{
{ "int_var", 4 },
{ "string_var", "cta_4"}
};
var experiment = Config.GetRolloutFromId("166661").Experiments[0];
var variation = Config.GetVariationFromKey(experiment.Key, "177775");
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT);
var userAttributes = new UserAttributes
{
{ "device_type", "iPhone" },
{ "company", "Optimizely" },
{ "location", "San Francisco" }
};

DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, Config, userAttributes)).Returns(decision);
NotificationCallbackMock.Setup(nc => nc.TestDecisionCallback(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<UserAttributes>(),
It.IsAny<Dictionary<string, object>>()));

var optly = Helper.CreatePrivateOptimizely();

optly.SetFieldOrProperty("ProjectConfigManager", ConfigManager);
var optStronglyTyped = optly.GetObject() as Optimizely;

optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
optStronglyTyped.NotificationCenter.AddNotification(NotificationCenter.NotificationType.Decision, NotificationCallbackMock.Object.TestDecisionCallback);

var variableValue = (OptimizelyJson)optly.Invoke("GetFeatureVariableJSON", featureKey, variableKey, TestUserId, userAttributes);
Assert.IsTrue(TestData.CompareObjects(expectedDict, variableValue.ToDictionary()));
var decisionInfo = new Dictionary<string, object>
{
{ "featureKey", featureKey },
{ "featureEnabled", true },
{ "variableKey", variableKey },
{ "variableValue", expectedDict },
{ "variableType", FEATUREVARIABLE_JSONTYPE },
{ "source", FeatureDecision.DECISION_SOURCE_ROLLOUT },
{ "sourceInfo", new Dictionary<string, string>() },
};

NotificationCallbackMock.Verify(nc => nc.TestDecisionCallback(DecisionNotificationTypes.FEATURE_VARIABLE, TestUserId, userAttributes, It.Is<Dictionary<string, object>>(info => TestData.CompareObjects(info, decisionInfo))), Times.Once);
}

[Test]
public void TestGetFeatureVariableIntegerSendsNotificationWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOn()
{
Expand Down
Loading