97a837c147
The two discovery-path libplctag tags (@tags symbol-list enumerator, @udt template reader) still passed the bare Gateway host, so a browse against a device authored on a non-default port silently browsed whatever answers on 44818 — #534's defect surviving in its discovery half. Both sites now consume AbCipTagCreateParams.LibplctagGateway, with the Tag construction extracted into internal static builders so the seam is unit-assertable (the #534 tests pinned the property's composition but nothing pinned each site's consumption, which is exactly how these two survived). New guard: LibplctagGatewayConsumptionGuardTests scans both AB drivers' sources and fails on any libplctag Tag built from the bare Gateway, so a future call site cannot reintroduce the silent 44818 redirect. Live-gated against the fixture host: browse of ab://10.100.0.35:44818 returns the nine-tag symbol table; browse of ab://10.100.0.35:44999 (nothing listening — the issue's exact repro) now fails ErrorTimeout where it previously returned the 44818 fixture's table. Closes #539. Claude-Session: https://claude.ai/code/session_014WNM4vjoVksyyBraTXSZE1
67 lines
2.8 KiB
C#
67 lines
2.8 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests;
|
|
|
|
/// <summary>
|
|
/// Gitea #534 — the authored EtherNet/IP port must reach libplctag's <c>gateway</c> attribute.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This driver carried the identical defect to AbLegacy, where it was found:
|
|
/// <see cref="AbCipTagCreateParams.Port"/> was on the record and consumed by nobody, so the runtime
|
|
/// handed libplctag the bare host and libplctag substituted 44818. It survived here precisely because
|
|
/// it is invisible here — every AbCip fixture profile binds 44818, so no test this driver has could
|
|
/// distinguish "uses the authored port" from "always uses 44818". Worth remembering as a shape: a
|
|
/// fixture that only ever exercises the default value cannot falsify a rule about non-default values,
|
|
/// however many tests point at it.
|
|
/// </remarks>
|
|
public sealed class AbCipGatewayCompositionTests
|
|
{
|
|
private static AbCipTagCreateParams Params(string host, int port) =>
|
|
new(Gateway: host, Port: port, CipPath: "1,0", LibplctagPlcAttribute: "controllogix",
|
|
TagName: "TestDINT", Timeout: TimeSpan.FromSeconds(5));
|
|
|
|
[Fact]
|
|
public void The_authored_port_is_appended_to_the_gateway()
|
|
{
|
|
Params("10.100.0.35", 44900).LibplctagGateway.ShouldBe("10.100.0.35:44900");
|
|
}
|
|
|
|
[Fact]
|
|
public void The_default_port_is_still_written_explicitly()
|
|
{
|
|
Params("plc1.plant.local", 44818).LibplctagGateway.ShouldBe("plc1.plant.local:44818");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-1)]
|
|
public void A_missing_port_falls_back_to_the_bare_host(int port)
|
|
{
|
|
Params("10.100.0.35", port).LibplctagGateway.ShouldBe("10.100.0.35");
|
|
}
|
|
|
|
// Gitea #539 — #534 fixed the data path but both DISCOVERY call sites kept passing the bare
|
|
// Gateway, so "Browse controller" against a device authored on a non-default port silently
|
|
// browsed whatever answers on 44818. These pin the composed gateway at the actual libplctag
|
|
// Tag construction seam, which the property-only tests above structurally cannot: they proved
|
|
// LibplctagGateway composes correctly while nothing proved each Tag builder consumes it.
|
|
|
|
[Fact]
|
|
public void The_symbol_list_browse_tag_carries_the_authored_port()
|
|
{
|
|
using var tag = LibplctagTagEnumerator.BuildSymbolListTag(Params("10.100.0.35", 44999));
|
|
tag.Gateway.ShouldBe("10.100.0.35:44999");
|
|
tag.Name.ShouldBe("@tags");
|
|
}
|
|
|
|
[Fact]
|
|
public void The_template_read_tag_carries_the_authored_port()
|
|
{
|
|
using var tag = LibplctagTemplateReader.BuildTemplateTag(Params("10.100.0.35", 44999), templateInstanceId: 0x123);
|
|
tag.Gateway.ShouldBe("10.100.0.35:44999");
|
|
tag.Name.ShouldBe("@udt/291");
|
|
}
|
|
}
|