feat(opcua): diff Equipment VirtualTags in Phase7Plan + rebuild trigger
This commit is contained in:
@@ -281,6 +281,31 @@ public sealed class Phase7ApplierTests
|
||||
sink.RebuildCalls.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that added Equipment VirtualTags in an otherwise-empty plan trigger an
|
||||
/// address-space rebuild (parity with the equipment-tag path — the planner now diffs VirtualTags,
|
||||
/// so a VirtualTag-only deploy is no longer a silent no-op).</summary>
|
||||
[Fact]
|
||||
public void Added_equipment_virtual_tags_trigger_rebuild()
|
||||
{
|
||||
var sink = new RecordingSink();
|
||||
var applier = new Phase7Applier(sink, NullLogger<Phase7Applier>.Instance);
|
||||
|
||||
var plan = EmptyPlan with
|
||||
{
|
||||
AddedEquipmentVirtualTags = new[]
|
||||
{
|
||||
new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float",
|
||||
Expression: "a + b", DependencyRefs: new[] { "a", "b" }),
|
||||
},
|
||||
};
|
||||
|
||||
var outcome = applier.Apply(plan);
|
||||
|
||||
outcome.RebuildCalled.ShouldBeTrue();
|
||||
outcome.AddedNodes.ShouldBe(1);
|
||||
sink.RebuildCalls.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that added Galaxy tags in an otherwise-empty plan trigger an address-space rebuild.</summary>
|
||||
[Fact]
|
||||
public void Added_galaxy_tags_trigger_rebuild()
|
||||
|
||||
@@ -55,6 +55,90 @@ public sealed class Phase7PlannerTests
|
||||
plan.ChangedEquipmentTags.ShouldBeEmpty();
|
||||
}
|
||||
|
||||
/// <summary>Verifies a VirtualTag-only delta (no equipment/driver/alarm/galaxy/tag change)
|
||||
/// yields a NON-empty plan with the new VirtualTag in AddedEquipmentVirtualTags, so a deploy that
|
||||
/// only adds VirtualTags is no longer a silent no-op at the IsEmpty gate.</summary>
|
||||
[Fact]
|
||||
public void Equipment_virtual_tag_only_change_yields_non_empty_plan_with_added_tag()
|
||||
{
|
||||
var prev = new Phase7CompositionResult(
|
||||
Array.Empty<EquipmentNode>(), Array.Empty<DriverInstancePlan>(), Array.Empty<ScriptedAlarmPlan>());
|
||||
var next = new Phase7CompositionResult(
|
||||
Array.Empty<EquipmentNode>(), Array.Empty<DriverInstancePlan>(), Array.Empty<ScriptedAlarmPlan>())
|
||||
{
|
||||
EquipmentVirtualTags = new[]
|
||||
{
|
||||
new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float",
|
||||
Expression: "a + b", DependencyRefs: new[] { "a", "b" }),
|
||||
},
|
||||
};
|
||||
|
||||
var plan = Phase7Planner.Compute(prev, next);
|
||||
|
||||
plan.IsEmpty.ShouldBeFalse();
|
||||
plan.AddedEquipmentVirtualTags.Single().VirtualTagId.ShouldBe("vt-1");
|
||||
plan.RemovedEquipmentVirtualTags.ShouldBeEmpty();
|
||||
plan.ChangedEquipmentVirtualTags.ShouldBeEmpty();
|
||||
}
|
||||
|
||||
/// <summary>Verifies a disappeared VirtualTag routes to RemovedEquipmentVirtualTags.</summary>
|
||||
[Fact]
|
||||
public void Disappeared_virtual_tag_goes_to_RemovedEquipmentVirtualTags()
|
||||
{
|
||||
var prev = new Phase7CompositionResult(
|
||||
Array.Empty<EquipmentNode>(), Array.Empty<DriverInstancePlan>(), Array.Empty<ScriptedAlarmPlan>())
|
||||
{
|
||||
EquipmentVirtualTags = new[]
|
||||
{
|
||||
new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float",
|
||||
Expression: "a + b", DependencyRefs: new[] { "a", "b" }),
|
||||
},
|
||||
};
|
||||
var next = new Phase7CompositionResult(
|
||||
Array.Empty<EquipmentNode>(), Array.Empty<DriverInstancePlan>(), Array.Empty<ScriptedAlarmPlan>());
|
||||
|
||||
var plan = Phase7Planner.Compute(prev, next);
|
||||
|
||||
plan.IsEmpty.ShouldBeFalse();
|
||||
plan.RemovedEquipmentVirtualTags.Single().VirtualTagId.ShouldBe("vt-1");
|
||||
plan.AddedEquipmentVirtualTags.ShouldBeEmpty();
|
||||
plan.ChangedEquipmentVirtualTags.ShouldBeEmpty();
|
||||
}
|
||||
|
||||
/// <summary>Verifies a VirtualTag with the same id but a different Expression routes to
|
||||
/// ChangedEquipmentVirtualTags (the diff identity is VirtualTagId; any field difference,
|
||||
/// including the evaluated Expression, moves it from stable to changed).</summary>
|
||||
[Fact]
|
||||
public void Same_id_with_different_expression_routes_to_ChangedEquipmentVirtualTags()
|
||||
{
|
||||
var prev = new Phase7CompositionResult(
|
||||
Array.Empty<EquipmentNode>(), Array.Empty<DriverInstancePlan>(), Array.Empty<ScriptedAlarmPlan>())
|
||||
{
|
||||
EquipmentVirtualTags = new[]
|
||||
{
|
||||
new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float",
|
||||
Expression: "a + b", DependencyRefs: new[] { "a", "b" }),
|
||||
},
|
||||
};
|
||||
var next = new Phase7CompositionResult(
|
||||
Array.Empty<EquipmentNode>(), Array.Empty<DriverInstancePlan>(), Array.Empty<ScriptedAlarmPlan>())
|
||||
{
|
||||
EquipmentVirtualTags = new[]
|
||||
{
|
||||
new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float",
|
||||
Expression: "a - b", DependencyRefs: new[] { "a", "b" }),
|
||||
},
|
||||
};
|
||||
|
||||
var plan = Phase7Planner.Compute(prev, next);
|
||||
|
||||
plan.IsEmpty.ShouldBeFalse();
|
||||
plan.ChangedEquipmentVirtualTags.Single().Previous.Expression.ShouldBe("a + b");
|
||||
plan.ChangedEquipmentVirtualTags.Single().Current.Expression.ShouldBe("a - b");
|
||||
plan.AddedEquipmentVirtualTags.ShouldBeEmpty();
|
||||
plan.RemovedEquipmentVirtualTags.ShouldBeEmpty();
|
||||
}
|
||||
|
||||
/// <summary>Verifies that new equipment goes to the AddedEquipment list.</summary>
|
||||
[Fact]
|
||||
public void New_equipment_goes_to_AddedEquipment()
|
||||
|
||||
Reference in New Issue
Block a user