using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health; using ZB.MOM.WW.ScadaBridge.Commons.Types; using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; using ZB.MOM.WW.ScadaBridge.HealthMonitoring.Kpi; namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring.Tests.Kpi; /// /// Task 10 (arch-review 04) coverage for . /// The provider sums the latest per-site SiteAuditBacklog.PendingCount across the /// in-memory — the same aggregate the live Audit /// backlog tile shows — so the backlogTotal KPI history stops recording a hardwired /// zero. Sites with no report or a null backlog snapshot contribute nothing. /// public class CentralHealthAuditBacklogProviderTests { private static readonly DateTime At = new(2026, 6, 17, 12, 0, 0, DateTimeKind.Utc); [Fact] public void GetPendingBacklogTotal_Sums_PendingCount_Across_Sites() { var aggregator = new StubAggregator { States = { ["site-a"] = StateWithBacklog("site-a", 9), ["site-b"] = StateWithBacklog("site-b", 4), ["site-c"] = new SiteHealthState { SiteId = "site-c", LatestReport = null }, // heartbeat-only }, }; var provider = new CentralHealthAuditBacklogProvider(aggregator); // 9 + 4; the null-report site contributes nothing. Assert.Equal(13, provider.GetPendingBacklogTotal()); } [Fact] public void GetPendingBacklogTotal_Returns_Zero_When_No_Backlog_Reported() { var aggregator = new StubAggregator { States = { ["site-a"] = new SiteHealthState { SiteId = "site-a", LatestReport = MinimalReport("site-a") with { SiteAuditBacklog = null } }, ["site-b"] = new SiteHealthState { SiteId = "site-b", LatestReport = null }, }, }; var provider = new CentralHealthAuditBacklogProvider(aggregator); Assert.Equal(0, provider.GetPendingBacklogTotal()); } private static SiteHealthState StateWithBacklog(string siteId, int pending) => new() { SiteId = siteId, LatestReport = MinimalReport(siteId) with { SiteAuditBacklog = new SiteAuditBacklogSnapshot( PendingCount: pending, OldestPendingUtc: null, OnDiskBytes: 0), }, }; private static SiteHealthReport MinimalReport(string siteId) => new( SiteId: siteId, SequenceNumber: 1, ReportTimestamp: At, DataConnectionStatuses: new Dictionary(), TagResolutionCounts: new Dictionary(), ScriptErrorCount: 0, AlarmEvaluationErrorCount: 0, StoreAndForwardBufferDepths: new Dictionary(), DeadLetterCount: 0, DeployedInstanceCount: 0, EnabledInstanceCount: 0, DisabledInstanceCount: 0); /// /// Hand-rolled stub — the HealthMonitoring.Tests /// project has no mocking library. Only is exercised. /// private sealed class StubAggregator : ICentralHealthAggregator { public Dictionary States { get; } = new(); public IReadOnlyDictionary GetAllSiteStates() => States; public SiteHealthState? GetSiteState(string siteId) => States.TryGetValue(siteId, out var state) ? state : null; public void ProcessReport(SiteHealthReport report) => throw new NotSupportedException(); public void MarkHeartbeat(string siteId, DateTimeOffset receivedAt) => throw new NotSupportedException(); public void PruneUnknownSites(IReadOnlyCollection knownSiteIds) => throw new NotSupportedException(); } }