using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using ZB.MOM.WW.Secrets.Abstractions;
using ZB.MOM.WW.Secrets.DependencyInjection;
using ZB.MOM.WW.Secrets.Replication;
using ZB.MOM.WW.Secrets.Replicator.SqlServer.DependencyInjection;
using ZB.MOM.WW.Secrets.Sqlite;
namespace ZB.MOM.WW.Secrets.Replicator.SqlServer.Tests.DependencyInjection;
///
/// scadaproj#30 (Secrets-001): the SQL-Server extensions must produce the same graph whether the
/// application calls AddZbSecrets before or after them.
///
///
/// Before the fix both modes put their registrations in with TryAdd ahead of their own
/// internal AddZbSecrets call, so an application that had ALREADY called AddZbSecrets
/// — the order the README teaches, and the only way to pass contentRootPath — silently kept
/// the SQLite store (shared-store mode) or the no-op replicator (hub mode). Every test here builds the
/// real container and resolves, in both orders.
///
public sealed class RegistrationOrderTests
{
public enum Order
{
CoreFirst,
ExtensionFirst,
}
private static IConfiguration Config() =>
new ConfigurationBuilder().AddInMemoryCollection(new Dictionary
{
["Secrets:SqlitePath"] = Path.Combine(Path.GetTempPath(), $"zb-order-{Guid.NewGuid():N}.db"),
["Secrets:RunMigrationsOnStartup"] = "false",
["Secrets:MasterKey:Source"] = "Environment",
["Secrets:MasterKey:EnvVarName"] = "ZB_SECRETS_TEST_KEY",
["Secrets:SqlServer:ConnectionString"] = "Server=unused;Database=x;",
}).Build();
private static ServiceProvider Build(Order order, Action extension)
{
IConfiguration config = Config();
var services = new ServiceCollection();
services.AddLogging();
if (order == Order.CoreFirst)
{
services.AddZbSecrets(config, "Secrets");
extension(services, config);
}
else
{
extension(services, config);
services.AddZbSecrets(config, "Secrets");
}
return services.BuildServiceProvider();
}
[Theory]
[InlineData(Order.CoreFirst)]
[InlineData(Order.ExtensionFirst)]
public void SharedStore_mode_wins_in_either_order(Order order)
{
using ServiceProvider provider = Build(order, (s, c) => s.AddZbSecretsSqlServerStore(c));
Assert.IsType(provider.GetRequiredService());
Assert.IsType(provider.GetRequiredService());
// Exactly one store registration is visible, so nothing enumerating the seam can pick up the
// displaced SQLite store either.
Assert.IsType(Assert.Single(provider.GetServices()));
}
[Theory]
[InlineData(Order.CoreFirst)]
[InlineData(Order.ExtensionFirst)]
public void HubReplication_mode_publishes_through_the_hub_in_either_order(Order order)
{
using ServiceProvider provider = Build(order, (s, c) => s.AddZbSecretsSqlServerReplication(c));
Assert.IsType(provider.GetRequiredService());
Assert.IsType(Assert.Single(provider.GetServices()));
Assert.IsType(provider.GetRequiredService());
}
}