Files
honey-biscuit-workshop/tests/upm/test_python.py
T
2026-04-28 16:56:53 +08:00

164 lines
5.7 KiB
Python

"""Python UPM system tests — pip, uv, poetry, pipx via bare prebake."""
import os
import pytest
from probes import binary_exists
RUST_LOG = os.environ.get("RUST_LOG", "info")
def _yml(actions_yaml):
return """\
version: "1.0"
environment:
builder: "baremetal"
bootstrap:
user: "vulcan"
security:
drop_after: never
dependencies:
config:
repology_endpoint: none
system:
pacman:
packages:
user:
python:
""" + _indent(actions_yaml, 6)
def _indent(text, spaces):
pad = " " * spaces
return "\n".join(pad + line if line.strip() else line
for line in text.splitlines())
def _query(cmd, timeout=60):
import subprocess
try:
r = subprocess.run(cmd, capture_output=True, text=True,
timeout=timeout, env={**os.environ, "HOME": "/root"})
return {"success": r.returncode == 0, "stdout": r.stdout, "stderr": r.stderr}
except Exception as e:
return {"success": False, "stdout": "", "stderr": str(e)}
def _run_prebake(run_baker, config_path, timeout, operation, expected):
env_vars = {"RUST_LOG": RUST_LOG}
r = run_baker("prebake", config_path, timeout=timeout, env=env_vars)
full_log = "[stdout]\n{}\n[stderr]\n{}".format(r["stdout"], r["stderr"])
return r, full_log
def _check(r, full_log, operation, expected):
if r["success"]:
return
diagnosis = ""
try:
from llm import judge_log
j = judge_log(operation, expected, full_log)
diagnosis = "\n LLM diagnosis: [{}] {}".format(j.verdict, j.reason)
except Exception:
pass
pytest.fail("{} failed ({} chars):\n{}\n{}".format(
operation, len(full_log), full_log, diagnosis))
# ── pip ─────────────────────────────────────────────────────────────
def test_pip_install_package(run_baker, work_dir):
"""Install a package via pip."""
cfg = os.path.join(work_dir, "python.yml")
with open(cfg, "w") as f:
f.write(_yml("""\
- type: pip
packages: [requests]
index: "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
args: ["--break-system-packages"]
"""))
r, log = _run_prebake(run_baker, cfg, timeout=120,
operation="pip install requests", expected="requests module importable")
_check(r, log, "pip install", "pip installs requests successfully")
r2 = _query(["python3", "-c", "import requests"])
assert r2["success"], f"import requests failed: {r2['stderr']}"
# ── pip + venv ──────────────────────────────────────────────────────
def test_pip_venv_install(run_baker, work_dir):
"""Create venv and install inside it."""
cfg = os.path.join(work_dir, "python.yml")
with open(cfg, "w") as f:
f.write(_yml("""\
- type: pip
directory: "/tmp/test-venv"
index: "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
packages: [requests]
"""))
r, log = _run_prebake(run_baker, cfg, timeout=120,
operation="venv + pip install",
expected="requests installed inside venv")
_check(r, log, "pip venv install", "venv created, requests installed")
r2 = _query(["/tmp/test-venv/bin/python3", "-c", "import requests"])
assert r2["success"], f"import from venv failed: {r2['stderr']}"
# ── pip + requirements ──────────────────────────────────────────────
def test_pip_requirements_file(run_baker, work_dir):
"""Install from a requirements.txt file."""
req_path = os.path.join(work_dir, "requirements.txt")
with open(req_path, "w") as f:
f.write("requests\n")
cfg = os.path.join(work_dir, "python.yml")
with open(cfg, "w") as f:
f.write(_yml("""\
- type: pip
directory: "/tmp/test-venv2"
index: "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
manifest: "{}"
""".format(req_path)))
r, log = _run_prebake(run_baker, cfg, timeout=120,
operation="pip install -r requirements.txt",
expected="requests installed from requirements file")
_check(r, log, "pip -r requirements.txt", "pip installs from requirements file")
r2 = _query(["/tmp/test-venv2/bin/python3", "-c", "import requests"])
assert r2["success"], f"import from venv failed: {r2['stderr']}"
# ── multiple actions ────────────────────────────────────────────────
def test_multiple_actions(run_baker, work_dir):
"""Two pip actions in one config."""
cfg = os.path.join(work_dir, "python.yml")
with open(cfg, "w") as f:
f.write(_yml("""\
- type: pip
directory: "/tmp/test-venv-a"
index: "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
packages: [requests]
args: ["--break-system-packages"]
- type: pip
directory: "/tmp/test-venv-b"
index: "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
packages: [pytest]
"""))
r, log = _run_prebake(run_baker, cfg, timeout=180,
operation="two pip actions",
expected="both venvs have their packages")
_check(r, log, "multiple pip actions", "both requests and pytest installed")
r2 = _query(["/tmp/test-venv-a/bin/python3", "-c", "import requests"])
assert r2["success"], f"venv-a missing requests: {r2['stderr']}"
r3 = _query(["/tmp/test-venv-b/bin/python3", "-c", "import pytest"])
assert r3["success"], f"venv-b missing pytest: {r3['stderr']}"