Localize the web console and persist custom model and capability settings. Use OpenAI Responses exclusively and move runtime limits into environment configuration. Bootstrap uv and the virtual environment on Windows, support optional China mirrors, and package source distributions without environments, build output, or credentials. Update regression tests and repository quality checks for the new behavior.
149 lines
5.2 KiB
Python
149 lines
5.2 KiB
Python
"""Exercise the Windows bootstrap in disposable projects without installing host tools."""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
pytestmark = pytest.mark.skipif(
|
|
sys.platform != "win32" or not shutil.which("uv"), reason="Windows and uv required"
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def project(tmp_path):
|
|
# Import fixtures let the final smoke check run without downloading project dependencies.
|
|
path = tmp_path / "source with spaces!"
|
|
path.mkdir()
|
|
(path / "pyproject.toml").write_text(
|
|
'[project]\nname="bootstrap-fixture"\nversion="0.1.0"\nrequires-python=">=3.12"\ndependencies=[]\n'
|
|
)
|
|
for name in ("artemis", "uvicorn", "fastapi", "langchain_openai"):
|
|
(path / f"{name}.py").write_text("")
|
|
subprocess.run(["uv", "lock", "--offline"], cwd=path, check=True, capture_output=True)
|
|
return path
|
|
|
|
|
|
def run_bootstrap(
|
|
project, *, missing_uv=False, installer_failure=False, sync_failure=False, mirror_index=""
|
|
):
|
|
script = project / "check.ps1"
|
|
script.write_text(
|
|
"""
|
|
$ErrorActionPreference = 'Continue'
|
|
$realUv = (Get-Command uv).Source
|
|
. $env:BOOTSTRAP_SCRIPT
|
|
. (Join-Path (Split-Path $env:BOOTSTRAP_SCRIPT -Parent) 'download_config.ps1')
|
|
if ($env:TEST_MIRROR) { $script:ArtemisDownloads = @{ python_index = $env:TEST_MIRROR } }
|
|
$script:uvInstalled = $env:SIMULATE_MISSING_UV -ne '1'
|
|
function Test-CommandExists { param($Command); return $script:uvInstalled }
|
|
function Update-EnvironmentPath {}
|
|
function Invoke-DownloadFile {
|
|
param($Uri, $OutFile, $TimeoutSec)
|
|
if ($Uri -ne 'https://astral.sh/uv/install.ps1') { throw 'Unexpected installer source' }
|
|
Set-Content -LiteralPath $OutFile -Value '# fixture installer'
|
|
return $true
|
|
}
|
|
function powershell.exe {
|
|
Write-Host 'INSTALLER_CALLED'
|
|
if ($env:SIMULATE_INSTALL_FAILURE -eq '1') { $global:LASTEXITCODE = 25; return }
|
|
$script:uvInstalled = $true
|
|
$global:LASTEXITCODE = 0
|
|
}
|
|
function uv {
|
|
if ($env:SIMULATE_SYNC_FAILURE -eq '1' -and $args[0] -eq 'sync') {
|
|
$global:LASTEXITCODE = 9
|
|
return
|
|
}
|
|
& $realUv @args
|
|
}
|
|
try {
|
|
$python = Initialize-ArtemisPython -ProjectRoot $PSScriptRoot
|
|
Write-Host "PYTHON_READY=$python"
|
|
exit 0
|
|
} catch { Write-Host "EXPECTED_ERROR=$_"; exit 1 }
|
|
""",
|
|
encoding="ascii",
|
|
)
|
|
env = dict(os.environ)
|
|
env.update(
|
|
BOOTSTRAP_SCRIPT=str(ROOT / "scripts/bootstrap_python.ps1"),
|
|
SIMULATE_MISSING_UV=str(int(missing_uv)),
|
|
SIMULATE_INSTALL_FAILURE=str(int(installer_failure)),
|
|
SIMULATE_SYNC_FAILURE=str(int(sync_failure)),
|
|
UV_OFFLINE="0" if mirror_index else "1",
|
|
TEST_MIRROR=mirror_index,
|
|
)
|
|
return subprocess.run(
|
|
["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", str(script)],
|
|
env=env,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60,
|
|
)
|
|
|
|
|
|
def test_first_setup_and_repeat_reuse_environment(project):
|
|
first = run_bootstrap(project, missing_uv=True)
|
|
assert first.returncode == 0, first.stdout + first.stderr
|
|
assert "INSTALLER_CALLED" in first.stdout
|
|
assert "Creating .venv" in first.stdout
|
|
config = project / ".venv/pyvenv.cfg"
|
|
before = config.stat().st_mtime_ns
|
|
second = run_bootstrap(project)
|
|
assert second.returncode == 0, second.stdout + second.stderr
|
|
assert "INSTALLER_CALLED" not in second.stdout
|
|
assert "Reusing the existing" in second.stdout
|
|
assert "dependencies are already ready" in second.stdout
|
|
assert config.stat().st_mtime_ns == before
|
|
|
|
|
|
def test_installer_failure_stops_before_environment_creation(project):
|
|
result = run_bootstrap(project, missing_uv=True, installer_failure=True)
|
|
assert result.returncode == 1
|
|
assert "uv installation failed" in result.stdout
|
|
assert not (project / ".venv").exists()
|
|
|
|
|
|
def test_dependency_failure_stops_before_launch(project):
|
|
result = run_bootstrap(project, sync_failure=True)
|
|
assert result.returncode == 1
|
|
assert "Dependency installation failed" in result.stdout
|
|
assert "PYTHON_READY=" not in result.stdout
|
|
|
|
|
|
def test_incomplete_environment_is_preserved(project):
|
|
(project / ".venv").mkdir()
|
|
sentinel = project / ".venv/keep.txt"
|
|
sentinel.write_text("existing data")
|
|
result = run_bootstrap(project)
|
|
assert result.returncode == 1
|
|
assert "incomplete" in result.stdout
|
|
assert sentinel.read_text() == "existing data"
|
|
|
|
|
|
@pytest.mark.parametrize("exit_code", [0, 7])
|
|
def test_batch_preserves_exit_code_and_handles_space_and_exclamation_paths(tmp_path, exit_code):
|
|
root = tmp_path / "source with spaces!"
|
|
(root / "scripts").mkdir(parents=True)
|
|
shutil.copy2(ROOT / "start.bat", root / "start.bat")
|
|
(root / "scripts/start.ps1").write_text(
|
|
"param([switch]$SetupOnly)\n"
|
|
"if (-not $SetupOnly) { exit 19 }\n"
|
|
"if ((Get-Location).Path -ne (Split-Path $PSScriptRoot -Parent)) { exit 20 }\n"
|
|
f"exit {exit_code}\n",
|
|
encoding="ascii",
|
|
)
|
|
result = subprocess.run(
|
|
["cmd.exe", "/d", "/c", "call", str(root / "start.bat"), "-SetupOnly"],
|
|
cwd=tmp_path,
|
|
env={**os.environ, "ARTEMIS_NO_PAUSE": "1"},
|
|
capture_output=True,
|
|
timeout=30,
|
|
)
|
|
assert result.returncode == exit_code, result.stdout + result.stderr
|