106 lines
4.5 KiB
Python
106 lines
4.5 KiB
Python
"""Smoke-тесты Celery-обвязки точек выхода газосети (#2119 Фаза B2, PR-4).
|
||
|
||
- sync_gas_outlet_points зарегистрирована (module в include-списке celery_app);
|
||
- beat содержит gas-outlet-points-sync-weekly (еженедельно, вторник);
|
||
- таск дважды дёргает лоадер: load_gas_outlet_points → geocode_gas_outlets(apply=True),
|
||
каждый шаг graceful (сбой одного не роняет второй) — mock без сети/БД.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from unittest.mock import patch
|
||
|
||
|
||
def test_task_registered_in_celery_include() -> None:
|
||
"""Модуль connection_capacity_sync в include-списке celery_app."""
|
||
from app.workers.celery_app import celery_app
|
||
|
||
assert "app.workers.tasks.connection_capacity_sync" in celery_app.conf.include
|
||
|
||
|
||
def test_beat_schedule_includes_gas_outlet_sync_weekly_tuesday() -> None:
|
||
"""gas-outlet-points-sync-weekly зарегистрирована еженедельно во вторник."""
|
||
from app.workers import beat_schedule
|
||
|
||
# build_beat_schedule читает DB → мокаем _build_beat_schedule_from_db,
|
||
# чтобы тест не зависел от живого Postgres.
|
||
with patch.object(beat_schedule, "_build_beat_schedule_from_db", return_value={}):
|
||
schedule = beat_schedule.build_beat_schedule()
|
||
|
||
assert (
|
||
"gas-outlet-points-sync-weekly" in schedule
|
||
), f"gas-outlet-points-sync-weekly отсутствует в beat: {sorted(schedule.keys())}"
|
||
entry = schedule["gas-outlet-points-sync-weekly"]
|
||
assert entry["task"] == "tasks.connection_capacity_sync.sync_gas_outlet_points"
|
||
# crontab day_of_week = вторник (2).
|
||
assert 2 in entry["schedule"].day_of_week
|
||
|
||
|
||
def test_sync_gas_outlet_points_load_then_geocode() -> None:
|
||
"""Таск: load_gas_outlet_points → geocode_gas_outlets(apply=True), оба результата в ответе."""
|
||
from app.workers.tasks import connection_capacity_sync as ccs
|
||
|
||
load_result = {"rows": 1037, "inserted": 10, "updated": 1027}
|
||
geo_result = {"candidates": 5, "geocoded": 3, "applied": True}
|
||
with (
|
||
patch(
|
||
"app.services.site_finder.ekgas_outlet_loader.load_gas_outlet_points",
|
||
return_value=load_result,
|
||
),
|
||
patch(
|
||
"app.services.site_finder.ekgas_outlet_loader.geocode_gas_outlets",
|
||
return_value=geo_result,
|
||
) as mock_geo,
|
||
patch.object(ccs, "_log_breadcrumb"),
|
||
):
|
||
out = ccs.sync_gas_outlet_points()
|
||
|
||
assert out["load"] == load_result
|
||
assert out["geocode"] == geo_result
|
||
# геокод вызван С apply=True (реальная запись geom на проде).
|
||
assert mock_geo.call_args.kwargs.get("apply") is True
|
||
|
||
|
||
def test_sync_gas_outlet_points_geocode_failure_graceful() -> None:
|
||
"""Сбой geocode-шага не роняет таск: load-результат сохраняется, geocode → error-словарь."""
|
||
from app.workers.tasks import connection_capacity_sync as ccs
|
||
|
||
load_result = {"rows": 1037, "inserted": 0, "updated": 1037}
|
||
with (
|
||
patch(
|
||
"app.services.site_finder.ekgas_outlet_loader.load_gas_outlet_points",
|
||
return_value=load_result,
|
||
),
|
||
patch(
|
||
"app.services.site_finder.ekgas_outlet_loader.geocode_gas_outlets",
|
||
side_effect=RuntimeError("DaData quota exhausted"),
|
||
),
|
||
patch.object(ccs, "_log_breadcrumb"),
|
||
):
|
||
out = ccs.sync_gas_outlet_points()
|
||
|
||
assert out["load"] == load_result # шаг 1 не откатывается сбоем шага 2
|
||
assert "error" in out["geocode"]
|
||
assert "DaData" in out["geocode"]["error"]
|
||
|
||
|
||
def test_sync_gas_outlet_points_load_failure_still_attempts_geocode() -> None:
|
||
"""Сбой load-шага не мешает попытке geocode (шаги независимы, каждый graceful)."""
|
||
from app.workers.tasks import connection_capacity_sync as ccs
|
||
|
||
geo_result = {"candidates": 0, "geocoded": 0, "applied": True}
|
||
with (
|
||
patch(
|
||
"app.services.site_finder.ekgas_outlet_loader.load_gas_outlet_points",
|
||
side_effect=RuntimeError("ekgas catalog 503"),
|
||
),
|
||
patch(
|
||
"app.services.site_finder.ekgas_outlet_loader.geocode_gas_outlets",
|
||
return_value=geo_result,
|
||
),
|
||
patch.object(ccs, "_log_breadcrumb"),
|
||
):
|
||
out = ccs.sync_gas_outlet_points()
|
||
|
||
assert "error" in out["load"]
|
||
assert out["geocode"] == geo_result
|