Files
hermes-agent/tests/scripts/install/test_install_ps1_managed_python_provenance.py
ethernet 4aadff7bd6 test(install): expect the arch-qualified bootstrap Python request
419a3cbe00 made install.ps1 ask uv for cpython-<minor>-windows-<arch>-none,
but this test still pinned the bare version.
2026-09-24 11:31:09 -04:00

80 lines
3.7 KiB
Python

"""The real installer waits for bootstrap uv before it delegates to PM."""
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import pytest
pytestmark = pytest.mark.platforms("windows")
INSTALLER = Path(__file__).resolve().parents[3] / "scripts" / "install.ps1"
@pytest.mark.parametrize("stage,exit_code", [("venv", 0), ("python-deps", 0), ("python-deps", 17)])
def test_python_stage_delegates_to_pin_without_touching_existing_env(tmp_path, stage, exit_code):
powershell = shutil.which("powershell")
assert powershell
install = tmp_path / "install with spaces"
package = install / "pm"
package.mkdir(parents=True)
(package / "lock.json").write_text(json.dumps({"packages": {"python": {"version": "3.12.8+fixture"}}}), encoding="utf-8")
(package / "__init__.py").write_text("", encoding="utf-8")
(package / "cli.py").write_text(
"import json, os, pathlib, sys\n"
"assert not pathlib.Path(os.environ['UV_BUSY']).exists()\n"
"pathlib.Path(os.environ['PM_LOG']).write_text(json.dumps(sys.argv[1:]))\n"
"sys.exit(int(os.environ['PROBE_EXIT']))\n", encoding="utf-8",
)
existing = install / "venv" / "sentinel"
existing.parent.mkdir()
existing.write_text("previous generation", encoding="utf-8")
log = tmp_path / "uv-calls.jsonl"
pm_log = tmp_path / "pm-call.json"
wrapper = tmp_path / "boundary.ps1"
wrapper.write_text(r'''
param([string]$Installer, [string]$InstallDir, [string]$HomeDir, [string]$Log)
$ErrorActionPreference = 'Stop'
function uv {
Set-Content -Path $env:UV_BUSY -Value 'running'
try {
ConvertTo-Json -Compress -InputObject @($args) | Add-Content -Encoding UTF8 $Log
switch ($args[1]) {
'install' { }
'find' { Write-Output $env:BOOTSTRAP_PYTHON }
default { throw 'PM must not be a child of the bootstrap uv' }
}
$global:LASTEXITCODE = 0
} finally { Remove-Item $env:UV_BUSY }
}
function Invoke-WebRequest { throw 'network access outside test boundary' }
. $Installer -InstallDir $InstallDir -HermesHome $HomeDir
# Dot-sourcing defines Get-Uv, so override only that acquisition boundary.
function Get-Uv { return 'uv' }
Invoke-StageByName $env:PROBE_STAGE
exit $LASTEXITCODE
''', encoding="utf-8-sig")
# uv python find returns the distribution interpreter, not a venv launcher.
env = dict(os.environ, PROBE_STAGE=stage, PROBE_EXIT=str(exit_code), BOOTSTRAP_PYTHON=sys._base_executable,
PM_LOG=str(pm_log), UV_BUSY=str(tmp_path / "uv-busy"), PATHEXT=".COM;.EXE;.BAT;.CMD")
env.pop("PYTHONPATH", None)
run = subprocess.run([powershell, "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", str(wrapper),
"-Installer", str(INSTALLER), "-InstallDir", str(install), "-HomeDir", str(tmp_path / "home"), "-Log", str(log)],
cwd=tmp_path, env=env, stdin=subprocess.DEVNULL,
capture_output=True, text=True, timeout=120)
assert (run.returncode == 0) == (exit_code == 0), run.stdout + run.stderr
from hermes_platform.host.facts import native_arch
# The request names the machine's architecture: a bare version lets uv
# pick an emulated x86_64 build on Windows-on-ARM.
uv_arch = "aarch64" if native_arch() == "arm64" else "x86_64"
assert [json.loads(line) for line in log.read_text(encoding="utf-8-sig").splitlines()] == [
["python", "find", "--managed-python", "--no-project", f"cpython-3.12-windows-{uv_arch}-none"],
]
if stage == "python-deps":
assert json.loads(pm_log.read_text(encoding="utf-8-sig")) == ["install"]
else:
assert not pm_log.exists()
assert existing.read_text(encoding="utf-8-sig") == "previous generation"