using Microsoft.Extensions.Logging.Abstractions; namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring.Tests; /// /// M2.16 (#30) — unit tests for . /// Verifies that the poller reads the count provided by the /// delegate and pushes it into /// . /// public class SiteEventLogFailureCountReporterTests { [Fact] public async Task StopAsync_AfterDispose_DoesNotThrow() { // Regression (Gitea #15 follow-up): Dispose tears down the CTS StopAsync // cancels, and the host does not guarantee StopAsync is driven before the DI // container is disposed. Cancel() on a disposed CTS throws, and letting that // escape an IHostedService aborts the host's whole shutdown sequence. var reporter = new SiteEventLogFailureCountReporter( failedWriteCountProvider: () => 0L, collector: new SiteHealthCollector(), logger: NullLogger.Instance, refreshInterval: TimeSpan.FromHours(1)); await reporter.StartAsync(CancellationToken.None); reporter.Dispose(); // The assertion is the absence of ObjectDisposedException. await reporter.StopAsync(CancellationToken.None); reporter.Dispose(); } [Fact] public async Task StartAsync_ImmediatelyProbes_FailedWriteCount() { // Arrange var count = 99L; var collector = new SiteHealthCollector(); using var reporter = new SiteEventLogFailureCountReporter( failedWriteCountProvider: () => count, collector: collector, logger: NullLogger.Instance, refreshInterval: TimeSpan.FromHours(1)); // long interval — only immediate tick matters // Act await reporter.StartAsync(CancellationToken.None); // Give the background Task a moment to execute its synchronous immediate probe. var deadline = DateTime.UtcNow.AddSeconds(5); while (collector.CollectReport("probe").SiteEventLogWriteFailures == 0L && DateTime.UtcNow < deadline) { await Task.Delay(10); } // Assert — the immediate probe before the first Delay must have fired. var report = collector.CollectReport("site-1"); Assert.Equal(99L, report.SiteEventLogWriteFailures); await reporter.StopAsync(CancellationToken.None); } [Fact] public async Task StartAsync_PushesLatestCount_OnEachTick() { // Arrange — start with count 5; advance to 12 after the first tick. var count = 5L; var collector = new SiteHealthCollector(); using var reporter = new SiteEventLogFailureCountReporter( failedWriteCountProvider: () => count, collector: collector, logger: NullLogger.Instance, refreshInterval: TimeSpan.FromMilliseconds(50)); await reporter.StartAsync(CancellationToken.None); // Wait for immediate probe. var deadline = DateTime.UtcNow.AddSeconds(5); while (collector.CollectReport("probe").SiteEventLogWriteFailures != 5L && DateTime.UtcNow < deadline) await Task.Delay(10); Assert.Equal(5L, collector.CollectReport("site-1").SiteEventLogWriteFailures); // Advance the counter and wait for the next tick to push the new value. count = 12L; deadline = DateTime.UtcNow.AddSeconds(5); while (collector.CollectReport("probe").SiteEventLogWriteFailures != 12L && DateTime.UtcNow < deadline) await Task.Delay(10); Assert.Equal(12L, collector.CollectReport("site-1").SiteEventLogWriteFailures); await reporter.StopAsync(CancellationToken.None); } }