test(abcip): read-only differential harness comparing native and libplctag on one target
This commit is contained in:
@@ -45,7 +45,78 @@ defect is pre-existing and libplctag-side; it is recorded, not fixed, here.
|
||||
|
||||
## Differential vs ab_server (T18)
|
||||
|
||||
_(pending)_
|
||||
Run 2026-10-07 on branch `feat/native-ab-transport`, harness
|
||||
`tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests/Differential/`, against `ab_server`
|
||||
(`controllogix` profile only, `/opt/otopcua-abcip` on 10.100.0.35):
|
||||
|
||||
```bash
|
||||
AB_DIFF_ENDPOINT=10.100.0.35:44818 AB_DIFF_COUNT_OPENS=1 \
|
||||
dotnet test tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests \
|
||||
--filter "FullyQualifiedName~Differential" --logger "console;verbosity=detailed"
|
||||
```
|
||||
|
||||
Target as the harness resolved it: `10.100.0.35:44818`, path `1,0`, family `CompactLogix`
|
||||
(the defaults; libplctag attribute `compactlogix`, connection size 504).
|
||||
|
||||
**Result: 7/7 passed, 0 unexpected divergences, 0 expected divergences.**
|
||||
|
||||
| Check | Result |
|
||||
|---|---|
|
||||
| Browse parity (`@tags` + program listings) | 9 tags via libplctag, 9 via native, identical as multisets |
|
||||
| Template parity | vacuous: ab_server serves no UDTs, so 0 template ids. Task 21's press is the first real exercise |
|
||||
| Read parity | 9/9 tags equal on status, raw buffer and decoded value |
|
||||
| Native Forward Opens over the run (`AB_DIFF_COUNT_OPENS=1`) | **1** |
|
||||
| TCP connections to the target before the native phase | 0 (baseline 0). libplctag's session closed within 1 ms of the last handle being disposed |
|
||||
| Read-only guard (offline, runs without the endpoint) | pass |
|
||||
| Comparison falsifiability (offline) | pass |
|
||||
|
||||
| Tag | Type | libplctag status | native status | Equal? |
|
||||
|---|---|---|---|---|
|
||||
| `Motor_Run` | Bool | Ok | Ok | yes |
|
||||
| `Line1_Count` | DInt | Ok | Ok | yes |
|
||||
| `Pump_1_Speed` | Real | Ok | Ok | yes |
|
||||
| `TestString` | String | Ok | Ok | yes |
|
||||
| `TestSINT` | SInt | Ok | Ok | yes |
|
||||
| `TestBOOL` | Bool | Ok | Ok | yes |
|
||||
| `TestREAL` | Real | Ok | Ok | yes |
|
||||
| `TestDINT` | DInt | Ok | Ok | yes |
|
||||
| `TestArray` | DInt[16] | Ok | Ok | yes |
|
||||
|
||||
**The values were made non-zero first.** An all-zero simulator would make raw and value equality
|
||||
vacuous. Before the run, the simulator was seeded through a throwaway libplctag scratch program
|
||||
outside the repo. The harness itself never writes. Seeded values:
|
||||
|
||||
- `TestDINT` = −123456789
|
||||
- `TestREAL` = 3.14159
|
||||
- `Pump_1_Speed` = 1234.5
|
||||
- `Line1_Count` = 987654
|
||||
- `TestArray[i]` = (i−8)·100003+7, which includes negatives
|
||||
- `TestString` = `"Hello T18"`
|
||||
|
||||
ab_server refuses 1-byte writes (`ErrorBadParam`), so `TestBOOL`, `TestSINT` and `Motor_Run` stay 0.
|
||||
Their parity is therefore weaker evidence.
|
||||
|
||||
**Wire capture of the same run.** tcpdump ran in the ab_server container's network namespace
|
||||
(`nicolaka/netshoot`), and the capture was decoded with tshark:
|
||||
|
||||
| TCP stream | Session | RegisterSession | Forward Open | Forward Close | Requests | Window (s, relative) |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 12 | libplctag | 1 | 1 (Large, 0x5B) | 1 | 1× 0x55 listing, 18× 0x52 Read Fragmented | 0.243 → 0.336 |
|
||||
| 13 | native | 1 | 1 (0x54) | 1 | 1× 0x55 listing, 18× 0x52 Read Fragmented | 0.349 → 0.452 |
|
||||
|
||||
- Exactly two sessions, with no overlap: a 13 ms gap between them.
|
||||
- Zero write services on the wire: no 0x4D, 0x53 or 0x10.
|
||||
- The 12 earlier sub-10 ms TCP connections are the `AbServerFact`/`AbServerTheory` reachability probes. xUnit runs them during discovery for the *other* suites, even under the filter. They target `AB_SERVER_ENDPOINT` (default 10.100.0.35), never `AB_DIFF_ENDPOINT`.
|
||||
|
||||
**Explicit-list path.** `AB_DIFF_TAGS="TestDINT,NoSuchTag,TestArray,TestString"`: 4/4 equal.
|
||||
`NoSuchTag` returned `NotFound` under both transports, and there was still exactly one native Forward Open.
|
||||
|
||||
**Transport fixes found by the differential: none.** One harness defect was found and fixed before
|
||||
this result. libplctag closes a session as soon as its last handle is destroyed. The first version of the
|
||||
libplctag phase created, read and disposed one handle at a time, so it opened a fresh session (and a
|
||||
fresh Forward Open) per tag: 9+ sessions, which the netstat sampling showed. The libplctag phase now holds an anchor handle
|
||||
on `@tags` for its whole duration, which mirrors the native anchor lease. That leaves the one-session
|
||||
capture above.
|
||||
|
||||
## AdminUI /run (T19)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user