test(alarms): native ack wrong-role deny + tidy NativeAlarmAck doc (code-review)

This commit is contained in:
Joseph Doherty
2026-06-15 14:39:26 -04:00
parent a6d9de091b
commit 87dd65b97a
2 changed files with 32 additions and 3 deletions
@@ -480,6 +480,35 @@ public sealed class AlarmCommandRouterTests : IDisposable
await host.DisposeAsync();
}
/// <summary>H6c — a NATIVE condition's Acknowledge from a non-null identity that lacks the
/// <c>AlarmAck</c> role is vetoed (BadUserAccessDenied) and NEITHER router is invoked — the gate
/// fails closed before any route, exactly as for scripted conditions.</summary>
[Fact]
public async Task Native_OnAcknowledge_without_AlarmAck_returns_denied_and_routes_nothing()
{
var (host, server) = await BootAsync();
var nm = server.NodeManager!;
var scripted = new List<AlarmCommand>();
var native = new List<NativeAlarmAck>();
nm.AlarmCommandRouter = scripted.Add;
nm.NativeAlarmAckRouter = native.Add;
nm.EnsureFolder("eq-nak4", parentNodeId: null, displayName: "Equipment NAK4");
nm.MaterialiseAlarmCondition("alm-nak4", "eq-nak4", "HighTemp", "OffNormalAlarm", severity: 700, isNative: true);
var condition = nm.TryGetAlarmCondition("alm-nak4");
condition.ShouldNotBeNull();
var ctx = SessionContext(server, "pete", "ReadOnly"); // non-null identity, but no AlarmAck
var result = condition!.OnAcknowledge!(ctx, condition, EventIdBytes(), new LocalizedText("nope"));
result.StatusCode.Code.ShouldBe(StatusCodes.BadUserAccessDenied);
native.ShouldBeEmpty();
scripted.ShouldBeEmpty();
await host.DisposeAsync();
}
/// <summary>H6c — a NATIVE condition's Acknowledge from an anonymous / role-less identity is vetoed
/// (BadUserAccessDenied) and NEITHER router is invoked — the gate fails closed before any route.</summary>
[Fact]