gendesign/backend/tests/api/v1/test_2464_parcels_savepoint_pair.py
bot-backend 38163a1186
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 3m13s
Deploy / build-worker (push) Successful in 3m29s
Deploy / deploy (push) Successful in 1m25s
Deploy / deploy-status (push) Successful in 0s
Deploy / perimeter-smoke (push) Successful in 10s
fix(ptica): два блока analyze_parcel глотали ошибку БД без SAVEPOINT (#2464) (#2949)
2026-08-20 07:19:49 +00:00

78 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""#2464: два места analyze_parcel глотали ошибку БД без SAVEPOINT.
Найдено поиском «правило соблюдено рядом — нарушено здесь»: в самой функции
`analyze_parcel` двенадцать соседних блоков оборачивают свой `db.execute` в
`db.begin_nested()`, и у velocity-блока правило записано словами —
«SAVEPOINT защищает outer transaction если velocity SQL падает — иначе
следующие queries (_geotech_risk и пр.) крашатся с InFailedSqlTransaction»
Два блока из правила выпадали:
* `get_permits_nearby` (вызов на общей сессии, своей защиты не имеет, ошибку
глотает вызывающий) — а после него идут `_geotech_risk`, `_neighbors_summary`
и запись прогона: терялся бы весь анализ, а не блок разрешений;
* `_neighbors_summary` — вызывается перед `persist_analysis_run`.
Двойник сессии (`tests/support/pg_session.py`) воспроизводит семантику Postgres:
обычный MagicMock aborted-состояния не имеет, и проверка «сессия осталась рабочей»
на нём зелена независимо от наличия SAVEPOINT.
ЧТО ЗДЕСЬ НЕ ПОКРЫТО И ПОЧЕМУ
─────────────────────────────
Прямой тест есть только на `_neighbors_summary` — это отдельная функция, её можно
вызвать. Блок `get_permits_nearby` лежит ВНУТРИ обработчика `analyze_parcel`, и
дотянуться до него можно лишь через полный эндпоинт, чей мок-двойник сессии должен
уметь отвечать на десятки разных запросов.
Первая версия этого файла «покрывала» его так: тест сам писал
`with db.begin_nested():` вокруг вызова и проверял, что сессия выжила. Такая
проверка зелена независимо от боевого кода — она проверяет собственную обёртку.
Убрана: лучше честно отсутствующее покрытие, чем поддельное. Правка там та же
самая и по тому же доводу, но подтверждена чтением, а не тестом.
"""
from __future__ import annotations
import pytest
from tests.support.pg_session import AbortedTransactionError, PostgresLikeSession
def test_neighbors_summary_failure_leaves_session_usable() -> None:
"""Сбой запроса соседей не должен помешать сохранить прогон."""
from app.api.v1 import parcels
db = PostgresLikeSession()
wkt = "POLYGON((60.6 56.83, 60.61 56.83, 60.61 56.84, 60.6 56.84, 60.6 56.83))"
out = parcels._neighbors_summary(db, wkt, "66:41:0402029:25")
assert out["data_available"] is False, "деградация должна остаться graceful"
db.execute("SELECT 1") # на origin/main здесь AbortedTransactionError
assert db.calls == 2
def test_double_still_poisons_without_a_savepoint() -> None:
"""Контроль на инструмент: без SAVEPOINT двойник ОБЯЗАН отравляться.
Без этой проверки обе проверки выше были бы зелёными по построению.
"""
db = PostgresLikeSession()
with pytest.raises(RuntimeError):
db.execute("boom")
with pytest.raises(AbortedTransactionError):
db.execute("SELECT 1")
def test_neighbors_summary_healthy_path_unchanged() -> None:
"""Контроль: без сбоя поведение прежнее — данные читаются, не fallback."""
from app.api.v1 import parcels
db = PostgresLikeSession(
fail_on=(),
row={"neighbors": [], "overlap_rows": [], "neighbors_total_count": 0},
)
out = parcels._neighbors_summary(db, "POLYGON EMPTY", "66:41:0402029:25")
assert out.get("data_available") is not False