test(api): étend la couverture de 16 à 82 tests

Trois domaines n'étaient pas couverts : l'historique et les courbes
d'évolution, les contrôles de sécurité, et le CRUD des référentiels.

- test_historique.py : bornes de dates passées en paramètres, rejet d'un
  format de date invalide, agrégation des séries par monitoring et par
  service à partir de lignes à plat.
- test_securite.py : protection 401 vérifiée route par route, RBAC 403 pour
  Superviseur et Consultant sur chaque écriture, rejet d'un jeton signé avec
  une autre clé, en-têtes de sécurité, rate-limit 429 à la 6e tentative,
  refus d'un compte désactivé, absence du hachage dans la réponse de login,
  anonymisation RGPD sans suppression de ligne.
- test_referentiels.py : CRUD catégories et contacts, refus 409 sur
  rattachement, 404 sur enregistrement inexistant, modification partielle
  limitée aux champs fournis, réactivation d'un monitoring, plafonnement de
  limit, terme de recherche transmis en paramètre et non concaténé.

Corrige au passage un défaut d'isolation révélé par la suite complète : le
limiteur de débit est un état global, les tests de connexion se
comptabilisaient entre eux et un test échouait selon l'ordre d'exécution
tout en passant fichier par fichier. La fixture limiteur_vierge le remet à
zéro, et un test dédié vérifie désormais explicitement le seuil.

Suite vérifiée stable sur 3 exécutions consécutives et fichier par fichier.
This commit is contained in:
2026-08-15 15:01:42 +02:00
parent 8bf83d0a7f
commit 138bc3c87c
5 changed files with 442 additions and 3 deletions
+16
View File
@@ -9,6 +9,7 @@ from fastapi.testclient import TestClient
import main
from auth import create_access_token
from rate_limit import limiter
from routers import (
admin,
authentification,
@@ -62,6 +63,21 @@ def cur(monkeypatch):
return c
@pytest.fixture(autouse=True)
def limiteur_vierge():
"""
Remet le compteur anti brute-force à zéro entre les tests.
Le limiteur est un état global partagé par toute l'application : sans
remise à zéro, les tests de connexion se comptabilisent entre eux et
finissent par recevoir un 429, avec des échecs qui dépendent de l'ordre
d'exécution et ne se reproduisent pas fichier par fichier.
"""
limiter.reset()
yield
limiter.reset()
@pytest.fixture
def client():
return TestClient(main.app)