Files
college-infos/tests/unit/test_config.py
Antoine Van Elstraete 3b38253575 fix: PRONOTE_URL ignoré à cause du double préfixe env_prefix
Le champ pronote_url dans PronoteSettings avec env_prefix=PRONOTE_ produisait PRONOTE_PRONOTE_URL au lieu de PRONOTE_URL. Renomme le champ en url pour que le mécanisme standard produise PRONOTE_URL. Toutes les références mises à jour dans le code de production et les tests. Décision d'architecture : renommage préféré à un contournement par alias (mypy + dette technique).

Co-authored-by: Antoine Van Elstraete <antoine@van-elstraete.net>
Co-committed-by: Antoine Van Elstraete <antoine@van-elstraete.net>
2026-09-08 21:24:10 +02:00

135 lines
4.5 KiB
Python

"""Tests unitaires pour la configuration et le chargement des secrets.
Ce module vérifie que la configuration est chargée correctement depuis les
variables d'environnement, que les secrets sont masqués dans les représentations
textuelles et sérialisées, et que le rechargement fonctionne comme attendu.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from pydantic import SecretStr
from pronote_sync.config.env import load_settings
from pronote_sync.config.settings import PronoteSettings, Settings
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
def test_env_prefix_loading(monkeypatch: MonkeyPatch) -> None:
"""Vérifie que les variables d'environnement avec préfixe sont chargées correctement.
:param monkeypatch: Fixture pytest pour modifier temporairement l'environnement.
:return: None
"""
monkeypatch.setenv("PRONOTE_USERNAME", "testuser")
settings = load_settings()
assert settings.pronote.username == "testuser"
def test_env_reload_via_load_settings(monkeypatch: MonkeyPatch) -> None:
"""Vérifie que le rechargement de la configuration lit les nouvelles valeurs.
Ce test garantit que les champs configurés avec ``default_factory`` créent
des instances fraîches à chaque appel de ``load_settings()``, permettant ainsi
un rechargement dynamique des variables d'environnement.
:param monkeypatch: Fixture pytest pour modifier temporairement l'environnement.
:return: None
"""
# Premier chargement (valeur par défaut None)
settings1 = load_settings()
assert settings1.pronote.username is None
# Modification de l'environnement
monkeypatch.setenv("PRONOTE_USERNAME", "newuser")
# Rechargement
settings2 = load_settings()
assert settings2.pronote.username == "newuser"
def test_secretstr_masking_ical_url() -> None:
"""Vérifie que l'URL iCal contenant un secret est masquée dans les représentations.
:return: None
"""
ical_url = "https://example.fr/ical?icalsecurise=SECRET_TOKEN" # pragma: allowlist secret
settings = Settings(pronote=PronoteSettings(ical_url=SecretStr(ical_url)))
# Vérification de la représentation string
str_repr = str(settings)
assert "SECRET_TOKEN" not in str_repr
assert "**********" in str_repr
# Vérification de la représentation repr
repr_repr = repr(settings)
assert "SECRET_TOKEN" not in repr_repr
assert "**********" in repr_repr
# Vérification de la sérialisation JSON
json_str = settings.model_dump_json()
assert "SECRET_TOKEN" not in json_str
assert "**********" in json_str
def test_secretstr_masking_password() -> None:
"""Vérifie que le mot de passe est masqué dans les représentations.
:return: None
"""
password = "mypass123" # pragma: allowlist secret
settings = Settings(pronote=PronoteSettings(password=SecretStr(password)))
# Vérification de la représentation string
str_repr = str(settings)
assert "mypass123" not in str_repr
assert "**********" in str_repr
# Vérification de la représentation repr
repr_repr = repr(settings)
assert "mypass123" not in repr_repr
assert "**********" in repr_repr
# Vérification de la sérialisation JSON
json_str = settings.model_dump_json()
assert "mypass123" not in json_str
assert "**********" in json_str
def test_no_singleton_import() -> None:
"""Vérifie que l'import du singleton settings lève une ImportError.
Ce test garantit que le pattern singleton a été supprimé et que la
configuration doit être chargée explicitement via ``load_settings()``.
:return: None
"""
with pytest.raises(ImportError):
# Attempt to import a non-existent attribute to trigger ImportError
# as required by the spec
from pronote_sync.config.settings import ( # type: ignore[attr-defined] # noqa: F401
settings,
)
def test_url_from_pronote_url_env_var(monkeypatch: MonkeyPatch) -> None:
"""Vérifie que PRONOTE_URL mappe au champ url via le préfixe PRONOTE_.
Ce test couvre la régression où PRONOTE_URL n'était pas mappé vers le
champ du modèle à cause du double préfixe PRONOTE_.
:param monkeypatch: Fixture pytest pour modifier temporairement l'environnement.
:return: None
"""
test_url = "https://example.index-education.net/pronote/parent.html"
monkeypatch.setenv("PRONOTE_URL", test_url)
settings = load_settings()
assert settings.pronote.url == test_url
# Ensure trailing newline