Two real bugs uncovered by re-running with the new fixture defaults
pointing at the shared docker host. Both are test-side, not driver-side.
AbCip — Driver_reads_seeded_DInt_from_ab_server (4 parametrized rows):
Hardcoded 'ab://127.0.0.1:{port}/1,0' in the deviceUri instead of
the resolved fixture.Host. The new 10.100.0.35 default (and any
AB_SERVER_ENDPOINT override) silently couldn't reach this test —
the driver tried to connect to a non-existent localhost:44818 and
returned BadCommunicationError on all 4 profile rows. The sibling
Emulate tests already use the fixture's resolved endpoint; this
smoke test was missed in the original migration.
Fix: deviceUri = $"ab://{fixture.Host}:{fixture.Port}/1,0".
Modbus — Float32_With_CDAB_Roundtrips_Through_Wire:
Test wrote a Float32 to HR 100 (2 consecutive registers: 100+101).
standard.json's writable HR range declares [100,100] only — a
single-cell auto-incrementing register, not a 2-register pair. The
write to register 101 was rejected with Illegal Data Address
(BadOutOfRange).
Fix: moved the tag from HR 100 to HR 200 (in standard.json's
'[200, 209]' scratch range — 10 consecutive writable HRs). The
Float32+CDAB semantic the test exercises is unchanged.
Modbus — Block_Read_Coalescing_Reduces_PDU_Count_End_To_End:
Test read HR 300, 302, 304 — outside both the writable ranges and
the uint16 seed list. pymodbus rejects reads to unseeded HRs even
though 'hr size' is 2048. BadOutOfRange on every read.
Fix: moved the tags from 300/302/304 to 200/202/204 (within the
scratch range). The non-contiguous coalescing semantic (3 tags
inside a 5-register window with MaxReadGap=5) is preserved.
After this commit:
- Modbus.IntegrationTests: 6/38 pass / 32 skip / 0 fail
(was 4 pass / 32 skip / 2 fail; 32 skips are profile-gated
ExceptionInjectionTests — they need MODBUS_SIM_PROFILE=
exception_injection and a different container, intentional gating)
- AbCip.IntegrationTests: 10/12 pass / 2 skip / 0 fail
(was 6 pass / 2 skip / 4 fail; 2 skips are Emulate tests that
need the fixture for separate scenarios)
No driver code changed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
55 lines
2.2 KiB
C#
55 lines
2.2 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests;
|
|
|
|
/// <summary>
|
|
/// End-to-end smoke tests that exercise the real libplctag stack against a running
|
|
/// <c>ab_server</c>. Skipped when the binary isn't on PATH (<see cref="AbServerFactAttribute"/>).
|
|
/// Parametrized over <see cref="KnownProfiles.All"/> so one test file covers every family
|
|
/// (ControlLogix / CompactLogix / Micro800 / GuardLogix).
|
|
/// </summary>
|
|
[Trait("Category", "Integration")]
|
|
[Trait("Requires", "AbServer")]
|
|
public sealed class AbCipReadSmokeTests
|
|
{
|
|
public static IEnumerable<object[]> Profiles =>
|
|
KnownProfiles.All.Select(p => new object[] { p });
|
|
|
|
[AbServerTheory]
|
|
[MemberData(nameof(Profiles))]
|
|
public async Task Driver_reads_seeded_DInt_from_ab_server(AbServerProfile profile)
|
|
{
|
|
var fixture = new AbServerFixture(profile);
|
|
await fixture.InitializeAsync();
|
|
try
|
|
{
|
|
// Use fixture.Host (not hardcoded 127.0.0.1) so the docker-host migration
|
|
// (10.100.0.35) and AB_SERVER_ENDPOINT overrides reach this test too. The
|
|
// sibling Emulate tests already use the fixture's resolved endpoint; this
|
|
// smoke test was missed.
|
|
var deviceUri = $"ab://{fixture.Host}:{fixture.Port}/1,0";
|
|
var drv = new AbCipDriver(new AbCipDriverOptions
|
|
{
|
|
Devices = [new AbCipDeviceOptions(deviceUri, profile.Family)],
|
|
Tags = [new AbCipTagDefinition("Counter", deviceUri, "TestDINT", AbCipDataType.DInt)],
|
|
Timeout = TimeSpan.FromSeconds(5),
|
|
}, $"drv-smoke-{profile.Family}");
|
|
|
|
await drv.InitializeAsync("{}", CancellationToken.None);
|
|
var snapshots = await drv.ReadAsync(["Counter"], CancellationToken.None);
|
|
|
|
snapshots.Single().StatusCode.ShouldBe(AbCipStatusMapper.Good);
|
|
drv.GetHealth().State.ShouldBe(DriverState.Healthy);
|
|
|
|
await drv.ShutdownAsync(CancellationToken.None);
|
|
}
|
|
finally
|
|
{
|
|
await fixture.DisposeAsync();
|
|
}
|
|
}
|
|
}
|