refactor(opcua): repoint Phase7Applier + VirtualTagHostActor to shared EquipmentNodeIds
This commit is contained in:
@@ -139,6 +139,8 @@ public sealed class Phase7ApplierTests
|
||||
|
||||
sink.FolderCalls.ShouldBeEmpty(); // equipment folder already exists; no sub-folder needed
|
||||
sink.VariableCalls.ShouldHaveSingleItem().ShouldBe(("eq-1/Speed", "eq-1", "Speed", "Float"));
|
||||
// Parity: the materialiser's NodeId is the shared EquipmentNodeIds formula (null/empty FolderPath).
|
||||
sink.VariableCalls.Single().NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "Speed"));
|
||||
}
|
||||
|
||||
/// <summary>Verifies a FolderPath on an equipment tag becomes a sub-folder UNDER the equipment
|
||||
@@ -163,6 +165,8 @@ public sealed class Phase7ApplierTests
|
||||
|
||||
sink.FolderCalls.ShouldHaveSingleItem().ShouldBe(("eq-1/Diagnostics", "eq-1", "Diagnostics"));
|
||||
sink.VariableCalls.ShouldHaveSingleItem().ShouldBe(("eq-1/Diagnostics/Temp", "eq-1/Diagnostics", "Temp", "Float"));
|
||||
// Parity: the materialiser's NodeId is the shared EquipmentNodeIds formula (with FolderPath).
|
||||
sink.VariableCalls.Single().NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "Diagnostics", "Temp"));
|
||||
}
|
||||
|
||||
/// <summary>Regression for the FullName-as-NodeId collision: two identical machines exposing the
|
||||
@@ -215,6 +219,47 @@ public sealed class Phase7ApplierTests
|
||||
|
||||
sink.FolderCalls.ShouldBeEmpty(); // equipment folder already exists; no sub-folder needed
|
||||
sink.VariableCalls.ShouldHaveSingleItem().ShouldBe(("eq-1/speed-rpm", "eq-1", "speed-rpm", "Float64"));
|
||||
// Parity: the vtag materialiser's NodeId is the shared EquipmentNodeIds formula.
|
||||
sink.VariableCalls.Single().NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "speed-rpm"));
|
||||
}
|
||||
|
||||
/// <summary>Golden/parity guard: the materialiser's Variable NodeId for BOTH the equipment-tag and
|
||||
/// the equipment-VirtualTag pass is byte-identical to <see cref="EquipmentNodeIds.Variable"/> — the
|
||||
/// single source of truth Phase7Applier + VirtualTagHostActor both point at. Covers null/empty
|
||||
/// FolderPath (directly under equipment) and a non-empty FolderPath (sub-folder scoped). This test
|
||||
/// LOCKS the formula against drift: any change to the materialiser NodeId that diverges from the
|
||||
/// shared helper fails here.</summary>
|
||||
[Fact]
|
||||
public void Materialised_variable_node_ids_match_shared_EquipmentNodeIds_formula()
|
||||
{
|
||||
var sink = new RecordingSink();
|
||||
var applier = new Phase7Applier(sink, NullLogger<Phase7Applier>.Instance);
|
||||
|
||||
var composition = new Phase7CompositionResult(
|
||||
Array.Empty<EquipmentNode>(), Array.Empty<DriverInstancePlan>(), Array.Empty<ScriptedAlarmPlan>())
|
||||
{
|
||||
EquipmentTags = new[]
|
||||
{
|
||||
new EquipmentTagPlan("tag-flat", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001"),
|
||||
new EquipmentTagPlan("tag-nested", "eq-1", "drv", FolderPath: "Diagnostics", Name: "Temp", DataType: "Float", FullName: "40002"),
|
||||
},
|
||||
EquipmentVirtualTags = new[]
|
||||
{
|
||||
new EquipmentVirtualTagPlan("vt-flat", "eq-2", FolderPath: "", Name: "Efficiency", DataType: "Float64",
|
||||
Expression: "ctx.GetTag(\"a\")", DependencyRefs: new[] { "a" }),
|
||||
new EquipmentVirtualTagPlan("vt-nested", "eq-2", FolderPath: "Calc", Name: "Avg", DataType: "Float64",
|
||||
Expression: "ctx.GetTag(\"b\")", DependencyRefs: new[] { "b" }),
|
||||
},
|
||||
};
|
||||
|
||||
applier.MaterialiseEquipmentTags(composition);
|
||||
applier.MaterialiseEquipmentVirtualTags(composition);
|
||||
|
||||
var nodeIds = sink.VariableCalls.Select(v => v.NodeId).ToList();
|
||||
nodeIds.ShouldContain(EquipmentNodeIds.Variable("eq-1", "", "Speed"));
|
||||
nodeIds.ShouldContain(EquipmentNodeIds.Variable("eq-1", "Diagnostics", "Temp"));
|
||||
nodeIds.ShouldContain(EquipmentNodeIds.Variable("eq-2", "", "Efficiency"));
|
||||
nodeIds.ShouldContain(EquipmentNodeIds.Variable("eq-2", "Calc", "Avg"));
|
||||
}
|
||||
|
||||
/// <summary>Two VirtualTags under the SAME equipment produce two distinct folder-scoped variables
|
||||
|
||||
Reference in New Issue
Block a user