Task #253 follow-up — fix test-all.ps1 StrictMode crash on missing JSON keys #215

Merged
dohertj2 merged 1 commits from task-253d-e2e-debug-harness into v2 2026-04-21 10:57:36 -04:00
Owner

Summary

Running the e2e suite end-to-end surfaced one more harness bug: test-all.ps1 crashed with "The property 'X' cannot be found on this object" whenever the sidecar JSON omitted an optional key.

Root cause

_common.ps1 sets Set-StrictMode -Version 3.0. Under strict mode, missing-property access on a PSCustomObject (what ConvertFrom-Json returns by default) throws. Every $config.<driver>.<optional> ?? $default + if ($config.<missing-section>) was unsafe.

Fix

  • ConvertFrom-Json -AsHashtable — hashtables tolerate .ContainsKey() / indexer lookup under strict mode.
  • Get-Or helper: Get-Or $table "key" $default returns the value if present, else the default.
  • Rewrite every per-driver section (Modbus / AB CIP / AB Legacy / S7 / FOCAS / TwinCAT / Phase 7) to use the helper.

Verified end-to-end

With docker compose up for pymodbus / ab_server / python-snap7 fixtures, plus the three driver sections populated in a local e2e-config.json:

==================== FINAL MATRIX ====================
  modbus     FAIL  # stages 1+2 PASS, 3-5 FAIL (blocked on #209)
  abcip      FAIL  # same
  ablegacy   SKIP (no config entry)
  s7         FAIL  # same
  focas      SKIP (no config entry)
  twincat    SKIP (no config entry)
  phase7     SKIP (no config entry)

Also ran each per-driver script directly:

  • test-modbus.ps1 / test-abcip.ps1 / test-s7.ps1 — 2/5 PASS (probe + driver loopback), 3/5 FAIL at the bridge as expected (server-wiring blocker #209).
  • test-focas.ps1 / test-twincat.ps1 / test-ablegacy.ps1 — SKIP with clear gate messages when the respective *_TRUST_WIRE env var isn't set.

Test plan

  • Harness runs to completion against live fixtures
  • Final matrix renders PASS / FAIL / SKIP correctly
  • SKIP gates fire for hardware-only drivers
  • All-green run — blocked on #209 (server factory wiring)
## Summary Running the e2e suite end-to-end surfaced one more harness bug: `test-all.ps1` crashed with "The property 'X' cannot be found on this object" whenever the sidecar JSON omitted an optional key. ## Root cause `_common.ps1` sets `Set-StrictMode -Version 3.0`. Under strict mode, missing-property access on a `PSCustomObject` (what `ConvertFrom-Json` returns by default) throws. Every `$config.<driver>.<optional> ?? $default` + `if ($config.<missing-section>)` was unsafe. ## Fix - `ConvertFrom-Json -AsHashtable` — hashtables tolerate `.ContainsKey()` / indexer lookup under strict mode. - `Get-Or` helper: `Get-Or $table "key" $default` returns the value if present, else the default. - Rewrite every per-driver section (Modbus / AB CIP / AB Legacy / S7 / FOCAS / TwinCAT / Phase 7) to use the helper. ## Verified end-to-end With `docker compose up` for pymodbus / ab_server / python-snap7 fixtures, plus the three driver sections populated in a local `e2e-config.json`: ``` ==================== FINAL MATRIX ==================== modbus FAIL # stages 1+2 PASS, 3-5 FAIL (blocked on #209) abcip FAIL # same ablegacy SKIP (no config entry) s7 FAIL # same focas SKIP (no config entry) twincat SKIP (no config entry) phase7 SKIP (no config entry) ``` Also ran each per-driver script directly: - `test-modbus.ps1` / `test-abcip.ps1` / `test-s7.ps1` — 2/5 PASS (probe + driver loopback), 3/5 FAIL at the bridge as expected (server-wiring blocker #209). - `test-focas.ps1` / `test-twincat.ps1` / `test-ablegacy.ps1` — SKIP with clear gate messages when the respective `*_TRUST_WIRE` env var isn't set. ## Test plan - [x] Harness runs to completion against live fixtures - [x] Final matrix renders PASS / FAIL / SKIP correctly - [x] SKIP gates fire for hardware-only drivers - [ ] All-green run — blocked on #209 (server factory wiring)
dohertj2 added 1 commit 2026-04-21 10:57:32 -04:00
Running `test-all.ps1` end-to-end with a partial sidecar (only modbus/
abcip/s7 populated, no focas/twincat/phase7) crashed:

    [FAIL] modbus runner crashed: The property 'opcUaUrl' cannot be
    found on this object. Verify that the property exists.

Root cause: `_common.ps1` sets `Set-StrictMode -Version 3.0`, which
turns missing-property access on PSCustomObject into a throw. Every
`$config.<driver>.<optional-field> ?? $default` and `if
($config.<missing-section>)` check is therefore unsafe against a
normal JSON where optional fields are omitted.

Fix: switch to `ConvertFrom-Json -AsHashtable` and add a `Get-Or`
helper. Hashtables tolerate `.ContainsKey()` / indexer access even
under StrictMode, so the per-driver sections now read:

    $modbus = Get-Or $config "modbus"
    if ($modbus) {
        ... -OpcUaUrl (Get-Or $modbus "opcUaUrl" $OpcUaUrl) ...
    }

Verified end-to-end with live docker-compose fixtures:
 - Modbus / AB CIP / S7 each run to completion, report 2/5 PASS (the
   driver-only stages) and FAIL the 3 server-bridge stages (expected —
   server-side factory wiring is blocked on #209).
 - The FINAL MATRIX header renders cleanly with SKIP rows for the
   drivers not present in the sidecar + FAIL rows for the present ones.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit 16d9592a8a into v2 2026-04-21 10:57:36 -04:00
dohertj2 deleted branch task-253d-e2e-debug-harness 2026-04-21 10:57:36 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#215