Files
lmxopcua/tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/Docker/README.md
Joseph Doherty a0cf7c5860 AB Legacy ab_server PCCC Docker fixture scaffold (#224) — Docker infrastructure + test-class shape in place; wire-level round-trip currently blocked by an ab_server-side PCCC coverage gap documented honestly in the fixture + coverage docs. Closes the Docker-infrastructure piece of #224; the remaining work is upstream (patch ab_server's PCCC server opcodes) or sideways (RSEmulate 500 golden-box tier, lab rig).
New project tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/ with four pieces. AbLegacyServerFixture — TCP probe against localhost:44818 (or AB_LEGACY_ENDPOINT override), distinct from AB_SERVER_ENDPOINT so both CIP + PCCC containers can run simultaneously. Single-public-ctor to satisfy xunit collection-fixture constraint. AbLegacyServerProfile + KnownProfiles carry the per-family (SLC500 / MicroLogix / PLC-5) ComposeProfile + Notes; drives per-theory parameterisation. AbLegacyFactAttribute / AbLegacyTheoryAttribute match the AB CIP skip-attribute pattern.

Docker/docker-compose.yml reuses the AB CIP otopcua-ab-server:libplctag-release image — `build:` block points at ../../AbCip.IntegrationTests/Docker context so `docker compose build` from here produces / reuses the same multi-stage build. Three compose profiles (slc500 / micrologix / plc5) with per-family `--plc` + `--tag=<file>[<size>]` flags matching the PCCC tag syntax (different from CIP's `Name:Type[size]`).

AbLegacyReadSmokeTests — one parametric theory reading N7:0 across all three families + one SLC500 write-then-read on N7:5. Targets the shape the driver would use against real hardware. Verified 2026-04-20 against a live SLC500 container: TCP probe passes + container accepts connections + libplctag negotiates session, but read/write returns BadCommunicationError (libplctag status 0x80050000). Root-caused to ab_server's PCCC server-side opcode coverage being narrower than libplctag's PCCC client expects — not a driver-side bug, not a scaffold bug, just an ab_server upstream limitation. Documented honestly in Docker/README.md + AbLegacy-Test-Fixture.md rather than skipping the tests or weakening assertions; tests now skip cleanly when container is absent, fail with clear message when container is up but the protocol gap surfaces. Operator resolves by filing an ab_server upstream patch, pointing AB_LEGACY_ENDPOINT at real hardware, or scaffolding an RSEmulate 500 golden-box tier.

Docker/README.md — Known limitations section leads with the PCCC round-trip gap (test date, failure signature, possible root causes, three resolution paths) before the pre-existing limitations (T/C file decomposition, ST file quirks, indirect addressing, DF1 serial). Reader can't miss the "scaffolded but blocked on upstream" framing.

docs/drivers/AbLegacy-Test-Fixture.md — TL;DR flipped from "no integration fixture" to "Docker scaffold in place; wire-level round-trip currently blocked by ab_server PCCC gap". What-the-fixture-is gains an Integration section. Follow-up candidates rewritten: #1 is now "fix ab_server PCCC upstream", #2 is RSEmulate 500 golden-box (with cost callouts matching our existing Logix Emulate + TwinCAT XAR scaffolds — license + Hyper-V conflict + binary project format), #3 is lab rig. Key-files list adds the four new files. docs/drivers/README.md coverage-map row updated from "no integration fixture" to "Docker scaffold via ab_server PCCC; wire-level round-trip currently blocked, docs call out resolution paths".

Solution file picks up the new tests/.../AbLegacy.IntegrationTests entry. AbLegacyDataType.Int used throughout (not Int16 — the enum uses SLC file-type naming). Build 0 errors; 2 smoke tests skip cleanly without container + fail with clear errors when container up (proving the infrastructure works end-to-end + the gap is specifically the ab_server protocol coverage, not the scaffold).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 13:26:19 -04:00

5.8 KiB

AB Legacy PCCC integration-test fixture — ab_server (Docker)

libplctag's ab_server supports both CIP (ControlLogix / CompactLogix / Micro800) and PCCC (SLC 500 / MicroLogix / PLC-5) families from one binary. This fixture reuses the AB CIP Docker image (otopcua-ab-server:libplctag-release) with different --plc flags. No new Dockerfile needed — the compose file's build: block points at the AB CIP Docker/ folder so docker compose build from here reuses the same multi-stage build.

Docker is the only supported launch path; a fresh clone needs Docker Desktop and nothing else.

File Purpose
docker-compose.yml Three per-family services (slc500 / micrologix / plc5); all bind :44818

Run

From the repo root:

# SLC 500 family — widest PCCC coverage
docker compose -f tests\ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests\Docker\docker-compose.yml --profile slc500 up

# Per-family
docker compose -f tests\...\Docker\docker-compose.yml --profile micrologix up
docker compose -f tests\...\Docker\docker-compose.yml --profile plc5 up

Detached + stop:

docker compose -f tests\...\Docker\docker-compose.yml --profile slc500 up -d
docker compose -f tests\...\Docker\docker-compose.yml --profile slc500 down

First run builds the otopcua-ab-server:libplctag-release image (~3-5 min — clones libplctag + compiles ab_server). If the AB CIP fixture already built the image locally, docker reuses the cached layers + this runs in seconds. Only one family binds :44818 at a time; to switch families stop the current service + start another.

Endpoint

  • Default: localhost:44818 (EtherNet/IP standard)
  • Override with AB_LEGACY_ENDPOINT=host:port to point at a real SLC / MicroLogix / PLC-5 PLC on its native port.

Run the integration tests

In a separate shell with a container up:

cd C:\Users\dohertj2\Desktop\lmxopcua
dotnet test tests\ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests

AbLegacyServerFixture TCP-probes localhost:44818 at collection init + records a skip reason when unreachable. Tests use [AbLegacyFact] / [AbLegacyTheory] which check the same probe.

What each family seeds

PCCC tag format is <file>[<size>] without a type suffix — file letter implies type:

  • N = 16-bit signed integer
  • F = 32-bit IEEE 754 float
  • B = 1-bit boolean (stored as uint16, bit-addressable via /n)
  • L = 32-bit signed integer (SLC 5/05 V15+ only)
  • ST = 82-byte ASCII string (MicroLogix-specific extension)
Family Seeded tags Notes
SLC 500 N7[10], F8[10], B3[10], L19[10] Baseline; covers the four numeric file types a typical SLC project uses
MicroLogix B3[10], N7[10], L19[10] No F8 — MicroLogix 1000 has no float file; use L19 when scaled integers aren't enough
PLC-5 N7[10], F8[10], B3[10] No L — PLC-5 predates the L file type; DINT equivalents went in integer files

Known limitations

ab_server PCCC read/write round-trip (verified 2026-04-20)

Scaffold is in place; wire-level round-trip does NOT currently pass against ab_server --plc=SLC500. With the SLC500 compose profile up, TCP 44818 accepts connections and libplctag negotiates the session, but the three smoke tests in AbLegacyReadSmokeTests.cs all fail at read/write with BadCommunicationError (libplctag status 0x80050000). Possible root causes:

  • ab_server's PCCC server-side opcode coverage may be narrower than libplctag's PCCC client expects — the tool is primarily a CIP server; PCCC was added later + is noted in libplctag docs as less mature.
  • libplctag's PCCC-over-CIP encapsulation may assume a real SLC 5/05 EtherNet/IP NIC's framing that ab_server doesn't emit.

The scaffold ships as-is because:

  1. The Docker infrastructure + fixture pattern works cleanly (probe passes, container lifecycle is clean, tests skip when absent).
  2. The test classes target the correct shape for what the AB Legacy driver would do against real hardware.
  3. Pointing AB_LEGACY_ENDPOINT at a real SLC 5/05 / MicroLogix 1100 / 1400 should make the tests pass outright — the failure mode is ab_server-specific, not driver-specific.

Resolution paths (pick one):

  1. File an ab_server bug in libplctag/libplctag to expand PCCC server-side coverage.
  2. Golden-box tier via Rockwell RSEmulate 500 — closer to real firmware, but license-gated + RSLinx-dependent.
  3. Lab rig — used SLC 5/05 / MicroLogix 1100 on a dedicated network; the authoritative path.

Other known gaps (unchanged from ab_server)

  • Timer / Counter file decomposition — PCCC T4 / C5 files contain three-field structs (.ACC / .PRE / .DN). Not in ab_server's scope; tests targeting T4:0.ACC stay unit-only.
  • ST (ASCII string) files — real MicroLogix ST files have a length field plus CRLF-sensitive semantics that don't round-trip cleanly.
  • Indirect addressing (N7:[N10:5]) — not in ab_server's scope.
  • DF1 serial wire behaviour — the whole ab_server path is TCP; DF1 radio / serial fidelity needs real hardware.

See docs/drivers/AbLegacy-Test-Fixture.md for the full coverage map.

References