using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Resilience; using ZB.MOM.WW.OtOpcUa.Host.Drivers; namespace ZB.MOM.WW.OtOpcUa.Host.IntegrationTests; /// /// Pure-DI (no fixture) coverage of the publisher's snapshot→message mapping — the only unit-testable /// seam of . The DPS Publish shell is /// verified by the R2-10 live gate; this asserts the mapping the shell publishes. /// public sealed class DriverResilienceStatusPublisherServiceTests { private static readonly DateTime Published = new(2026, 7, 13, 9, 0, 0, DateTimeKind.Utc); private static readonly DateTime Sampled = new(2026, 7, 13, 8, 59, 0, DateTimeKind.Utc); [Fact] public void BuildMessages_EmptyTracker_ReturnsEmpty() { var tracker = new DriverResilienceStatusTracker(); var messages = DriverResilienceStatusPublisherService.BuildMessages(tracker, Published); messages.ShouldBeEmpty(); } [Fact] public void BuildMessages_MapsTrackerSnapshot_OneMessagePerInstanceHost() { var tracker = new DriverResilienceStatusTracker(); // (drv-1, host-a): an open breaker with a standing failure count. tracker.RecordFailure("drv-1", "host-a", Sampled); tracker.RecordFailure("drv-1", "host-a", Sampled); tracker.RecordBreakerOpen("drv-1", "host-a", Sampled); // (drv-1, host-b): a healthy host with in-flight calls. tracker.RecordCallStart("drv-1", "host-b"); var messages = DriverResilienceStatusPublisherService.BuildMessages(tracker, Published); messages.Count.ShouldBe(2); var open = messages.Single(m => m.HostName == "host-a"); open.DriverInstanceId.ShouldBe("drv-1"); open.BreakerOpen.ShouldBeTrue(); open.ConsecutiveFailures.ShouldBe(2); open.LastBreakerOpenUtc.ShouldBe(Sampled); open.PublishedUtc.ShouldBe(Published); var healthy = messages.Single(m => m.HostName == "host-b"); healthy.BreakerOpen.ShouldBeFalse(); healthy.ConsecutiveFailures.ShouldBe(0); healthy.CurrentInFlight.ShouldBe(1); healthy.PublishedUtc.ShouldBe(Published); } }