Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ internal class FeatureManagementConstants
public const string ETag = "ETag";
public const string FeatureFlagId = "FeatureFlagId";
public const string FeatureFlagReference = "FeatureFlagReference";
public const string Status = "Status";
public const string AlwaysOnFilter = "AlwaysOn";
public const string Conditional = "Conditional";
public const string Disabled = "Disabled";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ public Task<IEnumerable<KeyValuePair<string, string>>> ProcessKeyValue(Configura

if (featureFlag.Enabled)
{
keyValues.Add(new KeyValuePair<string, string>($"{featureFlagPath}:{FeatureManagementConstants.Status}", FeatureManagementConstants.Conditional));

//if (featureFlag.Conditions?.ClientFilters == null)
if (featureFlag.Conditions?.ClientFilters == null || !featureFlag.Conditions.ClientFilters.Any()) // workaround since we are not yet setting client filters to null
{
//
// Always on
keyValues.Add(new KeyValuePair<string, string>(featureFlagPath, true.ToString()));
keyValues.Add(new KeyValuePair<string, string>($"{featureFlagPath}:{FeatureManagementConstants.EnabledFor}:{0}:{FeatureManagementConstants.Name}", FeatureManagementConstants.AlwaysOnFilter));
}
else
{
Expand Down Expand Up @@ -80,7 +80,7 @@ public Task<IEnumerable<KeyValuePair<string, string>>> ProcessKeyValue(Configura
}
else
{
keyValues.Add(new KeyValuePair<string, string>($"{FeatureManagementConstants.SectionName}:{featureFlag.Id}", false.ToString()));
keyValues.Add(new KeyValuePair<string, string>($"{featureFlagPath}:{FeatureManagementConstants.Status}", FeatureManagementConstants.Disabled));
}

if (featureFlag.Variants != null)
Expand Down
96 changes: 56 additions & 40 deletions tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,6 @@ public class FeatureManagementTests
""enabled"": true,
""conditions"": {
""client_filters"": [
{
""name"": ""AlwaysOn""
}
]
},
""variants"": [
Expand Down Expand Up @@ -278,9 +275,6 @@ public class FeatureManagementTests
""enabled"": true,
""conditions"": {
""client_filters"": [
{
""name"": ""AlwaysOn""
}
]
},
""telemetry"": {
Expand Down Expand Up @@ -577,8 +571,8 @@ public void SelectFeatureFlags()
})
.Build();

Assert.Equal("True", config["FeatureManagement:App1_Feature1"]);
Assert.Equal("False", config["FeatureManagement:App1_Feature2"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App1_Feature1:EnabledFor:0:Name"]);
Assert.Equal("Disabled", config["FeatureManagement:App1_Feature2:Status"]);

// Verify that the feature flag that did not start with the specified prefix was not loaded
Assert.Null(config["FeatureManagement:Feature1"]);
Expand Down Expand Up @@ -620,10 +614,10 @@ public void MultipleSelectsInSameUseFeatureFlags()
})
.Build();

Assert.Equal("True", config["FeatureManagement:App1_Feature1"]);
Assert.Equal("False", config["FeatureManagement:App1_Feature2"]);
Assert.Equal("False", config["FeatureManagement:App2_Feature1"]);
Assert.Equal("True", config["FeatureManagement:App2_Feature2"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App1_Feature1:EnabledFor:0:Name"]);
Assert.Equal("Disabled", config["FeatureManagement:App1_Feature2:Status"]);
Assert.Equal("Disabled", config["FeatureManagement:App2_Feature1:Status"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App2_Feature2:EnabledFor:0:Name"]);

// Verify that the feature flag that did not start with the specified prefix was not loaded
Assert.Null(config["FeatureManagement:Feature1"]);
Expand Down Expand Up @@ -661,7 +655,7 @@ public void KeepSelectorPrecedenceAfterDedup()
})
.Build();
// label: App1_Label has higher precedence
Assert.Equal("True", config["FeatureManagement:Feature1"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:Feature1:EnabledFor:0:Name"]);
}

[Fact]
Expand Down Expand Up @@ -733,10 +727,10 @@ public void MultipleCallsToUseFeatureFlags()
})
.Build();

Assert.Equal("True", config["FeatureManagement:App1_Feature1"]);
Assert.Equal("False", config["FeatureManagement:App1_Feature2"]);
Assert.Equal("False", config["FeatureManagement:App2_Feature1"]);
Assert.Equal("True", config["FeatureManagement:App2_Feature2"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App1_Feature1:EnabledFor:0:Name"]);
Assert.Equal("Disabled", config["FeatureManagement:App1_Feature2:Status"]);
Assert.Equal("Disabled", config["FeatureManagement:App2_Feature1:Status"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App2_Feature2:EnabledFor:0:Name"]);

// Verify that the feature flag that did not start with the specified prefix was not loaded
Assert.Null(config["FeatureManagement:Feature1"]);
Expand Down Expand Up @@ -777,13 +771,13 @@ public void MultipleCallsToUseFeatureFlagsWithSelectAndLabel()
.Build();

// Loaded from prefix1 and label1
Assert.Equal("True", config["FeatureManagement:App1_Feature1"]);
Assert.Equal("False", config["FeatureManagement:App1_Feature2"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App1_Feature1:EnabledFor:0:Name"]);
Assert.Equal("Disabled", config["FeatureManagement:App1_Feature2:Status"]);

// Loaded from label2
Assert.Equal("False", config["FeatureManagement:App2_Feature1"]);
Assert.Equal("True", config["FeatureManagement:App2_Feature2"]);
Assert.Equal("True", config["FeatureManagement:Feature1"]);
Assert.Equal("Disabled", config["FeatureManagement:App2_Feature1:Status"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App2_Feature2:EnabledFor:0:Name"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:Feature1:EnabledFor:0:Name"]);
}

[Fact]
Expand Down Expand Up @@ -827,10 +821,10 @@ public void DifferentCacheExpirationsForMultipleFeatureFlagRegistrations()
})
.Build();

Assert.Equal("True", config["FeatureManagement:App1_Feature1"]);
Assert.Equal("False", config["FeatureManagement:App1_Feature2"]);
Assert.Equal("False", config["FeatureManagement:App2_Feature1"]);
Assert.Equal("True", config["FeatureManagement:App2_Feature2"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App1_Feature1:EnabledFor:0:Name"]);
Assert.Equal("Disabled", config["FeatureManagement:App1_Feature2:Status"]);
Assert.Equal("Disabled", config["FeatureManagement:App2_Feature1:Status"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App2_Feature2:EnabledFor:0:Name"]);

// update the value of App1_Feature1 feature flag with label1
featureFlagCollection[0] = ConfigurationModelFactory.ConfigurationSetting(
Expand Down Expand Up @@ -878,9 +872,9 @@ public void DifferentCacheExpirationsForMultipleFeatureFlagRegistrations()
Assert.Equal("Browser", config["FeatureManagement:App1_Feature1:EnabledFor:0:Name"]);
Assert.Equal("Chrome", config["FeatureManagement:App1_Feature1:EnabledFor:0:Parameters:AllowedBrowsers:0"]);
Assert.Equal("Edge", config["FeatureManagement:App1_Feature1:EnabledFor:0:Parameters:AllowedBrowsers:1"]);
Assert.Equal("False", config["FeatureManagement:App1_Feature2"]);
Assert.Equal("False", config["FeatureManagement:App2_Feature1"]);
Assert.Equal("True", config["FeatureManagement:App2_Feature2"]);
Assert.Equal("Disabled", config["FeatureManagement:App1_Feature2:Status"]);
Assert.Equal("Disabled", config["FeatureManagement:App2_Feature1:Status"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App2_Feature2:EnabledFor:0:Name"]);

// even though App2_Feature3 feature flag has been added, its value should not be loaded in config because label2 cache has not expired
Assert.Null(config["FeatureManagement:App2_Feature3"]);
Expand Down Expand Up @@ -920,11 +914,11 @@ public void OverwrittenCacheExpirationForSameFeatureFlagRegistrations()
})
.Build();

Assert.Equal("True", config["FeatureManagement:App1_Feature1"]);
Assert.Equal("False", config["FeatureManagement:App1_Feature2"]);
Assert.Equal("False", config["FeatureManagement:App2_Feature1"]);
Assert.Equal("True", config["FeatureManagement:App2_Feature2"]);
Assert.Equal("True", config["FeatureManagement:Feature1"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App1_Feature1:EnabledFor:0:Name"]);
Assert.Equal("Disabled", config["FeatureManagement:App1_Feature2:Status"]);
Assert.Equal("Disabled", config["FeatureManagement:App2_Feature1:Status"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App2_Feature2:EnabledFor:0:Name"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:Feature1:EnabledFor:0:Name"]);

// update the value of App1_Feature1 feature flag with label1
featureFlagCollection[0] = ConfigurationModelFactory.ConfigurationSetting(
Expand Down Expand Up @@ -954,11 +948,11 @@ public void OverwrittenCacheExpirationForSameFeatureFlagRegistrations()

// The cache expiration time for feature flags was overwritten by second call to UseFeatureFlags.
// Sleeping for cacheExpiration1 time should not update feature flags.
Assert.Equal("True", config["FeatureManagement:App1_Feature1"]);
Assert.Equal("False", config["FeatureManagement:App1_Feature2"]);
Assert.Equal("False", config["FeatureManagement:App2_Feature1"]);
Assert.Equal("True", config["FeatureManagement:App2_Feature2"]);
Assert.Equal("True", config["FeatureManagement:Feature1"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App1_Feature1:EnabledFor:0:Name"]);
Assert.Equal("Disabled", config["FeatureManagement:App1_Feature2:Status"]);
Assert.Equal("Disabled", config["FeatureManagement:App2_Feature1:Status"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:App2_Feature2:EnabledFor:0:Name"]);
Assert.Equal("AlwaysOn", config["FeatureManagement:Feature1:EnabledFor:0:Name"]);
}

[Fact]
Expand Down Expand Up @@ -993,7 +987,7 @@ public void SelectAndRefreshSingleFeatureFlag()
})
.Build();

Assert.Equal("False", config["FeatureManagement:Feature1"]);
Assert.Equal("Disabled", config["FeatureManagement:Feature1:Status"]);

// update the value of Feature1 feature flag with App1_Label
featureFlagCollection[2] = ConfigurationModelFactory.ConfigurationSetting(
Expand Down Expand Up @@ -1289,6 +1283,7 @@ public void WithVariants()
})
.Build();

Assert.Equal("AlwaysOn", config["FeatureManagement:VariantsFeature:EnabledFor:0:Name"]);
Assert.Equal("Big", config["FeatureManagement:VariantsFeature:Variants:0:Name"]);
Assert.Equal("600px", config["FeatureManagement:VariantsFeature:Variants:0:ConfigurationValue"]);
Assert.Equal("Small", config["FeatureManagement:VariantsFeature:Variants:1:Name"]);
Expand Down Expand Up @@ -1316,6 +1311,27 @@ public void WithVariants()
Assert.Equal("13992821", config["FeatureManagement:VariantsFeature:Allocation:Seed"]);
}

[Fact]
public void WithStatus()
{
var mockResponse = new Mock<Response>();
var mockClient = new Mock<ConfigurationClient>(MockBehavior.Strict);

mockClient.Setup(c => c.GetConfigurationSettingsAsync(It.IsAny<SettingSelector>(), It.IsAny<CancellationToken>()))
.Returns(new MockAsyncPageable(_featureFlagCollection));

var config = new ConfigurationBuilder()
.AddAzureAppConfiguration(options =>
{
options.ClientManager = TestHelpers.CreateMockedConfigurationClientManager(mockClient.Object);
options.UseFeatureFlags();
})
.Build();

Assert.Equal("Disabled", config["FeatureManagement:App1_Feature2:Status"]);
Assert.Equal("Conditional", config["FeatureManagement:Feature1:Status"]);
}

[Fact]
public void WithTelemetry()
{
Expand Down