diff --git a/OptimizelySDK.Tests/DecisionServiceTest.cs b/OptimizelySDK.Tests/DecisionServiceTest.cs
index acb475ad..f90e8507 100644
--- a/OptimizelySDK.Tests/DecisionServiceTest.cs
+++ b/OptimizelySDK.Tests/DecisionServiceTest.cs
@@ -569,6 +569,24 @@ public void TestGetVariationForFeatureExperimentGivenMutexGroupAndUserNotBuckete
#region GetVariationForFeatureRollout Tests
// Should return null when rollout doesn't exist for the feature.
+ [Test]
+ public void TestGetVariationForFeatureRolloutWhenNoRuleInRollouts()
+ {
+ var projectConfig = DatafileProjectConfig.Create(TestData.EmptyRolloutDatafile, new NoOpLogger(), new NoOpErrorHandler());
+
+ Assert.IsNotNull(projectConfig);
+ var featureFlag = projectConfig.FeatureKeyMap["empty_rollout"];
+ var rollout = projectConfig.GetRolloutFromId(featureFlag.RolloutId);
+
+ Assert.AreEqual(rollout.Experiments.Count, 0);
+
+ var decisionService = new DecisionService(new Bucketer(new NoOpLogger()), new NoOpErrorHandler(), null, new NoOpLogger());
+
+ var variation = decisionService.GetVariationForFeatureRollout(featureFlag, "userId1", null, projectConfig);
+
+ Assert.IsNull(variation);
+ }
+
[Test]
public void TestGetVariationForFeatureRolloutWhenRolloutIsNotInDataFile()
{
diff --git a/OptimizelySDK.Tests/EmptyRolloutRule.json b/OptimizelySDK.Tests/EmptyRolloutRule.json
new file mode 100644
index 00000000..70913612
--- /dev/null
+++ b/OptimizelySDK.Tests/EmptyRolloutRule.json
@@ -0,0 +1,44 @@
+{
+ "version": "4",
+ "rollouts": [
+ {
+ "experiments": [
+ ],
+ "id": "18309384009"
+ }
+ ],
+ "typedAudiences": [],
+ "anonymizeIP": true,
+ "projectId": "18326250003",
+ "variables": [],
+ "featureFlags": [
+ {
+ "experimentIds": [],
+ "rolloutId": "18309384009",
+ "variables": [
+ {
+ "defaultValue": "",
+ "type": "string",
+ "id": "18323951833",
+ "key": "var_1"
+ }
+ ],
+ "id": "18244658520",
+ "key": "empty_rollout"
+ }
+ ],
+ "experiments": [],
+ "audiences": [
+ {
+ "conditions": "[\"or\", {\"match\": \"exact\", \"name\": \"$opt_dummy_attribute\", \"type\": \"custom_attribute\", \"value\": \"$opt_dummy_value\"}]",
+ "id": "$opt_dummy_audience",
+ "name": "Optimizely-Generated Audience for Backwards Compatibility"
+ }
+ ],
+ "groups": [],
+ "attributes": [],
+ "botFiltering": false,
+ "accountId": "8272261422",
+ "events": [],
+ "revision": "2"
+}
diff --git a/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj b/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj
index d25a2da7..eb22549c 100644
--- a/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj
+++ b/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj
@@ -119,6 +119,7 @@
+
diff --git a/OptimizelySDK.Tests/Utils/TestData.cs b/OptimizelySDK.Tests/Utils/TestData.cs
index 1a8d0a63..32688d8b 100644
--- a/OptimizelySDK.Tests/Utils/TestData.cs
+++ b/OptimizelySDK.Tests/Utils/TestData.cs
@@ -27,6 +27,7 @@ public class TestData
private static string simpleABExperimentsDatafile = null;
private static string unsupportedVersionDatafile = null;
private static string typedAudienceDatafile = null;
+ private static string emptyRolloutDatafile = null;
public static string Datafile
{
@@ -52,6 +53,12 @@ public static string UnsupportedVersionDatafile
}
}
+ public static string EmptyRolloutDatafile {
+ get {
+ return emptyRolloutDatafile ?? (emptyRolloutDatafile = LoadJsonData("EmptyRolloutRule.json"));
+ }
+ }
+
public static string TypedAudienceDatafile
{
get
diff --git a/OptimizelySDK/Bucketing/DecisionService.cs b/OptimizelySDK/Bucketing/DecisionService.cs
index f5f45c89..0abb7341 100644
--- a/OptimizelySDK/Bucketing/DecisionService.cs
+++ b/OptimizelySDK/Bucketing/DecisionService.cs
@@ -389,6 +389,10 @@ public virtual FeatureDecision GetVariationForFeatureRollout(FeatureFlag feature
return null;
}
+ if (rollout.Experiments == null || rollout.Experiments.Count == 0) {
+ return null;
+ }
+
Variation variation = null;
var rolloutRulesLength = rollout.Experiments.Count;