diff --git a/tradein-mvp/backend/tests/test_scraper_kit_scheduler_parity.py b/tradein-mvp/backend/tests/test_scraper_kit_scheduler_parity.py index 1480dfcc..b657bf60 100644 --- a/tradein-mvp/backend/tests/test_scraper_kit_scheduler_parity.py +++ b/tradein-mvp/backend/tests/test_scraper_kit_scheduler_parity.py @@ -550,17 +550,20 @@ async def test_job_avito_city_sweep_without_city_param_falls_back_to_none() -> N assert kwargs["anchors"] is None -async def test_job_avito_city_sweep_unknown_city_falls_back_to_none() -> None: - """Неизвестный city slug (typo/будущий город без CITY_ANCHORS-записи) → anchors=None, +async def test_job_avito_city_sweep_unknown_city_raises_instead_of_sweeping() -> None: + """Неизвестный city slug (опечатка в расписании) обязан упасть, а не собрать ЕКБ. - НЕ падает с KeyError. + Раньше `get_city_anchors` отдавал None, и свип уходил на EKB_ANCHORS: опечатка в + `default_params.city` тихо давала прогон по Екатеринбургу, проштампованный чужим + городом. Теперь реестр падает с ValueError; прогон крашится, а тик планировщика + это ловит (`logger.exception` в `_run`, scheduler.py) — цикл не умирает, но и + мусора в корпус не попадает. """ with patch.object(kit_sched, "run_avito_city_sweep", AsyncMock()) as mock_run: - await _job_avito_city_sweep(MagicMock(), 1, {"city": "nonexistent_town"}, _oblast_ctx()) + with pytest.raises(ValueError, match="nonexistent_town"): + await _job_avito_city_sweep(MagicMock(), 1, {"city": "nonexistent_town"}, _oblast_ctx()) - mock_run.assert_awaited_once() - _args, kwargs = mock_run.call_args - assert kwargs["anchors"] is None + mock_run.assert_not_awaited() # ── #2616: _job_avito_full_load(_exhaustive) прокидывает ctx.proxy_provider ────── diff --git a/tradein-mvp/packages/scraper-kit/src/scraper_kit/orchestration/scheduler.py b/tradein-mvp/packages/scraper-kit/src/scraper_kit/orchestration/scheduler.py index 4e6e1a14..2611fa02 100644 --- a/tradein-mvp/packages/scraper-kit/src/scraper_kit/orchestration/scheduler.py +++ b/tradein-mvp/packages/scraper-kit/src/scraper_kit/orchestration/scheduler.py @@ -1058,8 +1058,10 @@ async def _job_avito_city_sweep( db: Session, run_id: int, params: dict[str, Any], ctx: SchedulerContext ) -> None: # #B1 oblast rollout: default_params["city"] (slug, e.g. "nizhniy_tagil") → anchors - # города вместо EKB_ANCHORS. Отсутствует/неизвестен → get_city_anchors вернёт None → - # run_avito_city_sweep сам падает на EKB_ANCHORS (прежнее поведение без city). + # города вместо EKB_ANCHORS. Ключа нет вовсе → anchors=None → citywide-свип ЕКБ + # (прежнее поведение расписаний без city). Ключ ЕСТЬ, но слаг неизвестен → + # get_city_anchors падает с ValueError: опечатка в расписании раньше тихо давала + # прогон по Екатеринбургу под именем чужого города. city = params.get("city") anchors = get_city_anchors(city) if city else None await run_avito_city_sweep(