"""Repo-wide test config for tradein-mvp/backend. Регистрирует кастомные pytest-маркеры (иначе PytestUnknownMarkWarning: `--strict-markers` в pyproject.toml не включён, так что незарегистрированный маркер только предупреждал бы) и сторожит глобальное состояние, которое переживает отдельный тест, — см. `_no_leaked_password_verify_slots`. """ from __future__ import annotations import sys import pytest def pytest_configure(config) -> None: config.addinivalue_line( "markers", "pdf_render: real (non-mocked) WeasyPrint render — needs native " "Pango/cairo/GObject libs, self-skips where unavailable (see " "tests/test_pdf_real_render.py docstring for how to run it for real).", ) @pytest.fixture(autouse=True) def _no_leaked_password_verify_slots(): """Тест не оставляет за собой занятых слотов проверки пароля (#2665, #2714). Счётчики в `app.core.password` — состояние ПРОЦЕССА, а `pytest-asyncio` даёт каждому тесту свой событийный цикл. Слот освобождает колбэк, посланный в цикл через `call_soon_threadsafe`; если цикл к тому моменту закрыт, `_schedule_verify_slot_release` ловит RuntimeError и слот не возвращается никогда. На проде цикл живёт столько же, сколько процесс, и ветка недостижима — а в тестах она копится молча и роняет НЕ ТОТ тест, который её устроил: при пуле в 1 поток пары утечек хватает, чтобы всё дальнейшее получало 429 «на ровном месте». Поэтому проверка тут и общая: считаем слоты после каждого теста. `sys.modules.get`, а не import: тестам, которые password.py не трогают (большинство), незачем тянуть `Settings()` с его требованием DATABASE_URL. """ yield password_mod = sys.modules.get("app.core.password") if password_mod is None: return inflight = password_mod._verify_inflight by_key = dict(password_mod._verify_inflight_by_key) # Сброс ДО assert: иначе одна утечка красит все последующие тесты и виновник # теряется среди пострадавших. password_mod._verify_inflight = 0 password_mod._verify_inflight_by_key.clear() assert inflight == 0 and not by_key, ( f"тест оставил {inflight} занятых слотов проверки пароля (по ключам: {by_key}) — " "утечка слота при пуле в 1 поток это вечный 429 всем на входе" )