feat(client): AddComment + comment CLI, drop Galaxy-era alarm fallback, serialize CLI tests (#598); Client.Shared off obsolete sync SDK APIs (#621)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 06:53:57 -04:00
parent 3baa332d6b
commit 48bd266e19
18 changed files with 363 additions and 211 deletions
@@ -18,7 +18,7 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests;
/// <remarks>
/// The condition id is passed exactly as a CLI user passes <c>--node</c>: the condition node's own id.
/// Each call must return Good <b>and</b> move the condition — read back from the condition events the
/// server reports, not from the call result alone. The client exposes no AddComment API, so it is not covered.
/// server reports, not from the call result alone. AddComment is covered on both the scripted and the native condition (the native one supports Acknowledge and AddComment only).
/// </remarks>
public sealed class ClientAlarmMethodTests
{
@@ -66,6 +66,10 @@ public sealed class ClientAlarmMethodTests
conditionId, events.LatestEventId(item, "base"), "confirm", ct)).ShouldBeTrue();
(await Next(++n))[RecordedEvents.ConfirmedField].Value.ShouldBe(true);
StatusCode.IsGood(await client.AddCommentAsync(
conditionId, events.LatestEventId(item, "base"), "note", ct)).ShouldBeTrue();
((await Next(++n))[RecordedEvents.CommentField].Value as LocalizedText).ShouldNotBeNull().Text.ShouldBe("note");
StatusCode.IsGood(await client.ShelveAlarmAsync(conditionId, ShelveKind.OneShot, 0, ct)).ShouldBeTrue();
(await Next(++n))[RecordedEvents.ShelvingField].Value.ShouldBe(ObjectIds.ShelvedStateMachineType_OneShotShelved);
@@ -120,6 +124,12 @@ public sealed class ClientAlarmMethodTests
ack[RecordedEvents.ConfirmedField].Value.ShouldBe(true);
ack[RecordedEvents.ShelvingField].Value.ShouldBe(ObjectIds.ShelvedStateMachineType_Unshelved);
StatusCode.IsGood(await client.AddCommentAsync(
conditionId, events.LatestEventId(item, "base"), "note", ct)).ShouldBeTrue();
await rig.DrainProjectionsAsync();
await RecordedEvents.WaitUntilAsync(() => events.ConditionEvents(item, "base").Count >= 3);
(events.ConditionEvents(item, "base")[2][RecordedEvents.CommentField].Value as LocalizedText).ShouldNotBeNull().Text.ShouldBe("note");
await subscription.DeleteAsync(true, ct);
}
finally { await rig.DisposeAsync(); }