audit, advisories and doctors/setup work
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.FeatureFlags.Tests;
|
||||
|
||||
[Trait("Category", "Unit")]
|
||||
public class FeatureFlagServiceCollectionExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void AddFeatureFlags_RegistersFeatureFlagService()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
// Act
|
||||
services.AddFeatureFlags();
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
// Assert
|
||||
var service = provider.GetService<IFeatureFlagService>();
|
||||
service.Should().NotBeNull();
|
||||
service.Should().BeOfType<CompositeFeatureFlagService>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddFeatureFlags_WithOptions_ConfiguresOptions()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
// Act
|
||||
services.AddFeatureFlags(options =>
|
||||
{
|
||||
options.EnableCaching = true;
|
||||
options.CacheDuration = TimeSpan.FromMinutes(5);
|
||||
options.DefaultValue = true;
|
||||
});
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
var options = provider.GetRequiredService<Microsoft.Extensions.Options.IOptions<FeatureFlagOptions>>();
|
||||
|
||||
// Assert
|
||||
options.Value.EnableCaching.Should().BeTrue();
|
||||
options.Value.CacheDuration.Should().Be(TimeSpan.FromMinutes(5));
|
||||
options.Value.DefaultValue.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddConfigurationFeatureFlags_RegistersConfigurationProvider()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
var configData = new Dictionary<string, string?>
|
||||
{
|
||||
{ "FeatureFlags:TestFlag", "true" }
|
||||
};
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(configData)
|
||||
.Build();
|
||||
|
||||
services.AddSingleton<IConfiguration>(configuration);
|
||||
services.AddFeatureFlags();
|
||||
services.AddConfigurationFeatureFlags();
|
||||
|
||||
// Act
|
||||
var provider = services.BuildServiceProvider();
|
||||
var featureFlagProviders = provider.GetServices<IFeatureFlagProvider>().ToList();
|
||||
|
||||
// Assert
|
||||
featureFlagProviders.Should().ContainSingle();
|
||||
featureFlagProviders[0].Name.Should().Be("Configuration");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddConfigurationFeatureFlags_WithCustomSectionName_UsesCorrectSection()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
var configData = new Dictionary<string, string?>
|
||||
{
|
||||
{ "CustomFlags:MyFlag", "true" }
|
||||
};
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(configData)
|
||||
.Build();
|
||||
|
||||
services.AddSingleton<IConfiguration>(configuration);
|
||||
services.AddFeatureFlags();
|
||||
services.AddConfigurationFeatureFlags(sectionName: "CustomFlags");
|
||||
|
||||
// Act
|
||||
var provider = services.BuildServiceProvider();
|
||||
var featureFlagService = provider.GetRequiredService<IFeatureFlagService>();
|
||||
var result = featureFlagService.IsEnabledAsync("MyFlag").Result;
|
||||
|
||||
// Assert
|
||||
result.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddInMemoryFeatureFlags_RegistersInMemoryProvider()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
var flags = new Dictionary<string, bool>
|
||||
{
|
||||
{ "InMemoryFlag", true }
|
||||
};
|
||||
|
||||
services.AddFeatureFlags();
|
||||
services.AddInMemoryFeatureFlags(flags);
|
||||
|
||||
// Act
|
||||
var provider = services.BuildServiceProvider();
|
||||
var featureFlagService = provider.GetRequiredService<IFeatureFlagService>();
|
||||
var result = featureFlagService.IsEnabledAsync("InMemoryFlag").Result;
|
||||
|
||||
// Assert
|
||||
result.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddInMemoryFeatureFlags_WithPriority_SetsCorrectPriority()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
services.AddFeatureFlags();
|
||||
services.AddInMemoryFeatureFlags(new Dictionary<string, bool> { { "Flag", true } }, priority: 5);
|
||||
|
||||
// Act
|
||||
var provider = services.BuildServiceProvider();
|
||||
var featureFlagProviders = provider.GetServices<IFeatureFlagProvider>().ToList();
|
||||
|
||||
// Assert
|
||||
featureFlagProviders.Single().Priority.Should().Be(5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddFeatureFlagProvider_RegistersCustomProvider()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
services.AddFeatureFlags();
|
||||
services.AddFeatureFlagProvider<TestFeatureFlagProvider>();
|
||||
|
||||
// Act
|
||||
var provider = services.BuildServiceProvider();
|
||||
var featureFlagProviders = provider.GetServices<IFeatureFlagProvider>().ToList();
|
||||
|
||||
// Assert
|
||||
featureFlagProviders.Should().ContainSingle();
|
||||
featureFlagProviders[0].Should().BeOfType<TestFeatureFlagProvider>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddFeatureFlagProvider_WithFactory_RegistersCustomProvider()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
services.AddFeatureFlags();
|
||||
services.AddFeatureFlagProvider(_ => new TestFeatureFlagProvider());
|
||||
|
||||
// Act
|
||||
var provider = services.BuildServiceProvider();
|
||||
var featureFlagProviders = provider.GetServices<IFeatureFlagProvider>().ToList();
|
||||
|
||||
// Assert
|
||||
featureFlagProviders.Should().ContainSingle();
|
||||
featureFlagProviders[0].Should().BeOfType<TestFeatureFlagProvider>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultipleProviders_AreRegisteredInPriorityOrder()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
var configData = new Dictionary<string, string?>
|
||||
{
|
||||
{ "FeatureFlags:SharedFlag", "false" }
|
||||
};
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(configData)
|
||||
.Build();
|
||||
|
||||
services.AddSingleton<IConfiguration>(configuration);
|
||||
services.AddFeatureFlags();
|
||||
services.AddConfigurationFeatureFlags(priority: 50);
|
||||
services.AddInMemoryFeatureFlags(new Dictionary<string, bool> { { "SharedFlag", true } }, priority: 10);
|
||||
|
||||
// Act
|
||||
var provider = services.BuildServiceProvider();
|
||||
var featureFlagService = provider.GetRequiredService<IFeatureFlagService>();
|
||||
var result = featureFlagService.IsEnabledAsync("SharedFlag").Result;
|
||||
|
||||
// Assert - InMemory has lower priority number (higher precedence), so it wins
|
||||
result.Should().BeTrue();
|
||||
}
|
||||
|
||||
private class TestFeatureFlagProvider : FeatureFlagProviderBase
|
||||
{
|
||||
public override string Name => "Test";
|
||||
|
||||
public override Task<FeatureFlagResult?> TryGetFlagAsync(
|
||||
string flagKey,
|
||||
FeatureFlagEvaluationContext context,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return Task.FromResult<FeatureFlagResult?>(
|
||||
new FeatureFlagResult(flagKey, true, null, "Test", Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user