Files
hermes-agent/tests/pm/test_held_entry_windows_live.py
teknium1 d00d57b70f test(pm): pin read-only file removal on a real Windows runner
A read-only file (PortableGit's etc/hosts) inside a replaced entry made
_remove_entry fail every attempt. Since the held-tree fix the install no
longer aborts, but the tree is set aside and gc can never reclaim it, so
every replaced git entry leaked. The live Windows case requires the
replaced tree to be gone outright after a reinstall. Also trims the
salvaged comment to its why.
2026-10-03 01:11:10 -07:00

71 lines
2.5 KiB
Python

"""Live Windows obstacles to removing a replaced PM entry.
A running Hermes process keeps the replaced interpreter's DLLs mapped (#124807),
and archives such as PortableGit ship read-only files; both make deleting the
old entry fail with WinError 5. The OS produces each obstacle here, no model.
"""
from __future__ import annotations
import ctypes
import shutil
import sys
from pathlib import Path
import pytest
from pm.lock import Facts
from tests.pm.test_pm_core import pm_env as pm_env # noqa: F401 — fixture
from tests.pm._fixtures import served as served # noqa: F401 — fixture
@pytest.mark.platforms("windows")
def test_mapped_dll_in_replaced_entry_does_not_fail_reinstall(pm_env): # noqa: F811
from pm.cli import cmd_gc
from pm.install import ensure
_, runtime, *_ = pm_env
ensure("faketool", base_env={})
entry = runtime / Facts(runtime / "facts.json").get("faketool")["entry"]
dlls = Path(sys.base_prefix) / "DLLs"
source = next(iter(sorted(dlls.glob("libcrypto-3*.dll")) or sorted(dlls.glob("*.dll"))))
held = entry / "DLLs" / "held.dll"
held.parent.mkdir()
shutil.copy2(source, held)
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
kernel32.LoadLibraryW.restype = ctypes.c_void_p
kernel32.FreeLibrary.argtypes = [ctypes.c_void_p]
handle = kernel32.LoadLibraryW(str(held))
assert handle, ctypes.get_last_error()
try:
(entry / "bin/faketool").unlink()
runner = ensure("faketool", base_env={})
assert entry.name in runner.env["PATH"]
assert (entry / "bin/faketool").read_bytes() == b"#!x"
assert not (runtime / f".previous-{entry.name}").exists()
assert [p.name for p in runtime.glob(".reclaim-*/DLLs/held.dll")]
finally:
kernel32.FreeLibrary(handle)
cmd_gc(None)
assert not list(runtime.glob(".reclaim-*"))
@pytest.mark.platforms("windows")
def test_read_only_file_in_replaced_entry_is_removed_on_reinstall(pm_env): # noqa: F811
import os
import stat
from pm.install import ensure
_, runtime, *_ = pm_env
ensure("faketool", base_env={})
entry = runtime / Facts(runtime / "facts.json").get("faketool")["entry"]
hosts = entry / "etc" / "hosts"
hosts.parent.mkdir()
hosts.write_bytes(b"127.0.0.1 localhost")
os.chmod(hosts, stat.S_IREAD)
(entry / "bin/faketool").unlink()
ensure("faketool", base_env={})
assert not (runtime / f".previous-{entry.name}").exists()
assert not list(runtime.glob(".reclaim-*")), "a read-only file must not strand the replaced tree"