first
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
"""Shared pytest fixtures for asf-worker tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
WORKER_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(WORKER_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(WORKER_ROOT))
|
||||
|
||||
TENANT_ID = UUID("00000000-0000-0000-0000-000000000099")
|
||||
PROJECT_ID = UUID("00000000-0000-0000-0000-000000000088")
|
||||
CORRELATION_ID = "test-correlation-worker"
|
||||
|
||||
|
||||
class FakeJobsCollection:
|
||||
"""In-memory AsyncIOMotorCollection stand-in for claim/persistence tests.
|
||||
|
||||
Mirrors the tiny subset of the Motor API that `_claim_running` and
|
||||
`_mark_job_done` exercise: ``update_one(filter, ops)`` with
|
||||
``matched_count`` on the returned UpdateResult.
|
||||
"""
|
||||
|
||||
@dataclass
|
||||
class UpdateResult:
|
||||
matched_count: int = 0
|
||||
modified_count: int = 0
|
||||
upserted_id: object = None
|
||||
|
||||
def __init__(self, docs: dict[UUID, dict] | None = None) -> None:
|
||||
self._docs: dict[UUID, dict] = {k: dict(v) for k, v in (docs or {}).items()}
|
||||
self.last_update_filter: object = None
|
||||
self.last_update_ops: object = None
|
||||
|
||||
async def update_one(self, filt: dict, ops: dict) -> UpdateResult:
|
||||
self.last_update_filter = filt
|
||||
self.last_update_ops = ops
|
||||
jid = filt.get("_id")
|
||||
existing = self._docs.get(jid) if jid is not None else None
|
||||
if existing is None:
|
||||
return FakeJobsCollection.UpdateResult(matched_count=0)
|
||||
|
||||
# Apply the whole filter object like MongoDB does (simple top-level equality match).
|
||||
for k, v in filt.items():
|
||||
if k == "status" and isinstance(v, dict) and "$in" in v:
|
||||
if existing.get(k) not in v["$in"]:
|
||||
return FakeJobsCollection.UpdateResult(matched_count=0)
|
||||
elif k == "_id":
|
||||
if existing.get(k) != v:
|
||||
return FakeJobsCollection.UpdateResult(matched_count=0)
|
||||
else:
|
||||
if existing.get(k) != v:
|
||||
return FakeJobsCollection.UpdateResult(matched_count=0)
|
||||
|
||||
if "$set" in ops:
|
||||
for k, v in ops["$set"].items():
|
||||
existing[k] = v
|
||||
if "$inc" in ops:
|
||||
for k, v in ops["$inc"].items():
|
||||
existing[k] = (existing.get(k) or 0) + v
|
||||
return FakeJobsCollection.UpdateResult(matched_count=1, modified_count=1)
|
||||
|
||||
|
||||
class FakeDb:
|
||||
def __init__(self, jobs: FakeJobsCollection | None = None) -> None:
|
||||
self._jobs = jobs or FakeJobsCollection()
|
||||
|
||||
def __getitem__(self, col: str):
|
||||
if col == "jobs":
|
||||
return self._jobs
|
||||
raise KeyError(col)
|
||||
|
||||
|
||||
class FakeSettings:
|
||||
mongo_uri = "mongodb://fake"
|
||||
mongo_db = "fake_asf"
|
||||
rabbitmq_uri = "amqp://fake"
|
||||
queues: list[str] = []
|
||||
prefetch_count: int = 1
|
||||
worker_id: str = "test-worker"
|
||||
enable_ai_handlers: bool = False
|
||||
ai_gateway_provider: str = "mock"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_settings():
|
||||
return FakeSettings()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_jobs_collection():
|
||||
return FakeJobsCollection()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_db(fake_jobs_collection):
|
||||
return FakeDb(jobs=fake_jobs_collection)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def worker_deps(fake_settings, fake_db, fake_jobs_collection):
|
||||
from app.handlers import WorkerDependencies
|
||||
return WorkerDependencies(
|
||||
db=fake_db,
|
||||
jobs=fake_jobs_collection,
|
||||
ai_executions=fake_db["jobs"], # fine - not exercised
|
||||
artifacts=fake_db["jobs"],
|
||||
settings=fake_settings,
|
||||
worker_id=fake_settings.worker_id,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_envelope():
|
||||
from asf_events.base import JobRequestEnvelope
|
||||
from asf_domain import JobType
|
||||
return JobRequestEnvelope(
|
||||
job_id=uuid4(),
|
||||
tenant_id=TENANT_ID,
|
||||
project_id=PROJECT_ID,
|
||||
correlation_id=CORRELATION_ID,
|
||||
type=JobType.DEVOPS.value,
|
||||
payload={"hello": "world", "sequence": 7},
|
||||
priority="normal",
|
||||
)
|
||||
Reference in New Issue
Block a user