using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.AdminUI.Hubs; using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers; namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests; /// /// Covers the in-process push contract the Blazor Server driver status panel's resilience section /// relies on: fires on every /// , keyed per (instance, host) with /// last-write-wins, and GetForInstance returns only the queried instance's hosts. Mirrors /// ; the panel reads this store directly (no /// self-targeted SignalR connection). /// public sealed class DriverResilienceStatusStoreTests { private static DriverResilienceStatusChanged Msg( string instance, string host, bool breakerOpen = false, int failures = 0) => new(instance, host, breakerOpen, failures, 0, null, new DateTime(2026, 7, 13, 0, 0, 0, DateTimeKind.Utc), new DateTime(2026, 7, 13, 0, 0, 0, DateTimeKind.Utc)); [Fact] public void Upsert_raises_SnapshotChanged_with_the_stored_snapshot() { var store = new InMemoryDriverResilienceStatusStore(); var received = new List(); store.SnapshotChanged += received.Add; var msg = Msg("drv-1", "host-a", breakerOpen: true); store.Upsert(msg); received.Count.ShouldBe(1); received[0].ShouldBeSameAs(msg); } [Fact] public void Upsert_is_last_write_wins_per_instance_host() { var store = new InMemoryDriverResilienceStatusStore(); store.Upsert(Msg("drv-1", "host-a", failures: 3)); store.Upsert(Msg("drv-1", "host-a", failures: 0)); var hosts = store.GetForInstance("drv-1"); hosts.Count.ShouldBe(1); hosts[0].ConsecutiveFailures.ShouldBe(0); } [Fact] public void GetForInstance_returns_only_the_queried_instances_hosts() { var store = new InMemoryDriverResilienceStatusStore(); store.Upsert(Msg("drv-1", "host-a")); store.Upsert(Msg("drv-1", "host-b")); store.Upsert(Msg("drv-2", "host-a")); var hosts = store.GetForInstance("drv-1"); hosts.Count.ShouldBe(2); hosts.ShouldAllBe(h => h.DriverInstanceId == "drv-1"); } [Fact] public void GetForInstance_returns_empty_for_unknown_instance() { var store = new InMemoryDriverResilienceStatusStore(); store.Upsert(Msg("drv-1", "host-a")); store.GetForInstance("nope").ShouldBeEmpty(); } [Fact] public void Unsubscribed_handler_stops_receiving_after_removal() { var store = new InMemoryDriverResilienceStatusStore(); var count = 0; void Handler(DriverResilienceStatusChanged _) => count++; store.SnapshotChanged += Handler; store.Upsert(Msg("drv-1", "host-a")); store.SnapshotChanged -= Handler; store.Upsert(Msg("drv-1", "host-a")); count.ShouldBe(1); } }