All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-frontend (push) Has been skipped
Deploy / deploy-caddy (push) Has been skipped
Deploy / build-backend (push) Successful in 39s
Deploy / build-worker (push) Successful in 40s
Deploy / deploy (push) Successful in 1m12s
Deploy / deploy-status (push) Successful in 1s
Deploy / perimeter-smoke (push) Successful in 1m41s
Co-authored-by: bot-backend <bot-backend@gendsgn.local> Co-committed-by: bot-backend <bot-backend@gendsgn.local>
80 lines
5.4 KiB
Python
80 lines
5.4 KiB
Python
"""Общие фикстуры для api/v1 analyze-тестов.
|
||
|
||
PR-A (#1891) сделал geoportal зон-резолвер (``get_or_fetch_zone_regulation``)
|
||
БЕЗУСЛОВНЫМ в ``analyze_parcel`` — раньше он был gated за наличием dump-зоны
|
||
(``_nspd_zoning is not None``), теперь вызывается для любого ЕКБ-участка с centroid.
|
||
|
||
Analyze-тесты с ПОЗИЦИОННЫМ DB-моком (``_make_db_for_analyze`` + ``call_idx``/
|
||
``responses[...]``) НЕ мокали резолвер (до PR-A он не вызывался). Новый безусловный
|
||
вызов добавляет ``db.execute`` (get_cached) → сдвигает последовательность ответов
|
||
мока → последующие запросы (напр. ``parcel_meta``) получают чужой/пустой ответ и
|
||
становятся ``None``. Локально проходило (резолвер мог не разрезолвить точку), в CI
|
||
падало (``test_parcel_meta_found_in_cad_parcels``).
|
||
|
||
Авто-фикстура по умолчанию глушит резолвер в no-op (``return None``) для ВСЕХ тестов
|
||
в этом каталоге → блок 9e-bis ничего не синтезирует и не трогает БД (поведение
|
||
идентично до-PR-A). Тесты, которые проверяют САМ резолвер
|
||
(``test_analyze_zoning_regulation.py``), переопределяют этот же target своим
|
||
per-test ``patch`` — он применяется ПОВЕРХ авто-фикстуры (вложенный mock-scope), так
|
||
что их ожидаемые значения резолвера сохраняются.
|
||
|
||
Perf-fix (2026-09-12): в конце ``analyze_parcel`` — безусловный best-effort
|
||
``forecast_site_finder_report.delay(...)`` (§22-форсайт enqueue, см. app/api/v1/parcels.py).
|
||
В песочнице тестов Celery-брокер (Redis) недоступен → ``.delay()`` синхронно ждёт
|
||
kombu-реконнект с растущим backoff (~69с) ДО того как try/except его проглотит —
|
||
эта пауза оказалась внутри КАЖДОГО теста, который дергает ``POST /analyze`` и не
|
||
мокал форсайт-таску. Авто-фикстура ниже глушит ``.delay`` в no-op-мок для ВСЕХ
|
||
тестов каталога (как и с резолвером выше) — тесты самого enqueue
|
||
(``test_parcels_forecast.py``, ``test_run_history_and_response_contract.py``)
|
||
переопределяют тот же target своим per-test ``patch`` поверх авто-фикстуры.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from collections.abc import Iterator
|
||
from unittest.mock import MagicMock, patch
|
||
|
||
import pytest
|
||
|
||
|
||
@pytest.fixture(autouse=True)
|
||
def _stub_zone_regulation_resolver() -> Iterator[None]:
|
||
"""No-op geoportal зон-резолвер по умолчанию (без сети, без desync DB-мока).
|
||
|
||
``return None`` → ``analyze`` не синтезирует ``nspd_zoning`` и не делает лишних
|
||
``db.execute``. Тесты резолвера переопределяют ``get_or_fetch_zone_regulation``
|
||
своим ``patch`` per-test.
|
||
"""
|
||
with patch("app.api.v1.parcels.get_or_fetch_zone_regulation", return_value=None):
|
||
yield
|
||
|
||
|
||
@pytest.fixture(autouse=True)
|
||
def _stub_forecast_enqueue() -> Iterator[None]:
|
||
"""No-op форсайт-enqueue по умолчанию (без реального Celery/Redis round-trip).
|
||
|
||
``.delay(...)`` в проде — fire-and-forget (best-effort, обёрнут в try/except в
|
||
``analyze_parcel``), тестам сам форсайт не нужен, а живой брокер в CI/локальной
|
||
песочнице недоступен и держит запрос ~69с на реконнект-backoff.
|
||
"""
|
||
with patch("app.workers.tasks.forecast.forecast_site_finder_report.delay", MagicMock()):
|
||
yield
|
||
|
||
|
||
@pytest.fixture(autouse=True)
|
||
def _fast_inline_fetch_wait(monkeypatch: pytest.MonkeyPatch) -> None:
|
||
"""Схлопнуть inline-ожидание NSPD-фетча (#93 graceful fallback) до миллисекунд.
|
||
|
||
В ``analyze_parcel`` ветка «участка нет в БД» ждёт появления геометрии циклом
|
||
``sleep(_INLINE_FETCH_POLL_INTERVAL_S)`` до ``_INLINE_FETCH_WAIT_S`` (15с прод-
|
||
значение). В тестах фетч замокан и геометрия не появится никогда → каждый такой
|
||
тест честно спал 16с (``test_market_price_invalid_cad_returns_404``,
|
||
``test_recent_permits_invalid_cad_no_regression``).
|
||
|
||
Оставляем цикл РАБОЧИМ (несколько итераций по 10мс), а не выключаем его нулём:
|
||
тесты, проверяющие сам fast-path «строка появилась на N-м опросе», продолжают
|
||
видеть опросы. Тесты с собственным ``patch`` того же имени (напр.
|
||
``test_run_history_and_response_contract.py``) переопределяют это поверх.
|
||
"""
|
||
monkeypatch.setattr("app.api.v1.parcels._INLINE_FETCH_WAIT_S", 0.05)
|
||
monkeypatch.setattr("app.api.v1.parcels._INLINE_FETCH_POLL_INTERVAL_S", 0.01)
|