From 7ae2ec6f48885d4a45d2a71af784d66fb446c822 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Wed, 26 Feb 2025 10:44:12 -0800 Subject: [PATCH 1/2] fix select order bug with feature flags --- .../AzureAppConfigurationOptions.cs | 4 +- .../FeatureManagementTests.cs | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs index 9391f21b..4b92c027 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs @@ -201,7 +201,7 @@ public AzureAppConfigurationOptions Select(string keyFilter, string labelFilter if (!_selectCalled) { - _selectors.Clear(); + _selectors.RemoveAll(selector => !selector.IsFeatureFlagSelector); _selectCalled = true; } @@ -229,7 +229,7 @@ public AzureAppConfigurationOptions SelectSnapshot(string name) if (!_selectCalled) { - _selectors.Clear(); + _selectors.RemoveAll(selector => !selector.IsFeatureFlagSelector); _selectCalled = true; } diff --git a/tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs b/tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs index c374e2c3..785c0219 100644 --- a/tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs +++ b/tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs @@ -1066,6 +1066,63 @@ public void SelectFeatureFlags() Assert.Null(config["FeatureManagement:App2_Feature2"]); } + [Fact] + public void SelectOrderDoesNotAffectLoad() + { + var mockResponse = new Mock(); + var mockClient = new Mock(MockBehavior.Strict); + + List kvCollection = new List + { + ConfigurationModelFactory.ConfigurationSetting("TestKey1", "TestValue1", "label", + eTag: new ETag("0a76e3d7-7ec1-4e37-883c-9ea6d0d89e63")), + ConfigurationModelFactory.ConfigurationSetting("TestKey2", "TestValue2", "label", + eTag: new ETag("31c38369-831f-4bf1-b9ad-79db56c8b989")), + }; + + MockAsyncPageable GetTestKeys(SettingSelector selector, CancellationToken ct) + { + List settingCollection; + + if (selector.KeyFilter.StartsWith(FeatureManagementConstants.FeatureFlagMarker)) + { + settingCollection = _featureFlagCollection; + } + else + { + settingCollection = kvCollection; + } + + var copy = new List(); + var newSetting = settingCollection.FirstOrDefault(s => (s.Key == selector.KeyFilter && s.Label == selector.LabelFilter)); + if (newSetting != null) + copy.Add(TestHelpers.CloneSetting(newSetting)); + return new MockAsyncPageable(copy); + } + + mockClient.Setup(c => c.GetConfigurationSettingsAsync(It.IsAny(), It.IsAny())) + .Returns((Func)GetTestKeys); + + var config = new ConfigurationBuilder() + .AddAzureAppConfiguration(options => + { + options.ClientManager = TestHelpers.CreateMockedConfigurationClientManager(mockClient.Object); + options.UseFeatureFlags(ff => + { + ff.Select("App1_Feature1", "App1_Label"); + ff.Select("App2_Feature1", "App2_Label"); + }); + options.Select("TestKey1", "label"); + options.Select("TestKey2", "label"); + }) + .Build(); + + Assert.Equal("True", config["FeatureManagement:App1_Feature1"]); + Assert.Equal("False", config["FeatureManagement:App2_Feature1"]); + Assert.Equal("TestValue1", config["TestKey1"]); + Assert.Equal("TestValue2", config["TestKey2"]); + } + [Fact] public void TestNullAndMissingValuesForConditions() { From 8b84a01787687ec6d0547d6c04dea2da4bc9b6e3 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Wed, 26 Feb 2025 11:22:03 -0800 Subject: [PATCH 2/2] update to use default query static selector --- .../AzureAppConfigurationOptions.cs | 7 ++++--- .../Tests.AzureAppConfiguration/FeatureManagementTests.cs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs index 4b92c027..a3dbfa05 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs @@ -22,6 +22,7 @@ public class AzureAppConfigurationOptions { private const int MaxRetries = 2; private static readonly TimeSpan MaxRetryDelay = TimeSpan.FromMinutes(1); + private static readonly KeyValueSelector DefaultQuery = new KeyValueSelector { KeyFilter = KeyFilter.Any, LabelFilter = LabelFilter.Null }; private List _individualKvWatchers = new List(); private List _ffWatchers = new List(); @@ -159,7 +160,7 @@ public AzureAppConfigurationOptions() }; // Adds the default query to App Configuration if and are never called. - _selectors = new List { new KeyValueSelector { KeyFilter = KeyFilter.Any, LabelFilter = LabelFilter.Null } }; + _selectors = new List { DefaultQuery }; } /// @@ -201,7 +202,7 @@ public AzureAppConfigurationOptions Select(string keyFilter, string labelFilter if (!_selectCalled) { - _selectors.RemoveAll(selector => !selector.IsFeatureFlagSelector); + _selectors.Remove(DefaultQuery); _selectCalled = true; } @@ -229,7 +230,7 @@ public AzureAppConfigurationOptions SelectSnapshot(string name) if (!_selectCalled) { - _selectors.RemoveAll(selector => !selector.IsFeatureFlagSelector); + _selectors.Remove(DefaultQuery); _selectCalled = true; } diff --git a/tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs b/tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs index 785c0219..d96e9e39 100644 --- a/tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs +++ b/tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs @@ -1077,7 +1077,7 @@ public void SelectOrderDoesNotAffectLoad() ConfigurationModelFactory.ConfigurationSetting("TestKey1", "TestValue1", "label", eTag: new ETag("0a76e3d7-7ec1-4e37-883c-9ea6d0d89e63")), ConfigurationModelFactory.ConfigurationSetting("TestKey2", "TestValue2", "label", - eTag: new ETag("31c38369-831f-4bf1-b9ad-79db56c8b989")), + eTag: new ETag("31c38369-831f-4bf1-b9ad-79db56c8b989")) }; MockAsyncPageable GetTestKeys(SettingSelector selector, CancellationToken ct)