Phase 12.J.E.4 — ship-blocking upgrade scenarios (3 tests)
Summary
Phase 1 of the J.E.3.1 follow-up plan. Three high-value E2E tests targeting the most operator-impactful upgrade-flow regressions — all verifying existing production behavior using the J.E.3 high-fidelity infrastructure.
Scenarios covered
| ID | Test | What it pins | Operator impact if regressed |
|---|---|---|---|
| E15.h | E15h_UpgradePreservesInstanceConfigAndCertFiles |
Pre-stages instances.json + per-instance config.json + 2KB cert under test-isolated %ProgramData%, captures pre-upgrade SHA256, runs full Phase A+B, asserts byte-for-byte preservation |
Agent loses ALL identity → server console shows machine "disappeared" → re-registration required for every host |
| E11.u1 | E11u1_ConcurrentDispatch_PreExistingLockPreventsSecondRun |
Pre-stages upgrade.lock with a fake first-dispatch PID, asserts exit 13 + lock content unchanged + Phase B reverse-asserted as skipped (marker stays at v1, no .bak directory) |
Two concurrent upgrade dispatches race the Stop-Service / Move-Item / Start-Service sequence → service in unrecoverable state |
| E12.u2 | E12u2_Sha256Companion404_FallsThroughCleanly_FullLifecycleStillSucceeds |
Promotes existing fetch-isolated coverage to full-lifecycle tier. mirror.SuppressSha256Companion() → runs full Phase A+B, asserts SUCCESS + marker swap to v2 |
Air-gap mirror operators without companion hashes can't upgrade |
Coverage delta vs J.E.3 (PR #196)
J.E.3 covered the happy path + 2 unhappy paths (download 404 + SHA mismatch) at lifecycle tier. J.E.4 adds the 3 ship-blocking gaps that didn't have lifecycle-tier coverage: identity preservation, idempotency lock, mirror-without-companion fallthrough.
Verification
- 84/84 cross-platform E2E pass locally (was 81 + 3 new). 3 new tests skip-guard on macOS/Linux dev hosts (Windows-only sc.exe + Stop-Service dependencies).
- Will verify on Windows runner via this PR's CI.
Matrix update
- Section E: 12 → 15 covered (47%)
- Grand total: 81 → 84 (42% covered)
Deferred to Phase 12.J.E.5+
- E11.u2 (stale lock break) — requires new prod code: stale-PID detection in the .ps1
- E10.u1 (server-side Redis lock) — requires MachineUpgradeService E2E fixture
- E6.u1 / E7.u1 (Phase B rollback on mid-flight crash / OnStart 1053) — requires new prod code: .ps1 doesn't currently have rollback logic
- E4.h (already-up-to-date short-circuit) — requires version-stamped test binary
- E14.u1 (mid-script Halibut disconnect) — promotion blocked by timing fragility (StubAgent's LocalScriptService runs the wrapper synchronously inside StartScriptAsync; can't inject mid-script disconnect without redesigning the fixture)
Test plan
-
Local cross-platform: 84/84 pass ✅ -
Windows runner: J.E.4 tests + existing J.E.3 + Wrapper + Service + ShaVerify all green -
No regression in existing 81-test baseline