import hashlib import json import os from pathlib import Path import pytest from tools.runtime.report_files import report_log, report_output, resolve_report_input from tools.evaluation.report_maintenance import apply_moves, migration_plan, retention_plan def test_migration_preserves_operational_data_and_report_bytes(tmp_path): for name in [ "documents.json", "chunks.json", "index_version.json", ".reindex.lock", "zp_index.sqlite", ]: (tmp_path / name).write_text("operational") (tmp_path / "old.json").write_bytes(b'{"old":true}\n') (tmp_path / "old.pytest.log").write_text("log") plan = migration_plan(tmp_path) assert {Path(m["source"]).name for m in plan} == {"old.json", "old.pytest.log"} journal = apply_moves(plan, data_dir=tmp_path) assert len(json.loads(journal.read_text())["moves"]) == 2 for move in plan: assert hashlib.sha256(Path(move["destination"]).read_bytes()).hexdigest() == move["sha256"] assert resolve_report_input(Path(move["source"]), data_dir=tmp_path) == Path( move["destination"] ) assert (tmp_path / "documents.json").read_text() == "operational" assert not migration_plan(tmp_path) def test_no_overwrites_and_changed_plan_is_rejected_before_any_move(tmp_path): for name in ["a.json", "b.json"]: (tmp_path / name).write_text("{}") plan = migration_plan(tmp_path) (tmp_path / "b.json").write_text('{"changed":1}') with pytest.raises(RuntimeError): apply_moves(plan, data_dir=tmp_path) assert (tmp_path / "a.json").exists() output = report_output(None, "verification", data_dir=tmp_path) output.write_text("{}") with pytest.raises(FileExistsError): report_output(output, "verification", data_dir=tmp_path) for name in ["documents.json", "chunks.json", "index_version.json", "zp_index.sqlite"]: with pytest.raises(ValueError): report_output(tmp_path / name, "verification", data_dir=tmp_path) def test_flat_legacy_output_is_redirected_and_unique_default_has_separate_log(tmp_path): output = report_output(tmp_path / "old.json", "verification", data_dir=tmp_path) assert output == tmp_path / "reports/verification/old.json" assert report_log(output, data_dir=tmp_path) == tmp_path / "logs/verification/old.pytest.log" assert report_output(None, "verification", data_dir=tmp_path) != report_output( None, "verification", data_dir=tmp_path ) assert ( report_log(tmp_path / "custom/result.json", data_dir=tmp_path).parent == tmp_path / "logs/custom" ) def test_retention_archives_only_completed_verifications_and_follows_move_chain(tmp_path): outputs = [] for i in range(8): output = report_output(tmp_path / f"run{i}.json", "verification", data_dir=tmp_path) output.write_text(json.dumps({"passed": bool(i % 2)})) os.utime(output, (100 + i, 100 + i)) report_log(output, data_dir=tmp_path).write_text("log") outputs.append(output) incomplete = tmp_path / "reports/verification/incomplete.json" incomplete.write_text("{}") experiment = report_output(None, "rag_verified", data_dir=tmp_path) experiment.write_text('{"passed":true}') plan = retention_plan(tmp_path, keep=5) assert len(plan) == 6 apply_moves(plan, data_dir=tmp_path) assert incomplete.exists() and experiment.exists() assert len(list((tmp_path / "reports/verification").glob("*.json"))) == 6 archived = resolve_report_input(outputs[0], data_dir=tmp_path) assert archived.exists() and archived.parent == tmp_path / "reports/archive/verification" next_target = tmp_path / "reports/archive/older" / archived.name apply_moves( [ { "source": str(archived), "destination": str(next_target), "sha256": hashlib.sha256(archived.read_bytes()).hexdigest(), } ], data_dir=tmp_path, ) assert resolve_report_input(outputs[0], data_dir=tmp_path) == next_target