test-infra: port local_instrumented.sh to Python + rewire preflight off GMD (#281) #332

Merged
JMR-dev merged 1 commits from feat-281-python-dev-scripts into main 2026-07-05 01:16:51 +00:00
JMR-dev commented 2026-07-05 00:59:29 +00:00 (Migrated from github.com)

Closes #281

Ports the last bash dev-script to cross-platform Python and rewires the local /preflight E2E off Gradle Managed Devices (GMD).

What changed

  • local_instrumented.sh → local_instrumented.py (the .sh is removed). Stdlib-only Python 3, cross-platform (Windows / Linux / macOS), matching api37_e2e.py's style. Behavior preserved exactly: comma-separated test-class CLI arg, pre-boot orphan-kill, manual cold-boot of the dev36 AVD (no GMD, no snapshot), targeted connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=…, and the EXIT-trap teardown — now try/finally + atexit + SIGINT/SIGTERM handlers (idempotent). Exit codes 0/2/3/4 preserved.
  • Cross-platform process kill abstracted per-OS: taskkill /F /IM … on Windows, pkill -f qemu-system on *nix; process listing via tasklist / ps ax.
  • Teardown hardened vs the .sh: it now also reaps the emulator launcher image, not just qemu. The Windows -no-window emulator spawns a sibling emulator.exe that briefly outlives the qemu VM, which the qemu-only sweep left as an orphan on return — caught by the smoke run and fixed (the non-negotiable no-orphan rule).
  • Preflight rewire (SKILL.md + CLAUDE.md): the local api35DebugAndroidTest / api36DebugAndroidTest GMD steps are replaced with python3 .claude/skills/preflight/local_instrumented.py <classes>. CI's own multi-API matrix (ci.yml, build.gradle.kts) is untouched — this is local preflight only.
  • Convention documented in CLAUDE.md: prefer Python (stdlib) for cross-platform dev scripts; no new bash-only (.sh) or PowerShell-only helpers.

Validation

  • python -m py_compile, --help, and no-arg → exit 2 (argparse).
  • Logic diff vs the .sh confirmed on every branch (gradle command, emulator flags, boot loop, preamble/teardown kills, exit codes, JAVA_HOME/ANDROID_AVD_HOME pinning).
  • Guarded emulator smoke run PASSED. local_instrumented.py org.libremail.data.local.DatabaseEncryptionTest cold-booted the dev36 AVD, ran green, and tore down clean — no qemu/emulator orphan on return (verified independently after the run).

🤖 Generated with Claude Code

Closes #281 Ports the last bash dev-script to cross-platform Python and rewires the local `/preflight` E2E off Gradle Managed Devices (GMD). ## What changed - **`local_instrumented.sh` → `local_instrumented.py`** (the `.sh` is removed). Stdlib-only Python 3, cross-platform (Windows / Linux / macOS), matching `api37_e2e.py`'s style. Behavior preserved exactly: comma-separated test-class CLI arg, pre-boot orphan-kill, manual cold-boot of the `dev36` AVD (no GMD, no snapshot), targeted `connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=…`, and the EXIT-trap teardown — now `try/finally` + `atexit` + `SIGINT`/`SIGTERM` handlers (idempotent). Exit codes **0/2/3/4** preserved. - **Cross-platform process kill** abstracted per-OS: `taskkill /F /IM …` on Windows, `pkill -f qemu-system` on \*nix; process listing via `tasklist` / `ps ax`. - **Teardown hardened** vs the `.sh`: it now also reaps the emulator *launcher* image, not just `qemu`. The Windows `-no-window` emulator spawns a sibling `emulator.exe` that briefly outlives the qemu VM, which the qemu-only sweep left as an orphan on return — caught by the smoke run and fixed (the non-negotiable no-orphan rule). - **Preflight rewire** (`SKILL.md` + `CLAUDE.md`): the local `api35DebugAndroidTest` / `api36DebugAndroidTest` GMD steps are replaced with `python3 .claude/skills/preflight/local_instrumented.py <classes>`. CI's own multi-API matrix (`ci.yml`, `build.gradle.kts`) is **untouched** — this is local preflight only. - **Convention documented** in `CLAUDE.md`: prefer Python (stdlib) for cross-platform dev scripts; no new bash-only (`.sh`) or PowerShell-only helpers. ## Validation - `python -m py_compile`, `--help`, and no-arg → exit 2 (argparse). - Logic diff vs the `.sh` confirmed on every branch (gradle command, emulator flags, boot loop, preamble/teardown kills, exit codes, `JAVA_HOME`/`ANDROID_AVD_HOME` pinning). - **Guarded emulator smoke run PASSED.** `local_instrumented.py org.libremail.data.local.DatabaseEncryptionTest` cold-booted the `dev36` AVD, ran green, and tore down **clean — no qemu/emulator orphan on return** (verified independently after the run). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.