From ea6998ac116b1e628acc3c9abd9a3259b62c6bcf Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Fri, 10 Jul 2026 16:27:05 +0200 Subject: [PATCH] fix(mcp): isole le reload de src.app dans test_app_wiring (pollution inter-tests avec AG-Grid, #111) --- tests/mcp/test_app_wiring.py | 43 +++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/tests/mcp/test_app_wiring.py b/tests/mcp/test_app_wiring.py index 66bb2b2..f28b25c 100644 --- a/tests/mcp/test_app_wiring.py +++ b/tests/mcp/test_app_wiring.py @@ -1,4 +1,5 @@ import importlib +import sys def test_mcp_endpoint_guarded_and_csrf_exempt(monkeypatch, tmp_path): @@ -12,15 +13,37 @@ def test_mcp_endpoint_guarded_and_csrf_exempt(monkeypatch, tmp_path): auth_db.reset_conn_for_tests() - import src.app as app_module + # Recharger src.app avec le flag activé ré-exécute la découverte use_pages, + # qui REMPLACE les objets-modules src.pages.* dans sys.modules (Dash les + # ré-exécute via exec_module). Sans restauration, un test ultérieur ayant + # importé une fonction de page (ex. tests/test_grid.py: get_rows_tableau) + # verrait son patch("src.pages.tableau.") cibler un objet-module différent + # de celui d'où provient la fonction importée → pollution inter-tests. On + # snapshot les modules concernés puis on les restaure en fin de test. + snapshot = { + name: mod + for name, mod in sys.modules.items() + if name == "src.app" or name.startswith("src.pages") + } + try: + import src.app as app_module - app_module = importlib.reload(app_module) - client = app_module.app.server.test_client() + app_module = importlib.reload(app_module) + client = app_module.app.server.test_client() - # Pas de jeton : le garde renvoie 401 (et NON une erreur CSRF 400/403), - # ce qui prouve exemption CSRF + garde câblés sur /_mcp. - resp = client.post("/_mcp", json={"jsonrpc": "2.0", "method": "ping", "id": 1}) - assert resp.status_code == 401 - assert resp.headers.get("WWW-Authenticate") == 'Bearer realm="colibre-mcp"' - - auth_db.reset_conn_for_tests() + # Pas de jeton : le garde renvoie 401 (et NON une erreur CSRF 400/403), + # ce qui prouve exemption CSRF + garde câblés sur /_mcp. + resp = client.post("/_mcp", json={"jsonrpc": "2.0", "method": "ping", "id": 1}) + assert resp.status_code == 401 + assert resp.headers.get("WWW-Authenticate") == 'Bearer realm="colibre-mcp"' + finally: + # Restaurer les objets-modules d'origine et purger ceux créés par le + # reload, pour ne pas polluer les tests suivants. + for name in [ + n for n in sys.modules if n == "src.app" or n.startswith("src.pages") + ]: + if name in snapshot: + sys.modules[name] = snapshot[name] + else: + del sys.modules[name] + auth_db.reset_conn_for_tests()