"""Shared autouse fixture that stops the SF lifecycle service from making real outbound HTTP during webhook / admin-sync tests. Why this exists --------------- ``SuccessFactorsLifecycleService._apply_event`` (the webhook + sync apply path) calls ``_ensure_master_data_loaded()``, which fires ~11 sequential SF OData list requests (``list_active_companies``, ``list_active_locations``, ``list_email_group_labels``, ``list_job_functions`` …). The sync path also calls ``get_employments_for_users`` as best-effort enrichment. Tests that only stub ``get_users`` / ``get_jobs_for_users`` leave those other calls pointed at the fake ``https://fake.sapsf.cn`` base URL, where each hits the client's 30 s httpx timeout. ``_ensure_master_data_loaded`` swallows the failures, so the test still passes — just ~30 s slower. Eight such tests in ``test_successfactors_webhook_coordinator.py`` plus two in the offboarding/admin files burned ~390 s of CI wall-clock in the ``hr-misc`` shard alone. This mirrors the already-established pattern in ``test_successfactors_lifecycle.py`` (pre-seed ``service._companies = {}`` so ``_ensure_master_data_loaded`` early-returns) but applies it as an autouse fixture so every test in the importing module is covered without touching a service instance that's constructed deep inside the route handler. Scope note: this is imported per-file (NOT placed in a ``test_hr/`` directory conftest) because ``test_run_scheduled_full.py`` and ``test_full_sync_forfeited.py`` provide their own ``_FakeLifecycleClient`` with populated ``list_active_companies`` etc. and DEPEND on ``_ensure_master_data_loaded`` actually calling them. A directory-level patch would break those. """ import pytest # Every cache attribute _ensure_master_data_loaded populates. Seeding all # of them to {} reproduces the "loaded but empty" terminal state without # any network I/O, and trips the ``if self._companies is not None`` early # return on any subsequent call. _MASTER_DATA_CACHE_ATTRS = ( "_companies", "_locations", "_departments", "_positions", "_email_group_labels", "_job_functions", "_job_families", "_personal_mobiles", "_personal_emails", "_personal_birthdays", "_personal_genders", ) @pytest.fixture(autouse=True) def sf_no_network_master_data(monkeypatch): """Neutralise the unmocked SF master-data + employments calls.""" from app.domains.hr.service import SuccessFactorsLifecycleService from app.identity.successfactors_client import SuccessFactorsClient async def _seed_empty(self) -> None: # Honour the real early-return semantics: once loaded, no-op. if self._companies is not None: return for attr in _MASTER_DATA_CACHE_ATTRS: setattr(self, attr, {}) async def _no_employments(self, user_ids): # noqa: ANN001 return [] monkeypatch.setattr( SuccessFactorsLifecycleService, "_ensure_master_data_loaded", _seed_empty, ) monkeypatch.setattr( SuccessFactorsClient, "get_employments_for_users", _no_employments, ) yield