Root-level tests/ is for root-level modules; 19 files testing scripts/, 3 testing pm/ and 5 testing hermes_cli/ move to the mirrored directory (workflow file lists and cross-imports updated; path arithmetic bumped one level). tests/pm gains a conftest with the isolated_machine_home fixture that seven modules had copy-pasted verbatim.
90 lines
4.2 KiB
Python
90 lines
4.2 KiB
Python
"""A restored cache is usable only for the exact proven build inputs."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
from scripts.termux import wheelhouse_cache
|
|
|
|
|
|
def cache_tree(tmp_path: Path) -> tuple[Path, dict[str, str]]:
|
|
payload = tmp_path / "payload"
|
|
wheelhouse = payload / "wheelhouse"
|
|
work = payload / ".work"
|
|
wheelhouse.mkdir(parents=True)
|
|
work.mkdir()
|
|
(wheelhouse / "example-1.0-py3-none-any.whl").write_bytes(b"cache artifact")
|
|
(work / "resolved.txt").write_text("example\t==1.0\t\n", encoding="utf-8")
|
|
(work / "build_set.txt").write_text("example\n", encoding="utf-8")
|
|
identity = {"lock": "lock-a", "python": "python-a", "builder": "image-a"}
|
|
return payload, identity
|
|
|
|
|
|
@pytest.mark.parametrize("bom", [b"", b"\xef\xbb\xbf"])
|
|
def test_cache_rejects_changed_inputs_and_modified_outputs(tmp_path, bom):
|
|
payload, identity = cache_tree(tmp_path)
|
|
wheelhouse_cache.write_manifest(payload, identity)
|
|
index = payload / "index.json"
|
|
index.write_bytes(bom + index.read_bytes())
|
|
assert wheelhouse_cache.is_usable(payload, identity)
|
|
for key in identity:
|
|
assert not wheelhouse_cache.is_usable(payload, {**identity, key: "changed"})
|
|
artifact = next((payload / "wheelhouse").glob("*.whl"))
|
|
artifact.write_bytes(b"corrupt artifact")
|
|
assert not wheelhouse_cache.is_usable(payload, identity)
|
|
|
|
|
|
@pytest.mark.parametrize("damage", ["empty", "missing", "extra", "requirements", "build-set", "traversal", "malformed"])
|
|
def test_cache_rejects_incomplete_or_inconsistent_manifests(tmp_path, damage):
|
|
payload, identity = cache_tree(tmp_path)
|
|
wheelhouse_cache.write_manifest(payload, identity)
|
|
manifest_path = payload / "index.json"
|
|
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
|
if damage == "empty":
|
|
manifest["wheels"] = []
|
|
manifest_path.write_text(json.dumps(manifest), encoding="utf-8")
|
|
elif damage == "missing":
|
|
next((payload / "wheelhouse").glob("*.whl")).unlink()
|
|
elif damage == "extra":
|
|
(payload / "wheelhouse/foreign-9.0-py3-none-any.whl").write_bytes(b"foreign")
|
|
elif damage == "requirements":
|
|
(payload / ".work/resolved.txt").write_text("other\t==9.0\t\n", encoding="utf-8")
|
|
elif damage == "build-set":
|
|
(payload / ".work/build_set.txt").unlink()
|
|
elif damage == "traversal":
|
|
manifest["wheels"][0]["name"] = "../outside.whl"
|
|
manifest_path.write_text(json.dumps(manifest), encoding="utf-8")
|
|
else:
|
|
manifest_path.write_text("{broken", encoding="utf-8")
|
|
assert not wheelhouse_cache.is_usable(payload, identity)
|
|
|
|
|
|
def test_cache_cli_keeps_commit_and_tag_provenance_distinct(tmp_path):
|
|
payload, _ = cache_tree(tmp_path)
|
|
repo = Path(__file__).resolve().parents[2]
|
|
args = [sys.executable, str(repo / 'scripts/termux/wheelhouse_cache.py'), 'write',
|
|
'--payload', str(payload), '--repo', str(repo), '--builder', 'fixture-image',
|
|
'--platform-tag', 'android_24_arm64_v8a', '--python-abi', 'cp314']
|
|
commit = 'a' * 40
|
|
result = subprocess.run([*args, '--commit', commit], cwd=tmp_path,
|
|
capture_output=True, text=True, encoding='utf-8', timeout=30)
|
|
assert result.returncode == 0, result.stdout + result.stderr
|
|
manifest_path = payload / 'index.json'
|
|
manifest = json.loads(manifest_path.read_text(encoding='utf-8'))
|
|
assert manifest['commit'] == commit and 'tag' not in manifest
|
|
assert wheelhouse_cache.is_usable(payload, manifest['inputs'])
|
|
before = manifest_path.read_bytes()
|
|
for flags in (['--commit', 'short'], ['--commit', commit, '--tag', 'v1.2.3']):
|
|
refused = subprocess.run([*args, *flags], cwd=tmp_path, capture_output=True, timeout=30)
|
|
assert refused.returncode != 0
|
|
assert manifest_path.read_bytes() == before
|
|
tagged = subprocess.run([*args, '--tag', 'v1.2.3'], cwd=tmp_path,
|
|
capture_output=True, text=True, encoding='utf-8', timeout=30)
|
|
assert tagged.returncode == 0, tagged.stdout + tagged.stderr
|
|
manifest = json.loads(manifest_path.read_text(encoding='utf-8'))
|
|
assert manifest['tag'] == 'v1.2.3' and 'commit' not in manifest
|