test(tradein/scheduler): нетавтологичный kit registry-completeness guard (#2397 Part C)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 14s
CI / changes (pull_request) Successful in 14s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m57s
All checks were successful
CI Trade-In / changes (pull_request) Successful in 14s
CI / changes (pull_request) Successful in 14s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m57s
Deep-review нашёл: удалённый test_kit_registry_completeness.py заменялся
test_routing_coverage_sets_match, но тот строил registry ИЗ хардкоженного
_PRODUCT_SOURCES через recording-stub и проверял тот же набор — тавтология,
не гоняющая реальный build_product_handlers(). Плюс _PRODUCT_SOURCES был
устаревшим: не хватало cian_history_backfill, deals_freshness_monitor,
osm_poi_ekb_refresh (все три есть в реальном build_product_handlers).
Фикс:
- _PRODUCT_SOURCES дополнен тремя пропущенными source'ами, сверен построчным
grep '"...": Handler(' по product_handlers.py (20 exact + 1 wildcard).
Список остаётся canonical hardcode (источник правды — сам product_handlers.py
+ scrape_schedules seed-миграции), с явным комментарием "поддерживается вручную".
- test_routing_coverage_sets_match удалён, заменён
test_real_build_product_handlers_covers_all_scheduled_sources: зовёт РЕАЛЬНЫЙ
product_handlers.build_product_handlers(ctx=None) + build_registry (не stub),
ассертит resolve_handler для каждого source из _PRODUCT_SOURCES ∪
_KIT_NATIVE_SOURCES. Уроненная handler-entry или scheduled source без
handler'а теперь роняет CI.
Регресс-пруф (сделан вручную, откачен): временно закомментировал
"osm_poi_ekb_refresh" в build_product_handlers → новый тест упал с
"misses source=osm_poi_ekb_refresh"; вернул строку → тест снова зелёный
(git diff на product_handlers.py пуст после отката).
Verify: full pytest 3179 passed / 6 skipped / 1 known-unrelated fail
(test_search_cache_hit, #2208); ruff 0.7.4 чист на изменённых файлах.
This commit is contained in:
parent
85059aeb1b
commit
c30581ae8d
1 changed files with 36 additions and 11 deletions
|
|
@ -5,9 +5,9 @@ Kit — единственный scheduler-путь (#2397 Part C убрал leg
|
||||||
reap_zombies machinery; сравнивать «golden-parity» больше не с чем). Этот файл проверяет
|
reap_zombies machinery; сравнивать «golden-parity» больше не с чем). Этот файл проверяет
|
||||||
форму и инварианты kit-реестра самого по себе:
|
форму и инварианты kit-реестра самого по себе:
|
||||||
|
|
||||||
1. REGISTRY: kit-native sweep-handler'ы зарегистрированы (`build_registry`), продуктовые
|
1. REGISTRY: реальный `build_product_handlers()` (НЕ stub) + `build_registry` покрывает
|
||||||
source'ы резолвятся через `resolve_handler` (включая deactivate_stale_* wildcard),
|
каждый canonical scheduled source (kit-native + продуктовые + deactivate_stale_*
|
||||||
неизвестный source → None.
|
wildcard-члены); неизвестный source → None.
|
||||||
2. CLAIM: `_claim_run` — happy-path, already-running skip, lock-busy skip, appeared-under-
|
2. CLAIM: `_claim_run` — happy-path, already-running skip, lock-busy skip, appeared-under-
|
||||||
lock rollback. Мокаем БД + ctx.runs.
|
lock rollback. Мокаем БД + ctx.runs.
|
||||||
3. ZOMBIE: `reap_zombies` возвращает число + commit.
|
3. ZOMBIE: `reap_zombies` возвращает число + commit.
|
||||||
|
|
@ -39,10 +39,17 @@ from scraper_kit.orchestration.scheduler import (
|
||||||
resolve_handler,
|
resolve_handler,
|
||||||
)
|
)
|
||||||
|
|
||||||
# ── продуктовые source'ы (НЕ kit-native), которые build_product_handlers регистрирует ──
|
# ── продуктовые source'ы (НЕ kit-native) — CANONICAL, поддерживается ВРУЧНУЮ ─────────
|
||||||
# (было ключами таблицы source → старый trigger_*; сам старый dispatch удалён #2397 Part C,
|
# Источник истины: app.services.product_handlers.build_product_handlers() keys (минус
|
||||||
# но список source-имён остаётся полезным для recording-registry ниже).
|
# wildcard "deactivate_stale_*", раскрытый в 3 конкретных member-source'а) + семейство
|
||||||
|
# scrape_schedules-сидов (data/sql/*scrape_schedules*seed*.sql, 158_seed_proxy_healthcheck_
|
||||||
|
# schedule.sql, 162_seed_deals_freshness_monitor.sql). Этот список НЕ выводится из кода —
|
||||||
|
# добавил/убрал источник в product_handlers.py? Обнови и здесь, иначе
|
||||||
|
# test_real_build_product_handlers_covers_all_scheduled_sources ничего не поймает.
|
||||||
|
# (2026-07-04 deep-review #2397 Part C: список был устаревшим — не хватало
|
||||||
|
# cian_history_backfill/deals_freshness_monitor/osm_poi_ekb_refresh; исправлено.)
|
||||||
_PRODUCT_SOURCES: set[str] = {
|
_PRODUCT_SOURCES: set[str] = {
|
||||||
|
"cian_history_backfill",
|
||||||
"rosreestr_dkp_import",
|
"rosreestr_dkp_import",
|
||||||
"listing_source_snapshot",
|
"listing_source_snapshot",
|
||||||
"asking_to_sold_ratio_refresh",
|
"asking_to_sold_ratio_refresh",
|
||||||
|
|
@ -53,6 +60,7 @@ _PRODUCT_SOURCES: set[str] = {
|
||||||
"deactivate_stale_cian",
|
"deactivate_stale_cian",
|
||||||
"sber_index_pull",
|
"sber_index_pull",
|
||||||
"rosreestr_quarter_poll",
|
"rosreestr_quarter_poll",
|
||||||
|
"deals_freshness_monitor",
|
||||||
"newbuilding_enrich",
|
"newbuilding_enrich",
|
||||||
"yandex_newbuilding_sweep",
|
"yandex_newbuilding_sweep",
|
||||||
"geoportal_coords_backfill",
|
"geoportal_coords_backfill",
|
||||||
|
|
@ -60,6 +68,7 @@ _PRODUCT_SOURCES: set[str] = {
|
||||||
"avito_detail_backfill",
|
"avito_detail_backfill",
|
||||||
"yandex_detail_backfill",
|
"yandex_detail_backfill",
|
||||||
"cadastral_geo_match",
|
"cadastral_geo_match",
|
||||||
|
"osm_poi_ekb_refresh",
|
||||||
"house_imv_backfill",
|
"house_imv_backfill",
|
||||||
"house_dedup_merge",
|
"house_dedup_merge",
|
||||||
"proxy_healthcheck",
|
"proxy_healthcheck",
|
||||||
|
|
@ -123,11 +132,27 @@ def _build_recording_registry() -> tuple[dict[str, Handler], dict[str, MagicMock
|
||||||
# ── 1. REGISTRY shape ────────────────────────────────────────────────────────
|
# ── 1. REGISTRY shape ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
def test_routing_coverage_sets_match() -> None:
|
def test_real_build_product_handlers_covers_all_scheduled_sources() -> None:
|
||||||
"""Множество source'ов kit-реестра ⊇ множество продуктовых source'ов."""
|
"""Реальный (не stub!) build_product_handlers покрывает КАЖДЫЙ canonical source.
|
||||||
registry, _ = _build_recording_registry()
|
|
||||||
for source in _PRODUCT_SOURCES:
|
2026-07-04 deep-review #2397 Part C: старая версия этого теста строила registry ИЗ
|
||||||
assert resolve_handler(source, registry) is not None, f"kit misses source={source}"
|
`_PRODUCT_SOURCES` через recording-stub (`_build_recording_registry`) и проверяла, что
|
||||||
|
тот же набор резолвится — тавтология, ничего не гоняющая через реальный код. Эта версия
|
||||||
|
зовёт настоящий `product_handlers.build_product_handlers(ctx)` — если кто-то уронит
|
||||||
|
handler-entry в product_handlers.py (или source добавили в scrape_schedules seed, но
|
||||||
|
забыли завести handler), тест падает.
|
||||||
|
|
||||||
|
ctx=None безопасен: build_product_handlers его не замыкает при сборке dict (сами job'ы
|
||||||
|
получают ctx только во время dispatch) — см. её докстринг + test_deals_freshness_monitor.
|
||||||
|
"""
|
||||||
|
from app.services.product_handlers import build_product_handlers
|
||||||
|
|
||||||
|
real_registry = build_registry(build_product_handlers(ctx=None)) # type: ignore[arg-type]
|
||||||
|
|
||||||
|
for source in _PRODUCT_SOURCES | _KIT_NATIVE_SOURCES:
|
||||||
|
assert (
|
||||||
|
resolve_handler(source, real_registry) is not None
|
||||||
|
), f"real build_product_handlers()/build_registry() misses source={source}"
|
||||||
|
|
||||||
|
|
||||||
def test_kit_native_handler_set() -> None:
|
def test_kit_native_handler_set() -> None:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue