Skip to content

Commit e17424f

Browse files
mfahadahmedaliabbasrizvi
authored andcommitted
feat(api): Feature variable APIs now return default variable value when featureEnabled property is false. (#151)
1 parent 723a0fb commit e17424f

File tree

4 files changed

+313
-8
lines changed

4 files changed

+313
-8
lines changed

OptimizelySDK.Tests/OptimizelyTest.cs

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,229 @@ public void TestGetFeatureVariableStringReturnTypecastedValue()
13061306
Assert.Null(OptimizelyMock.Object.GetFeatureVariableString(featureKey, variableKeyNull, TestUserId, null));
13071307
}
13081308

1309+
#region Feature Toggle Tests
1310+
1311+
[Test]
1312+
public void TestGetFeatureVariableDoubleReturnsRightValueWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOn()
1313+
{
1314+
var featureKey = "double_single_variable_feature";
1315+
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
1316+
var variableKey = "double_variable";
1317+
var expectedValue = 42.42;
1318+
var experiment = Config.GetExperimentFromKey("test_experiment_double_feature");
1319+
var variation = Config.GetVariationFromKey("test_experiment_double_feature", "control");
1320+
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_EXPERIMENT);
1321+
1322+
DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, null)).Returns(decision);
1323+
1324+
var optly = Helper.CreatePrivateOptimizely();
1325+
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
1326+
1327+
var variableValue = (double)optly.Invoke("GetFeatureVariableDouble", featureKey, variableKey, TestUserId, null);
1328+
Assert.AreEqual(expectedValue, variableValue);
1329+
1330+
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureKey}""."));
1331+
}
1332+
1333+
[Test]
1334+
public void TestGetFeatureVariableIntegerReturnsRightValueWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOn()
1335+
{
1336+
var featureKey = "integer_single_variable_feature";
1337+
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
1338+
var variableKey = "integer_variable";
1339+
var expectedValue = 13;
1340+
var experiment = Config.GetExperimentFromKey("test_experiment_integer_feature");
1341+
var variation = Config.GetVariationFromKey("test_experiment_integer_feature", "variation");
1342+
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_EXPERIMENT);
1343+
var userAttributes = new UserAttributes
1344+
{
1345+
{ "device_type", "iPhone" },
1346+
{ "company", "Optimizely" },
1347+
{ "location", "San Francisco" }
1348+
};
1349+
1350+
DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, userAttributes)).Returns(decision);
1351+
1352+
var optly = Helper.CreatePrivateOptimizely();
1353+
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
1354+
1355+
var variableValue = (int)optly.Invoke("GetFeatureVariableInteger", featureKey, variableKey, TestUserId, userAttributes);
1356+
Assert.AreEqual(expectedValue, variableValue);
1357+
1358+
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureKey}""."));
1359+
}
1360+
1361+
[Test]
1362+
public void TestGetFeatureVariableDoubleReturnsDefaultValueWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOff()
1363+
{
1364+
var featureKey = "double_single_variable_feature";
1365+
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
1366+
var variableKey = "double_variable";
1367+
var expectedValue = 14.99;
1368+
var experiment = Config.GetExperimentFromKey("test_experiment_double_feature");
1369+
var variation = Config.GetVariationFromKey("test_experiment_double_feature", "variation");
1370+
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_EXPERIMENT);
1371+
1372+
DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, null)).Returns(decision);
1373+
1374+
var optly = Helper.CreatePrivateOptimizely();
1375+
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
1376+
1377+
var variableValue = (double)optly.Invoke("GetFeatureVariableDouble", featureKey, variableKey, TestUserId, null);
1378+
Assert.AreEqual(expectedValue, variableValue);
1379+
1380+
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning default value for variable ""{variableKey}""."));
1381+
}
1382+
1383+
[Test]
1384+
public void TestGetFeatureVariableIntegerReturnsDefaultValueWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOff()
1385+
{
1386+
var featureKey = "integer_single_variable_feature";
1387+
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
1388+
var variableKey = "integer_variable";
1389+
var expectedValue = 7;
1390+
var experiment = Config.GetExperimentFromKey("test_experiment_integer_feature");
1391+
var variation = Config.GetVariationFromKey("test_experiment_integer_feature", "control");
1392+
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_EXPERIMENT);
1393+
var userAttributes = new UserAttributes
1394+
{
1395+
{ "device_type", "iPhone" },
1396+
{ "company", "Optimizely" },
1397+
{ "location", "San Francisco" }
1398+
};
1399+
1400+
DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, userAttributes)).Returns(decision);
1401+
1402+
var optly = Helper.CreatePrivateOptimizely();
1403+
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
1404+
1405+
var variableValue = (int)optly.Invoke("GetFeatureVariableInteger", featureKey, variableKey, TestUserId, userAttributes);
1406+
Assert.AreEqual(expectedValue, variableValue);
1407+
1408+
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning default value for variable ""{variableKey}""."));
1409+
}
1410+
1411+
[Test]
1412+
public void TestGetFeatureVariableBooleanReturnsRightValueWhenUserBuckedIntoRolloutAndVariationIsToggleOn()
1413+
{
1414+
var featureKey = "boolean_single_variable_feature";
1415+
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
1416+
var variableKey = "boolean_variable";
1417+
var expectedValue = true;
1418+
var experiment = Config.GetRolloutFromId("166660").Experiments[0];
1419+
var variation = Config.GetVariationFromKey(experiment.Key, "177771");
1420+
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT);
1421+
1422+
DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, null)).Returns(decision);
1423+
1424+
var optly = Helper.CreatePrivateOptimizely();
1425+
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
1426+
1427+
var variableValue = (bool)optly.Invoke("GetFeatureVariableBoolean", featureKey, variableKey, TestUserId, null);
1428+
Assert.AreEqual(expectedValue, variableValue);
1429+
1430+
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""true"" for variation ""{variation.Key}"" of feature flag ""{featureKey}""."));
1431+
}
1432+
1433+
[Test]
1434+
public void TestGetFeatureVariableStringReturnsRightValueWhenUserBuckedIntoRolloutAndVariationIsToggleOn()
1435+
{
1436+
var featureKey = "string_single_variable_feature";
1437+
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
1438+
var variableKey = "string_variable";
1439+
var expectedValue = "cta_4";
1440+
var experiment = Config.GetRolloutFromId("166661").Experiments[0];
1441+
var variation = Config.GetVariationFromKey(experiment.Key, "177775");
1442+
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT);
1443+
var userAttributes = new UserAttributes
1444+
{
1445+
{ "device_type", "iPhone" },
1446+
{ "company", "Optimizely" },
1447+
{ "location", "San Francisco" }
1448+
};
1449+
1450+
DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, userAttributes)).Returns(decision);
1451+
1452+
var optly = Helper.CreatePrivateOptimizely();
1453+
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
1454+
1455+
var variableValue = (string)optly.Invoke("GetFeatureVariableString", featureKey, variableKey, TestUserId, userAttributes);
1456+
Assert.AreEqual(expectedValue, variableValue);
1457+
1458+
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureKey}""."));
1459+
}
1460+
1461+
[Test]
1462+
public void TestGetFeatureVariableBooleanReturnsDefaultValueWhenUserBuckedIntoRolloutAndVariationIsToggleOff()
1463+
{
1464+
var featureKey = "boolean_single_variable_feature";
1465+
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
1466+
var variableKey = "boolean_variable";
1467+
var expectedValue = true;
1468+
var experiment = Config.GetRolloutFromId("166660").Experiments[3];
1469+
var variation = Config.GetVariationFromKey(experiment.Key, "177782");
1470+
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT);
1471+
1472+
DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, null)).Returns(decision);
1473+
1474+
var optly = Helper.CreatePrivateOptimizely();
1475+
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
1476+
1477+
var variableValue = (bool)optly.Invoke("GetFeatureVariableBoolean", featureKey, variableKey, TestUserId, null);
1478+
Assert.AreEqual(expectedValue, variableValue);
1479+
1480+
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning default value for variable ""{variableKey}""."));
1481+
}
1482+
1483+
[Test]
1484+
public void TestGetFeatureVariableStringReturnsDefaultValueWhenUserBuckedIntoRolloutAndVariationIsToggleOff()
1485+
{
1486+
var featureKey = "string_single_variable_feature";
1487+
var featureFlag = Config.GetFeatureFlagFromKey(featureKey);
1488+
var variableKey = "string_variable";
1489+
var expectedValue = "wingardium leviosa";
1490+
var experiment = Config.GetRolloutFromId("166661").Experiments[2];
1491+
var variation = Config.GetVariationFromKey(experiment.Key, "177784");
1492+
var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT);
1493+
var userAttributes = new UserAttributes
1494+
{
1495+
{ "device_type", "iPhone" },
1496+
{ "company", "Optimizely" },
1497+
{ "location", "San Francisco" }
1498+
};
1499+
1500+
DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, userAttributes)).Returns(decision);
1501+
1502+
var optly = Helper.CreatePrivateOptimizely();
1503+
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
1504+
1505+
var variableValue = (string)optly.Invoke("GetFeatureVariableString", featureKey, variableKey, TestUserId, userAttributes);
1506+
Assert.AreEqual(expectedValue, variableValue);
1507+
1508+
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning default value for variable ""{variableKey}""."));
1509+
}
1510+
1511+
[Test]
1512+
public void TestGetFeatureVariableDoubleReturnsDefaultValueWhenUserNotBuckedIntoBothFeatureExperimentAndRollout()
1513+
{
1514+
var featureKey = "double_single_variable_feature";
1515+
var featureFlag = Config.GetFeatureFlagFromKey("double_single_variable_feature");
1516+
var variableKey = "double_variable";
1517+
var expectedValue = 14.99;
1518+
1519+
DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, null)).Returns<FeatureDecision>(null);
1520+
1521+
var optly = Helper.CreatePrivateOptimizely();
1522+
optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object);
1523+
1524+
var variableValue = (double)optly.Invoke("GetFeatureVariableDouble", featureKey, variableKey, TestUserId, null);
1525+
Assert.AreEqual(expectedValue, variableValue);
1526+
1527+
LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"User ""{TestUserId}"" is not in any variation for feature flag ""{featureKey}"", returning default value ""{variableValue}""."));
1528+
}
1529+
1530+
#endregion Feature Toggle Tests
1531+
13091532
#endregion // Test GetFeatureVariable<Type> TypeCasting
13101533

