Files
Joseph Doherty 40e8a23e7c
v2-ci / build (push) Failing after 37s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
refactor(opcuaserver): rename Phase7* address-space pipeline to AddressSpace*
The OPC UA address-space build pipeline was named after a v2-roadmap
milestone number rather than its domain. Rename the family to describe
what it does (build/diff/apply the OPC UA address space):

  Phase7Composer          -> AddressSpaceComposer
  Phase7CompositionResult -> AddressSpaceComposition
  Phase7Planner           -> AddressSpacePlanner
  Phase7Plan              -> AddressSpacePlan
  Phase7Applier           -> AddressSpaceApplier
  Phase7ApplyOutcome      -> AddressSpaceApplyOutcome

The 9 Phase7*Tests suites follow suit; Phase7ScriptingEntitiesTests ->
ScriptingEntitiesTests (it tests the scripting migration, not the
pipeline). Log-message prefixes move to the new class names.

Pure mechanical rename, no behavioral change. EF migration classes/IDs
(AddPhase7ScriptingTables, ExtendComputeGenerationDiffWithPhase7) are
immutable and left untouched, as are historical design docs.

Build clean; OpcUaServer 261/261, Runtime 272/272, ScriptingEntities
12/12 green.
2026-06-18 19:16:28 -04:00

72 lines
2.6 KiB
C#

using System.Text.Json;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Runtime.Drivers;
namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers;
/// <summary>
/// Verifies the artifact-decode mirror substitutes the reserved <c>{{equip}}</c> token in a
/// VirtualTag script's <c>ctx.GetTag("…")</c> literals with the owning equipment's tag base
/// (derived from its child Equipment-namespace tag's FullName) — byte-parity with
/// <c>AddressSpaceComposer.Compose</c>'s live-edit path, using the same shared
/// <c>EquipmentScriptPaths</c> helper and the same equipmentTags-derived base.
/// </summary>
public sealed class DeploymentArtifactEquipTokenTests
{
[Fact]
public void ParseComposition_substitutes_equip_token_in_virtual_tag_expression()
{
var blob = JsonSerializer.SerializeToUtf8Bytes(new
{
Namespaces = new[]
{
new { NamespaceId = "ns-eq", Kind = 0 }, // NamespaceKind.Equipment
},
DriverInstances = new[]
{
new { DriverInstanceId = "drv-modbus", DriverType = "Modbus", DriverConfig = "{}", NamespaceId = "ns-eq" },
},
Tags = new object[]
{
new
{
TagId = "tag-source",
DriverInstanceId = "drv-modbus",
EquipmentId = "TestMachine_001",
Name = "Source",
FolderPath = (string?)null,
DataType = "Float",
TagConfig = "{\"FullName\":\"TestMachine_001.Source\"}",
},
},
Scripts = new[]
{
new
{
ScriptId = "s-equip",
SourceCode = "return System.Convert.ToInt32(ctx.GetTag(\"{{equip}}.Source\").Value) > 50;",
},
},
VirtualTags = new[]
{
new
{
VirtualTagId = "vt-equip",
EquipmentId = "TestMachine_001",
Name = "OverThreshold",
DataType = "Boolean",
ScriptId = "s-equip",
},
},
});
var c = DeploymentArtifact.ParseComposition(blob);
var vt = c.EquipmentVirtualTags.ShouldHaveSingleItem();
vt.Expression.ShouldContain("ctx.GetTag(\"TestMachine_001.Source\")");
vt.Expression.ShouldNotContain("{{equip}}");
vt.DependencyRefs.ShouldBe(new[] { "TestMachine_001.Source" });
}
}