feat(audit): M5.2 per-node stuck-count KPIs (T6) — repo per-node aggregation, actor message pair, CentralUI tiles

This commit is contained in:
Joseph Doherty
2026-06-16 21:34:14 -04:00
parent a07ff28f10
commit 209f368cb5
25 changed files with 840 additions and 6 deletions
@@ -495,4 +495,50 @@ public class NotificationOutboxActorQueryTests : TestKit
Assert.Contains("db down", response.ErrorMessage);
Assert.Empty(response.Sites);
}
// ── Per-node KPI (T6: M5.2 per-node stuck-count KPIs) ──────────────────
[Fact]
public void PerNodeKpiRequest_RepliesWithPerNodeSnapshots()
{
_repository.ComputePerNodeKpisAsync(
Arg.Any<DateTimeOffset>(), Arg.Any<DateTimeOffset>(), Arg.Any<CancellationToken>())
.Returns(new List<NodeNotificationKpiSnapshot>
{
new("node-a", QueueDepth: 3, StuckCount: 1, ParkedCount: 0,
DeliveredLastInterval: 5, OldestPendingAge: TimeSpan.FromMinutes(12)),
});
var actor = CreateActor();
actor.Tell(new PerNodeNotificationKpiRequest("corr-pn"), TestActor);
var response = ExpectMsg<PerNodeNotificationKpiResponse>();
Assert.True(response.Success);
Assert.Null(response.ErrorMessage);
Assert.Equal("corr-pn", response.CorrelationId);
Assert.Single(response.Nodes);
Assert.Equal("node-a", response.Nodes[0].SourceNode);
Assert.Equal(1, response.Nodes[0].StuckCount);
_repository.Received(1).ComputePerNodeKpisAsync(
Arg.Any<DateTimeOffset>(), Arg.Any<DateTimeOffset>(), Arg.Any<CancellationToken>());
}
[Fact]
public void PerNodeKpiRequest_RepositoryFault_RepliesUnsuccessful()
{
_repository.ComputePerNodeKpisAsync(
Arg.Any<DateTimeOffset>(), Arg.Any<DateTimeOffset>(), Arg.Any<CancellationToken>())
.ThrowsAsync(new InvalidOperationException("node-kpi db down"));
var actor = CreateActor();
actor.Tell(new PerNodeNotificationKpiRequest("corr-pn"), TestActor);
var response = ExpectMsg<PerNodeNotificationKpiResponse>();
Assert.False(response.Success);
Assert.Equal("corr-pn", response.CorrelationId);
Assert.NotNull(response.ErrorMessage);
Assert.Contains("node-kpi db down", response.ErrorMessage);
Assert.Empty(response.Nodes);
}
}