13111534
#region Test GetFeatureVariableValueForType method

OptimizelySDK.Tests/ProjectConfigTest.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,16 @@ public void TestInit()
211211
{"177780", Config.GetVariationFromKey("177779", "177780") }
212212
}
213213
},
214+
{ "177781", new Dictionary<string, object>
215+
{
216+
{"177782", Config.GetVariationFromKey("177781", "177782") }
217+
}
218+
},
219+
{ "177783", new Dictionary<string, object>
220+
{
221+
{"177784", Config.GetVariationFromKey("177783", "177784") }
222+
}
223+
},
214224
{ "etag1", new Dictionary<string, object>
215225
{
216226
{"vtag1", Config.GetVariationFromKey("etag1", "vtag1") },
@@ -317,6 +327,16 @@ public void TestInit()
317327
{"177780", Config.GetVariationFromId("177779", "177780") }
318328
}
319329
},
330+
{ "177781", new Dictionary<string, object>
331+
{
332+
{"177782", Config.GetVariationFromId("177781", "177782") }
333+
}
334+
},
335+
{ "177783", new Dictionary<string, object>
336+
{
337+
{"177784", Config.GetVariationFromId("177783", "177784") }
338+
}
339+
},
320340
{ "etag1", new Dictionary<string, object>
321341
{
322342
{"276", Config.GetVariationFromId("etag1", "276") },

OptimizelySDK.Tests/TestData.json

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,32 @@
722722
"endOfRange": 9000
723723
}
724724
]
725+
},
726+
{
727+
"id": "177781",
728+
"key": "177781",
729+
"status": "Running",
730+
"layerId": "166660",
731+
"audienceIds": [],
732+
"variations": [
733+
{
734+
"id": "177782",
735+
"key": "177782",
736+
"variables": [
737+
{
738+
"id": "155556",
739+
"value": "false"
740+
}
741+
],
742+
"featureEnabled": false
743+
}
744+
],
745+
"trafficAllocation": [
746+
{
747+
"entityId": "177778",
748+
"endOfRange": 9000
749+
}
750+
]
725751
}
726752
]
727753
},
@@ -738,7 +764,12 @@
738764
{
739765
"id": "177775",
740766
"key": "177775",
741-
"variables": [],
767+
"variables": [
768+
{
769+
"id": "155558",
770+
"value": "cta_4"
771+
}
772+
],
742773
"featureEnabled": true
743774
}
744775
],
@@ -769,6 +800,32 @@
769800
"endOfRange": 1500
770801
}
771802
]
803+
},
804+
{
805+
"id": "177783",
806+
"key": "177783",
807+
"status": "Running",
808+
"layerId": "166661",
809+
"audienceIds": [],
810+
"variations": [
811+
{
812+
"id": "177784",
813+
"key": "177784",
814+
"variables": [
815+
{
816+
"id": "155558",
817+
"value": "cta_5"
818+
}
819+
],
820+
"featureEnabled": false
821+
}
822+
],
823+
"trafficAllocation": [
824+
{
825+
"entityId": "177780",
826+
"endOfRange": 1500
827+
}
828+
]
772829
}
773830
]
774831
}

