docs(modbus-tests): document profile-cycling gotcha; sweep #2 was a false alarm
The 2026-07 integration sweep flagged the Modbus non-standard profiles as 8F/5F/3F/8F and guessed 'pymodbus 4.x drift'. Re-investigation shows that was wrong on both counts: - The image runs the PINNED pymodbus 3.13.0 (verified via import pymodbus; __version__). The '...removed in v4' log is 3.13.0's forward-deprecation warning, misread as running 4.x. - The failures were a fixture-cycling artifact: each profile is a separate profile-gated compose service sharing :5020, and a plain 'docker compose down' (no --profile) does NOT stop the running profile container. It kept holding :5020; the next '--profile up' container silently failed to bind (compose still says 'Started'), so every later profile run hit the STALE sim. Proven by a raw Modbus probe: the 'mitsubishi' sim served DL205's 0xCAFE at HR0. After force-removing all modbus containers and bringing up each profile cleanly (verifying it actually published :5020), all four pass: dl205 16/16, mitsubishi 13/13, s7_1500 10/10, exception_injection 17/17. No OtOpcUa or test code change needed. Added a profile-cycling gotcha + reliable-cycle recipe to Docker/README.md and corrected the sweep record. Integration-sweep follow-up #2.
This commit is contained in:
@@ -48,6 +48,31 @@ service + starting another. The integration tests discriminate by a
|
||||
separate `MODBUS_SIM_PROFILE` env var so they skip correctly when the
|
||||
wrong profile is live.
|
||||
|
||||
> **⚠️ Profile-cycling gotcha (bit us in the 2026-07 sweep — see
|
||||
> `archreview/plans/INTEGRATION-SWEEP-STATUS.md`).** Each profile is a
|
||||
> *separate compose service* selected by `--profile`, so a plain
|
||||
> `docker compose down` (no `--profile`) does **not** stop the
|
||||
> currently-running profile container — it keeps holding `:5020`. Start
|
||||
> another profile and the new container silently fails to bind the port
|
||||
> (compose still reports "Started"); every test then hits the **stale**
|
||||
> profile's data and fails with wrong values / Illegal-Data-Address. The
|
||||
> symptom is deceptive: reads succeed but return the previous profile's
|
||||
> seed (e.g. Mitsubishi's `D0` reads DL205's `0xCAFE`). Always tear the
|
||||
> old container down **by name / with its profile** before bringing up the
|
||||
> next, and verify the new container actually published `:5020`:
|
||||
>
|
||||
> ```bash
|
||||
> # reliable cycle (force-remove ALL modbus containers, then bring one up)
|
||||
> docker rm -f $(docker ps -aq --filter name=otopcua-modbus --filter name=otopcua-pymodbus)
|
||||
> docker compose --profile <profile> up -d --force-recreate
|
||||
> docker ps --filter name=otopcua --format '{{.Names}} {{.Ports}}' # MUST show 0.0.0.0:5020->5020
|
||||
> ```
|
||||
>
|
||||
> The `exception_injection` service uses a different container name
|
||||
> (`otopcua-modbus-exception-injector`, not `otopcua-pymodbus-*`), so a
|
||||
> name-filtered `docker rm` that only matches `otopcua-pymodbus` will miss
|
||||
> it — the `--force-recreate` above covers that case.
|
||||
|
||||
### Profile coverage matrix
|
||||
|
||||
The two general-purpose profiles cover disjoint test sets. A full pass
|
||||
|
||||
Reference in New Issue
Block a user