fix(r2-10): in-process resilience status store

This commit is contained in:
Joseph Doherty
2026-07-13 10:43:47 -04:00
parent 12b2ce078b
commit 99ce5b401e
5 changed files with 158 additions and 1 deletions
@@ -0,0 +1,87 @@
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;
/// <summary>
/// Covers the in-process push contract the Blazor Server driver status panel's resilience section
/// relies on: <see cref="IDriverResilienceStatusStore.SnapshotChanged"/> fires on every
/// <see cref="IDriverResilienceStatusStore.Upsert"/>, keyed per <c>(instance, host)</c> with
/// last-write-wins, and <c>GetForInstance</c> returns only the queried instance's hosts. Mirrors
/// <see cref="DriverStatusSnapshotStoreTests"/>; the panel reads this store directly (no
/// self-targeted SignalR connection).
/// </summary>
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<DriverResilienceStatusChanged>();
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);
}
}