OptimizelySDK/Optimizely.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ public virtual string GetFeatureVariableValueForType(string featureKey, string v
426426
$@"Variable is of type ""{featureVariable.Type}"", but you requested it as type ""{variableType}"".");
427427
return null;
428428
}
429-
429+
430430
var variableValue = featureVariable.DefaultValue;
431431
var decision = DecisionService.GetVariationForFeature(featureFlag, userId, userAttributes);
432432

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

438438
if (featureVariableUsageInstance != null)
439439
{
440-
variableValue = featureVariableUsageInstance.Value;
441-
Logger.Log(LogLevel.INFO,
442-
$@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureFlag.Key}"".");
440+
if (variation.FeatureEnabled == true)
441+
{
442+
variableValue = featureVariableUsageInstance.Value;
443+
Logger.Log(LogLevel.INFO, $@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureKey}"".");
444+
}
445+
else
446+
{
447+
Logger.Log(LogLevel.INFO, $@"Feature ""{featureKey}"" is not enabled for user {userId}. Returning default value for variable ""{variableKey}"".");
448+
}
443449
}
444450
else
445451
{
446-
Logger.Log(LogLevel.INFO,
447-
$@"Variable ""{variableKey}"" is not used in variation ""{variation.Key}"", returning default value ""{variableValue}"".");
452+
Logger.Log(LogLevel.INFO, $@"Variable ""{variableKey}"" is not used in variation ""{variation.Key}"", returning default value ""{variableValue}"".");
448453
}
449454
}
450455
else
451456
{
452457
Logger.Log(LogLevel.INFO,
453-
$@"User ""{userId}"" is not in any variation for feature flag ""{featureFlag.Key}"", returning default value ""{variableValue}"".");
458+
$@"User ""{userId}"" is not in any variation for feature flag ""{featureKey}"", returning default value ""{variableValue}"".");
454459
}
455460

456461
return variableValue;

0 commit comments

Comments
 (0)