"""The failure-artifact collector (US07-04). CI must be able to explain a randomized failure after the temporary library is gone, which means the seed, the database, the journals, the logs, and a complete filesystem manifest have to leave the temporary directory before pytest cleans it. """ from __future__ import annotations import hashlib import json from tests._artifacts import collect, manifest def _library(root): (root / "data").mkdir(parents=True) (root / "data" / "photo_pipeline.db").write_bytes(b"database bytes") (root / "data" / "photo_pipeline.db-wal").write_bytes(b"write ahead log") (root / "data" / "uploads").mkdir() (root / "data" / "uploads" / "batch.log").write_text("INFO uploaded a.jpg\n") (root / "lib").mkdir() (root / "lib" / "a.jpg").write_bytes(b"pixels") return root def test_the_manifest_covers_every_file_with_its_hash(tmp_path): root = _library(tmp_path / "run") entries = {entry["path"]: entry for entry in manifest(root)} assert set(entries) == { "data/photo_pipeline.db", "data/photo_pipeline.db-wal", "data/uploads/batch.log", "lib/a.jpg", } assert entries["lib/a.jpg"]["sha256"] == hashlib.sha256(b"pixels").hexdigest() assert entries["lib/a.jpg"]["bytes"] == 6 def test_collect_keeps_the_database_journals_logs_and_seed(tmp_path, monkeypatch): root = _library(tmp_path / "run") monkeypatch.setenv("PHOTO_PIPELINE_TEST_ARTIFACTS", str(tmp_path / "artifacts")) destination = collect(root, "tests/x.py::test_races[run1]", properties={"race_seed": 1234}) seeds = json.loads((destination / "seeds.json").read_text()) assert seeds["properties"]["race_seed"] == 1234 assert seeds["test"].endswith("test_races[run1]") kept = {str(p.relative_to(destination / "files")) for p in (destination / "files").rglob("*") if p.is_file()} assert kept == { "data/photo_pipeline.db", "data/photo_pipeline.db-wal", "data/uploads/batch.log", }, "databases, write-ahead logs, and logs are the diagnosable evidence" # The photo itself is never copied out of the library — but it is in the # manifest, so a file that went missing is still provable. assert any(entry["path"] == "lib/a.jpg" for entry in json.loads((destination / "manifest.json").read_text())) def test_collecting_twice_for_one_test_is_safe(tmp_path, monkeypatch): root = _library(tmp_path / "run") monkeypatch.setenv("PHOTO_PIPELINE_TEST_ARTIFACTS", str(tmp_path / "artifacts")) first = collect(root, "tests/x.py::test_a") second = collect(root, "tests/x.py::test_a") assert first == second and (second / "manifest.json").exists()