using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using ZB.MOM.WW.ScadaBridge.AuditLog.Central;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
using SiteEntity = ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites.Site;
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.Central;
///
/// Unit tests for the production — the central
/// reconciliation-singleton collaborator that projects the config-DB
/// rows into the targets the
/// polls.
///
///
/// The enumerator opens a fresh DI scope per
/// call (mirroring the per-tick scope pattern in the reconciliation actor)
/// because is a SCOPED EF Core service. The tests
/// register a substituted repository as a scoped service so the enumerator's
/// CreateAsyncScope resolves it and the projection / blank-address
/// filtering can be exercised without an MSSQL container.
///
public class SiteEnumeratorTests
{
private static SiteEntity SiteWith(string identifier, string? grpcNodeA, string? grpcNodeB = null)
{
var site = new SiteEntity($"Display {identifier}", identifier)
{
GrpcNodeAAddress = grpcNodeA,
GrpcNodeBAddress = grpcNodeB,
};
return site;
}
private static IServiceProvider BuildProvider(ISiteRepository repository)
{
var services = new ServiceCollection();
// Scoped to match the production lifetime (EF Core); the enumerator
// must open a scope to resolve it.
services.AddScoped(_ => repository);
return services.BuildServiceProvider();
}
[Fact]
public async Task EnumerateAsync_ProjectsSitesWithNodeAAddress_AndSkipsBlankOnes()
{
var repository = Substitute.For();
repository.GetAllSitesAsync(Arg.Any()).Returns(new List
{
SiteWith("site-a", "http://site-a:8083"),
SiteWith("site-b", grpcNodeA: " "), // blank NodeA -> skipped
});
var enumerator = new SiteEnumerator(BuildProvider(repository));
var result = await enumerator.EnumerateAsync();
var entry = Assert.Single(result);
Assert.Equal("site-a", entry.SiteId);
Assert.Equal("http://site-a:8083", entry.GrpcEndpoint);
}
[Fact]
public async Task EnumerateAsync_SkipsNullNodeAAddress()
{
var repository = Substitute.For();
repository.GetAllSitesAsync(Arg.Any()).Returns(new List
{
SiteWith("site-null", grpcNodeA: null),
});
var enumerator = new SiteEnumerator(BuildProvider(repository));
var result = await enumerator.EnumerateAsync();
Assert.Empty(result);
}
[Fact]
public async Task EnumerateAsync_ReturnsEmpty_WhenNoSites()
{
var repository = Substitute.For();
repository.GetAllSitesAsync(Arg.Any()).Returns(new List());
var enumerator = new SiteEnumerator(BuildProvider(repository));
var result = await enumerator.EnumerateAsync();
Assert.Empty(result);
}
}