generated from coulomb/repo-seed
111 lines
4.0 KiB
Python
111 lines
4.0 KiB
Python
"""Guide-board pilot ingestion tests (ARTIFACT-STORE-WP-0005)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from collections.abc import AsyncIterator
|
|
from pathlib import Path
|
|
from uuid import UUID
|
|
|
|
import pytest
|
|
import pytest_asyncio
|
|
from sqlalchemy import create_engine, insert
|
|
from sqlalchemy.ext.asyncio import create_async_engine
|
|
from typer.testing import CliRunner
|
|
|
|
from artifactstore.cli import app as cli_app
|
|
from artifactstore.dataplane import InProcessDataPlane
|
|
from artifactstore.db.schema import metadata, retention_classes
|
|
from artifactstore.db.seed import RETENTION_CLASS_SEEDS
|
|
from artifactstore.events import RegistryViewWriter
|
|
from artifactstore.manifest import decode as manifest_decode
|
|
from artifactstore.pilots.guide_board import GUIDE_BOARD_SCHEMA_SLUG, ingest_run
|
|
from artifactstore.registry import Registry
|
|
from artifactstore.storage import LocalBackend
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
FIXTURE = REPO_ROOT / "tests" / "fixtures" / "guide-board"
|
|
SCHEMA = REPO_ROOT / "schemas" / "guide-board.run.v1.json"
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def registry(tmp_path: Path) -> AsyncIterator[Registry]:
|
|
db_path = tmp_path / "guide-board.db"
|
|
engine = create_async_engine(f"sqlite+aiosqlite:///{db_path}")
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(metadata.create_all)
|
|
for seed in RETENTION_CLASS_SEEDS:
|
|
await conn.execute(insert(retention_classes).values(**seed))
|
|
backend = LocalBackend(tmp_path / "storage", backend_id="local")
|
|
reg = Registry(engine, InProcessDataPlane(backend), RegistryViewWriter())
|
|
try:
|
|
yield reg
|
|
finally:
|
|
await reg.dispose()
|
|
|
|
|
|
async def _consume(stream: AsyncIterator[bytes]) -> bytes:
|
|
out = bytearray()
|
|
async for chunk in stream:
|
|
out.extend(chunk)
|
|
return bytes(out)
|
|
|
|
|
|
async def test_guide_board_library_ingest_is_idempotent_and_downloadable(
|
|
registry: Registry,
|
|
) -> None:
|
|
schema = json.loads(SCHEMA.read_text(encoding="utf-8"))
|
|
await registry.register_metadata_schema(slug=GUIDE_BOARD_SCHEMA_SLUG, json_schema=schema)
|
|
|
|
first = await ingest_run(FIXTURE, registry=registry)
|
|
second = await ingest_run(FIXTURE, registry=registry)
|
|
|
|
assert first.package_id
|
|
assert first.manifest_digest.startswith("blake3:")
|
|
assert first.manifest_digest == second.manifest_digest
|
|
assert second.reused_existing is True
|
|
|
|
manifest = manifest_decode(
|
|
await registry.get_manifest_bytes(UUID(first.package_id), format="cbor")
|
|
)
|
|
assert manifest.package.producer == "guide-board"
|
|
assert manifest.package.metadata_schema_id is not None
|
|
assert manifest.retention_summary.retention_class == "release-evidence"
|
|
assert len(manifest.files) == 8
|
|
|
|
for file_entry in manifest.files:
|
|
stream = await registry.get_file(UUID(file_entry.id))
|
|
assert await _consume(stream) == (FIXTURE / file_entry.relative_path).read_bytes()
|
|
|
|
state = await registry.get_retention_state(UUID(first.package_id))
|
|
assert state.effective_class == "release-evidence"
|
|
|
|
|
|
def test_guide_board_cli_ingest_outputs_package_and_digest(
|
|
tmp_path: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
db_path = tmp_path / "guide-board-cli.db"
|
|
storage_root = tmp_path / "storage"
|
|
storage_root.mkdir()
|
|
sync_engine = create_engine(f"sqlite:///{db_path}", future=True)
|
|
metadata.create_all(sync_engine)
|
|
with sync_engine.begin() as conn:
|
|
conn.execute(insert(retention_classes), [dict(s) for s in RETENTION_CLASS_SEEDS])
|
|
sync_engine.dispose()
|
|
|
|
monkeypatch.setenv("ARTIFACTSTORE_DATABASE_URL", f"sqlite+aiosqlite:///{db_path}")
|
|
monkeypatch.setenv("ARTIFACTSTORE_STORAGE_LOCAL_ROOT", str(storage_root))
|
|
|
|
result = CliRunner().invoke(
|
|
cli_app,
|
|
["guide-board", "ingest", str(FIXTURE), "--schema", str(SCHEMA)],
|
|
)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
payload = json.loads(result.output)
|
|
assert payload["package_id"]
|
|
assert payload["manifest_digest"].startswith("blake3:")
|
|
assert payload["file_count"] == 8
|
|
assert payload["reused_existing"] is False
|