87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
"""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
|