"""Run the actual installer functions against a real disposable Python venv.""" import json import os import shutil import subprocess import sys from pathlib import Path import pytest SOURCE = Path(__file__).resolve().parents[1] / 'scripts/install.ps1' PS = shutil.which('powershell') or shutil.which('pwsh') pytestmark = pytest.mark.skipif(os.name != 'nt' or not PS, reason='Windows installer runtime test') def function(source, name): start = source.index('function ' + name + ' {') opening = source.index('{', start) depth = 0 for index in range(opening, len(source)): if source[index] == '{': depth += 1 elif source[index] == '}': depth -= 1 if depth == 0: return source[start:index + 1] raise AssertionError(name) @pytest.fixture(scope='module') def runtime(tmp_path_factory): root = tmp_path_factory.mktemp('installer-reuse') subprocess.run([sys.executable, '-m', 'venv', '--without-pip', str(root / 'venv')], check=True) return root def run(runtime, body): text = SOURCE.read_text(encoding='utf-8-sig') script = runtime / 'probe.ps1' prefix = "$ErrorActionPreference = 'Stop'\n" prefix += function(text, 'Test-ReusableManagedVenv') + '\n' prefix += function(text, 'Install-Venv') + '\n' prefix += "$InstallDir = '" + str(runtime).replace("'", "''") + "'\n" prefix += "$BasePython = '" + sys._base_executable.replace("'", "''") + "'\n" prefix += "$Version = '" + str(sys.version_info.major) + '.' + str(sys.version_info.minor) + "'\n" script.write_text(prefix + body, encoding='utf-8-sig') result = subprocess.run([PS, '-NoProfile', '-File', str(script)], capture_output=True, text=True, timeout=40) assert result.returncode == 0, result.stdout + result.stderr return result.stdout def test_healthy_update_keeps_live_python_and_never_reaches_kill_sweep(runtime): python = runtime / 'venv/Scripts/python.exe' live = subprocess.Popen([str(python), '-c', 'import time;time.sleep(90)']) try: output = run(runtime, r''' function Resolve-AvailablePythonVersion { return @{Path=$BasePython;Version=$Version} } function Write-Success { param($Message); Write-Output $Message } function Write-Info { throw 'Unexpected venv recreation/kill path' } function taskkill { throw 'Live process must not be killed' } Install-Venv ''') assert 'Reusing healthy' in output assert live.poll() is None assert python.is_file() finally: live.terminate();live.wait(timeout=10) def test_wrong_version_or_foreign_interpreter_does_not_reuse(runtime): output = run(runtime, r''' $venvPath = Join-Path $InstallDir 'venv' $results = @( (Test-ReusableManagedVenv $venvPath $BasePython '0.0'), (Test-ReusableManagedVenv $venvPath (Join-Path $InstallDir 'other-python.exe') $Version), (Test-ReusableManagedVenv (Join-Path $InstallDir 'missing') $BasePython $Version) ) ConvertTo-Json -Compress -InputObject $results ''') assert json.loads(output) == [False, False, False]