gendesign/backend/tests/skip_allowlist.txt
bot-backend 660232ffdc
All checks were successful
CI Trade-In / changes (pull_request) Successful in 13s
CI / changes (pull_request) Successful in 13s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m13s
CI / backend-tests (pull_request) Successful in 17m35s
fix(ptica): свежесть data-table источника считается по успешным строкам (#2956)
Сторож свежести молчал 24 суток, пока источник НСПД лежал.

nspd_quarter_dumps — контент-таблица: harvest пишет строку и когда получилось,
и когда упал (тогда harvest_error заполнен, счётчики нулевые, но fetched_at_utc
всё равно проставлен). Монитор брал MAX(fetched_at_utc) без разбора — и каждый
ПРОВАЛ обновлял часы свежести.

  последний успешный дамп   27.07.2026 01:06:59
  с 03.08                   61 дамп подряд, все с harvest_error
  что видел монитор         возраст ~3 дня при пороге fresh_days=14 → ok

Слепота по построению: мерилось «записали ли мы строку», а не «получили ли мы
данные». Правильный образец лежал в соседней ветке того же if — run-ledger режим
отделяет успех от попытки через FILTER (WHERE status = 'done').

Правка: у FreshnessSource появилось необязательное success_where, в data-table
ветке оно вешается на last_success_at. last_attempt_at остаётся MAX(ts) — это
именно РАЗДЕЛЕНИЕ, а не отбрасывание: признак «загрузчик ходит, но не приносит»
должен остаться виден. Для nspd success_where = "harvest_error IS NULL".

Больше нигде не включаю: из двух data-table источников колонка ошибки есть
только у nspd_quarter_dumps (проверено по information_schema). gisogd_permits —
чистая контент-таблица, где сама строка и есть данные, там разделять нечего.

Тест герметичный: все шесть таблиц реестра создаются ВРЕМЕННЫМИ в своей же
сессии, поэтому он не зависит от схемы CI-базы. В фикстуре стоит защита — сразу
после создания каждая таблица обязана быть пустой; если затенение не сработало
(опечатка в имени, изменившийся реестр), запросы ушли бы в настоящую таблицу и
тест читал бы боевые данные. По конвенции tests/sql DSN по умолчанию смотрит в
туннель к проду, так что цена такой опечатки реальна.

Против кода origin/main (прогон по живому Postgres):

  возраст 1.0д вместо >20          — провал обновил часы свежести → падает
  попытка не новее успеха          — на main это одно и то же MAX(ts) → падает
  успехом сочтена строка с ошибкой — last_success_at не None → падает
  свежий успех по-прежнему ok      — контроль, зелёный на обеих сторонах

Прогоны: tests/sql rc=0 (4 passed по живой БД); tests/workers + tests/services
3320 passed rc=0.

Четыре nodeid внесены в skip_allowlist.txt — нужен живой Postgres. В CI они
идут (postgres-сервис, #2745), запись нужна для машины без БД и без туннеля.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 13:15:29 +05:00

108 lines
10 KiB
Text
Raw Permalink 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.

# Объявленные пропуски сьюта backend/.
#
# Пропуск, которого здесь нет, роняет прогон (хук в tests/conftest.py). Смысл: не
# запретить пропуски, а запретить НЕЗАМЕТНЫЕ. Проверка, которая тихо перестала
# исполняться, со временем расходится с кодом, и узнают об этом ровно тогда,
# когда на неё понадобилось опереться (#2722, #2729, #2740).
#
# Формат: один nodeid в строке, без «[параметров]»; `#` — комментарий.
# Прежде чем добавить строку, ответь: почему эту проверку нельзя выполнить ЗДЕСЬ
# и где она выполняется вместо этого. Нет ответа — это не пропуск, а дыра.
#
# Список — НАДмножество сред: на CI (ubuntu + libpango + postgres-сервис) часть
# записей не срабатывает, на ноутбуке без них — срабатывает. Запись, чей пропуск
# не случился, безвредна; пропуск без записи — нет.
# ── WeasyPrint: нужны native-либы (Pango/cairo/GObject) ───────────────────────
# В CI ЭТИ ТЕСТЫ ИДУТ: ci.yml ставит libcairo2/libpango-1.0-0/libpangoft2-1.0-0.
# Записи нужны только для macOS-dev, где libgobject-2.0-0 нет.
tests/api/v1/test_parcels_forecast.py::test_export_forecast_pdf_returns_pdf
tests/services/exporters/test_report_pdf.py::TestConfidenceSectionParity::test_dict_shaped_factor_produces_valid_pdf
tests/services/exporters/test_report_pdf.py::TestFullReportExport::test_accepts_as_dict_input
tests/services/exporters/test_report_pdf.py::TestFullReportExport::test_returns_non_trivial_length
tests/services/exporters/test_report_pdf.py::TestFullReportExport::test_returns_pdf_magic_bytes
tests/services/exporters/test_report_pdf.py::TestGracefulPartialReport::test_empty_report_still_valid_pdf
tests/services/exporters/test_report_pdf.py::TestGracefulPartialReport::test_garbage_input_does_not_crash
tests/services/exporters/test_report_pdf.py::TestGracefulPartialReport::test_partial_report_some_sections
tests/services/generative/test_exporters.py::test_pdf_export_produces_pdf_bytes
tests/test_layout_tz_pdf.py
# ── phantom-column gate: нужна КОПИЯ ПРОДОВОЙ схемы ───────────────────────────
# Смысл этих тестов — поймать колонку, которой нет в реальной БД, поэтому пустой
# сервис-контейнер их не заменяет: против пустой схемы они дали бы красноту, не
# относящуюся к делу. Условие: TEST_DATABASE_URL на SSH-туннель к проду
# (`ssh -N gendesign` → localhost:15432), см. tests/integration/conftest.py.
# ЗАПУСКАТЬ ВРУЧНУЮ после правок SQL-запросов в app/services/**.
tests/integration/test_analyze_parcels_sql.py::TestIrdOverlapSql::test_explain_ird_overlap
tests/integration/test_analyze_parcels_sql.py::TestVelocityCompetitorsSql::test_explain_competitors
tests/integration/test_analyze_parcels_sql.py::TestNeighborsSummarySql::test_explain_neighbors_summary
tests/integration/test_phantom_columns.py::TestCadGeoTables::test_parcel_centroid_query
tests/integration/test_phantom_columns.py::TestDomrfKnFlats::test_avg_price_query
tests/integration/test_phantom_columns.py::TestDomrfKnFlats::test_supply_batch_query
tests/integration/test_phantom_columns.py::TestDomrfKnObjects::test_competitors_full_cte_query
tests/integration/test_phantom_columns.py::TestDomrfKnObjects::test_competitors_radius_query
tests/integration/test_phantom_columns.py::TestDomrfKnObjects::test_velocity_competitor_query_columns
tests/integration/test_phantom_columns.py::TestEkburgConstructionPermits::test_permits_rns_columns
tests/integration/test_phantom_columns.py::TestEkburgConstructionPermits::test_permits_rve_columns
tests/integration/test_phantom_columns.py::TestEkburgConstructionPermits::test_recent_permits_query
tests/integration/test_phantom_columns.py::TestMvLayoutVelocity::test_velocity_by_room_bucket
tests/integration/test_phantom_columns.py::TestObjectiveTables::test_objective_corpus_room_month_columns
tests/integration/test_phantom_columns.py::TestObjectiveTables::test_objective_mapping_columns
tests/integration/test_phantom_columns.py::TestObjectiveTables::test_sold_count_query
# ── SQL-логика на живой Postgres ──────────────────────────────────────────────
# В CI ЭТИ ТЕСТЫ ИДУТ с #2745 (postgres-сервис в ci.yml); до него не бежали ни
# разу с момента написания. Схема не нужна — строят себе временные таблицы.
# Локально: docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=... postgres:16
tests/sql/test_ddu_price_indicator.py::test_basis_and_previous_index
tests/sql/test_ddu_price_indicator.py::test_packaged_deal_bucketed_by_per_unit_area
tests/sql/test_ddu_price_indicator.py::test_prev_period_value_skips_filtered_quarter
tests/sql/test_mv_layout_velocity_weighted_avg.py::TestWeightedAvgFormula::test_hand_computed_weighted_average
tests/sql/test_mv_layout_velocity_weighted_avg.py::TestWeightedAvgFormula::test_no_zero_months_weighted_equals_naive
tests/sql/test_mv_layout_velocity_weighted_avg.py::TestWeightedAvgFormula::test_nullif_prevents_division_by_zero
tests/sql/test_mv_layout_velocity_weighted_avg.py::TestWeightedAvgFormula::test_weighted_differs_from_naive_sparse_project
tests/sql/test_mv_layout_velocity_weighted_avg.py::TestWeightedAvgFormula::test_zero_deal_months_skew_naive_avg
tests/sql/test_velocity_alerts.py::test_lookback_anchors_to_latest_data_month
tests/sql/test_velocity_alerts.py::test_sharp_drop_is_flagged
# ── Живая сеть NSPD (nspd.gov.ru) ─────────────────────────────────────────────
# Ходят в внешний сервис: в гейте это флейк и зависимость от чужого аптайма.
# Запуск вручную: uv run pytest tests/scrapers/ -m slow / -m integration -s
tests/scrapers/test_nspd_bulk_client.py::test_list_objects_in_building_real
tests/scrapers/test_nspd_bulk_client.py::test_search_by_quarter_empty
tests/scrapers/test_nspd_bulk_client.py::test_search_by_quarter_real_ekb
tests/scrapers/test_nspd_bulk_client.py::test_wms_feature_info_real
tests/scrapers/test_nspd_grid_walk.py::test_live_nspd_grid_walk_skipped
# ── Образец, которого нет в git ───────────────────────────────────────────────
# ДОЛГ, а не норма. Было 8 записей; 2 из них (test_ekb_krt_registry.py::
# TestMultiSiteCountFromDump) сняты в #2778: дампа `krt_page_raw.html` не
# оказалось НИГДЕ — ни в репозитории, ни на дисках, ни на проде (в БД лежит
# `raw_block` = уже очищенный текст, вход парсера из него не восстановить), —
# зато свойство, которое они проверяли (несколько блоков на странице, уникальные
# site_name), выразимо без дампа и теперь проверяется на многоблочной странице,
# собранной из блоков, уже лежащих в том же тест-файле.
#
# Оставшиеся 6 так не лечатся: они проверяют извлечение таблиц из НАСТОЯЩЕГО PDF
# через pdfplumber, соседний класс TestParsePptTep уже мокает pdfplumber целиком.
# Нужен файл `ppt2018_22823_poyasnit_PPT.pdf` (или рабочий URL на ГИСОГД ЕКБ) —
# запрошен у Anton в #2778, там же список того, что оживёт. Причин не коммитить
# нет: официальный градостроительный документ, без персональных данных.
# После получения — положить в tests/fixtures/, поправить `_REAL_PDF_PATH`,
# убрать эти шесть строк.
tests/services/scrapers/test_ekb_ppt_tep_parser.py::TestParsePptTepRealPdf::test_phasing_has_area
tests/services/scrapers/test_ekb_ppt_tep_parser.py::TestParsePptTepRealPdf::test_phasing_has_rows
tests/services/scrapers/test_ekb_ppt_tep_parser.py::TestParsePptTepRealPdf::test_raw_tables_not_empty
tests/services/scrapers/test_ekb_ppt_tep_parser.py::TestParsePptTepRealPdf::test_tep_has_rows
tests/services/scrapers/test_ekb_ppt_tep_parser.py::TestParsePptTepRealPdf::test_zone_balance_has_itogo
tests/services/scrapers/test_ekb_ppt_tep_parser.py::TestParsePptTepRealPdf::test_zone_balance_has_rows
# ── #2956: свежесть data-table источника считается по успешным строкам ────────
# Нужен живой Postgres: тест создаёт ВРЕМЕННЫЕ копии всех таблиц реестра freshness
# и гоняет по ним настоящий SQL compute_freshness. В CI ЭТИ ТЕСТЫ ИДУТ — postgres-
# сервис поднят (#2745), как и для соседних tests/sql/*. Записи нужны только для
# машины без БД и без туннеля на 15432.
tests/sql/test_2956_freshness_ignores_failed_dumps.py::test_failed_dumps_do_not_refresh_the_clock
tests/sql/test_2956_freshness_ignores_failed_dumps.py::test_successful_dump_still_counts_as_fresh
tests/sql/test_2956_freshness_ignores_failed_dumps.py::test_attempt_is_still_recorded
tests/sql/test_2956_freshness_ignores_failed_dumps.py::test_only_failures_means_no_success_at_all