test(alarms): cover isNative rebuild/kind-flip lifecycle + Phase7Applier call-site (code-review)
This commit is contained in:
@@ -354,6 +354,56 @@ public sealed class AlarmCommandRouterTests : IDisposable
|
||||
await host.DisposeAsync();
|
||||
}
|
||||
|
||||
/// <summary>H6a lifecycle — the native flag is NOT sticky across a rebuild + kind flip. Materialise an
|
||||
/// id as native (flag true), <see cref="OtOpcUaNodeManager.RebuildAddressSpace"/> (which clears the
|
||||
/// folder + condition + native-flag sets), re-ensure the equipment folder, then re-materialise the
|
||||
/// SAME id as scripted (<c>isNative:false</c>). The flag must read false — the rebuild dropped it and
|
||||
/// the scripted re-materialise did NOT re-add it. Guards against a stale-native leak that would route a
|
||||
/// now-scripted alarm's inbound ack to the driver.</summary>
|
||||
[Fact]
|
||||
public async Task Native_flag_clears_on_rebuild_then_kind_flip()
|
||||
{
|
||||
var (host, server) = await BootAsync();
|
||||
var nm = server.NodeManager!;
|
||||
|
||||
nm.EnsureFolder("eq", parentNodeId: null, displayName: "Equipment");
|
||||
nm.MaterialiseAlarmCondition("a1", "eq", "d", "OffNormalAlarm", 700, isNative: true);
|
||||
nm.IsNativeAlarmNode("a1").ShouldBeTrue();
|
||||
|
||||
// RebuildAddressSpace clears the folder set too, so the equipment folder must be re-ensured
|
||||
// before the same id can be re-materialised (ResolveParentFolder needs the parent back).
|
||||
nm.RebuildAddressSpace();
|
||||
nm.EnsureFolder("eq", parentNodeId: null, displayName: "Equipment");
|
||||
nm.MaterialiseAlarmCondition("a1", "eq", "d", "OffNormalAlarm", 700, isNative: false);
|
||||
|
||||
nm.IsNativeAlarmNode("a1").ShouldBeFalse();
|
||||
|
||||
await host.DisposeAsync();
|
||||
}
|
||||
|
||||
/// <summary>H6a lifecycle (converse) — a scripted condition can flip TO native across a rebuild.
|
||||
/// Materialise an id as scripted (flag false), rebuild, re-ensure the folder, re-materialise the SAME
|
||||
/// id as native (<c>isNative:true</c>). The flag must read true — the native re-materialise re-adds it
|
||||
/// cleanly after the rebuild cleared the slate.</summary>
|
||||
[Fact]
|
||||
public async Task Scripted_flag_can_flip_to_native_across_rebuild()
|
||||
{
|
||||
var (host, server) = await BootAsync();
|
||||
var nm = server.NodeManager!;
|
||||
|
||||
nm.EnsureFolder("eq", parentNodeId: null, displayName: "Equipment");
|
||||
nm.MaterialiseAlarmCondition("a1", "eq", "d", "OffNormalAlarm", 700, isNative: false);
|
||||
nm.IsNativeAlarmNode("a1").ShouldBeFalse();
|
||||
|
||||
nm.RebuildAddressSpace();
|
||||
nm.EnsureFolder("eq", parentNodeId: null, displayName: "Equipment");
|
||||
nm.MaterialiseAlarmCondition("a1", "eq", "d", "OffNormalAlarm", 700, isNative: true);
|
||||
|
||||
nm.IsNativeAlarmNode("a1").ShouldBeTrue();
|
||||
|
||||
await host.DisposeAsync();
|
||||
}
|
||||
|
||||
/// <summary>Builds a <see cref="ServerSystemContext"/> (an <see cref="ISessionOperationContext"/>)
|
||||
/// carrying a <see cref="RoleCarryingUserIdentity"/> with the given name + roles — the exact seam the
|
||||
/// gate reads via <c>(context as ISessionOperationContext)?.UserIdentity as RoleCarryingUserIdentity</c>.</summary>
|
||||
|
||||
Reference in New Issue
Block a user