66 lines
2.3 KiB
Python
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"
|