72 lines
2.9 KiB
C#
72 lines
2.9 KiB
C#
|
|
using FluentAssertions;
|
||
|
|
using Microsoft.Extensions.Configuration;
|
||
|
|
using Microsoft.Extensions.DependencyInjection;
|
||
|
|
using Microsoft.Extensions.Options;
|
||
|
|
using SIGCM2.Application.Audit;
|
||
|
|
using SIGCM2.Infrastructure;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
namespace SIGCM2.Application.Tests.Infrastructure.Audit;
|
||
|
|
|
||
|
|
/// UDT-010 Batch 3 — AuditOptions binding smoke tests.
|
||
|
|
/// Validates that AddInfrastructure binds AuditOptions from the "Audit" config section
|
||
|
|
/// and falls back to the POCO defaults when the section is absent.
|
||
|
|
public sealed class AuditOptionsBindingTests
|
||
|
|
{
|
||
|
|
private static IServiceProvider BuildProvider(IEnumerable<KeyValuePair<string, string?>>? overrides = null)
|
||
|
|
{
|
||
|
|
// Minimum required config for AddInfrastructure to succeed.
|
||
|
|
var inMemory = new Dictionary<string, string?>
|
||
|
|
{
|
||
|
|
["ConnectionStrings:SqlServer"] = "Server=nowhere;Database=x;Integrated Security=true;",
|
||
|
|
["Jwt:Issuer"] = "test",
|
||
|
|
["Jwt:Audience"] = "test",
|
||
|
|
["Jwt:AccessTokenMinutes"] = "60",
|
||
|
|
["Jwt:RefreshTokenDays"] = "7",
|
||
|
|
["Jwt:PrivateKeyPath"] = "unused-in-this-test.pem",
|
||
|
|
["Jwt:PublicKeyPath"] = "unused-in-this-test.pem",
|
||
|
|
};
|
||
|
|
|
||
|
|
if (overrides is not null)
|
||
|
|
foreach (var kv in overrides)
|
||
|
|
inMemory[kv.Key] = kv.Value;
|
||
|
|
|
||
|
|
var config = new ConfigurationBuilder().AddInMemoryCollection(inMemory).Build();
|
||
|
|
var services = new ServiceCollection();
|
||
|
|
services.AddInfrastructure(config);
|
||
|
|
return services.BuildServiceProvider();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AuditOptions_WithoutConfigSection_UsesPocoDefaults()
|
||
|
|
{
|
||
|
|
using var sp = (ServiceProvider)BuildProvider();
|
||
|
|
|
||
|
|
var opts = sp.GetRequiredService<IOptions<AuditOptions>>().Value;
|
||
|
|
|
||
|
|
opts.SanitizedKeys.Should().Contain("password");
|
||
|
|
opts.SanitizedKeys.Should().Contain("refreshToken");
|
||
|
|
opts.SanitizedKeys.Should().Contain("apiKey");
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AuditOptions_WithConfigSection_AddsToDefaults_PerIConfigurationArrayBinding()
|
||
|
|
{
|
||
|
|
// IConfiguration array binding is ADDITIVE, not REPLACE: config values at indices 0..N
|
||
|
|
// overwrite those indices but defaults beyond N are preserved. This is intended for
|
||
|
|
// AuditOptions — extensibility is additive (append, not replace).
|
||
|
|
using var sp = (ServiceProvider)BuildProvider(new[]
|
||
|
|
{
|
||
|
|
new KeyValuePair<string, string?>("Audit:SanitizedKeys:11", "customSecret"),
|
||
|
|
new KeyValuePair<string, string?>("Audit:SanitizedKeys:12", "internalToken"),
|
||
|
|
});
|
||
|
|
|
||
|
|
var opts = sp.GetRequiredService<IOptions<AuditOptions>>().Value;
|
||
|
|
|
||
|
|
// The 11 defaults remain + the 2 extras appear at the configured indices.
|
||
|
|
opts.SanitizedKeys.Should().Contain("password"); // default survived
|
||
|
|
opts.SanitizedKeys.Should().Contain("customSecret"); // appended via config
|
||
|
|
opts.SanitizedKeys.Should().Contain("internalToken"); // appended via config
|
||
|
|
}
|
||
|
|
}
|