fix: CI verte — fuite du client HTTP mocké + rate limiter actif dans test_agent
Deux causes indépendantes faisaient échouer le job test de la CI (et seulement en CI : ni .env ni les mêmes ordres de chargement en local) : - test_agent_web_tools.mock_http patche http_client.shared_client pendant sa fenêtre d'exécution. Le premier import d'importers/url_fetch dans cette fenêtre fige la factory moquée dans le namespace du module → tous les appels fetch_url suivants du processus passaient par le handler mocké de l'autre test (« assert '…/post' == '…/page' » dans test_v56_import). url_fetch résout désormais le client à l'appel, et le mock_http restaure la vraie factory (référence figée au chargement du module) y compris sur url_fetch ; - test_agent.py posait RATE_LIMIT_ENABLED=false en env var, sans effet sur le singleton Settings déjà instancié : sous pytest -n auto, le worker dépassait le quota de 60 req/min et 8 tests recevaient des 429 (KeyError 'id' au passage). Le fixture désactive maintenant le limiter sur le singleton, comme les autres fichiers de tests.
This commit is contained in:
@@ -36,6 +36,12 @@ def client():
|
||||
settings.agent_max_iterations = 12
|
||||
settings.agent_max_tokens_budget = 500_000
|
||||
settings.agent_run_timeout_seconds = 30
|
||||
# Le rate limiter est DÉJÀ instancié (singleton importé avant ce fixture) :
|
||||
# `os.environ["RATE_LIMIT_ENABLED"]="false"]` ci-dessus ne le touche pas.
|
||||
# Sans cette mutation, les tests suivants d'un même worker dépassent le
|
||||
# quota (60 req/min) et reçoivent des 429 — visible sous `pytest -n auto`
|
||||
# en CI, invisible en local (.env de dev désactivé le limiter).
|
||||
settings.rate_limit_enabled = False
|
||||
|
||||
init_db()
|
||||
with get_conn() as conn:
|
||||
|
||||
@@ -70,6 +70,13 @@ def registry() -> ToolRegistry:
|
||||
return ToolRegistry()
|
||||
|
||||
|
||||
#: Vraie factory du client partagé, figée AU CHARGEMENT du module (donc avant
|
||||
#: tout patch). La restauration repart de CETTE référence : si un import tardif
|
||||
#: d'un module consommateur a déjà figé une factory moquée, le `finally` la
|
||||
#: répare au lieu de perpétuer la fuite.
|
||||
_REAL_SHARED_CLIENT = http_client.shared_client
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def mock_http(handler):
|
||||
"""Injecte un transport httpx dans le client partagé des services.
|
||||
@@ -95,7 +102,12 @@ def mock_http(handler):
|
||||
finally:
|
||||
for module in targets:
|
||||
if getattr(module, "shared_client", None) is build:
|
||||
module.shared_client = original
|
||||
module.shared_client = _REAL_SHARED_CLIENT
|
||||
# Un consommateur importé PENDANT la fenêtre patchée a figé `build`
|
||||
# dans son propre namespace : on le remet sur la vraie factory.
|
||||
from app.services.importers import url_fetch
|
||||
if getattr(url_fetch, "shared_client", None) is build:
|
||||
url_fetch.shared_client = _REAL_SHARED_CLIENT
|
||||
|
||||
|
||||
def run(coro):
|
||||
|
||||
Reference in New Issue
Block a user