Skip to content

Commit 6ec290e

Browse files
Fix bug with feature flag and key-value select ordering (#629)
* fix select order bug with feature flags * update to use default query static selector
1 parent ab01890 commit 6ec290e

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class AzureAppConfigurationOptions
2222
{
2323
private const int MaxRetries = 2;
2424
private static readonly TimeSpan MaxRetryDelay = TimeSpan.FromMinutes(1);
25+
private static readonly KeyValueSelector DefaultQuery = new KeyValueSelector { KeyFilter = KeyFilter.Any, LabelFilter = LabelFilter.Null };
2526

2627
private List<KeyValueWatcher> _individualKvWatchers = new List<KeyValueWatcher>();
2728
private List<KeyValueWatcher> _ffWatchers = new List<KeyValueWatcher>();
@@ -159,7 +160,7 @@ public AzureAppConfigurationOptions()
159160
};
160161

161162
// Adds the default query to App Configuration if <see cref="Select"/> and <see cref="SelectSnapshot"/> are never called.
162-
_selectors = new List<KeyValueSelector> { new KeyValueSelector { KeyFilter = KeyFilter.Any, LabelFilter = LabelFilter.Null } };
163+
_selectors = new List<KeyValueSelector> { DefaultQuery };
163164
}
164165

165166
/// <summary>
@@ -201,7 +202,7 @@ public AzureAppConfigurationOptions Select(string keyFilter, string labelFilter
201202

202203
if (!_selectCalled)
203204
{
204-
_selectors.Clear();
205+
_selectors.Remove(DefaultQuery);
205206

206207
_selectCalled = true;
207208
}
@@ -229,7 +230,7 @@ public AzureAppConfigurationOptions SelectSnapshot(string name)
229230

230231
if (!_selectCalled)
231232
{
232-
_selectors.Clear();
233+
_selectors.Remove(DefaultQuery);
233234

234235
_selectCalled = true;
235236
}

tests/Tests.AzureAppConfiguration/FeatureManagementTests.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,63 @@ public void SelectFeatureFlags()
10661066
Assert.Null(config["FeatureManagement:App2_Feature2"]);
10671067
}
10681068

1069+
[Fact]
1070+
public void SelectOrderDoesNotAffectLoad()
1071+
{
1072+
var mockResponse = new Mock<Response>();
1073+
var mockClient = new Mock<ConfigurationClient>(MockBehavior.Strict);
1074+
1075+
List<ConfigurationSetting> kvCollection = new List<ConfigurationSetting>
1076+
{
1077+
ConfigurationModelFactory.ConfigurationSetting("TestKey1", "TestValue1", "label",
1078+
eTag: new ETag("0a76e3d7-7ec1-4e37-883c-9ea6d0d89e63")),
1079+
ConfigurationModelFactory.ConfigurationSetting("TestKey2", "TestValue2", "label",
1080+
eTag: new ETag("31c38369-831f-4bf1-b9ad-79db56c8b989"))
1081+
};
1082+
1083+
MockAsyncPageable GetTestKeys(SettingSelector selector, CancellationToken ct)
1084+
{
1085+
List<ConfigurationSetting> settingCollection;
1086+
1087+
if (selector.KeyFilter.StartsWith(FeatureManagementConstants.FeatureFlagMarker))
1088+
{
1089+
settingCollection = _featureFlagCollection;
1090+
}
1091+
else
1092+
{
1093+
settingCollection = kvCollection;
1094+
}
1095+
1096+
var copy = new List<ConfigurationSetting>();
1097+
var newSetting = settingCollection.FirstOrDefault(s => (s.Key == selector.KeyFilter && s.Label == selector.LabelFilter));
1098+
if (newSetting != null)
1099+
copy.Add(TestHelpers.CloneSetting(newSetting));
1100+
return new MockAsyncPageable(copy);
1101+
}
1102+
1103+
mockClient.Setup(c => c.GetConfigurationSettingsAsync(It.IsAny<SettingSelector>(), It.IsAny<CancellationToken>()))
1104+
.Returns((Func<SettingSelector, CancellationToken, MockAsyncPageable>)GetTestKeys);
1105+
1106+
var config = new ConfigurationBuilder()
1107+
.AddAzureAppConfiguration(options =>
1108+
{
1109+
options.ClientManager = TestHelpers.CreateMockedConfigurationClientManager(mockClient.Object);
1110+
options.UseFeatureFlags(ff =>
1111+
{
1112+
ff.Select("App1_Feature1", "App1_Label");
1113+
ff.Select("App2_Feature1", "App2_Label");
1114+
});
1115+
options.Select("TestKey1", "label");
1116+
options.Select("TestKey2", "label");
1117+
})
1118+
.Build();
1119+
1120+
Assert.Equal("True", config["FeatureManagement:App1_Feature1"]);
1121+
Assert.Equal("False", config["FeatureManagement:App2_Feature1"]);
1122+
Assert.Equal("TestValue1", config["TestKey1"]);
1123+
Assert.Equal("TestValue2", config["TestKey2"]);
1124+
}
1125+
10691126
[Fact]
10701127
public void TestNullAndMissingValuesForConditions()
10711128
{

0 commit comments

Comments
 (0)