Steph680/ormuz
0
1"""Tests du rattrapage historique presse (GDELT simulé, sans réseau)."""2 3import asyncio4 5import pytest6 7from app import db, gdelt_poller, topics8 9 10def _fake_articles(day_str, n, lang):11 return [{"url": f"https://ex/{lang}/{day_str}/{i}",12 "title": f"Iran seizes tanker number {i} of {day_str}",13 "domain": "ex.com", "seendate": f"{day_str.replace('-', '')}T060000Z",14 "language": lang} for i in range(n)]15 16 17@pytest.fixture(autouse=True)18def _caches_frais(monkeypatch):19 monkeypatch.setattr(gdelt_poller, "_done_spans", set())20 monkeypatch.setattr(gdelt_poller, "_split_spans", set())21 22 23def test_backfill_curseur_et_reprise(tmp_path, monkeypatch):24 monkeypatch.setenv("DB_PATH", str(tmp_path / "t.db"))25 monkeypatch.setattr(gdelt_poller, "BACKFILL_START", "2026-06-18")26 monkeypatch.setattr(gdelt_poller, "BACKFILL_END", "2026-06-21")27 monkeypatch.setattr(gdelt_poller, "BACKFILL_PAUSE_S", 0)28 29 calls = []30 31 async def fake_fetch(client, query, start="", end="", **kw):32 calls.append((start, end))33 return _fake_articles(f"{start[:4]}-{start[4:6]}-{start[6:8]}", 3,34 "English" if "eng" in query else "French")35 36 monkeypatch.setattr(gdelt_poller, "_fetch_with_retries", fake_fetch)37 38 async def scenario():39 await db.init_db()40 assert await gdelt_poller.backfill_once() is True41 # 3 jours × 2 requêtes (EN + FR), sans découpage (< 250 articles).42 assert len(calls) == 643 assert await db.get_setting(gdelt_poller.BACKFILL_SETTING) == "done"44 async with db.connect() as conn:45 cur = await conn.execute("SELECT COUNT(*) FROM news_events")46 assert (await cur.fetchone())[0] == 3 * 3 * 247 # Un second passage ne refait rien.48 calls.clear()49 assert await gdelt_poller.backfill_once() is True50 assert calls == []51 52 asyncio.run(scenario())53 54 55def test_backfill_reprend_au_curseur(tmp_path, monkeypatch):56 monkeypatch.setenv("DB_PATH", str(tmp_path / "t.db"))57 monkeypatch.setattr(gdelt_poller, "BACKFILL_START", "2026-06-18")58 monkeypatch.setattr(gdelt_poller, "BACKFILL_END", "2026-06-21")59 monkeypatch.setattr(gdelt_poller, "BACKFILL_PAUSE_S", 0)60 61 days_seen = []62 63 async def fake_fetch(client, query, start="", end="", **kw):64 days_seen.append(start[:8])65 return []66 67 monkeypatch.setattr(gdelt_poller, "_fetch_with_retries", fake_fetch)68 69 async def scenario():70 await db.init_db()71 # Simule un redémarrage après le 19 juin déjà traité.72 await db.set_setting(gdelt_poller.BACKFILL_SETTING, "2026-06-20")73 assert await gdelt_poller.backfill_once() is True74 assert set(days_seen) == {"20260620"}75 76 asyncio.run(scenario())77 78 79def test_backfill_ne_refait_pas_la_langue_deja_couverte(tmp_path, monkeypatch):80 monkeypatch.setenv("DB_PATH", str(tmp_path / "t.db"))81 monkeypatch.setattr(gdelt_poller, "BACKFILL_START", "2026-06-18")82 monkeypatch.setattr(gdelt_poller, "BACKFILL_END", "2026-06-20")83 monkeypatch.setattr(gdelt_poller, "BACKFILL_PAUSE_S", 0)84 85 seen = []86 87 async def fake_fetch(client, query, start="", end="", **kw):88 seen.append((start[:8], "en" if "eng" in query else "fr"))89 return []90 91 monkeypatch.setattr(gdelt_poller, "_fetch_with_retries", fake_fetch)92 93 async def scenario():94 await db.init_db()95 # Redémarrage en milieu de journée : l'anglais du 18 était déjà fait.96 await db.set_setting(gdelt_poller.BACKFILL_SETTING, "2026-06-18+en")97 assert await gdelt_poller.backfill_once() is True98 assert ("20260618", "en") not in seen99 assert ("20260618", "fr") in seen100 assert ("20260619", "en") in seen and ("20260619", "fr") in seen101 102 asyncio.run(scenario())103 104 105def test_backfill_decoupe_les_journees_saturees(tmp_path, monkeypatch):106 monkeypatch.setenv("DB_PATH", str(tmp_path / "t.db"))107 monkeypatch.setattr(gdelt_poller, "BACKFILL_START", "2026-06-18")108 monkeypatch.setattr(gdelt_poller, "BACKFILL_END", "2026-06-19")109 monkeypatch.setattr(gdelt_poller, "BACKFILL_PAUSE_S", 0)110 111 spans = []112 113 async def fake_fetch(client, query, start="", end="", **kw):114 spans.append((start, end))115 # Journée complète saturée -> l'appelant doit couper en deux.116 if start.endswith("000000") and end.endswith("000000") and start[:8] != end[:8]:117 return _fake_articles("2026-06-18", 250, "English")118 return _fake_articles("2026-06-18", 10, "English")119 120 monkeypatch.setattr(gdelt_poller, "_fetch_with_retries", fake_fetch)121 122 async def scenario():123 await db.init_db()124 await gdelt_poller.backfill_once()125 # Pour chaque langue : 1 appel journée (saturé) + 2 moitiés.126 assert len(spans) == 6127 128 asyncio.run(scenario())129 130 131def test_backfill_ne_regrille_pas_les_creneaux_reussis(tmp_path, monkeypatch):132 """Après un échec en cours de journée, la reprise ne refait pas les133 créneaux déjà stockés (mémoire de session)."""134 monkeypatch.setenv("DB_PATH", str(tmp_path / "t.db"))135 monkeypatch.setattr(gdelt_poller, "BACKFILL_START", "2026-06-18")136 monkeypatch.setattr(gdelt_poller, "BACKFILL_END", "2026-06-19")137 monkeypatch.setattr(gdelt_poller, "BACKFILL_PAUSE_S", 0)138 139 calls = []140 fail_first_fr = {"armed": True}141 142 async def fake_fetch(client, query, start="", end="", **kw):143 lang = "en" if "eng" in query else "fr"144 calls.append((lang, start, end))145 if lang == "fr" and fail_first_fr["armed"]:146 fail_first_fr["armed"] = False147 raise RuntimeError("429 simulé")148 return _fake_articles("2026-06-18", 3, "English" if lang == "en" else "French")149 150 monkeypatch.setattr(gdelt_poller, "_fetch_with_retries", fake_fetch)151 152 async def scenario():153 await db.init_db()154 with pytest.raises(RuntimeError):155 await gdelt_poller.backfill_once() # EN stocké, FR échoue156 en_calls_avant = sum(1 for l, *_ in calls if l == "en")157 assert await gdelt_poller.backfill_once() is True # reprise : FR seul158 assert sum(1 for l, *_ in calls if l == "en") == en_calls_avant159 160 asyncio.run(scenario())161 