Files
hermes-agent/tests/scripts/desktop_update/legacy_desktop_reader.py
Teknium d899d5a74b fix: an old Desktop stays parked when the Windows hand-off dies mid-update
Same shape as the POSIX hand-off: windows.ps1 heartbeats line 2 from its
own process, so `taskkill /F` (no finally runs) left line 1 naming a dead
pid while the resumed `hermes update` (the line-4 delegate) or a completion
survivor still held the checkout, and an old packaged Desktop - which judges
lines 1 and 2 alone - deleted the marker and booted its backend.

After its claim the hand-off starts a hidden watcher (-MarkerOp custody
-CustodyOf <pid>, Start-MarkerCustodian). Once the hand-off exits with its
claim still published and the delegate running or the checkout lock held,
the watcher names itself on line 1 under the marker lock, heartbeats line 2
and releases the marker when both end (bounded like the R6 wait).
Invoke-MarkerRelease stops the watcher once the hand-off's own release is
decided. The Windows kill-cell test now also runs the reader be3fd671d7
shipped; that reader runner moves to a helper shared with the POSIX test.
2026-10-06 05:44:21 -07:00

28 lines
1.3 KiB
Python

"""Run the update-marker reader an old packaged Desktop shipped (not collected)."""
from __future__ import annotations
import json
from pathlib import Path
import shutil
import subprocess
import pytest
LEGACY_READER = Path(__file__).resolve().parents[2] / "fixtures" / "legacy_desktop" / "update-marker-be3fd671.mts"
def legacy_read(home: Path) -> dict:
"""The exact reader an old packaged Desktop runs at boot: line 1 dead or line 2 past 20
minutes => it unlinks the marker and starts its backend. {'live': {pid, ageMs} | None,
'kept': marker still exists afterwards}."""
node = shutil.which("node")
if node is None:
pytest.skip("node is needed to run the shipped Desktop reader")
code = (f"import fs from 'fs'; import {{ readLiveUpdateMarker }} from {json.dumps(LEGACY_READER.as_uri())}; "
"const live = readLiveUpdateMarker(process.argv[1]); "
"console.log(JSON.stringify({ live, kept: fs.existsSync(process.argv[1] + '/.hermes-update-in-progress') }))")
out = subprocess.run([node, "--input-type=module", "-e", code, str(home)], capture_output=True, text=True,
encoding="utf-8", timeout=60)
assert out.returncode == 0, out.stderr
return json.loads(out.stdout.strip().splitlines()[-1])