dp-zp-agent/tools/rag/tests/test_rebuild_index.py

183 lines
5.1 KiB
Python

from __future__ import annotations
import multiprocessing
import subprocess
from pathlib import Path
import pytest
import tools.rag.rebuild_index as rebuild
import tools.sync.wiki_git as wiki_git
def hold_lock(lock_path: str, ready, release) -> None:
with rebuild.acquire_reindex_lock(Path(lock_path)):
ready.set()
release.wait(timeout=10)
def test_only_one_process_can_reindex(tmp_path: Path) -> None:
lock_file = tmp_path / "reindex.lock"
context = multiprocessing.get_context("fork")
ready = context.Event()
release = context.Event()
process = context.Process(
target=hold_lock,
args=(str(lock_file), ready, release),
)
process.start()
try:
assert ready.wait(timeout=5)
with pytest.raises(
rebuild.ReindexInProgressError,
match="už prebieha",
):
with rebuild.acquire_reindex_lock(lock_file):
pass
finally:
release.set()
process.join(timeout=5)
assert process.exitcode == 0
with rebuild.acquire_reindex_lock(lock_file):
pass
def test_rebuild_runs_pipeline_in_correct_order(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
calls: list[str] = []
monkeypatch.setattr(
rebuild,
"git_pull",
lambda root: calls.append("git_pull"),
)
import tools.sync.sync_indexes as sync
monkeypatch.setattr(
sync,
"synchronize_indexes",
lambda wiki, data: calls.append("sqlite_and_neo4j")
or {
"documents_scanned": 1,
"chunks_created": 1,
"counts": {"fts_chunks": 1},
"index_version": {"version": "both"},
},
)
result = rebuild.rebuild_index(
pull_git=True,
wiki_root=tmp_path / "wiki",
data_dir=tmp_path / "data",
lock_file=tmp_path / "lock",
)
assert calls == ["git_pull", "sqlite_and_neo4j"]
assert result["documents_scanned"] == 1
assert result["chunks_created"] == 1
assert result["counts"]["fts_chunks"] == 1
assert result["index_version"] == {"version": "both"}
def test_rebuild_pulls_and_locks_the_requested_snapshot_paths(tmp_path, monkeypatch):
import tools.sync.sync_indexes as sync
wiki = tmp_path / "alternate-wiki"
data = tmp_path / "alternate-data"
seen = []
monkeypatch.setattr(rebuild, "git_pull", lambda root: seen.append(("pull", root)))
def synchronized(root, target):
assert (data / ".reindex.lock").exists()
seen.append(("sync", root, target))
return {"index_version": {"version": "alternate"}}
monkeypatch.setattr(sync, "synchronize_indexes", synchronized)
result = rebuild.rebuild_index(pull_git=True, wiki_root=wiki, data_dir=data)
assert seen == [("pull", wiki), ("sync", wiki, data)]
assert result["index_version"]["version"] == "alternate"
def test_git_pull_uses_explicit_branch_and_fast_forward_only(tmp_path, monkeypatch):
repo = tmp_path / "repo"
(repo / ".git").mkdir(parents=True)
captured = []
def fake_run(args, **kwargs):
captured.append((args, kwargs))
output = {
"remote": "git@git.example:KEMT/zpwiki.git",
"branch": "master",
"status": "",
}.get(args[1], "")
return subprocess.CompletedProcess(args, 0, stdout=output, stderr="")
monkeypatch.setattr(wiki_git.subprocess, "run", fake_run)
monkeypatch.setenv("EXPECTED_GITEA_BRANCH", "master")
rebuild.git_pull(repo)
assert captured[-2][0] == [
"git",
"fetch",
"--no-tags",
"--no-recurse-submodules",
"origin",
"refs/heads/master:refs/remotes/origin/master",
]
assert captured[-1][0] == ["git", "merge", "--ff-only", "refs/remotes/origin/master"]
assert all(
kw["cwd"] == repo and kw["timeout"] == 120 and kw["env"]["GIT_TERMINAL_PROMPT"] == "0"
for _, kw in captured
)
def test_git_pull_rejects_non_repository(tmp_path: Path) -> None:
directory = tmp_path / "not-repo"
directory.mkdir()
with pytest.raises(RuntimeError, match="Nie je to git repozitár"):
rebuild.git_pull(directory)
def test_git_pull_reports_timeout(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
repo = tmp_path / "repo"
(repo / ".git").mkdir(parents=True)
def timeout(*args, **kwargs):
raise subprocess.TimeoutExpired(cmd="git pull", timeout=120)
monkeypatch.setattr(wiki_git.subprocess, "run", timeout)
with pytest.raises(RuntimeError, match="prekročila limit"):
rebuild.git_pull(repo)
def test_git_pull_reports_nonzero_exit(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
repo = tmp_path / "repo"
(repo / ".git").mkdir(parents=True)
monkeypatch.setattr(
wiki_git.subprocess,
"run",
lambda *args, **kwargs: subprocess.CompletedProcess(
args[0],
1,
stdout="",
stderr="chyba",
),
)
with pytest.raises(RuntimeError, match="návratovým kódom 1"):
rebuild.git_pull(repo)