from __future__ import annotations from pathlib import Path from types import SimpleNamespace import pytest from iaai_sync_service.models import SyncRun from iaai_sync_service.sync_engine import SyncStats from iaai_sync_service.tasks import execute_keepalive_job, execute_sync_job class _ScalarResult: def __init__(self, value): # noqa: ANN001 self._value = value def scalar_one(self): # noqa: ANN201 return self._value class FakeSession: def __init__(self, *, lock_acquired: bool) -> None: self.lock_acquired = lock_acquired self.runs: dict[int, SyncRun] = {} self.closed = False def execute(self, stmt, params=None): # noqa: ANN001, ANN201 sql = str(stmt) if "pg_try_advisory_lock" in sql: return _ScalarResult(self.lock_acquired) if "pg_advisory_unlock" in sql: return _ScalarResult(True) raise AssertionError(f"Unexpected SQL execute call: {sql}") def add(self, obj) -> None: # noqa: ANN001 if isinstance(obj, SyncRun): if obj.id is None: obj.id = len(self.runs) + 1 self.runs[obj.id] = obj def commit(self) -> None: return def rollback(self) -> None: return def get(self, model, run_id): # noqa: ANN001, ANN201 assert model is SyncRun return self.runs.get(run_id) def close(self) -> None: self.closed = True def _settings() -> SimpleNamespace: return SimpleNamespace( iaai_base_url="https://www.iaai.com", sync_runtime_config_file=Path("sync_runtime_config.json"), schema_bootstrap_enabled=True, advisory_lock_key=123, error_summary_max_len=2000, ) def test_execute_sync_job_skips_when_lock_not_available(monkeypatch) -> None: # noqa: ANN001 session = FakeSession(lock_acquired=False) monkeypatch.setattr("iaai_sync_service.tasks.get_settings", _settings) monkeypatch.setattr("iaai_sync_service.tasks.get_session", lambda: session) monkeypatch.setattr("iaai_sync_service.tasks.ensure_schema", lambda _session: None) result = execute_sync_job() assert result == {"status": "skipped_locked"} assert session.closed is True def test_execute_sync_job_success_writes_sync_run(monkeypatch) -> None: # noqa: ANN001 session = FakeSession(lock_acquired=True) monkeypatch.setattr("iaai_sync_service.tasks.get_settings", _settings) monkeypatch.setattr("iaai_sync_service.tasks.get_session", lambda: session) monkeypatch.setattr("iaai_sync_service.tasks.ensure_schema", lambda _session: None) monkeypatch.setattr( "iaai_sync_service.tasks.run_sync_once", lambda **kwargs: (SyncStats(ids_fetched=5, cars_upserted=4, cars_failed=0, images_upserted=12), []), ) result = execute_sync_job() assert result["status"] == "success" assert result["ids_fetched"] == 5 run = session.runs[result["run_id"]] assert run.status == "success" assert run.cars_upserted == 4 def test_execute_sync_job_marks_failed_when_sync_raises(monkeypatch) -> None: # noqa: ANN001 session = FakeSession(lock_acquired=True) monkeypatch.setattr("iaai_sync_service.tasks.get_settings", _settings) monkeypatch.setattr("iaai_sync_service.tasks.get_session", lambda: session) monkeypatch.setattr("iaai_sync_service.tasks.ensure_schema", lambda _session: None) def _raise(**kwargs): # noqa: ANN003, ANN202 raise RuntimeError("boom") monkeypatch.setattr("iaai_sync_service.tasks.run_sync_once", _raise) with pytest.raises(RuntimeError, match="boom"): execute_sync_job() failed = session.runs[1] assert failed.status == "failed" assert failed.error_summary is not None def test_execute_sync_job_skips_schema_bootstrap_when_disabled(monkeypatch) -> None: # noqa: ANN001 session = FakeSession(lock_acquired=False) settings = _settings() settings.schema_bootstrap_enabled = False monkeypatch.setattr("iaai_sync_service.tasks.get_settings", lambda: settings) monkeypatch.setattr("iaai_sync_service.tasks.get_session", lambda: session) def _fail_if_called(_session): # noqa: ANN001, ANN202 raise AssertionError("ensure_schema should not be called") monkeypatch.setattr("iaai_sync_service.tasks.ensure_schema", _fail_if_called) result = execute_sync_job() assert result == {"status": "skipped_locked"} def test_execute_keepalive_job_skips_when_lock_not_available(monkeypatch) -> None: # noqa: ANN001 session = FakeSession(lock_acquired=False) monkeypatch.setattr("iaai_sync_service.tasks.get_settings", _settings) monkeypatch.setattr("iaai_sync_service.tasks.get_session", lambda: session) result = execute_keepalive_job() assert result == {"status": "skipped_locked"} assert session.closed is True def test_execute_keepalive_job_success(monkeypatch) -> None: # noqa: ANN001 session = FakeSession(lock_acquired=True) monkeypatch.setattr("iaai_sync_service.tasks.get_settings", _settings) monkeypatch.setattr("iaai_sync_service.tasks.get_session", lambda: session) class _FakeClient: def __init__(self, settings): # noqa: ANN001 self._settings = settings def keep_session_alive(self): # noqa: ANN201 return { "scope": "https://www.iaai.com/Search?url=abc", "marker_present": True, "result_count": 1234, "elapsed_ms": 456, } monkeypatch.setattr("iaai_sync_service.tasks.IAAIClient", _FakeClient) result = execute_keepalive_job() assert result["status"] == "success" assert result["marker_present"] is True assert result["result_count"] == 1234 assert session.closed is True