"""Unit tests for atomic file store and manifest generation covering scenarios OUT-001, OUT-011, OUT-012.""" import hashlib from pathlib import Path import pytest from src.runtime.storage.file_store import ( create_manifest_dict, persist_manifest_atomically, write_file_atomically, ) def test_atomic_file_write_and_verification(tmp_path: Path): dest = tmp_path / "test_doc.md" content = "# Test Document Content" hash_hex, byte_count = write_file_atomically(dest, content) assert dest.exists() assert hash_hex == hashlib.sha256(content.encode("utf-8")).hexdigest() assert byte_count == len(content.encode("utf-8")) assert dest.read_text(encoding="utf-8") == content def test_atomic_file_write_hash_mismatch_raises(tmp_path: Path): dest = tmp_path / "test_doc.md" content = "Hello World" wrong_hash = "0" * 64 with pytest.raises(ValueError, match="Content hash mismatch"): write_file_atomically(dest, content, expected_hash=wrong_hash) def test_persist_manifest_atomically(tmp_path: Path): fp = "f" * 64 manifest = create_manifest_dict( fingerprint=fp, source_url="https://example.com/1", selected_extractor="trafilatura", final_status="completed_text", generate_markdown=True, markdown_path=str(tmp_path / f"{fp}.md"), markdown_hash="m" * 64, config_version="1.0.0", ecp_classification={ "category": "DIRECT_INHERENT", "confidence": 1.0, "rationale": "ok", "evidences": [], }, enrichment={"sentiment": "neutral", "tags": ["a", "b", "c"]}, provider_versions={ "hygiene": { "provider": "groq", "model": "llama-3.1-8b-instant", "role_config_version": "1.0.0", }, "enrichment": { "provider": "deepseek", "model": "deepseek-chat", "role_config_version": "1.0.0", }, }, model_versions={ "runtime_primary": { "provider": "groq", "model": "llama-3.1-8b-instant", "role_config_version": "1.0.0", }, "runtime_fallback": { "provider": "deepseek", "model": "deepseek-chat", "role_config_version": "1.0.0", }, }, prompt_versions={ "article_content_hygiene": {"version": "1.0.0", "hash": "h" * 64}, "article_sentiment_tags": {"version": "1.0.0", "hash": "s" * 64}, }, ) path, m_hash = persist_manifest_atomically(tmp_path, manifest) assert path.exists() assert path.name == f"{fp}.result.json" assert len(m_hash) == 64