Files
RAG/backend/tests/unit/test_job_queue.py
YoVinchen ecdb10c37a
Some checks failed
verify / verify (push) Has been cancelled
Make the governed RAG evidence path executable end to end
Separate local parsing from model indexing, bind review decisions to immutable manifests, persist vectors behind active profiles, and expose retrieval, chat, evaluation, and document workflows through the React workbench.

Constraint: Live Bailian authentication currently fails for all three configured capabilities

Rejected: Direct upload-to-embedding flow | bypasses local review and manifest binding

Confidence: high

Scope-risk: broad

Directive: Keep private-data deployment blocked until authentication, RBAC, and separate database roles land

Tested: make verify; fresh and replay Docker document smoke; worker recovery smoke; frozen synthetic evaluation; migration 0003-0004 roundtrip

Not-tested: Successful live Bailian calls, OCR, real multi-user authorization
2026-07-13 05:58:11 +08:00

259 lines
8.4 KiB
Python

from __future__ import annotations
import uuid
from datetime import UTC, datetime, timedelta
from unittest.mock import MagicMock
import pytest
from app.persistence.job_queue import (
InvalidJobRowError,
JobLease,
LeaseLostError,
PsycopgJobQueue,
)
NOW = datetime(2026, 7, 13, 8, 0, tzinfo=UTC)
JOB_ID = uuid.UUID("10000000-0000-0000-0000-000000000001")
RESOURCE_ID = uuid.UUID("20000000-0000-0000-0000-000000000002")
LEASE_TOKEN = uuid.UUID("30000000-0000-0000-0000-000000000003")
def _claimed_row(*, worker_id: str = "worker-a") -> dict[str, object]:
return {
"id": JOB_ID,
"job_type": "EMBED_DOCUMENT",
"required_capability": "embedding",
"resource_type": "document_version",
"resource_id": RESOURCE_ID,
"idempotency_key": "embed:version-1:profile-1",
"payload": {"document_version_id": str(RESOURCE_ID)},
"stage": "EMBEDDING",
"status": "RUNNING",
"progress": 20,
"priority": 5,
"attempt": 1,
"max_attempts": 3,
"run_after": NOW,
"lease_owner": worker_id,
"lease_token": LEASE_TOKEN,
"lease_until": NOW + timedelta(seconds=60),
"created_at": NOW - timedelta(minutes=1),
"updated_at": NOW,
"finished_at": None,
}
def _state_row(*, status: str = "SUCCEEDED") -> dict[str, object]:
return {
"id": JOB_ID,
"status": status,
"attempt": 1,
"max_attempts": 3,
"finished_at": NOW if status in {"SUCCEEDED", "FAILED"} else None,
}
def _repository_with_rows(
*,
one: dict[str, object] | None = None,
many: list[dict[str, object]] | None = None,
) -> tuple[PsycopgJobQueue, MagicMock, MagicMock, MagicMock]:
cursor = MagicMock()
cursor.fetchone.return_value = one
cursor.fetchall.return_value = many or []
transaction = MagicMock()
connection = MagicMock()
connection.__enter__.return_value = connection
connection.transaction.return_value = transaction
connection.execute.return_value = cursor
factory = MagicMock(return_value=connection)
repository = PsycopgJobQueue(
"postgresql://worker:private@db/rag",
connection_factory=factory,
)
return repository, factory, connection, transaction
def test_claim_runs_in_short_transaction_and_returns_complete_fence() -> None:
repository, factory, connection, transaction = _repository_with_rows(one=_claimed_row())
job = repository.claim(
worker_id="worker-a",
worker_capabilities=("embedding", "document_parse"),
lease_seconds=60,
)
assert job is not None
assert job.id == JOB_ID
assert job.payload == {"document_version_id": str(RESOURCE_ID)}
assert job.lease == JobLease(JOB_ID, "worker-a", LEASE_TOKEN)
factory.assert_called_once_with("postgresql://worker:private@db/rag", 5)
transaction.__enter__.assert_called_once_with()
transaction.__exit__.assert_called_once()
statement, parameters = connection.execute.call_args.args
assert "FOR UPDATE SKIP LOCKED" in statement
assert "%(worker_id)s" in statement
assert ":worker_id" not in statement
assert parameters == {
"worker_id": "worker-a",
"worker_capabilities": ["embedding", "document_parse"],
"lease_seconds": 60,
}
def test_claim_returns_none_without_fabricating_a_lease() -> None:
repository, _, _, _ = _repository_with_rows(one=None)
result = repository.claim(
worker_id="worker-a",
worker_capabilities=("embedding",),
lease_seconds=60,
)
assert result is None
def test_claim_rejects_a_row_not_fenced_to_the_requesting_worker() -> None:
repository, _, _, _ = _repository_with_rows(one=_claimed_row(worker_id="worker-b"))
with pytest.raises(InvalidJobRowError, match="unexpected lease owner"):
repository.claim(
worker_id="worker-a",
worker_capabilities=("embedding",),
lease_seconds=60,
)
def test_heartbeat_requires_owner_and_token_and_fails_closed() -> None:
heartbeat_row = {"id": JOB_ID, "lease_until": NOW + timedelta(seconds=60)}
repository, _, connection, _ = _repository_with_rows(one=heartbeat_row)
lease = JobLease(JOB_ID, "worker-a", LEASE_TOKEN)
heartbeat = repository.heartbeat(lease, lease_seconds=60)
assert heartbeat.job_id == JOB_ID
heartbeat_statement, parameters = connection.execute.call_args.args
assert "job.lease_until >= now()" in heartbeat_statement
assert parameters == {
"job_id": JOB_ID,
"worker_id": "worker-a",
"lease_token": LEASE_TOKEN,
"lease_seconds": 60,
}
lost_repository, _, _, _ = _repository_with_rows(one=None)
with pytest.raises(LeaseLostError, match="no longer owned"):
lost_repository.heartbeat(lease, lease_seconds=60)
def test_complete_and_failure_updates_carry_the_full_fence() -> None:
lease = JobLease(JOB_ID, "worker-a", LEASE_TOKEN)
complete_repository, _, complete_connection, _ = _repository_with_rows(one=_state_row())
completed = complete_repository.complete(lease)
assert completed.status == "SUCCEEDED"
complete_statement, complete_parameters = complete_connection.execute.call_args.args
assert "job.lease_until >= now()" in complete_statement
assert complete_parameters == {
"job_id": JOB_ID,
"worker_id": "worker-a",
"lease_token": LEASE_TOKEN,
}
retry_repository, _, retry_connection, _ = _repository_with_rows(
one=_state_row(status="QUEUED")
)
retried = retry_repository.fail_or_retry(
lease,
error_code="MODEL_TIMEOUT",
error_message="Safe bounded failure",
retry_delay_seconds=30,
)
assert retried.status == "QUEUED"
retry_statement, retry_parameters = retry_connection.execute.call_args.args
assert "job.lease_until >= now()" in retry_statement
assert retry_parameters == {
"job_id": JOB_ID,
"worker_id": "worker-a",
"lease_token": LEASE_TOKEN,
"error_code": "MODEL_TIMEOUT",
"error_message": "Safe bounded failure",
"retry_delay_seconds": 30,
}
def test_terminal_update_with_no_returning_row_is_lease_loss() -> None:
repository, _, _, _ = _repository_with_rows(one=None)
lease = JobLease(JOB_ID, "worker-a", LEASE_TOKEN)
with pytest.raises(LeaseLostError):
repository.complete(lease)
with pytest.raises(LeaseLostError):
repository.fail_or_retry(
lease,
error_code="JOB_HANDLER_FAILED",
error_message="Safe failure",
retry_delay_seconds=30,
)
def test_reaper_uses_advisory_lock_and_bounded_batch() -> None:
repository, _, connection, transaction = _repository_with_rows(
many=[_state_row(status="QUEUED"), _state_row(status="FAILED")]
)
states = repository.reap_expired(lock_key=42, batch_size=25)
assert [state.status for state in states] == ["QUEUED", "FAILED"]
statement, parameters = connection.execute.call_args.args
assert "pg_try_advisory_xact_lock" in statement
assert "FOR UPDATE OF job SKIP LOCKED" in statement
assert parameters == {"lock_key": 42, "batch_size": 25}
transaction.__exit__.assert_called_once()
@pytest.mark.parametrize(
("operation", "expected_message"),
[
("empty_capability", "worker_capabilities"),
("duplicate_capability", "duplicates"),
("bad_error_code", "stable uppercase"),
("bad_batch", "batch_size"),
],
)
def test_repository_rejects_invalid_operational_inputs(
operation: str,
expected_message: str,
) -> None:
repository, _, _, _ = _repository_with_rows(one=None)
lease = JobLease(JOB_ID, "worker-a", LEASE_TOKEN)
with pytest.raises(ValueError, match=expected_message):
if operation == "empty_capability":
repository.claim(
worker_id="worker-a",
worker_capabilities=(),
lease_seconds=60,
)
elif operation == "duplicate_capability":
repository.claim(
worker_id="worker-a",
worker_capabilities=("embedding", "embedding"),
lease_seconds=60,
)
elif operation == "bad_error_code":
repository.fail_or_retry(
lease,
error_code="contains spaces",
error_message="Safe failure",
retry_delay_seconds=30,
)
else:
repository.reap_expired(lock_key=42, batch_size=0)