170 lines
6.8 KiB
Python
170 lines
6.8 KiB
Python
"""Check download presets and install locked packages from an isolated local index."""
|
|
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import zipfile
|
|
|
|
import pytest
|
|
|
|
from tests.unit.test_windows_bootstrap import run_bootstrap
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
pytestmark = pytest.mark.skipif(
|
|
sys.platform != "win32" or not shutil.which("uv"), reason="Windows and uv required"
|
|
)
|
|
|
|
|
|
def powershell(tmp_path, script, **env):
|
|
path = tmp_path / "test.ps1"
|
|
path.write_text(
|
|
"$ErrorActionPreference = 'Stop'\n. $env:DOWNLOAD_SCRIPT\n" + script, encoding="ascii"
|
|
)
|
|
clean_env = {
|
|
key: value
|
|
for key, value in os.environ.items()
|
|
if not key.upper().startswith(("UV_", "NPM_CONFIG_"))
|
|
}
|
|
return subprocess.run(
|
|
["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", str(path)],
|
|
env={
|
|
**clean_env,
|
|
"DOWNLOAD_SCRIPT": str(ROOT / "scripts/download_config.ps1"),
|
|
"TEST_ROOT": str(tmp_path),
|
|
**env,
|
|
},
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=45,
|
|
)
|
|
|
|
|
|
def test_presets_overrides_and_process_environment(tmp_path):
|
|
(tmp_path / "config").mkdir()
|
|
config = json.loads((ROOT / "config/downloads.json").read_text())
|
|
config["mode"] = "China"
|
|
config["overrides"]["node_mirror"] = "https://intranet.example/node"
|
|
(tmp_path / "config/downloads.json").write_text(json.dumps(config))
|
|
result = powershell(
|
|
tmp_path,
|
|
"""
|
|
Initialize-ArtemisDownloads -ProjectRoot $env:TEST_ROOT
|
|
if ($ArtemisDownloads.mode -ne 'China') { throw 'Preset not selected' }
|
|
if ($ArtemisDownloads.node_mirror -ne 'https://intranet.example/node') { throw 'Override ignored' }
|
|
if ($ArtemisDownloads.python_index -ne 'https://intranet.example/simple') { throw 'Environment ignored' }
|
|
if ($env:npm_config_registry -ne 'https://registry.npmmirror.com') { throw 'npm mirror missing' }
|
|
if ($env:UV_HTTP_TIMEOUT -ne '180') { throw 'Timeout missing' }
|
|
if ($ArtemisDownloads.scrcpy_url -match 'github[.]com') { throw 'China scrcpy still uses GitHub' }
|
|
if ($ArtemisDownloads.scrcpy_sha256 -notmatch '^[a-f0-9]{64}$') { throw 'scrcpy digest missing' }
|
|
Remove-Item Env:npm_config_registry
|
|
Remove-Item Env:UV_PYTHON_INSTALL_MIRROR
|
|
Initialize-ArtemisDownloads -ProjectRoot $env:TEST_ROOT -Mode Official
|
|
if ($ArtemisDownloads.mode -ne 'Official') { throw 'CLI mode ignored' }
|
|
if ($env:npm_config_registry) { throw 'Official mode selected a China registry' }
|
|
""",
|
|
UV_DEFAULT_INDEX="https://intranet.example/simple",
|
|
)
|
|
assert result.returncode == 0, result.stdout + result.stderr
|
|
|
|
|
|
def test_scrcpy_archive_is_checked_before_extraction():
|
|
launcher = (ROOT / "scripts/start.ps1").read_text(encoding="utf-8-sig")
|
|
assert launcher.index("Get-FileHash -LiteralPath $zipPath") < launcher.index(
|
|
"Remove-Item $extractDir -Recurse"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("corrupt", [False, True])
|
|
def test_uv_mirror_bootstrap_verifies_wheel_without_python(tmp_path, corrupt):
|
|
with zipfile.ZipFile(tmp_path / "fixture.zip", "w") as wheel:
|
|
wheel.writestr("uv-1.2.3.data/scripts/uv.exe", b"standalone fixture")
|
|
digest = hashlib.sha256((tmp_path / "fixture.zip").read_bytes()).hexdigest()
|
|
if corrupt:
|
|
digest = "0" * 64
|
|
(tmp_path / "index.html").write_text(
|
|
f'<a href="../../packages/uv-1.2.3-py3-none-win_amd64.whl#sha256={digest}">uv</a>'
|
|
)
|
|
result = powershell(
|
|
tmp_path,
|
|
"""
|
|
function Invoke-DownloadFile {
|
|
param($Uri, $OutFile)
|
|
if ($Uri -eq 'https://mirror.example/simple/uv/') {
|
|
Copy-Item -LiteralPath (Join-Path $env:TEST_ROOT 'index.html') -Destination $OutFile
|
|
} elseif ($Uri -eq 'https://mirror.example/packages/uv-1.2.3-py3-none-win_amd64.whl') {
|
|
Copy-Item -LiteralPath (Join-Path $env:TEST_ROOT 'fixture.zip') -Destination $OutFile
|
|
} else { throw "Unexpected URL: $Uri" }
|
|
return $true
|
|
}
|
|
Install-ArtemisUvFromIndex -IndexUrl 'https://mirror.example/simple' -InstallDir (Join-Path $env:TEST_ROOT 'bin')
|
|
""",
|
|
PROCESSOR_ARCHITECTURE="AMD64",
|
|
PROCESSOR_ARCHITEW6432="AMD64",
|
|
)
|
|
if corrupt:
|
|
assert result.returncode != 0
|
|
assert "SHA256 verification" in result.stderr
|
|
assert not (tmp_path / "bin/uv.exe").exists()
|
|
else:
|
|
assert result.returncode == 0, result.stdout + result.stderr
|
|
assert (tmp_path / "bin/uv.exe").read_bytes() == b"standalone fixture"
|
|
|
|
|
|
def test_mirror_installs_locked_version_and_reuses_it_without_changing_lock(tmp_path):
|
|
project = tmp_path / "project"
|
|
project.mkdir()
|
|
package_dir = tmp_path / "simple/mirror-fixture"
|
|
package_dir.mkdir(parents=True)
|
|
wheel = package_dir / "mirror_fixture-1.0.0-py3-none-any.whl"
|
|
with zipfile.ZipFile(wheel, "w") as archive:
|
|
archive.writestr("mirror_fixture.py", 'VERSION = "1.0.0"\n')
|
|
archive.writestr(
|
|
"mirror_fixture-1.0.0.dist-info/METADATA",
|
|
"Metadata-Version: 2.1\nName: mirror-fixture\nVersion: 1.0.0\n",
|
|
)
|
|
archive.writestr(
|
|
"mirror_fixture-1.0.0.dist-info/WHEEL",
|
|
"Wheel-Version: 1.0\nRoot-Is-Purelib: true\nTag: py3-none-any\n",
|
|
)
|
|
archive.writestr("mirror_fixture-1.0.0.dist-info/RECORD", "")
|
|
digest = hashlib.sha256(wheel.read_bytes()).hexdigest()
|
|
(package_dir / "index.html").write_text(
|
|
f'<a href="{wheel.name}#sha256={digest}">{wheel.name}</a>'
|
|
)
|
|
(project / "pyproject.toml").write_text(
|
|
'[project]\nname="bootstrap-fixture"\nversion="0.1.0"\n'
|
|
'requires-python=">=3.12"\ndependencies=["mirror-fixture==1.0.0"]\n'
|
|
)
|
|
for module in ("artemis", "uvicorn", "fastapi", "langchain_openai"):
|
|
(project / f"{module}.py").write_text("")
|
|
lock = f"""version = 1
|
|
revision = 3
|
|
requires-python = ">=3.12"
|
|
[[package]]
|
|
name = "bootstrap-fixture"
|
|
version = "0.1.0"
|
|
source = {{ virtual = "." }}
|
|
dependencies = [{{ name = "mirror-fixture" }}]
|
|
[package.metadata]
|
|
requires-dist = [{{ name = "mirror-fixture", specifier = "==1.0.0" }}]
|
|
[[package]]
|
|
name = "mirror-fixture"
|
|
version = "1.0.0"
|
|
source = {{ registry = "https://pypi.org/simple" }}
|
|
wheels = [{{ url = "https://unreachable.invalid/{wheel.name}", hash = "sha256:{digest}", size = {wheel.stat().st_size} }}]
|
|
"""
|
|
(project / "uv.lock").write_text(lock)
|
|
index = (tmp_path / "simple").as_uri()
|
|
first = run_bootstrap(project, mirror_index=index)
|
|
assert first.returncode == 0, first.stdout + first.stderr
|
|
assert (project / ".venv/Lib/site-packages/mirror_fixture.py").exists()
|
|
assert (project / "uv.lock").read_text() == lock
|
|
second = run_bootstrap(project, mirror_index=index)
|
|
assert second.returncode == 0, second.stdout + second.stderr
|
|
assert "dependencies are already ready" in second.stdout
|
|
assert (project / "uv.lock").read_text() == lock
|