Files
TextNLPClassifierApp/tests/runtime/integration/test_crash_reconciliation.py
T

66 lines
2.3 KiB
Python

"""Crash recovery and state reconciliation integration tests."""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
from src.runtime.cli.reconcile import reconcile_runtime
from src.runtime.storage.sqlite_store import SQLiteStore
def test_reconcile_resolves_crash_mismatch(tmp_path: Path):
"""Simulates a crash where a Markdown file and manifest were written, but SQLite status remained in 'received' state.
Asserts:
1. Reconcile detects the completed artifact.
2. Reconcile calculates and verifies the SHA-256 hash.
3. Reconcile updates SQLite status to 'completed_text' with matching payload.
"""
db_path = tmp_path / "state.db"
out_dir = tmp_path / "out"
out_dir.mkdir()
base_cfg = json.loads(Path("runtime_config.local.json").read_text(encoding="utf-8"))
base_cfg["paths"]["sqlite_db"] = str(db_path)
base_cfg["paths"]["output_dir"] = str(out_dir)
cfg_file = tmp_path / "cfg.json"
cfg_file.write_text(json.dumps(base_cfg, indent=2), encoding="utf-8")
store = SQLiteStore(db_path)
fp = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
# Step 1: SQLite has received status
store.claim_or_get_execution(fp, "https://example.com/test", "trafilatura", "1.0.0")
# Step 2: Disk has completed markdown and manifest
md_content = "---\ntitle: Reconciled Article\n---\n\nContent here."
md_file = out_dir / f"{fp}.md"
md_file.write_text(md_content, encoding="utf-8")
md_hash = hashlib.sha256(md_content.encode("utf-8")).hexdigest()
manifest_data = {
"manifest_version": "1.0.0",
"fingerprint": fp,
"status": "completed_text",
"artifacts": {
"markdown_path": str(md_file),
"markdown_sha256": md_hash,
"manifest_path": str(out_dir / f"{fp}.result.json"),
},
}
manifest_file = out_dir / f"{fp}.result.json"
manifest_file.write_text(json.dumps(manifest_data, indent=2), encoding="utf-8")
# Step 3: Run reconciliation
report = reconcile_runtime(cfg_file)
assert report["divergent_states_recovered"] == 1
# Step 4: Verify DB updated to completed_text
record = store.get_execution(fp)
assert record is not None
assert record["current_status"] == "completed_text"