feat(alarms): AlarmAcknowledgeRequest carries OperatorUser; Galaxy/ScriptedAlarmSource honor it [H6b]

This commit is contained in:
Joseph Doherty
2026-06-15 14:11:40 -04:00
parent c236263e8d
commit ed941c51da
5 changed files with 65 additions and 7 deletions
@@ -129,6 +129,37 @@ public sealed class ScriptedAlarmSourceTests
state.LastAckComment.ShouldBe("ack via opcua");
}
/// <summary>
/// Verifies that AcknowledgeAsync honors a supplied authenticated principal
/// (<see cref="AlarmAcknowledgeRequest.OperatorUser"/>) and falls back to
/// <c>"opcua-client"</c> only when none is supplied.
/// </summary>
[Fact]
public async Task ScriptedAlarmSource_uses_supplied_principal_else_default()
{
var (engine, source, up) = await BuildAsync();
using var _e = engine;
using var _s = source;
// Supplied principal -> honored.
up.Push("Temp", 150);
await Task.Delay(200);
await source.AcknowledgeAsync([new AlarmAcknowledgeRequest(
"Plant/Line1", "Plant/Line1::HighTemp", "ack as bob", "bob")],
TestContext.Current.CancellationToken);
engine.GetState("Plant/Line1::HighTemp")!.LastAckUser.ShouldBe("bob");
// No principal -> default audit identity.
up.Push("Temp", 50);
await Task.Delay(200);
up.Push("Temp", 150);
await Task.Delay(200);
await source.AcknowledgeAsync([new AlarmAcknowledgeRequest(
"Plant/Line1", "Plant/Line1::HighTemp", "ack anon", null)],
TestContext.Current.CancellationToken);
engine.GetState("Plant/Line1::HighTemp")!.LastAckUser.ShouldBe("opcua-client");
}
/// <summary>Verifies that null arguments are rejected.</summary>
[Fact]
public async Task Null_arguments_rejected()