186 lines
6.9 KiB
Python
186 lines
6.9 KiB
Python
"""HUB-21 — réglages généraux du Hub consommés par Kanbante.
|
|
|
|
Propagation du pilote TikTak 0.61.22 : client serveur
|
|
``app.hub_reglages`` (cache 60 s, horodatage posé avant l'appel,
|
|
repli intégral sur les défauts actuels), bannière d'annonce dans
|
|
le partiel ``_header.html`` (texte échappé par l'autoescape
|
|
Jinja) et drapeau ``recherche_partout`` rendu en attribut
|
|
``data-recherche-partout`` de la page /recherche (la logique JS
|
|
associée est couverte par tests/recherche.test.js).
|
|
``domaine_defaut`` n'est pas appliqué : Kanbante n'a pas de
|
|
notion de domaine propre (voir le docstring du module).
|
|
"""
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from app import hub_reglages
|
|
|
|
|
|
class _Reponse:
|
|
def __init__(self, status_code=200, donnees=None):
|
|
self.status_code = status_code
|
|
self._donnees = donnees
|
|
|
|
def json(self):
|
|
if isinstance(self._donnees, Exception):
|
|
raise self._donnees
|
|
return self._donnees
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _cache_propre():
|
|
hub_reglages._reset_cache()
|
|
yield
|
|
hub_reglages._reset_cache()
|
|
|
|
|
|
@pytest.fixture()
|
|
def faux_hub(monkeypatch):
|
|
"""Faux Hub des réglages : état pilotable + journal d'appels."""
|
|
etat = {"reglages": None, "appels": [], "mode": "ok"}
|
|
|
|
def faux_get(url, headers=None, timeout=None):
|
|
etat["appels"].append(
|
|
{"url": url, "headers": dict(headers or {}), "timeout": timeout})
|
|
if etat["mode"] == "panne":
|
|
raise httpx.ConnectError("Hub injoignable (simulation)")
|
|
if etat["mode"] == "erreur500":
|
|
return _Reponse(500, {"detail": "erreur"})
|
|
return _Reponse(200, etat["reglages"])
|
|
|
|
monkeypatch.setattr(httpx, "get", faux_get)
|
|
return etat
|
|
|
|
|
|
# ── Client : validation, contrat d'appel, résolution d'URL ──────────
|
|
|
|
def test_validation_forme_du_contrat():
|
|
assert hub_reglages._valider({
|
|
"recherche_partout": False, "banniere": "Maintenance dimanche",
|
|
"domaine_defaut": "famille", "ttl_secondes": 60}) == {
|
|
"recherche_partout": False, "banniere": "Maintenance dimanche",
|
|
"domaine_defaut": "famille"}
|
|
for charge in (
|
|
None, "texte", ["x"], {},
|
|
{"recherche_partout": "oui", "banniere": "", "domaine_defaut": None},
|
|
{"recherche_partout": True, "banniere": 42, "domaine_defaut": None},
|
|
{"recherche_partout": True, "banniere": "", "domaine_defaut": "travail"},
|
|
):
|
|
assert hub_reglages._valider(charge) is None, charge
|
|
|
|
|
|
def test_appel_contrat_exact_et_cache(faux_hub):
|
|
faux_hub["reglages"] = {
|
|
"recherche_partout": False, "banniere": "Annonce A",
|
|
"domaine_defaut": None, "ttl_secondes": 60}
|
|
assert hub_reglages.banniere() == "Annonce A"
|
|
assert hub_reglages.recherche_partout() is False
|
|
assert len(faux_hub["appels"]) == 1 # cache 60 s
|
|
appel = faux_hub["appels"][0]
|
|
assert appel["url"] == "https://hub.dracodev.net/api/reglages/effectifs"
|
|
assert appel["headers"]["Accept"] == "application/json"
|
|
assert "Cookie" not in appel["headers"] # endpoint public
|
|
assert appel["timeout"] == 2.0
|
|
|
|
|
|
def test_url_hub_par_hote_dev(faux_hub):
|
|
faux_hub["reglages"] = {
|
|
"recherche_partout": True, "banniere": "", "domaine_defaut": None}
|
|
hub_reglages.reglages_effectifs(hote="kanbante-dev.dracodev.net")
|
|
assert faux_hub["appels"][0]["url"] == (
|
|
"https://hub-dev.dracodev.net/api/reglages/effectifs")
|
|
|
|
|
|
def test_ttl_expire_reconsulte(faux_hub):
|
|
faux_hub["reglages"] = {
|
|
"recherche_partout": True, "banniere": "Annonce A",
|
|
"domaine_defaut": None}
|
|
assert hub_reglages.banniere() == "Annonce A"
|
|
hub_reglages._cache_fetched_at -= hub_reglages.CACHE_TTL + 1
|
|
faux_hub["reglages"] = {
|
|
"recherche_partout": True, "banniere": "Annonce B",
|
|
"domaine_defaut": None}
|
|
assert hub_reglages.banniere() == "Annonce B"
|
|
assert len(faux_hub["appels"]) == 2
|
|
|
|
|
|
def test_hub_muet_repli_defauts(faux_hub):
|
|
faux_hub["mode"] = "panne"
|
|
assert hub_reglages.reglages_effectifs() == hub_reglages.DEFAUTS
|
|
hub_reglages._reset_cache()
|
|
faux_hub["mode"] = "erreur500"
|
|
assert hub_reglages.reglages_effectifs() == hub_reglages.DEFAUTS
|
|
hub_reglages._reset_cache()
|
|
faux_hub["mode"] = "ok"
|
|
faux_hub["reglages"] = {"forme": "inattendue"}
|
|
assert hub_reglages.reglages_effectifs() == hub_reglages.DEFAUTS
|
|
assert hub_reglages.banniere() == ""
|
|
assert hub_reglages.recherche_partout() is True
|
|
|
|
|
|
def test_echec_ancien_cache_sans_rafale(faux_hub):
|
|
faux_hub["reglages"] = {
|
|
"recherche_partout": True, "banniere": "Annonce A",
|
|
"domaine_defaut": None}
|
|
assert hub_reglages.banniere() == "Annonce A"
|
|
hub_reglages._cache_fetched_at -= hub_reglages.CACHE_TTL + 1
|
|
faux_hub["mode"] = "panne" # Hub tombe
|
|
assert hub_reglages.banniere() == "Annonce A" # ancien cache
|
|
appels = len(faux_hub["appels"])
|
|
assert hub_reglages.banniere() == "Annonce A"
|
|
assert len(faux_hub["appels"]) == appels # pas de rafale
|
|
|
|
|
|
# ── Intégration : bannière et drapeau dans les pages ────────────────
|
|
|
|
def test_banniere_presente_et_echappee(client, faux_hub):
|
|
faux_hub["reglages"] = {
|
|
"recherche_partout": True,
|
|
"banniere": "Maintenance dimanche <b>gras</b> & cie",
|
|
"domaine_defaut": None, "ttl_secondes": 60}
|
|
r = client.get("/recherche")
|
|
assert r.status_code == 200
|
|
assert 'id="banniere-hub"' in r.text
|
|
assert "Maintenance dimanche <b>gras</b> & cie" in r.text
|
|
assert "kanbante_banniere_masquee" in r.text
|
|
|
|
|
|
def test_banniere_absente_si_vide_ou_hub_muet(client, faux_hub):
|
|
faux_hub["reglages"] = {
|
|
"recherche_partout": True, "banniere": "", "domaine_defaut": "pro",
|
|
"ttl_secondes": 60}
|
|
r = client.get("/recherche")
|
|
assert r.status_code == 200
|
|
assert "banniere-hub" not in r.text
|
|
hub_reglages._reset_cache()
|
|
faux_hub["mode"] = "panne"
|
|
r = client.get("/recherche")
|
|
assert r.status_code == 200
|
|
assert "banniere-hub" not in r.text
|
|
|
|
|
|
def test_recherche_drapeau_rendu(client, faux_hub):
|
|
faux_hub["reglages"] = {
|
|
"recherche_partout": False, "banniere": "", "domaine_defaut": None,
|
|
"ttl_secondes": 60}
|
|
r = client.get("/recherche")
|
|
assert r.status_code == 200
|
|
assert 'data-recherche-partout="false"' in r.text
|
|
hub_reglages._reset_cache()
|
|
faux_hub["reglages"] = {
|
|
"recherche_partout": True, "banniere": "", "domaine_defaut": None,
|
|
"ttl_secondes": 60}
|
|
r = client.get("/recherche")
|
|
assert 'data-recherche-partout="true"' in r.text
|
|
hub_reglages._reset_cache()
|
|
faux_hub["mode"] = "panne" # Hub muet → défaut actif
|
|
r = client.get("/recherche")
|
|
assert 'data-recherche-partout="true"' in r.text
|
|
|
|
|
|
def test_version_0_46_3():
|
|
from pathlib import Path
|
|
version = (Path(__file__).parent.parent / "VERSION").read_text().strip()
|
|
assert version == "0.46.3"
|