# ============================================ # Projet : API-KA # Fichier : tests/test_retry.py # Node : m3u96b # Author : Simon-Pierre Boucher # Contact : contact@spboucher.ai # Date : 2026-08-16 # ============================================ """Tests de la logique de retry avec backoff (src/utils/retry.py).""" from __future__ import annotations import pytest from src.utils.retry import retry, retry_call def test_retry_call_succeeds_first_try() -> None: """Aucune relance si le premier essai réussit.""" calls = {"count": 0} def ok() -> str: calls["count"] += 1 return "ok" assert retry_call(ok, attempts=3, delays=(0, 0, 0)) == "ok" assert calls["count"] == 1 def test_retry_call_recovers_after_failures() -> None: """Les échecs transitoires sont relancés jusqu'au succès.""" calls = {"count": 0} retries: list[int] = [] def flaky() -> str: calls["count"] += 1 if calls["count"] < 3: raise RuntimeError("transitoire") return "ok" result = retry_call( flaky, attempts=3, delays=(0, 0, 0), on_retry=lambda attempt, exc, delay: retries.append(attempt), ) assert result == "ok" assert calls["count"] == 3 assert retries == [1, 2] def test_retry_call_raises_after_exhaustion() -> None: """Après épuisement des tentatives, la dernière exception est propagée.""" calls = {"count": 0} def always_fails() -> None: calls["count"] += 1 raise ValueError("permanent") with pytest.raises(ValueError, match="permanent"): retry_call(always_fails, attempts=3, delays=(0, 0, 0)) assert calls["count"] == 4 # essai initial + 3 relances def test_retry_decorator() -> None: """Le décorateur applique la même logique que retry_call.""" calls = {"count": 0} @retry(attempts=2, delays=(0, 0)) def flaky(value: int) -> int: calls["count"] += 1 if calls["count"] == 1: raise RuntimeError("transitoire") return value * 2 assert flaky(21) == 42 assert calls["count"] == 2