public void RefreshTests_SetDirtyForcesNextRefresh() { IConfigurationRefresher refresher = null; var mockClient = GetMockConfigurationClient(); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", "label") .SetCacheExpiration(TimeSpan.FromDays(1)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue"; refresher.RefreshAsync().Wait(); Assert.Equal("TestValue1", config["TestKey1"]); refresher.SetDirty(TimeSpan.FromSeconds(1)); // Wait for the cache to expire based on the randomized delay in SetDirty() Thread.Sleep(1200); refresher.RefreshAsync().Wait(); Assert.Equal("newValue", config["TestKey1"]); }
public async Task RefreshTests_UpdatesAllSettingsIfInitialLoadFails() { var mockResponse = new Mock <Response>(); var mockClient = new Mock <ConfigurationClient>(MockBehavior.Strict, TestHelpers.CreateMockEndpointString()); mockClient.SetupSequence(c => c.GetConfigurationSettingsAsync(It.IsAny <SettingSelector>(), It.IsAny <CancellationToken>())) .Throws(new RequestFailedException("Request failed")) .Throws(new RequestFailedException("Request failed")) .Returns(new MockAsyncPageable(_kvCollection)); mockClient.SetupSequence(c => c.GetConfigurationSettingAsync("TestKey1", It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(Response.FromValue(_kvCollection.FirstOrDefault(s => s.Key == "TestKey1" && s.Label == "label"), mockResponse.Object))); IConfigurationRefresher refresher = null; IConfiguration configuration = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Select("TestKey*"); options.Client = mockClient.Object; options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", "label") .SetCacheExpiration(TimeSpan.FromSeconds(1)); }); refresher = options.GetRefresher(); }, optional: true) .Build(); // Validate initial load failed to retrieve any setting Assert.Null(configuration["TestKey1"]); Assert.Null(configuration["TestKey2"]); Assert.Null(configuration["TestKey3"]); // Act await Assert.ThrowsAsync <RequestFailedException>(async() => { await refresher.RefreshAsync(); }); await refresher.RefreshAsync(); Assert.Null(configuration["TestKey1"]); Assert.Null(configuration["TestKey2"]); Assert.Null(configuration["TestKey3"]); // Wait for the cache to expire Thread.Sleep(1500); await refresher.RefreshAsync(); // Validate all settings were loaded, including the ones not registered for refresh Assert.Equal("TestValue1", configuration["TestKey1"]); Assert.Equal("TestValue2", configuration["TestKey2"]); Assert.Equal("TestValue3", configuration["TestKey3"]); }
public void RefreshAsyncUpdatesConfig() { // Arrange var mockResponse = new Mock <Response>(); var mockClient = GetMockConfigurationClient(); IConfigurationRefresher refresher = null; var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", "label") .SetCacheExpiration(TimeSpan.FromDays(30)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue1"; refresher.ProcessPushNotification(_pushNotificationList.First(), TimeSpan.FromSeconds(0)); refresher.RefreshAsync().Wait(); Assert.Equal("newValue1", config["TestKey1"]); }
public void RefreshTests_RefreshAsyncThrowsOnRequestFailedException() { IConfigurationRefresher refresher = null; var mockClient = GetMockConfigurationClient(); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1") .SetCacheExpiration(TimeSpan.FromSeconds(1)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue"; mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .Throws(new RequestFailedException("Request failed.")); // Wait for the cache to expire Thread.Sleep(1500); Action action = () => refresher.RefreshAsync().Wait(); Assert.Throws <AggregateException>(action); Assert.NotEqual("newValue", config["TestKey1"]); }
public void RefreshTests_RefreshIsSkippedIfKvNotInSelectAndCacheIsNotExpired() { IConfigurationRefresher refresher = null; var mockClient = GetMockConfigurationClientSelectKeyLabel(); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey2", "label"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", "label") .SetCacheExpiration(TimeSpan.FromSeconds(10)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue1"; refresher.RefreshAsync().Wait(); Assert.Equal("TestValue1", config["TestKey1"]); }
public async Task <IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("El trigger HTTP con C#, proceso un request."); string keyVaultEntry = "proxymusk"; string messageKeyVault = "keyvault es local"; await _configurationRefresher.TryRefreshAsync(); if (!isLocal) { await _configurationRefresher.RefreshAsync(); messageKeyVault = _configuration[keyVaultEntry]; } bool flag = await _featureManagerSnapshot.IsEnabledAsync("ActivacionMensaje"); string keyName = "TestApp:Settings:Message02"; string message = _configuration[keyName]; if (flag) { GuardaenBD(message, log); } return(message != null ? (ActionResult) new OkObjectResult($"La cadena recuperada desde AppConfig fue '{message}', y el valor desde KeyVault era '{messageKeyVault}' {flag} :)") : new BadRequestObjectResult($"Please create a key-value with the key '{keyName}' in App Configuration, gracias.")); }
public void RefreshTests_RefreshIsSkippedIfCacheIsNotExpired() { IConfigurationRefresher refresher = null; var mockClient = GetMockConfigurationClient(); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1") .SetCacheExpiration(TimeSpan.FromSeconds(10)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue1"; // Wait for some time but not enough to let the cache expire Thread.Sleep(5000); refresher.RefreshAsync().Wait(); Assert.Equal("TestValue1", config["TestKey1"]); }
public void SyncTokenUpdatesCorrectNumberOfTimes() { // Arrange var mockResponse = new Mock <Response>(); var mockClient = GetMockConfigurationClient(); IConfigurationRefresher refresher = null; var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", "label") .SetCacheExpiration(TimeSpan.FromDays(30)); }); refresher = options.GetRefresher(); }) .Build(); foreach (PushNotification pushNotification in _pushNotificationList) { refresher.ProcessPushNotification(pushNotification, TimeSpan.FromSeconds(0)); refresher.RefreshAsync().Wait(); } mockClient.Verify(c => c.GetConfigurationSettingAsync(It.IsAny <ConfigurationSetting>(), It.IsAny <bool>(), It.IsAny <CancellationToken>()), Times.Exactly(_pushNotificationList.Count)); mockClient.Verify(c => c.UpdateSyncToken(It.IsAny <string>()), Times.Exactly(_pushNotificationList.Count)); }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log) { if (bool.TryParse(req.Query["refresh"], out var result) && result) { await _refresher.RefreshAsync(); } var responseMessage = $"Message: {_config.Message}{Environment.NewLine}Secret: {_config.Secret}"; return(new OkObjectResult(responseMessage)); }
public void SecretsWithDifferentRefreshIntervals() { IConfigurationRefresher refresher = null; TimeSpan shortCacheExpirationTime = TimeSpan.FromSeconds(1); TimeSpan longCacheExpirationTime = TimeSpan.FromDays(1); var mockResponse = new Mock <Response>(); var mockClient = new Mock <ConfigurationClient>(MockBehavior.Strict, TestHelpers.CreateMockEndpointString()); mockClient.Setup(c => c.GetConfigurationSettingsAsync(It.IsAny <SettingSelector>(), It.IsAny <CancellationToken>())) .Returns(new MockAsyncPageable(_kvCollectionPageOne)); var mockSecretClient = new Mock <SecretClient>(MockBehavior.Strict); mockSecretClient.SetupGet(client => client.VaultUri).Returns(new Uri("https://keyvault-theclassics.vault.azure.net")); mockSecretClient.Setup(client => client.GetSecretAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns((string name, string version, CancellationToken cancellationToken) => Task.FromResult((Response <KeyVaultSecret>) new MockResponse <KeyVaultSecret>(new KeyVaultSecret(name, _secretValue)))); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.ConfigureKeyVault(kv => { kv.Register(mockSecretClient.Object); kv.SetSecretRefreshInterval("TK1", shortCacheExpirationTime); kv.SetSecretRefreshInterval(longCacheExpirationTime); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal(_secretValue, config["TK1"]); Assert.Equal(_secretValue, config["TK2"]); // Sleep to let the secret cache expire for one secret Thread.Sleep(shortCacheExpirationTime); refresher.RefreshAsync().Wait(); Assert.Equal(_secretValue, config["TK1"]); Assert.Equal(_secretValue, config["TK2"]); // Validate that 3 calls were made to fetch secrets from KeyVault because the secret cache had expired for only one secret. mockSecretClient.Verify(client => client.GetSecretAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Exactly(3)); }
public static async Task Main(string[] args) { IConfiguration _configuration = null; IConfigurationRefresher _refresher = null; var RefreshInterval = TimeSpan.FromSeconds(Double.Parse(ConfigurationManager.AppSettings["RefreshInterval"])); var builder = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options .Connect(ConfigurationManager.AppSettings["AzureApplicationConnectionString"]) .ConfigureRefresh(refresh => { refresh .Register("TestApp:Settings:Message") .SetCacheExpiration(RefreshInterval); }) .UseFeatureFlags(refresh => { refresh.CacheExpirationTime = RefreshInterval; }); _refresher = options.GetRefresher(); }); _configuration = builder.Build(); IServiceCollection services = new ServiceCollection(); services.AddSingleton <IConfiguration>(_configuration).AddFeatureManagement(); using (ServiceProvider serviceProvider = services.BuildServiceProvider()) { IFeatureManager featureManager = serviceProvider.GetRequiredService <IFeatureManager>(); if (await featureManager.IsEnabledAsync("Beta")) { Console.WriteLine("Welcome to the beta!"); } } PrintConfig(_configuration); await _refresher.RefreshAsync(); PrintConfig(_configuration); }
public async Task RefreshTests_RefreshAsyncThrowsOnExceptionWhenOptionalIsTrueForInitialLoad() { IConfigurationRefresher refresher = null; var mockResponse = new Mock <Response>(); var mockClient = new Mock <ConfigurationClient>(MockBehavior.Strict, TestHelpers.CreateMockEndpointString()); mockClient.SetupSequence(c => c.GetConfigurationSettingsAsync(It.IsAny <SettingSelector>(), It.IsAny <CancellationToken>())) .Returns(new MockAsyncPageable(_kvCollection)) .Throws(new RequestFailedException("Request failed.")); mockClient.SetupSequence(c => c.GetConfigurationSettingAsync("TestKey1", It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(Response.FromValue(_kvCollection.FirstOrDefault(s => s.Key == "TestKey1"), mockResponse.Object))) .Returns(Task.FromResult(Response.FromValue(_kvCollection.FirstOrDefault(s => s.Key == "TestKey1"), mockResponse.Object))); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", refreshAll: true) .SetCacheExpiration(TimeSpan.FromSeconds(1)); }); refresher = options.GetRefresher(); }, optional: true) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue"; // Wait for the cache to expire Thread.Sleep(1500); await Assert.ThrowsAsync <RequestFailedException>(async() => await refresher.RefreshAsync() ); }
public void RefreshTests_RefreshAllTrueUpdatesEntireConfiguration() { var serviceCollection = new List <ConfigurationSetting>(_kvCollection); IConfigurationRefresher refresher = null; var mockClient = GetMockConfigurationClient(); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", "label", refreshAll: true) .SetCacheExpiration(TimeSpan.FromSeconds(1)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); Assert.Equal("TestValue2", config["TestKey2"]); Assert.Equal("TestValue3", config["TestKey3"]); serviceCollection.ForEach(kv => kv.Value = "newValue"); // Wait for the cache to expire Thread.Sleep(1500); refresher.RefreshAsync().Wait(); Assert.Equal("newValue", config["TestKey1"]); Assert.Equal("newValue", config["TestKey2"]); Assert.Equal("newValue", config["TestKey3"]); }
private void WaitAndRefresh(IConfigurationRefresher refresher, int millisecondsDelay) { Task.Delay(millisecondsDelay).Wait(); refresher.RefreshAsync().Wait(); }
public void RefreshTests_RefreshAllForNonExistentSentinelDoesNothing() { var serviceCollection = new List <ConfigurationSetting>(_kvCollection); var mockResponse = new Mock <Response>(); var mockClient = new Mock <ConfigurationClient>(MockBehavior.Strict, TestHelpers.CreateMockEndpointString()); Response <ConfigurationSetting> GetSettingFromService(string k, string l, CancellationToken ct) { return(Response.FromValue(serviceCollection.FirstOrDefault(s => s.Key == k), mockResponse.Object)); } Response <ConfigurationSetting> GetIfChanged(ConfigurationSetting setting, bool cond, CancellationToken ct) { var newSetting = serviceCollection.FirstOrDefault(s => s.Key == setting.Key); var unchanged = (newSetting.Key == setting.Key && newSetting.Label == setting.Label && newSetting.Value == setting.Value); var response = new MockResponse(unchanged ? 304 : 200); return(Response.FromValue(newSetting, response)); } mockClient.Setup(c => c.GetConfigurationSettingsAsync(It.IsAny <SettingSelector>(), It.IsAny <CancellationToken>())) .Returns(() => { var copy = new List <ConfigurationSetting>(); foreach (var setting in serviceCollection) { copy.Add(TestHelpers.CloneSetting(setting)); } ; return(new MockAsyncPageable(copy)); }); mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync((Func <string, string, CancellationToken, Response <ConfigurationSetting> >)GetSettingFromService); mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <ConfigurationSetting>(), It.IsAny <bool>(), It.IsAny <CancellationToken>())) .ReturnsAsync((Func <ConfigurationSetting, bool, CancellationToken, Response <ConfigurationSetting> >)GetIfChanged); IConfigurationRefresher refresher = null; var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1") .Register("NonExistentKey", refreshAll: true) .SetCacheExpiration(TimeSpan.FromSeconds(1)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); Assert.Equal("TestValue2", config["TestKey2"]); Assert.Equal("TestValue3", config["TestKey3"]); serviceCollection.ElementAt(0).Value = "newValue1"; serviceCollection.ElementAt(1).Value = "newValue2"; serviceCollection.Remove(serviceCollection.Last()); // Wait for the cache to expire Thread.Sleep(1500); refresher.RefreshAsync().Wait(); // Validate that key-values registered for refresh were updated Assert.Equal("newValue1", config["TestKey1"]); // Validate that other key-values were not updated, which means refresh all wasn't triggered Assert.Equal("TestValue2", config["TestKey2"]); Assert.Equal("TestValue3", config["TestKey3"]); }
private async Task RefreshAsync(CancellationToken cancellationToken = default) { await configurationClient.SetConfigurationSettingAsync(ConfigurationConstants.SentinelKey, DateTime.UtcNow.ToString("o"), cancellationToken : cancellationToken).ConfigureAwait(false); await configurationRefresher.RefreshAsync().ConfigureAwait(false); }
public void CachedSecretIsInvalidatedWhenRefreshAllIsTrue() { IConfigurationRefresher refresher = null; TimeSpan cacheExpirationTime = TimeSpan.FromSeconds(1); var mockResponse = new Mock <Response>(); var mockClient = new Mock <ConfigurationClient>(MockBehavior.Strict, TestHelpers.CreateMockEndpointString()); Response <ConfigurationSetting> GetTestKey(string key, string label, CancellationToken cancellationToken) { return(Response.FromValue(TestHelpers.CloneSetting(sentinelKv), mockResponse.Object)); } Response <ConfigurationSetting> GetIfChanged(ConfigurationSetting setting, bool onlyIfChanged, CancellationToken cancellationToken) { var unchanged = sentinelKv.Key == setting.Key && sentinelKv.Label == setting.Label && sentinelKv.Value == setting.Value; var response = new MockResponse(unchanged ? 304 : 200); return(Response.FromValue(sentinelKv, response)); } mockClient.Setup(c => c.GetConfigurationSettingsAsync(It.IsAny <SettingSelector>(), It.IsAny <CancellationToken>())) .Returns(new MockAsyncPageable(new List <ConfigurationSetting> { _kv })); mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync((Func <string, string, CancellationToken, Response <ConfigurationSetting> >)GetTestKey); mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <ConfigurationSetting>(), It.IsAny <bool>(), It.IsAny <CancellationToken>())) .ReturnsAsync((Func <ConfigurationSetting, bool, CancellationToken, Response <ConfigurationSetting> >)GetIfChanged); var mockSecretClient = new Mock <SecretClient>(MockBehavior.Strict); mockSecretClient.SetupGet(client => client.VaultUri).Returns(new Uri("https://keyvault-theclassics.vault.azure.net")); mockSecretClient.Setup(client => client.GetSecretAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns((string name, string version, CancellationToken cancellationToken) => Task.FromResult((Response <KeyVaultSecret>) new MockResponse <KeyVaultSecret>(new KeyVaultSecret(name, _secretValue)))); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.ConfigureKeyVault(kv => { kv.Register(mockSecretClient.Object); kv.SetSecretRefreshInterval(_kv.Key, TimeSpan.FromDays(1)); }); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("Sentinel", refreshAll: true) .SetCacheExpiration(cacheExpirationTime); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("Value1", config["Sentinel"]); Assert.Equal(_secretValue, config[_kv.Key]); // Update sentinel key-value to trigger refresh operation sentinelKv.Value = "Value2"; Thread.Sleep(cacheExpirationTime); refresher.RefreshAsync().Wait(); Assert.Equal("Value2", config["Sentinel"]); Assert.Equal(_secretValue, config[_kv.Key]); // Validate that 2 calls were made to fetch secrets from KeyVault // Even though Key Vault refresh interval has not elapsed, refreshAll trigger should fetch secret from Key Vault again mockSecretClient.Verify(client => client.GetSecretAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); }