c2c3c52274
The AbCip controller browse could never be verified end to end: libplctag's ab_server answers CIP service 0x55 (Get Instance Attribute List) on the Symbol Object class with "unsupported", so the `@tags` walk had no backend. #468's own definition of done offered a sim that serves `@tags` as an alternative to real hardware; this is that. The fixture now applies a vendored patch teaching ab_server to serve the Symbol Object listing, with partial-transfer paging. Correctness is checked against libplctag's own `list_tags_logix` rather than against our decoder — our decoder is the thing under test, so its agreement would prove nothing. The clone is also pinned to a concrete tag: the Dockerfile called `--branch release` "pinned" while tracking a branch that moves. That immediately exposed a real defect. CipSymbolObjectDecoder advanced to an even byte boundary after each symbol name, but entries are packed with no padding — libplctag walks them by sizeof(entry) + string_len, and a captured reply confirms it. Any odd-length name therefore desynchronised every entry behind it, and odd-length names are ordinary. In the live browse below, `Motor_Run` is 9 bytes and first on the wire, so the old decoder would have shown that one tag and silently dropped the other eight. Every existing multi-entry test passed throughout, because the test builder padded exactly as the decoder did: the two agreed with each other and neither agreed with a controller. The builder no longer pads, and the layout is pinned by a captured reply (CipSymbolObjectWireCaptureTests) instead of by a second statement of the assumption. Restoring the alignment step reddens exactly the three new tests and none of the 29 others. Live gate on docker-dev, all three of #468's criteria: - populated tree — all nine seeded tags render as leaves, in wire order - refresh re-captures - leaf commit — Pump_1_Speed + TestDINT saved with their CIP tag paths The gate also surfaced two things it was not asked about: browse-commit drops the discovered data type, so a browsed REAL commits as a DINT and the driver decodes it as one (filed as #536), and Test Connect fails against this fixture regardless of the device because it probes `@raw_cpu_type` (documented). TwinCAT and FOCAS still have no browsable backend; #468's AbCip half is closed, theirs is not. Claude-Session: https://claude.ai/code/session_015p7wGqy3YpZNCpDzTpGMKo
107 lines
3.1 KiB
YAML
107 lines
3.1 KiB
YAML
# AB CIP integration-test fixture — ab_server (libplctag).
|
|
#
|
|
# One service per family. All bind :44818 on the host; only one runs at a
|
|
# time. Commands mirror the CLI args AbServerProfile.cs constructs for the
|
|
# native-binary path.
|
|
#
|
|
# Usage:
|
|
# docker compose --profile controllogix up
|
|
# docker compose --profile compactlogix up
|
|
# docker compose --profile micro800 up
|
|
# docker compose --profile guardlogix up
|
|
services:
|
|
controllogix:
|
|
profiles: ["controllogix"]
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
image: otopcua-ab-server:libplctag-release
|
|
container_name: otopcua-ab-server-controllogix
|
|
restart: "no"
|
|
ports:
|
|
- "44818:44818"
|
|
# The last three are here for the controller-browse gate (Gitea #468) and
|
|
# are additive — the read/write suites key off the Test* tags above.
|
|
# Odd-length names are deliberate: Symbol Object entries are packed with no
|
|
# padding, so a name with an odd byte count puts every following entry on an
|
|
# odd offset. A decoder that assumes even alignment reads all six correctly
|
|
# and then loses everything after the first odd name.
|
|
command: [
|
|
"ab_server",
|
|
"--plc=ControlLogix",
|
|
"--path=1,0",
|
|
"--port=44818",
|
|
"--tag=TestDINT:DINT[1]",
|
|
"--tag=TestREAL:REAL[1]",
|
|
"--tag=TestBOOL:BOOL[1]",
|
|
"--tag=TestSINT:SINT[1]",
|
|
"--tag=TestString:STRING[1]",
|
|
"--tag=TestArray:DINT[16]",
|
|
"--tag=Pump_1_Speed:REAL[1]",
|
|
"--tag=Line1_Count:DINT[1]",
|
|
"--tag=Motor_Run:BOOL[1]"
|
|
]
|
|
|
|
compactlogix:
|
|
profiles: ["compactlogix"]
|
|
image: otopcua-ab-server:libplctag-release
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
container_name: otopcua-ab-server-compactlogix
|
|
restart: "no"
|
|
ports:
|
|
- "44818:44818"
|
|
# ab_server doesn't distinguish CompactLogix from ControlLogix — no
|
|
# dedicated --plc mode. Driver-side ConnectionSize cap is enforced
|
|
# separately (see AbServerProfile.CompactLogix Notes).
|
|
command: [
|
|
"ab_server",
|
|
"--plc=ControlLogix",
|
|
"--path=1,0",
|
|
"--port=44818",
|
|
"--tag=TestDINT:DINT[1]",
|
|
"--tag=TestREAL:REAL[1]",
|
|
"--tag=TestBOOL:BOOL[1]"
|
|
]
|
|
|
|
micro800:
|
|
profiles: ["micro800"]
|
|
image: otopcua-ab-server:libplctag-release
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
container_name: otopcua-ab-server-micro800
|
|
restart: "no"
|
|
ports:
|
|
- "44818:44818"
|
|
# ab_server does have a Micro800 plc mode (unconnected-only, empty path).
|
|
command: [
|
|
"ab_server",
|
|
"--plc=Micro800",
|
|
"--port=44818",
|
|
"--tag=TestDINT:DINT[1]",
|
|
"--tag=TestREAL:REAL[1]"
|
|
]
|
|
|
|
guardlogix:
|
|
profiles: ["guardlogix"]
|
|
image: otopcua-ab-server:libplctag-release
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
container_name: otopcua-ab-server-guardlogix
|
|
restart: "no"
|
|
ports:
|
|
- "44818:44818"
|
|
# ab_server has no safety subsystem — _S suffix triggers driver-side
|
|
# classification only.
|
|
command: [
|
|
"ab_server",
|
|
"--plc=ControlLogix",
|
|
"--path=1,0",
|
|
"--port=44818",
|
|
"--tag=TestDINT:DINT[1]",
|
|
"--tag=SafetyDINT_S:DINT[1]"
|
|
]
|