Skip to content

Add testcase for refresh activity #665

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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 @@ -119,6 +119,11 @@ internal IEnumerable<IKeyValueAdapter> Adapters
/// </summary>
internal IConfigurationSettingPageIterator ConfigurationSettingPageIterator { get; set; }

/// <summary>
/// For use in tests only. An optional activity source name to specify the activity source used by the configuration provider.
/// </summary>
internal string ActivitySourceName { get; set; }

/// <summary>
/// An optional timespan value to set the minimum backoff duration to a value other than the default.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration
{
internal class AzureAppConfigurationProvider : ConfigurationProvider, IConfigurationRefresher, IDisposable
{
private readonly ActivitySource _activitySource = new ActivitySource(ActivityNames.AzureAppConfigurationActivitySource);
private readonly ActivitySource _activitySource;
private bool _optional;
private bool _isInitialLoadComplete = false;
private bool _isAssemblyInspected;
Expand Down Expand Up @@ -151,6 +151,8 @@ public AzureAppConfigurationProvider(IConfigurationClientManager configClientMan
{
SetRequestTracingOptions();
}

_activitySource = new ActivitySource(options.ActivitySourceName ?? ActivityNames.AzureAppConfigurationActivitySource);
}

/// <summary>
Expand All @@ -159,7 +161,7 @@ public AzureAppConfigurationProvider(IConfigurationClientManager configClientMan
public override void Load()
{
var watch = Stopwatch.StartNew();
using Activity activity = _activitySource.StartActivity(ActivityNames.Load);
using Activity activity = _activitySource?.StartActivity(ActivityNames.Load);
try
{
using var startupCancellationTokenSource = new CancellationTokenSource(_options.Startup.Timeout);
Expand Down Expand Up @@ -259,7 +261,7 @@ public async Task RefreshAsync(CancellationToken cancellationToken)
return;
}

using Activity activity = _activitySource.StartActivity(ActivityNames.Refresh);
using Activity activity = _activitySource?.StartActivity(ActivityNames.Refresh);
// Check if initial configuration load had failed
if (_mappedData == null)
{
Expand Down Expand Up @@ -1422,7 +1424,7 @@ private async Task ProcessKeyValueChangesAsync(
public void Dispose()
{
(_configClientManager as ConfigurationClientManager)?.Dispose();
_activitySource.Dispose();
_activitySource?.Dispose();
}
}
}
63 changes: 63 additions & 0 deletions tests/Tests.AzureAppConfiguration/RefreshTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Moq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -1218,6 +1219,68 @@ MockAsyncPageable GetTestKeys(SettingSelector selector, CancellationToken ct)
Assert.Null(config["FeatureManagement:MyFeature"]);
}

[Fact]
public async Task RefreshTests_StartsRefreshActivity()
{
string activitySourceName = Guid.NewGuid().ToString();

var _activities = new List<Activity>();
var _activityListener = new ActivityListener
{
ShouldListenTo = source => source.Name == activitySourceName,
Sample = (ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllData,
ActivityStarted = activity => _activities.Add(activity),
};
ActivitySource.AddActivityListener(_activityListener);

IConfigurationRefresher refresher = null;
var mockClient = GetMockConfigurationClient();

var mockAsyncPageable = new MockAsyncPageable(_kvCollection);

mockClient.Setup(c => c.GetConfigurationSettingsAsync(It.IsAny<SettingSelector>(), It.IsAny<CancellationToken>()))
.Callback(() => mockAsyncPageable.UpdateCollection(_kvCollection))
.Returns(mockAsyncPageable);

var config = new ConfigurationBuilder()
.AddAzureAppConfiguration(options =>
{
options.ClientManager = TestHelpers.CreateMockedConfigurationClientManager(mockClient.Object);
options.Select("TestKey*", "label");
options.ConfigurationSettingPageIterator = new MockConfigurationSettingPageIterator();
options.ConfigureRefresh(refreshOptions =>
{
refreshOptions.RegisterAll()
.SetRefreshInterval(TimeSpan.FromSeconds(1));
});
options.ActivitySourceName = activitySourceName;

refresher = options.GetRefresher();
})
.Build();

Assert.Single(_activities);
Assert.Contains(_activities, a => a.OperationName == "Load");

// Wait for the cache to expire
await Task.Delay(1500);
await refresher.RefreshAsync();

Assert.Equal(2, _activities.Count);
Assert.Equal("Refresh", _activities.Last().OperationName);

await refresher.RefreshAsync();
Assert.Equal(2, _activities.Count); // only start refresh activity when real refresh happens

// Wait for the cache to expire
await Task.Delay(1500);
await refresher.RefreshAsync();
Assert.Equal(3, _activities.Count);
Assert.Equal("Refresh", _activities.Last().OperationName);

_activityListener.Dispose();
}

#if NET8_0
[Fact]
public void RefreshTests_ChainedConfigurationProviderUsedAsRootForRefresherProvider()
Expand Down
32 changes: 32 additions & 0 deletions tests/Tests.AzureAppConfiguration/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
using Moq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace Tests.AzureAppConfiguration
Expand Down Expand Up @@ -346,5 +348,35 @@ public void TestKeepSelectorPrecedenceAfterDedup()

Assert.True(config["message"] == "message from dev label");
}

[Fact]
public void TestActivitySource()
{
var _activities = new List<Activity>();
var _activityListener = new ActivityListener
{
ShouldListenTo = source => source.Name == "Microsoft.Extensions.Configuration.AzureAppConfiguration",
Sample = (ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllData,
ActivityStarted = activity => _activities.Add(activity),
};
ActivitySource.AddActivityListener(_activityListener);

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(_kvCollectionPageOne));

mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Response.FromValue(_kv, mockResponse.Object));

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

Assert.Contains(_activities, a => a.OperationName == "Load");

_activityListener.Dispose();
}
}
}