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» больше не с чем). Этот файл проверяет
|
||||
форму и инварианты kit-реестра самого по себе:
|
||||
|
||||
1. REGISTRY: kit-native sweep-handler'ы зарегистрированы (`build_registry`), продуктовые
|
||||
source'ы резолвятся через `resolve_handler` (включая deactivate_stale_* wildcard),
|
||||
неизвестный source → None.
|
||||
1. REGISTRY: реальный `build_product_handlers()` (НЕ stub) + `build_registry` покрывает
|
||||
каждый canonical scheduled source (kit-native + продуктовые + deactivate_stale_*
|
||||
wildcard-члены); неизвестный source → None.
|
||||
2. CLAIM: `_claim_run` — happy-path, already-running skip, lock-busy skip, appeared-under-
|
||||
lock rollback. Мокаем БД + ctx.runs.
|
||||
3. ZOMBIE: `reap_zombies` возвращает число + commit.
|
||||
|
|
@ -39,10 +39,17 @@ from scraper_kit.orchestration.scheduler import (
|
|||
resolve_handler,
|
||||
)
|
||||
|
||||
# ── продуктовые source'ы (НЕ kit-native), которые build_product_handlers регистрирует ──
|
||||
# (было ключами таблицы source → старый trigger_*; сам старый dispatch удалён #2397 Part C,
|
||||
# но список source-имён остаётся полезным для recording-registry ниже).
|
||||
# ── продуктовые source'ы (НЕ kit-native) — CANONICAL, поддерживается ВРУЧНУЮ ─────────
|
||||
# Источник истины: app.services.product_handlers.build_product_handlers() keys (минус
|
||||
# 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] = {
|
||||
"cian_history_backfill",
|
||||
"rosreestr_dkp_import",
|
||||
"listing_source_snapshot",
|
||||
"asking_to_sold_ratio_refresh",
|
||||
|
|
@ -53,6 +60,7 @@ _PRODUCT_SOURCES: set[str] = {
|
|||
"deactivate_stale_cian",
|
||||
"sber_index_pull",
|
||||
"rosreestr_quarter_poll",
|
||||
"deals_freshness_monitor",
|
||||
"newbuilding_enrich",
|
||||
"yandex_newbuilding_sweep",
|
||||
"geoportal_coords_backfill",
|
||||
|
|
@ -60,6 +68,7 @@ _PRODUCT_SOURCES: set[str] = {
|
|||
"avito_detail_backfill",
|
||||
"yandex_detail_backfill",
|
||||
"cadastral_geo_match",
|
||||
"osm_poi_ekb_refresh",
|
||||
"house_imv_backfill",
|
||||
"house_dedup_merge",
|
||||
"proxy_healthcheck",
|
||||
|
|
@ -123,11 +132,27 @@ def _build_recording_registry() -> tuple[dict[str, Handler], dict[str, MagicMock
|
|||
# ── 1. REGISTRY shape ────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_routing_coverage_sets_match() -> None:
|
||||
"""Множество source'ов kit-реестра ⊇ множество продуктовых source'ов."""
|
||||
registry, _ = _build_recording_registry()
|
||||
for source in _PRODUCT_SOURCES:
|
||||
assert resolve_handler(source, registry) is not None, f"kit misses source={source}"
|
||||
def test_real_build_product_handlers_covers_all_scheduled_sources() -> None:
|
||||
"""Реальный (не stub!) build_product_handlers покрывает КАЖДЫЙ canonical source.
|
||||
|
||||
2026-07-04 deep-review #2397 Part C: старая версия этого теста строила registry ИЗ
|
||||
`_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:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue