Skip to content

feat(api): Feature variable APIs now return default variable value when featureEnabled property is false. #151

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

Merged
merged 3 commits into from
Apr 1, 2019
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
223 changes: 223 additions & 0 deletions OptimizelySDK.Tests/OptimizelyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,229 @@ public void TestGetFeatureVariableStringReturnTypecastedValue()
Assert.Null(OptimizelyMock.Object.GetFeatureVariableString(featureKey, variableKeyNull, TestUserId, null));
}

#region Feature Toggle Tests

[Test]
public void TestGetFeatureVariableDoubleReturnsRightValueWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOn()
{
var featureKey = "double_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "double_variable";
var expectedValue = 42.42;
var experiment = Config.GetExperimentFromKey("test_experiment_double_feature");
var variation = Config.GetVariationFromKey("test_experiment_double_feature", "control");
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_EXPERIMENT);

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

var optly = Helper.CreatePrivateOptimizely();
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (double)optly.Invoke("GetFeatureVariableDouble", featureKey, variableKey, TestUserId, null);
Assert.AreEqual(expectedValue, variableValue);

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

[Test]
public void TestGetFeatureVariableIntegerReturnsRightValueWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOn()
{
var featureKey = "integer_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "integer_variable";
var expectedValue = 13;
var experiment = Config.GetExperimentFromKey("test_experiment_integer_feature");
var variation = Config.GetVariationFromKey("test_experiment_integer_feature", "variation");
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_EXPERIMENT);
var userAttributes = new UserAttributes
{
{ "device_type", "iPhone" },
{ "company", "Optimizely" },
{ "location", "San Francisco" }
};

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

var optly = Helper.CreatePrivateOptimizely();
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (int)optly.Invoke("GetFeatureVariableInteger", featureKey, variableKey, TestUserId, userAttributes);
Assert.AreEqual(expectedValue, variableValue);

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

[Test]
public void TestGetFeatureVariableDoubleReturnsDefaultValueWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOff()
{
var featureKey = "double_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "double_variable";
var expectedValue = 14.99;
var experiment = Config.GetExperimentFromKey("test_experiment_double_feature");
var variation = Config.GetVariationFromKey("test_experiment_double_feature", "variation");
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_EXPERIMENT);

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

var optly = Helper.CreatePrivateOptimizely();
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (double)optly.Invoke("GetFeatureVariableDouble", featureKey, variableKey, TestUserId, null);
Assert.AreEqual(expectedValue, variableValue);

LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning default value for variable ""{variableKey}""."));
}

[Test]
public void TestGetFeatureVariableIntegerReturnsDefaultValueWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOff()
{
var featureKey = "integer_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "integer_variable";
var expectedValue = 7;
var experiment = Config.GetExperimentFromKey("test_experiment_integer_feature");
var variation = Config.GetVariationFromKey("test_experiment_integer_feature", "control");
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_EXPERIMENT);
var userAttributes = new UserAttributes
{
{ "device_type", "iPhone" },
{ "company", "Optimizely" },
{ "location", "San Francisco" }
};

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

var optly = Helper.CreatePrivateOptimizely();
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (int)optly.Invoke("GetFeatureVariableInteger", featureKey, variableKey, TestUserId, userAttributes);
Assert.AreEqual(expectedValue, variableValue);

LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning default value for variable ""{variableKey}""."));
}

[Test]
public void TestGetFeatureVariableBooleanReturnsRightValueWhenUserBuckedIntoRolloutAndVariationIsToggleOn()
{
var featureKey = "boolean_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "boolean_variable";
var expectedValue = true;
var experiment = Config.GetRolloutFromId("166660").Experiments[0];
var variation = Config.GetVariationFromKey(experiment.Key, "177771");
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT);

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

var optly = Helper.CreatePrivateOptimizely();
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (bool)optly.Invoke("GetFeatureVariableBoolean", featureKey, variableKey, TestUserId, null);
Assert.AreEqual(expectedValue, variableValue);

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

[Test]
public void TestGetFeatureVariableStringReturnsRightValueWhenUserBuckedIntoRolloutAndVariationIsToggleOn()
{
var featureKey = "string_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "string_variable";
var expectedValue = "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, userAttributes)).Returns(decision);

var optly = Helper.CreatePrivateOptimizely();
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (string)optly.Invoke("GetFeatureVariableString", featureKey, variableKey, TestUserId, userAttributes);
Assert.AreEqual(expectedValue, variableValue);

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

[Test]
public void TestGetFeatureVariableBooleanReturnsDefaultValueWhenUserBuckedIntoRolloutAndVariationIsToggleOff()
{
var featureKey = "boolean_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "boolean_variable";
var expectedValue = true;
var experiment = Config.GetRolloutFromId("166660").Experiments[3];
var variation = Config.GetVariationFromKey(experiment.Key, "177782");
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT);

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

var optly = Helper.CreatePrivateOptimizely();
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (bool)optly.Invoke("GetFeatureVariableBoolean", featureKey, variableKey, TestUserId, null);
Assert.AreEqual(expectedValue, variableValue);

LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning default value for variable ""{variableKey}""."));
}

[Test]
public void TestGetFeatureVariableStringReturnsDefaultValueWhenUserBuckedIntoRolloutAndVariationIsToggleOff()
{
var featureKey = "string_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
var variableKey = "string_variable";
var expectedValue = "wingardium leviosa";
var experiment = Config.GetRolloutFromId("166661").Experiments[2];
var variation = Config.GetVariationFromKey(experiment.Key, "177784");
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, userAttributes)).Returns(decision);

var optly = Helper.CreatePrivateOptimizely();
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (string)optly.Invoke("GetFeatureVariableString", featureKey, variableKey, TestUserId, userAttributes);
Assert.AreEqual(expectedValue, variableValue);

LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning default value for variable ""{variableKey}""."));
}

[Test]
public void TestGetFeatureVariableDoubleReturnsDefaultValueWhenUserNotBuckedIntoBothFeatureExperimentAndRollout()
{
var featureKey = "double_single_variable_feature";
var featureFlag = Config.GetFeatureFlagFromKey("double_single_variable_feature");
var variableKey = "double_variable";
var expectedValue = 14.99;

DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, null)).Returns<FeatureDecision>(null);

var optly = Helper.CreatePrivateOptimizely();
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);

var variableValue = (double)optly.Invoke("GetFeatureVariableDouble", featureKey, variableKey, TestUserId, null);
Assert.AreEqual(expectedValue, variableValue);

LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"User ""{TestUserId}"" is not in any variation for feature flag ""{featureKey}"", returning default value ""{variableValue}""."));
}

#endregion Feature Toggle Tests

#endregion // Test GetFeatureVariable<Type> TypeCasting

#region Test GetFeatureVariableValueForType method
Expand Down
20 changes: 20 additions & 0 deletions OptimizelySDK.Tests/ProjectConfigTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,16 @@ public void TestInit()
{"177780", Config.GetVariationFromKey("177779", "177780") }
}
},
{ "177781", new Dictionary<string, object>
{
{"177782", Config.GetVariationFromKey("177781", "177782") }
}
},
{ "177783", new Dictionary<string, object>
{
{"177784", Config.GetVariationFromKey("177783", "177784") }
}
},
{ "etag1", new Dictionary<string, object>
{
{"vtag1", Config.GetVariationFromKey("etag1", "vtag1") },
Expand Down Expand Up @@ -317,6 +327,16 @@ public void TestInit()
{"177780", Config.GetVariationFromId("177779", "177780") }
}
},
{ "177781", new Dictionary<string, object>
{
{"177782", Config.GetVariationFromId("177781", "177782") }
}
},
{ "177783", new Dictionary<string, object>
{
{"177784", Config.GetVariationFromId("177783", "177784") }
}
},
{ "etag1", new Dictionary<string, object>
{
{"276", Config.GetVariationFromId("etag1", "276") },
Expand Down
59 changes: 58 additions & 1 deletion OptimizelySDK.Tests/TestData.json
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,32 @@
"endOfRange": 9000
}
]
},
{
"id": "177781",
"key": "177781",
"status": "Running",
"layerId": "166660",
"audienceIds": [],
"variations": [
{
"id": "177782",
"key": "177782",
"variables": [
{
"id": "155556",
"value": "false"
}
],
"featureEnabled": false
}
],
"trafficAllocation": [
{
"entityId": "177778",
"endOfRange": 9000
}
]
}
]
},
Expand All @@ -738,7 +764,12 @@
{
"id": "177775",
"key": "177775",
"variables": [],
"variables": [
{
"id": "155558",
"value": "cta_4"
}
],
"featureEnabled": true
}
],
Expand Down Expand Up @@ -769,6 +800,32 @@
"endOfRange": 1500
}
]
},
{
"id": "177783",
"key": "177783",
"status": "Running",
"layerId": "166661",
"audienceIds": [],
"variations": [
{
"id": "177784",
"key": "177784",
"variables": [
{
"id": "155558",
"value": "cta_5"
}
],
"featureEnabled": false
}
],
"trafficAllocation": [
{
"entityId": "177780",
"endOfRange": 1500
}
]
}
]
}
Expand Down
19 changes: 12 additions & 7 deletions OptimizelySDK/Optimizely.cs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ public virtual string GetFeatureVariableValueForType(string featureKey, string v
$@"Variable is of type ""{featureVariable.Type}"", but you requested it as type ""{variableType}"".");
return null;
}

var variableValue = featureVariable.DefaultValue;
var decision = DecisionService.GetVariationForFeature(featureFlag, userId, userAttributes);

Expand All @@ -437,20 +437,25 @@ public virtual string GetFeatureVariableValueForType(string featureKey, string v

if (featureVariableUsageInstance != null)
{
variableValue = featureVariableUsageInstance.Value;
Logger.Log(LogLevel.INFO,
$@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureFlag.Key}"".");
if (variation.FeatureEnabled == true)
{
variableValue = featureVariableUsageInstance.Value;
Logger.Log(LogLevel.INFO, $@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureKey}"".");
}
else
{
Logger.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {userId}. Returning default value for variable ""{variableKey}"".");
}
}
else
{
Logger.Log(LogLevel.INFO,
$@"Variable ""{variableKey}"" is not used in variation ""{variation.Key}"", returning default value ""{variableValue}"".");
Logger.Log(LogLevel.INFO, $@"Variable ""{variableKey}"" is not used in variation ""{variation.Key}"", returning default value ""{variableValue}"".");
}
}
else
{
Logger.Log(LogLevel.INFO,
$@"User ""{userId}"" is not in any variation for feature flag ""{featureFlag.Key}"", returning default value ""{variableValue}"".");
$@"User ""{userId}"" is not in any variation for feature flag ""{featureKey}"", returning default value ""{variableValue}"".");
}

return variableValue;
Expand Down