Initial curated RAGcore source from c16667f0c9397e2bfc8dd0255b114fba23c8d05e

This commit is contained in:
Public Source Publisher committed 2026-10-01 01:34:21 +02:00
commit 7ca726caf2
659 files changed
+98171

No files matched your search

@@ -0,0 +1,352 @@
"""BackupService orchestration against fake ports: atomicity, verification, retention."""
from __future__ import annotations
import hashlib
import json
from collections.abc import Mapping, Sequence
from datetime import UTC, datetime, timedelta
from pathlib import Path
import pytest
from ragcore.application.backup.models import (
ArtifactChecksum,
BackupManifest,
BackupStatus,
BackupVerificationError,
)
from ragcore.application.backup.service import MANIFEST_FILENAME, BackupService
def _write_and_checksum(path: Path, content: bytes) -> ArtifactChecksum:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(content)
return ArtifactChecksum(
relative_path=path.name, sha256=hashlib.sha256(content).hexdigest(), size_bytes=len(content)
)
class _FakePostgresDumper:
def __init__(self, *, content: bytes = b"pg-dump-bytes", revision: str = "abc123") -> None:
self._content = content
self._revision = revision
self.dump_calls = 0
async def dump(self, *, destination: Path) -> ArtifactChecksum:
self.dump_calls += 1
return _write_and_checksum(destination, self._content)
async def schema_revision(self) -> str:
return self._revision
class _FakeQdrantSnapshotter:
def __init__(
self,
*,
collections: Mapping[str, bytes] | None = None,
aliases: Mapping[str, str] | None = None,
) -> None:
self._collections = collections if collections is not None else {"docs": b"snapshot-bytes"}
self._aliases = aliases if aliases is not None else {"docs-live": "docs"}
async def snapshot_collections(
self, *, collection_names: Sequence[str], destination_dir: Path
) -> tuple[ArtifactChecksum, ...]:
checksums = []
for name in collection_names:
content = self._collections[name]
checksums.append(_write_and_checksum(destination_dir / f"{name}.snapshot", content))
return tuple(checksums)
async def collection_aliases(self) -> Mapping[str, str]:
return self._aliases
class _FakeFileCopier:
def __init__(self, *, files: Mapping[str, bytes] | None = None) -> None:
self._files = files if files is not None else {"a.bin": b"blob-a", "sub/b.bin": b"blob-b"}
async def copy_tree(self, *, source: Path, destination: Path) -> tuple[ArtifactChecksum, ...]:
checksums = []
for relative_path, content in self._files.items():
target = destination / relative_path
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes(content)
checksums.append(
ArtifactChecksum(
relative_path=relative_path,
sha256=hashlib.sha256(content).hexdigest(),
size_bytes=len(content),
)
)
return tuple(checksums)
def _service(
*,
postgres: _FakePostgresDumper | None = None,
qdrant: _FakeQdrantSnapshotter | None = None,
files: _FakeFileCopier | None = None,
clock: object = None,
id_factory: object = None,
) -> BackupService:
kwargs: dict[str, object] = {
"postgres": postgres or _FakePostgresDumper(),
"qdrant": qdrant or _FakeQdrantSnapshotter(),
"files": files or _FakeFileCopier(),
}
if clock is not None:
kwargs["clock"] = clock
if id_factory is not None:
kwargs["id_factory"] = id_factory
return BackupService(**kwargs) # type: ignore[arg-type]
async def test_run_produces_a_complete_manifest_pinning_schema_and_profiles(tmp_path: Path) -> None:
service = _service(id_factory=lambda: "backup-1")
manifest = await service.run(
backup_root=tmp_path,
blob_root=tmp_path / "blobs-src",
parsed_root=tmp_path / "parsed-src",
collection_names=["docs"],
active_profiles={"embedding": "hybrid-v1:v3", "generation": "default:v1"},
)
assert manifest.status is BackupStatus.COMPLETE
assert manifest.backup_id == "backup-1"
assert manifest.schema_revision == "abc123"
assert manifest.active_profiles == {"embedding": "hybrid-v1:v3", "generation": "default:v1"}
assert manifest.postgres_dump is not None
assert manifest.postgres_dump.relative_path == "postgres.dump"
assert len(manifest.qdrant_snapshots) == 1
assert manifest.qdrant_snapshots[0].relative_path == "qdrant/docs.snapshot"
assert manifest.collection_aliases == {"docs-live": "docs"}
assert {c.relative_path for c in manifest.blob_artifacts} == {"blobs/a.bin", "blobs/sub/b.bin"}
assert {c.relative_path for c in manifest.parsed_artifacts} == {
"parsed/a.bin",
"parsed/sub/b.bin",
}
assert manifest.counts == {"qdrant_snapshots": 1, "blob_artifacts": 2, "parsed_artifacts": 2}
async def test_run_filters_out_aliases_for_collections_not_in_this_backup(tmp_path: Path) -> None:
"""collection_aliases() reports every alias in the whole Qdrant cluster;
only the ones for collections this backup actually snapshotted may end
up in the manifest, or restore would later look for a snapshot of
someone else's unrelated collection."""
service = _service(
qdrant=_FakeQdrantSnapshotter(
collections={"docs": b"snapshot-bytes"},
aliases={"docs-live": "docs", "unrelated-live": "unrelated-collection"},
),
id_factory=lambda: "backup-1",
)
manifest = await service.run(
backup_root=tmp_path,
blob_root=tmp_path / "blobs-src",
parsed_root=tmp_path / "parsed-src",
collection_names=["docs"],
active_profiles={},
)
assert manifest.collection_aliases == {"docs-live": "docs"}
async def test_run_writes_every_artifact_relative_to_backup_dir_on_disk(tmp_path: Path) -> None:
service = _service(id_factory=lambda: "backup-1")
manifest = await service.run(
backup_root=tmp_path,
blob_root=tmp_path / "blobs-src",
parsed_root=tmp_path / "parsed-src",
collection_names=["docs"],
active_profiles={},
)
backup_dir = tmp_path / "backup-1"
assert manifest.postgres_dump is not None
for checksum in (
manifest.postgres_dump,
*manifest.qdrant_snapshots,
*manifest.blob_artifacts,
*manifest.parsed_artifacts,
):
assert (backup_dir / checksum.relative_path).is_file()
async def test_manifest_on_disk_is_incomplete_before_run_finishes(tmp_path: Path) -> None:
"""The atomic-completion invariant: an in-flight backup must never look done."""
seen_status: list[str] = []
real_dump = _FakePostgresDumper()
class _ObservingDumper(_FakePostgresDumper):
async def dump(self, *, destination: Path) -> ArtifactChecksum:
manifest_path = destination.parent / MANIFEST_FILENAME
seen_status.append(json.loads(manifest_path.read_text())["status"])
return await real_dump.dump(destination=destination)
async def schema_revision(self) -> str:
return await real_dump.schema_revision()
service = _service(postgres=_ObservingDumper(), id_factory=lambda: "backup-2")
await service.run(
backup_root=tmp_path,
blob_root=tmp_path / "blobs-src",
parsed_root=tmp_path / "parsed-src",
collection_names=["docs"],
active_profiles={},
)
assert seen_status == ["incomplete"]
final_status = json.loads((tmp_path / "backup-2" / MANIFEST_FILENAME).read_text())["status"]
assert final_status == "complete"
async def test_a_partial_backup_is_never_promoted_to_complete(tmp_path: Path) -> None:
class _FailingFileCopier(_FakeFileCopier):
async def copy_tree(
self, *, source: Path, destination: Path
) -> tuple[ArtifactChecksum, ...]:
raise RuntimeError("disk full")
service = _service(files=_FailingFileCopier(), id_factory=lambda: "backup-3")
with pytest.raises(RuntimeError, match="disk full"):
await service.run(
backup_root=tmp_path,
blob_root=tmp_path / "blobs-src",
parsed_root=tmp_path / "parsed-src",
collection_names=["docs"],
active_profiles={},
)
manifest_path = tmp_path / "backup-3" / MANIFEST_FILENAME
assert json.loads(manifest_path.read_text())["status"] == "incomplete"
async def test_run_raises_if_a_checksum_is_corrupted_before_verification(tmp_path: Path) -> None:
"""Simulates on-disk corruption between write and the re-verify step."""
class _CorruptingFileCopier(_FakeFileCopier):
async def copy_tree(
self, *, source: Path, destination: Path
) -> tuple[ArtifactChecksum, ...]:
checksums = await super().copy_tree(source=source, destination=destination)
first = destination / checksums[0].relative_path
first.write_bytes(b"corrupted")
return checksums
service = _service(files=_CorruptingFileCopier(), id_factory=lambda: "backup-4")
with pytest.raises(BackupVerificationError, match="mismatch"):
await service.run(
backup_root=tmp_path,
blob_root=tmp_path / "blobs-src",
parsed_root=tmp_path / "parsed-src",
collection_names=["docs"],
active_profiles={},
)
manifest_path = tmp_path / "backup-4" / MANIFEST_FILENAME
assert json.loads(manifest_path.read_text())["status"] == "incomplete"
async def test_run_raises_if_an_artifact_is_missing_before_verification(tmp_path: Path) -> None:
class _DeletingFileCopier(_FakeFileCopier):
async def copy_tree(
self, *, source: Path, destination: Path
) -> tuple[ArtifactChecksum, ...]:
checksums = await super().copy_tree(source=source, destination=destination)
(destination / checksums[0].relative_path).unlink()
return checksums
service = _service(files=_DeletingFileCopier(), id_factory=lambda: "backup-5")
with pytest.raises(BackupVerificationError, match="missing"):
await service.run(
backup_root=tmp_path,
blob_root=tmp_path / "blobs-src",
parsed_root=tmp_path / "parsed-src",
collection_names=["docs"],
active_profiles={},
)
async def test_manifest_never_contains_settings_style_secret_fields(tmp_path: Path) -> None:
service = _service(id_factory=lambda: "backup-6")
manifest = await service.run(
backup_root=tmp_path,
blob_root=tmp_path / "blobs-src",
parsed_root=tmp_path / "parsed-src",
collection_names=["docs"],
active_profiles={"embedding": "hybrid-v1:v3"},
)
serialized = json.dumps(manifest.to_json_dict())
for forbidden in ("database_url", "api_key", "secret", "password", "token"):
assert forbidden not in serialized.lower()
def _manifest(backup_id: str, status: BackupStatus, created_at: datetime) -> BackupManifest:
return BackupManifest(
backup_id=backup_id,
status=status,
created_at=created_at,
software_version="0.0.0",
schema_revision="rev",
)
def _write_manifest(backup_root: Path, manifest: BackupManifest) -> None:
backup_dir = backup_root / manifest.backup_id
backup_dir.mkdir(parents=True)
(backup_dir / MANIFEST_FILENAME).write_text(json.dumps(manifest.to_json_dict()))
def test_prune_keeps_only_the_newest_complete_backups(tmp_path: Path) -> None:
base = datetime(2026, 1, 1, tzinfo=UTC)
_write_manifest(tmp_path, _manifest("oldest", BackupStatus.COMPLETE, base))
_write_manifest(tmp_path, _manifest("middle", BackupStatus.COMPLETE, base + timedelta(days=1)))
_write_manifest(tmp_path, _manifest("newest", BackupStatus.COMPLETE, base + timedelta(days=2)))
service = _service()
removed = service.prune(backup_root=tmp_path, keep_complete=2)
assert removed == ("oldest",)
assert not (tmp_path / "oldest").exists()
assert (tmp_path / "middle").exists()
assert (tmp_path / "newest").exists()
def test_prune_never_removes_an_incomplete_backup(tmp_path: Path) -> None:
base = datetime(2026, 1, 1, tzinfo=UTC)
_write_manifest(tmp_path, _manifest("stale-incomplete", BackupStatus.INCOMPLETE, base))
_write_manifest(
tmp_path, _manifest("complete-one", BackupStatus.COMPLETE, base + timedelta(days=1))
)
service = _service()
removed = service.prune(backup_root=tmp_path, keep_complete=0)
assert removed == ("complete-one",)
assert (tmp_path / "stale-incomplete").exists()
def test_prune_rejects_negative_retention(tmp_path: Path) -> None:
service = _service()
with pytest.raises(ValueError, match="keep_complete"):
service.prune(backup_root=tmp_path, keep_complete=-1)
def test_prune_on_nonexistent_backup_root_is_a_noop(tmp_path: Path) -> None:
service = _service()
removed = service.prune(backup_root=tmp_path / "does-not-exist", keep_complete=5)
assert removed == ()