Files
OBLITERATUS/tests/test_jetson_support_tooling.py
Brian 73601bb13d packaging: stop exact-pinning build backends
Exact setuptools/wheel pins block platform-specific backend patches and
make isolated pip installs fail on Android/Termux Python. Keep a setuptools
lower bound only, drop the unused wheel backend pin, keep requirements.txt
aligned with core package deps, and install the Spaces extra in Docker
instead of pulling bitsandbytes by default.

Android/Termux is still not a supported runtime; the new platform note
documents host wheels, ANDROID_API_LEVEL, and --no-build-isolation so
pip does not isolate a second setuptools or compile manylinux-only
extensions.
2026-09-20 06:25:34 -07:00

279 lines
9.5 KiB
Python

"""CPU-testable contracts for the experimental Jetson support path."""
from __future__ import annotations
import importlib.metadata
import json
import sys
from pathlib import Path
from types import SimpleNamespace
import pytest
import yaml
try:
import tomllib
except ModuleNotFoundError: # pragma: no cover - exercised by the Python 3.10 CI lane
import tomli as tomllib
from scripts import jetson_support
from scripts import run_conditional_gate
from scripts import setup_jetson
ROOT = Path(__file__).parents[1]
def test_host_evidence_is_allow_listed(monkeypatch, tmp_path):
tegra = tmp_path / "nv_tegra_release"
tegra.write_text("# R36 (release), REVISION: 4.3\nserial=secret\n")
os_release = tmp_path / "os-release"
os_release.write_text(
'ID=ubuntu\nVERSION_ID="22.04"\nPRETTY_NAME="Ubuntu 22.04"\nSECRET=value\n'
)
monkeypatch.setattr(jetson_support.platform, "machine", lambda: "aarch64")
monkeypatch.setattr(jetson_support.platform, "python_version", lambda: "3.10.12")
monkeypatch.setattr(jetson_support, "_capture", lambda command, **kwargs: "6.2+b17")
facts = jetson_support.collect_host_facts(
tegra_release=tegra,
os_release=os_release,
)
assert facts == {
"architecture": "aarch64",
"python_version": "3.10.12",
"os": {
"id": "ubuntu",
"version_id": "22.04",
"pretty_name": "Ubuntu 22.04",
},
"l4t_release": "# R36 (release), REVISION: 4.3",
"jetpack_package": "6.2+b17",
}
assert "secret" not in json.dumps(facts).lower()
def test_runtime_evidence_reports_cuda_without_device_identity(monkeypatch):
properties = SimpleNamespace(name="Orin", total_memory=64 * 1024**3)
fake_cuda = SimpleNamespace(
is_available=lambda: True,
device_count=lambda: 1,
get_device_properties=lambda _index: properties,
get_device_capability=lambda _index: (8, 7),
)
fake_torch = SimpleNamespace(
__version__="2.8.0a0+nv25.06",
version=SimpleNamespace(cuda="12.6"),
cuda=fake_cuda,
)
monkeypatch.setitem(sys.modules, "torch", fake_torch)
def missing_package(_name):
raise importlib.metadata.PackageNotFoundError
monkeypatch.setattr(jetson_support.importlib.metadata, "version", missing_package)
facts = jetson_support.collect_runtime_facts()
assert facts["cuda_available"] is True
assert facts["device_name"] == "Orin"
assert facts["compute_capability"] == [8, 7]
assert facts["total_memory_gb"] == 64.0
assert set(facts) == {
"torch_imported",
"torch_version",
"torch_cuda_version",
"cuda_available",
"cuda_device_count",
"device_name",
"compute_capability",
"total_memory_gb",
"bitsandbytes_version",
}
def test_report_validation_blocks_non_jetson_or_non_cuda_and_warns_on_bnb():
report = {
"host": {"architecture": "x86_64", "l4t_release": None},
"runtime": {
"torch_imported": True,
"torch_cuda_version": None,
"cuda_available": False,
"bitsandbytes_version": "0.47.0",
},
}
errors, warnings = jetson_support.validate_report(report)
assert len(errors) == 3
assert any("ARM64" in error for error in errors)
assert any("Jetson L4T" in error for error in errors)
assert any("not a CUDA build" in error for error in errors)
assert warnings and "unsupported" in warnings[0]
def test_gate_evidence_and_issue_body_cannot_copy_arbitrary_fields(tmp_path):
evidence = tmp_path / "gate.json"
evidence.write_text(json.dumps({
"gate": "jetson-runtime",
"status": "passed",
"git_sha": "a" * 40,
"counts": {"tests": 1, "token": "nested-secret"},
"token": "must-not-escape",
"hostname": "must-not-escape",
}))
summary = jetson_support._gate_summary(evidence)
body = jetson_support.issue_body({"gate_evidence": summary})
assert summary == {
"gate": "jetson-runtime",
"status": "passed",
"git_sha": "a" * 40,
"counts": {"tests": 1},
}
assert "must-not-escape" not in body
assert "nested-secret" not in body
assert "excludes environment variables" in body
def test_dependency_export_rejects_torch_and_bitsandbytes(tmp_path):
requirements = tmp_path / "requirements.txt"
requirements.write_text("transformers==4.56.0\npytest==8.4.1\n")
setup_jetson._require_exclusions(requirements)
for forbidden in (
"torch==2.8.0",
"torch @ https://example.invalid/torch.whl",
"bitsandbytes[diagnostics]==0.47.0",
):
requirements.write_text(forbidden + "\n")
with pytest.raises(RuntimeError, match="forbidden packages"):
setup_jetson._require_exclusions(requirements)
def test_jetson_bootstrap_preserves_vendor_runtime_and_uses_locked_no_deps(
monkeypatch,
tmp_path,
):
project = tmp_path / "project"
(project / "scripts").mkdir(parents=True)
(project / "scripts" / "jetson_support.py").write_text("# fixture\n")
(project / "uv.lock").write_text("# fixture\n")
venv = tmp_path / "jetson-venv"
commands: list[list[str]] = []
def fake_run(command, *, cwd):
command = list(command)
commands.append(command)
if command[1:4] == ["-m", "venv", "--system-site-packages"]:
(venv / "bin").mkdir(parents=True)
(venv / "pyvenv.cfg").write_text("include-system-site-packages = true\n")
if "--output-file" in command:
output = Path(command[command.index("--output-file") + 1])
output.write_text("transformers==4.56.0\n")
monkeypatch.setattr(setup_jetson, "_run", fake_run)
setup_jetson.prepare(
project=project,
venv=venv,
python="vendor-python",
uv_python="tool-python",
reuse=False,
)
assert commands[0][0] == "vendor-python"
assert "--check" in commands[0]
export = next(command for command in commands if "export" in command)
assert export.count("--no-emit-package") == 2
assert "torch" in export and "bitsandbytes" in export
installs = [command for command in commands if "install" in command]
assert len(installs) == 2
assert all("--no-deps" in command for command in installs)
assert any("check" in command for command in commands)
def test_bootstrap_rejects_unsafe_or_non_vendor_reusable_targets(tmp_path):
project = tmp_path / "project"
project.mkdir()
with pytest.raises(ValueError, match="unsafe"):
setup_jetson._require_safe_target(project, project)
existing = tmp_path / "existing"
existing.mkdir()
(existing / "pyvenv.cfg").write_text("include-system-site-packages = false\n")
with pytest.raises(ValueError, match="does not expose JetPack"):
setup_jetson._require_new_or_reusable_venv(existing, reuse=True)
def test_bitsandbytes_is_opt_in_for_quantization_only():
metadata = tomllib.loads((ROOT / "pyproject.toml").read_text())
base = metadata["project"]["dependencies"]
extras = metadata["project"]["optional-dependencies"]
assert not any(value.startswith("bitsandbytes") for value in base)
assert extras["quantization"] == ["bitsandbytes>=0.46.1"]
def test_requirements_txt_mirrors_core_pyproject_dependencies():
metadata = tomllib.loads((ROOT / "pyproject.toml").read_text())
requirements = [
line.strip()
for line in (ROOT / "requirements.txt").read_text().splitlines()
if line.strip() and not line.startswith("#")
]
assert requirements == metadata["project"]["dependencies"]
assert not any(value.startswith("bitsandbytes") for value in requirements)
assert not any(value.startswith("gradio") for value in requirements)
def test_dockerfile_installs_spaces_extra_not_quantization():
dockerfile = (ROOT / "Dockerfile").read_text()
assert 'pip install --no-cache-dir ".[spaces]"' in dockerfile
assert "bitsandbytes" not in dockerfile
def test_jetson_issue_form_requires_reproducible_sanitized_hardware_evidence():
form = yaml.safe_load(
(ROOT / ".github" / "ISSUE_TEMPLATE" / "jetson-runtime.yml").read_text(),
)
fields = {value.get("id"): value for value in form["body"] if value.get("id")}
assert set(fields) == {
"device",
"jetpack",
"commit",
"reproduction",
"expected",
"actual",
"evidence",
"confirmations",
}
assert all(value.get("validations", {}).get("required") for value in fields.values())
confirmations = fields["confirmations"]["attributes"]["options"]
assert all(option["required"] for option in confirmations)
assert any("secrets" in option["label"] for option in confirmations)
def test_jetson_conditional_prerequisites_are_physical_and_cuda(monkeypatch, tmp_path):
fake_torch = SimpleNamespace(cuda=SimpleNamespace(is_available=lambda: True))
monkeypatch.setitem(sys.modules, "torch", fake_torch)
monkeypatch.setattr(run_conditional_gate.platform, "machine", lambda: "aarch64")
tegra = tmp_path / "nv_tegra_release"
tegra.write_text("# R36\n")
monkeypatch.setattr(run_conditional_gate, "JETSON_RELEASE", tegra)
assert run_conditional_gate.missing_prerequisites("jetson-runtime") == []
monkeypatch.setattr(run_conditional_gate.platform, "machine", lambda: "x86_64")
fake_torch.cuda.is_available = lambda: False
tegra.unlink()
assert run_conditional_gate.missing_prerequisites("jetson-runtime") == [
"a CUDA-capable PyTorch runtime",
"an ARM64 host",
"a Jetson L4T runtime",
]