test(cli): cover Windows self-lock recovery guard + cmd-quote its hint

Add two tests for the self-lock guard in _recover_from_interrupted_install:
one asserting it clears the marker and skips install when hermes.exe is a
process ancestor (breaking the #52378/#45542 loop), one asserting it falls
through to a normal recovery install when the shim is NOT an ancestor.

The guard's manual-recovery hint runs only inside the Windows branch, so
quote it for cmd.exe (cd /d, double-quoted paths) — the cross-platform
fallback hint at the end of the function is left POSIX-correct.

Map Icather in scripts/release.py AUTHOR_MAP for the salvage.
This commit is contained in:
teknium1 2026-06-28 02:19:43 -07:00 committed by Teknium
parent b6f592dbdc
commit 7c9cdad9fd
3 changed files with 88 additions and 3 deletions

View file

@ -7027,10 +7027,10 @@ def _recover_from_interrupted_install() -> None:
" Restart Hermes from a different terminal, "
"then run the manual recovery command below:"
)
print(f" cd {PROJECT_ROOT}")
print(f' cd /d "{PROJECT_ROOT}"')
print(
f" {sys.executable} -m pip install "
"-e '.[all]'"
f' "{sys.executable}" -m pip install '
'-e ".[all]"'
)
_clear_update_incomplete_marker()
try:

View file

@ -168,6 +168,7 @@ AUTHOR_MAP = {
"290859878+synapsesx@users.noreply.github.com": "synapsesx",
"157689911+itsflownium@users.noreply.github.com": "itsflownium",
"dirtyren@users.noreply.github.com": "dirtyren",
"97326386+Icather@users.noreply.github.com": "Icather", # PR #45554 salvage (self-lock guard breaks Windows update-recovery infinite loop; #52378 / #45542)
"--email": "andryypaez@gmail.com",
"mucio@mucio.net": "francescomucio",
"291572938+thestral123@users.noreply.github.com": "thestral123",

View file

@ -139,6 +139,90 @@ def _stub_install_env(monkeypatch, m, seen):
)
def test_recovery_self_lock_guard_clears_marker_without_install(tmp_path, monkeypatch):
# Windows self-lock: hermes.exe is an ancestor of this Python process, so a
# pip-install would fail trying to replace the running launcher (WinError 32
# / 拒绝访问). Recovery must short-circuit — clear the marker, skip install,
# break the loop (#45542 / #52378) — instead of retrying forever.
monkeypatch.setattr(m, "PROJECT_ROOT", tmp_path)
(tmp_path / "pyproject.toml").write_text("[project]\nname='x'\n")
m._write_update_incomplete_marker()
scripts_dir = tmp_path / "venv" / "Scripts"
scripts_dir.mkdir(parents=True)
shim = scripts_dir / "hermes.exe"
shim.write_text("")
monkeypatch.setattr(m, "_is_windows", lambda: True)
monkeypatch.setattr(m, "_venv_scripts_dir", lambda: scripts_dir)
monkeypatch.setattr(m, "_hermes_exe_shims", lambda d: [shim])
class FakeProc:
def __init__(self, exe_path):
self._exe = exe_path
def exe(self):
return self._exe
def parents(self):
return [FakeProc(str(shim))]
monkeypatch.setattr("psutil.Process", lambda: FakeProc(sys_executable_path()))
seen = {"install": False}
_stub_install_env(monkeypatch, m, seen)
m._recover_from_interrupted_install()
assert seen["install"] is False, "self-lock must skip the install"
assert not m._update_marker_path().exists(), "marker cleared to break the loop"
def sys_executable_path():
import sys
return sys.executable
def test_recovery_self_lock_guard_inactive_when_not_ancestor(tmp_path, monkeypatch):
# Windows, but hermes.exe is NOT in the ancestry (launched via `hermes
# dashboard` from a separate cmd, say). The guard must fall through to the
# normal install so a genuinely interrupted install still gets healed.
monkeypatch.setattr(m, "PROJECT_ROOT", tmp_path)
(tmp_path / "pyproject.toml").write_text("[project]\nname='x'\n")
m._write_update_incomplete_marker()
scripts_dir = tmp_path / "venv" / "Scripts"
scripts_dir.mkdir(parents=True)
shim = scripts_dir / "hermes.exe"
shim.write_text("")
monkeypatch.setattr(m, "_is_windows", lambda: True)
monkeypatch.setattr(m, "_venv_scripts_dir", lambda: scripts_dir)
monkeypatch.setattr(m, "_hermes_exe_shims", lambda d: [shim])
class FakeProc:
def __init__(self, exe_path):
self._exe = exe_path
def exe(self):
return self._exe
def parents(self):
# Ancestry is plain pythons / cmd — no hermes.exe shim.
return [FakeProc(str(tmp_path / "cmd.exe"))]
monkeypatch.setattr("psutil.Process", lambda: FakeProc(sys_executable_path()))
seen = {"install": False}
_stub_install_env(monkeypatch, m, seen)
m._recover_from_interrupted_install()
assert seen["install"] is True, "without self-lock, normal recovery runs"
assert not m._update_marker_path().exists(), "marker cleared on successful install"
def test_recovery_skips_when_lock_held(tmp_path, monkeypatch):
# Another process is mid-recovery (fresh lockfile) — this launch must skip
# the install entirely and leave both marker and lock untouched.