`make openapi` écrit apps/backend/openapi.json, et un test compare le fichier versionné au schéma généré. Une route qui change son contrat public le montre donc dans la diff d'une pull request, et une PR qui oublie de régénérer échoue en CI : le fichier vit sous apps/backend, que le filtre de chemins de backend.yml couvre. Le schéma exporté ne lit ni le .env du poste ni les variables APP_ : tout ce qui l'atteint est posé par settings_du_contrat(), sans quoi le fichier changerait de machine en machine. main() réclamait un mot de passe avant de lire la commande. Le branchement passe devant, sinon l'export serait resté bloqué sur getpass.
110 lines
3.5 KiB
Python
110 lines
3.5 KiB
Python
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from app import cli
|
|
|
|
|
|
def test_build_parser_reads_the_create_admin_arguments() -> None:
|
|
arguments = cli.build_parser().parse_args(
|
|
["create-admin", "--email", "admin@enervision.fr", "--generate", "--force"]
|
|
)
|
|
|
|
assert arguments.commande == "create-admin"
|
|
assert arguments.email == "admin@enervision.fr"
|
|
assert arguments.generate is True
|
|
assert arguments.force is True
|
|
|
|
|
|
def test_build_parser_requires_a_subcommand() -> None:
|
|
with pytest.raises(SystemExit):
|
|
cli.build_parser().parse_args([])
|
|
|
|
|
|
def test_build_parser_requires_an_email() -> None:
|
|
with pytest.raises(SystemExit):
|
|
cli.build_parser().parse_args(["create-admin"])
|
|
|
|
|
|
def test_read_password_generates_a_long_secret_when_asked(
|
|
capsys: pytest.CaptureFixture[str],
|
|
) -> None:
|
|
mot_de_passe = cli.read_password(generate=True)
|
|
|
|
assert len(mot_de_passe) >= cli.LONGUEUR_MOT_DE_PASSE_GENERE
|
|
assert mot_de_passe in capsys.readouterr().out
|
|
|
|
|
|
def test_read_password_accepts_two_matching_entries(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
saisies = iter(["un-mot-de-passe-valide", "un-mot-de-passe-valide"])
|
|
monkeypatch.setattr(cli, "getpass", lambda _: next(saisies))
|
|
|
|
assert cli.read_password(generate=False) == "un-mot-de-passe-valide"
|
|
|
|
|
|
def test_read_password_refuses_a_password_below_the_minimum_length(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
monkeypatch.setattr(cli, "getpass", lambda _: "court")
|
|
|
|
with pytest.raises(SystemExit):
|
|
cli.read_password(generate=False)
|
|
|
|
|
|
def test_read_password_refuses_two_different_entries(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
saisies = iter(["un-mot-de-passe-valide", "un-autre-mot-de-passe"])
|
|
monkeypatch.setattr(cli, "getpass", lambda _: next(saisies))
|
|
|
|
with pytest.raises(SystemExit):
|
|
cli.read_password(generate=False)
|
|
|
|
|
|
def test_build_parser_reads_the_export_openapi_arguments() -> None:
|
|
arguments = cli.build_parser().parse_args(
|
|
["export-openapi", "--output", "ailleurs/contrat.json"]
|
|
)
|
|
|
|
assert arguments.commande == "export-openapi"
|
|
assert arguments.output == "ailleurs/contrat.json"
|
|
|
|
|
|
def test_build_parser_defaults_the_export_to_the_versioned_contract() -> None:
|
|
arguments = cli.build_parser().parse_args(["export-openapi"])
|
|
|
|
assert arguments.output == str(cli.CHEMIN_CONTRAT)
|
|
|
|
|
|
def test_settings_of_the_contract_ignore_the_local_environment(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
monkeypatch.setenv("APP_API_PREFIX", "/api/v9")
|
|
monkeypatch.setenv("APP_NAME", "API du poste de Johan")
|
|
|
|
settings = cli.settings_du_contrat()
|
|
|
|
assert settings.api_prefix == "/api/v1"
|
|
assert settings.name == "EnerVision API"
|
|
|
|
|
|
def test_export_openapi_writes_a_readable_schema_where_asked(tmp_path: Path) -> None:
|
|
destination = tmp_path / "contrat.json"
|
|
|
|
cli.export_openapi(destination)
|
|
|
|
assert json.loads(destination.read_text(encoding="utf-8"))["openapi"].startswith("3.")
|
|
|
|
|
|
# Piège : `main()` réclamait un mot de passe avant de lire la commande. Sans le branchement,
|
|
# l'export resterait bloqué sur `getpass` et aucune CI ne pourrait le rejouer.
|
|
def test_main_exports_the_contract_without_asking_for_a_password(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
destination = tmp_path / "contrat.json"
|
|
|
|
code = cli.main(["export-openapi", "--output", str(destination)])
|
|
|
|
assert code == 0
|
|
assert destination.exists()
|
|
assert str(destination) in capsys.readouterr().out
|