using Microsoft.Extensions.Diagnostics.HealthChecks; using ZB.MOM.WW.ScadaBridge.AuditLog.Central.HeadExport; using ZB.MOM.WW.ScadaBridge.Host.Health; namespace ZB.MOM.WW.ScadaBridge.Host.Tests; /// ScadaBridge#115: the chain-head export readiness entry. public sealed class AuditChainHeadExportHealthCheckTests { private sealed class Clock(DateTime now) : TimeProvider { public DateTime Now { get; set; } = now; public override DateTimeOffset GetUtcNow() => new(DateTime.SpecifyKind(Now, DateTimeKind.Utc)); } private static readonly DateTime T0 = new(2026, 11, 10, 12, 0, 0, DateTimeKind.Utc); private static async Task Check(AuditChainHeadExportStatus s, Clock c) => (await new AuditChainHeadExportHealthCheck(s, c).CheckHealthAsync(new HealthCheckContext())).Status; /// Disabled export is healthy; failing or stale export is Degraded; recovery clears it. [Fact] public async Task Status_follows_export_outcome() { var clock = new Clock(T0); var status = new AuditChainHeadExportStatus(); Assert.Equal(HealthStatus.Healthy, await Check(status, clock)); // disabled status.MarkStarted(60, T0); Assert.Equal(HealthStatus.Healthy, await Check(status, clock)); status.RecordFailure(T0, "share offline"); var result = await new AuditChainHeadExportHealthCheck(status, clock).CheckHealthAsync(new HealthCheckContext()); Assert.Equal(HealthStatus.Degraded, result.Status); Assert.Contains("share offline", result.Description); status.RecordSuccess(T0); Assert.Equal(HealthStatus.Healthy, await Check(status, clock)); clock.Now = T0.AddMinutes(121); // no success for > 2 intervals Assert.Equal(HealthStatus.Degraded, await Check(status, clock)); status.RecordSuccess(clock.Now); Assert.Equal(HealthStatus.Healthy, await Check(status, clock)); } }