# ============================================ # Projet : API-KA # Fichier : tests/test_backfill.py # Node : m3u96b # Author : Simon-Pierre Boucher # Contact : contact@spboucher.ai # Date : 2026-08-16 # ============================================ """Tests du rattrapage des dates manquées (src/scheduler/backfill.py).""" from __future__ import annotations import datetime import pytest from src.database.db import session_scope from src.database.models import CollectionRun from src.scheduler.backfill import backfill_date, missing_dates def _insert_success_run(service: str, date_key: datetime.date) -> None: now = datetime.datetime.now(tz=datetime.UTC) with session_scope() as session: session.add( CollectionRun( service=service, date_key=date_key, status="success", records_count=1, duration_seconds=0.1, error_message=None, node="m3u96b", started_at=now, finished_at=now, ) ) def _insert_failed_run(service: str, date_key: datetime.date) -> None: now = datetime.datetime.now(tz=datetime.UTC) with session_scope() as session: session.add( CollectionRun( service=service, date_key=date_key, status="failed", records_count=0, duration_seconds=0.1, error_message="boom", node="m3u96b", started_at=now, finished_at=now, ) ) def test_missing_dates_empty_for_brand_new_service() -> None: """Aucune activité connue → aucun backfill (on ne fabrique pas d'historique).""" assert missing_dates("foodka", days=7) == [] def test_missing_dates_detects_gaps_after_first_activity() -> None: """Les jours sans collecte APRÈS la première activité sont manqués.""" today = datetime.date.today() _insert_success_run("immoka", today - datetime.timedelta(days=3)) missing = missing_dates("immoka", days=5) assert missing == [ today - datetime.timedelta(days=2), today - datetime.timedelta(days=1), ] def test_missing_dates_includes_failed_only_dates() -> None: """Une date avec seulement un run failed doit être rattrapée.""" yesterday = datetime.date.today() - datetime.timedelta(days=1) _insert_failed_run("fabrika", yesterday) assert yesterday in missing_dates("fabrika", days=3) def test_missing_dates_excludes_successful_runs() -> None: """Une date couverte par un run success n'est plus considérée manquée.""" yesterday = datetime.date.today() - datetime.timedelta(days=1) _insert_success_run("autoka", yesterday) assert yesterday not in missing_dates("autoka", days=2) def test_missing_dates_rejects_unknown_service() -> None: """Un service inconnu lève une ValueError.""" with pytest.raises(ValueError): missing_dates("inconnu") def test_backfill_date_runs_collectors(monkeypatch: pytest.MonkeyPatch) -> None: """backfill_date relance le collecteur de chaque service demandé.""" called: list[tuple[str, datetime.date]] = [] class FakeCollector: def __init__(self, service: str) -> None: self.service = service def run(self, date_key: datetime.date) -> dict: called.append((self.service, date_key)) return {"service": self.service, "status": "success", "records_count": 0} monkeypatch.setattr( "src.scheduler.backfill.get_collector", lambda service: FakeCollector(service) ) target = datetime.date(2026, 8, 15) results = backfill_date(target, services=["fabrika"]) assert called == [("fabrika", target)] assert results[0]["status"] == "success"