feat(modbus): resolve equipment-tag refs (read + write) via EquipmentTagRefResolver

This commit is contained in:
Joseph Doherty
2026-06-13 11:12:01 -04:00
parent eaa335d779
commit 232c557985
3 changed files with 128 additions and 4 deletions
@@ -0,0 +1,61 @@
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.Modbus;
namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests;
[Trait("Category", "Unit")]
public class ModbusEquipmentTagTests
{
[Fact]
public void Parses_equipment_tagconfig_into_a_transient_definition()
{
var json = """{"region":"HoldingRegisters","address":40001,"dataType":"UInt16","byteOrder":"BigEndian","bitIndex":0,"stringLength":0}""";
ModbusEquipmentTagParser.TryParse(json, out var def).ShouldBeTrue();
def!.Name.ShouldBe(json);
def.Region.ShouldBe(ModbusRegion.HoldingRegisters);
def.Address.ShouldBe((ushort)40001);
def.DataType.ShouldBe(ModbusDataType.UInt16);
}
[Fact]
public void Rejects_a_non_address_blob()
=> ModbusEquipmentTagParser.TryParse("""{"FullName":"x"}""", out _).ShouldBeFalse();
[Fact]
public void Rejects_garbage()
=> ModbusEquipmentTagParser.TryParse("not json", out _).ShouldBeFalse();
[Fact]
public void Rejects_address_as_a_json_string()
=> ModbusEquipmentTagParser.TryParse(
"""{"region":"HoldingRegisters","address":"40001","dataType":"UInt16"}""", out _).ShouldBeFalse();
[Fact]
public void Rejects_address_out_of_ushort_range()
=> ModbusEquipmentTagParser.TryParse(
"""{"region":"HoldingRegisters","address":70000,"dataType":"UInt16"}""", out _).ShouldBeFalse();
/// <summary>
/// End-to-end driver-level proof: a Modbus driver with NO authored tags can still read an
/// equipment-tag ref (the raw TagConfig JSON) — the resolver parses it into a transient
/// definition and the read goes to the wire instead of returning BadNodeIdUnknown.
/// </summary>
[Fact]
public async Task Driver_resolves_an_equipment_ref_and_reads_instead_of_BadNodeIdUnknown()
{
// Address 10 fits the fake transport's 256-register bank (40001 would overflow it).
var json = """{"region":"HoldingRegisters","address":10,"dataType":"UInt16","byteOrder":"BigEndian","bitIndex":0,"stringLength":0}""";
var fake = new ModbusDriverTests.FakeTransport();
var opts = new ModbusDriverOptions { Host = "fake", Tags = [] };
var drv = new ModbusDriver(opts, "modbus-eq", _ => fake);
await drv.InitializeAsync("{}", CancellationToken.None);
fake.HoldingRegisters[10] = 4242;
var r = await drv.ReadAsync([json], CancellationToken.None);
r[0].StatusCode.ShouldBe(0u);
r[0].StatusCode.ShouldNotBe(0x80340000u); // not BadNodeIdUnknown
r[0].Value.ShouldBe((ushort)4242);
}
}