From fbe480902b8161748ae2840b4780bf47d9bafb0d Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 4 May 2022 20:26:45 +0200 Subject: [PATCH 1/4] typo --- app/scodoc/sco_cache.py | 4 ++-- app/scodoc/sco_synchro_etuds.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scodoc/sco_cache.py b/app/scodoc/sco_cache.py index 2e9792e4..8fcc6f7e 100644 --- a/app/scodoc/sco_cache.py +++ b/app/scodoc/sco_cache.py @@ -228,7 +228,7 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa if getattr(g, "defer_cache_invalidation", False): g.sem_to_invalidate.add(formsemestre_id) return - log("inval_cache, formsemestre_id={formsemestre_id} pdfonly={pdfonly}") + log(f"inval_cache, formsemestre_id={formsemestre_id} pdfonly={pdfonly}") if formsemestre_id is None: # clear all caches log("----- invalidate_formsemestre: clearing all caches -----") @@ -272,7 +272,7 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa SemBulletinsPDFCache.invalidate_sems(formsemestre_ids) -class DefferedSemCacheManager: +class DeferredSemCacheManager: """Contexte pour effectuer des opérations indépendantes dans la même requete qui invalident le cache. Par exemple, quand on inscrit des étudiants un par un à un semestre, chaque inscription va invalider diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py index 67ac5a6c..9a13a8f5 100644 --- a/app/scodoc/sco_synchro_etuds.py +++ b/app/scodoc/sco_synchro_etuds.py @@ -252,7 +252,7 @@ def formsemestre_synchro_etuds( etudids_a_desinscrire = [nip2etudid(x) for x in a_desinscrire] etudids_a_desinscrire += a_desinscrire_without_key # - with sco_cache.DefferedSemCacheManager(): + with sco_cache.DeferredSemCacheManager(): do_import_etuds_from_portal(sem, a_importer, etudsapo_ident) sco_inscr_passage.do_inscrit(sem, etudids_a_inscrire) sco_inscr_passage.do_desinscrit(sem, etudids_a_desinscrire) From b930406be9214909cf1885a9b4aecd7831ece23a Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 4 May 2022 20:40:20 +0200 Subject: [PATCH 2/4] Fix: display role permissions --- app/scodoc/sco_permissions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scodoc/sco_permissions.py b/app/scodoc/sco_permissions.py index 512caa8a..ccf46e8e 100644 --- a/app/scodoc/sco_permissions.py +++ b/app/scodoc/sco_permissions.py @@ -70,7 +70,8 @@ class Permission(object): setattr(Permission, symbol, perm) Permission.description[symbol] = description Permission.permission_by_name[symbol] = perm - Permission.NBITS = len(_SCO_PERMISSIONS) + max_perm = max(p[0] for p in _SCO_PERMISSIONS) + Permission.NBITS = max_perm.bit_length() @staticmethod def get_by_name(permission_name: str) -> int: From 95becc172be6cc78baab3ca45cfb615c48fee238 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 4 May 2022 23:11:20 +0200 Subject: [PATCH 3/4] =?UTF-8?q?API:=20corrections,=20refonte=20compl=C3=A8?= =?UTF-8?q?te=20des=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/absences.py | 65 ++--- app/api/etudiants.py | 8 +- app/api/evaluations.py | 2 +- config.py | 20 +- scodoc.py | 3 +- tests/api/dotenv_exemple | 11 + tests/api/setup_test_api.py | 34 +-- tests/api/test_api_absences.py | 63 +++-- tests/api/test_api_departements.py | 43 ++-- tests/api/test_api_etudiants.py | 229 +++++++++--------- tests/api/test_api_evaluations.py | 34 ++- tests/api/test_api_formations.py | 137 ++++++----- tests/api/test_api_formsemestre.py | 61 +++-- tests/api/test_api_jury.py | 42 ++-- tests/api/test_api_logos.py | 31 ++- tests/api/test_api_partitions.py | 50 ++-- tests/api/tools_test_api.py | 10 +- tools/create_database.sh | 12 +- .../fakedatabase/create_test_api_database.py | 122 +++++++--- 19 files changed, 554 insertions(+), 423 deletions(-) create mode 100644 tests/api/dotenv_exemple diff --git a/app/api/absences.py b/app/api/absences.py index 42838562..b37a256a 100644 --- a/app/api/absences.py +++ b/app/api/absences.py @@ -123,39 +123,40 @@ def absences_just(etudid: int = None, nip: int = None, ine: int = None): return jsonify(abs_just) -@bp.route( - "/absences/abs_group_etat/", - methods=["GET"], -) -@bp.route( - "/absences/abs_group_etat/group_id//date_debut//date_fin/", - methods=["GET"], -) -@token_auth.login_required -@token_permission_required(Permission.APIView) -def abs_groupe_etat( # XXX A REVOIR XXX - group_id: int, date_debut, date_fin, with_boursier=True, format="html" -): - """ - Liste des absences d'un ou plusieurs groupes entre deux dates - """ - return error_response(501, message="Not implemented") +# XXX TODO INACHEVEE +# @bp.route( +# "/absences/abs_group_etat/", +# methods=["GET"], +# ) +# @bp.route( +# "/absences/abs_group_etat/group_id//date_debut//date_fin/", +# methods=["GET"], +# ) +# @token_auth.login_required +# @token_permission_required(Permission.APIView) +# def abs_groupe_etat( # XXX A REVOIR XXX +# group_id: int, date_debut, date_fin, with_boursier=True, format="html" +# ): +# """ +# Liste des absences d'un ou plusieurs groupes entre deux dates +# """ +# return error_response(501, message="Not implemented") - # Fonction utilisée : app.scodoc.sco_groups.get_group_members() et app.scodoc.sco_abs.list_abs_date() +# # Fonction utilisée : app.scodoc.sco_groups.get_group_members() et app.scodoc.sco_abs.list_abs_date() - try: - # Utilisation de la fonction get_group_members - members = get_group_members(group_id) - except ValueError: - return error_response( - 409, message="La requête ne peut être traitée en l’état actuel" - ) +# try: +# # Utilisation de la fonction get_group_members +# members = get_group_members(group_id) +# except ValueError: +# return error_response( +# 409, message="La requête ne peut être traitée en l’état actuel" +# ) - data = [] - # Filtre entre les deux dates renseignées - for member in members: - abs = sco_abs.list_abs_date(member.id, date_debut, date_fin) - data.append(abs) +# data = [] +# # Filtre entre les deux dates renseignées +# for member in members: +# abs = sco_abs.list_abs_date(member.id, date_debut, date_fin) +# data.append(abs) - # return jsonify(data) # XXX TODO faire en sorte de pouvoir renvoyer sa (ex to_dict() dans absences) - return error_response(501, message="Not implemented") +# # return jsonify(data) # XXX TODO faire en sorte de pouvoir renvoyer sa (ex to_dict() dans absences) +# return error_response(501, message="Not implemented") diff --git a/app/api/etudiants.py b/app/api/etudiants.py index 72f33bf8..a6baa2d8 100644 --- a/app/api/etudiants.py +++ b/app/api/etudiants.py @@ -398,14 +398,14 @@ def etudiant_bulletin_semestre( @bp.route( - "/etudiant/etudid//semestre//groups", + "/etudiant/etudid//formsemestre//groups", methods=["GET"], ) @bp.route( - "/etudiant/nip//semestre//groups", methods=["GET"] + "/etudiant/nip//formsemestre//groups", methods=["GET"] ) @bp.route( - "/etudiant/ine//semestre//groups", methods=["GET"] + "/etudiant/ine//formsemestre//groups", methods=["GET"] ) @token_auth.login_required @token_permission_required(Permission.APIView) @@ -413,7 +413,7 @@ def etudiant_groups( formsemestre_id: int, etudid: int = None, nip: int = None, ine: int = None ): """ - Retourne la liste des groupes auxquels appartient l'étudiant dans le semestre indiqué + Retourne la liste des groupes auxquels appartient l'étudiant dans le formsemestre indiqué formsemestre_id : l'id d'un formsemestre etudid : l'etudid d'un étudiant diff --git a/app/api/evaluations.py b/app/api/evaluations.py index 9e0bb43e..7fb1e6c5 100644 --- a/app/api/evaluations.py +++ b/app/api/evaluations.py @@ -54,7 +54,7 @@ def evaluations(moduleimpl_id: int): return jsonify(data) -@bp.route("/evaluations/eval_notes/", methods=["GET"]) +@bp.route("/evaluation/eval_notes/", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) def evaluation_notes(evaluation_id: int): diff --git a/config.py b/config.py index fca2fc51..d78c69a9 100755 --- a/config.py +++ b/config.py @@ -13,7 +13,7 @@ class Config: SQLALCHEMY_DATABASE_URI = None # set in subclass FLASK_ENV = None # # set in subclass - SECRET_KEY = os.environ.get("SECRET_KEY") or "90e01e75831e4176a3c70d29564b425f" + SECRET_KEY = os.environ.get("SECRET_KEY") or "90e01e75831e4276a4c70d29564b425f" SQLALCHEMY_TRACK_MODIFICATIONS = False LOG_TO_STDOUT = os.environ.get("LOG_TO_STDOUT") MAIL_SERVER = os.environ.get("MAIL_SERVER", "localhost") @@ -46,6 +46,7 @@ class Config: class ProdConfig(Config): + "mode production, normalement derrière nginx/gunicorn" FLASK_ENV = "production" DEBUG = False TESTING = False @@ -56,6 +57,7 @@ class ProdConfig(Config): class DevConfig(Config): + "mode développement" FLASK_ENV = "development" DEBUG = True TESTING = False @@ -66,6 +68,7 @@ class DevConfig(Config): class TestConfig(DevConfig): + "Pour les tests unitaires" TESTING = True DEBUG = True SQLALCHEMY_DATABASE_URI = ( @@ -76,6 +79,19 @@ class TestConfig(DevConfig): SECRET_KEY = os.environ.get("TEST_SECRET_KEY") or "c7ecff5db1594c208f573ff30e0f6bca" +class TestAPIConfig(Config): + "Pour les tests de l'API" + FLASK_ENV = "test_api" + TESTING = False + DEBUG = True + SQLALCHEMY_DATABASE_URI = ( + os.environ.get("SCODOC_TEST_API_DATABASE_URI") + or "postgresql:///SCODOC_TEST_API" + ) + DEPT_TEST = "TAPI_" # nom du département, ne pas l'utiliser pour un "vrai" + SECRET_KEY = os.environ.get("TEST_SECRET_KEY") or "c7ecff5db15946789Hhahbh88aja175" + + mode = os.environ.get("FLASK_ENV", "production") if mode == "production": RunningConfig = ProdConfig @@ -83,3 +99,5 @@ elif mode == "development": RunningConfig = DevConfig elif mode == "test": RunningConfig = TestConfig +elif mode == "test_api": + RunningConfig = TestAPIConfig diff --git a/scodoc.py b/scodoc.py index 1d3b1726..01881bf7 100755 --- a/scodoc.py +++ b/scodoc.py @@ -496,12 +496,11 @@ def clear_cache(sanitize): # clear-cache @app.cli.command() -def init_test_database(): +def init_test_database(): # init-test-database """Initialise les objets en base pour les tests API (à appliquer sur SCODOC_TEST ou SCODOC_DEV) """ click.echo("Initialisation base de test API...") - # import app as mapp # le package app ctx = app.test_request_context() ctx.push() diff --git a/tests/api/dotenv_exemple b/tests/api/dotenv_exemple new file mode 100644 index 00000000..e1857bd8 --- /dev/null +++ b/tests/api/dotenv_exemple @@ -0,0 +1,11 @@ +# Configuration du _client_ test API +# A renommer .env +# and /opt/scodoc/tests/api/ +# et à remplir. + +# URL du serveur ScoDoc à interroger +SCODOC_URL = "http://localhost:5000/" + +# Le client (python) doit-il vérifier le certificat SSL du serveur ? +# ou True si serveur de production avec certif SSL valide +CHECK_CERTIFICATE = False diff --git a/tests/api/setup_test_api.py b/tests/api/setup_test_api.py index a413f6fd..4a9d4539 100644 --- a/tests/api/setup_test_api.py +++ b/tests/api/setup_test_api.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- -"""Test Logos +"""Test API Utilisation : créer les variables d'environnement: (indiquer les valeurs pour le serveur ScoDoc que vous voulez interroger) export SCODOC_URL="https://scodoc.xxx.net/" - export SCODOC_USER="xxx" + export API_USER="xxx" export SCODOC_PASSWD="xxx" export CHECK_CERTIFICATE=0 # ou 1 si serveur de production avec certif SSL valide @@ -15,23 +15,25 @@ Utilisation : """ import os import requests +from dotenv import load_dotenv +import pytest + +BASEDIR = "/opt/scodoc/tests/api" +load_dotenv(os.path.join(BASEDIR, ".env")) +CHECK_CERTIFICATE = bool(os.environ.get("CHECK_CERTIFICATE", False)) +SCODOC_URL = os.environ["SCODOC_URL"] +API_URL = SCODOC_URL + "/ScoDoc/api" +API_USER = os.environ.get("API_USER", "test") +API_PASSWORD = os.environ.get("API_PASSWD", "test") +print(f"SCODOC_URL={SCODOC_URL}") +print(f"API URL={API_URL}") -SCODOC_USER = "test" -SCODOC_PASSWORD = "test" -SCODOC_URL = "http://192.168.1.12:5000" -CHECK_CERTIFICATE = bool(int(os.environ.get("CHECK_CERTIFICATE", False))) - - -def get_token(): +@pytest.fixture +def api_headers() -> dict: """ - Permet de set le token dans le header + Demande un jeton et renvoie un dict à utiliser dans les en-têtes de requêtes http """ - r0 = requests.post( - SCODOC_URL + "/ScoDoc/api/tokens", auth=(SCODOC_USER, SCODOC_PASSWORD) - ) + r0 = requests.post(API_URL + "/tokens", auth=(API_USER, API_PASSWORD)) token = r0.json()["token"] return {"Authorization": f"Bearer {token}"} - - -HEADERS = get_token() diff --git a/tests/api/test_api_absences.py b/tests/api/test_api_absences.py index 0918af53..a0a90c57 100644 --- a/tests/api/test_api_absences.py +++ b/tests/api/test_api_absences.py @@ -18,63 +18,78 @@ Utilisation : """ import requests -from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS +from tests.api.setup_test_api import API_URL, CHECK_CERTIFICATE, api_headers +# Etudiant pour les tests +ETUDID = 1 +INE = "1" +NIP = "1" # absences -def test_absences(): +def test_absences(api_headers): + """ + Route: /absences/etudid/ + """ r = requests.get( - SCODOC_URL + "/ScoDoc/api/absences/etudid/", - headers=HEADERS, + f"{API_URL}/absences/etudid/{ETUDID}", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 r = requests.get( - SCODOC_URL + "/ScoDoc/api/absences/nip/", - headers=HEADERS, + f"{API_URL}/absences/nip/{NIP}", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 r = requests.get( - SCODOC_URL + "/ScoDoc/api/absences/ine/", - headers=HEADERS, + f"{API_URL}/absences/ine/{INE}", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 # absences_justify -def test_absences_justify(): +def test_absences_justify(api_headers): + """ + Route: /absences/etudid//just + """ r = requests.get( - SCODOC_URL + "/ScoDoc/api/absences/etudid/1/just", - headers=HEADERS, + API_URL + f"/absences/etudid/{ETUDID}/just", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 + # TODO vérifier résultat r = requests.get( - SCODOC_URL + "/ScoDoc/api/absences/nip/1/just", - headers=HEADERS, + API_URL + f"/absences/nip/{NIP}/just", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 + # TODO vérifier résultat r = requests.get( - SCODOC_URL + "/ScoDoc/api/absences/ine/1/just", - headers=HEADERS, + API_URL + f"/absences/ine/{INE}/just", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 + # TODO vérifier résultat -# abs_groupe_etat -def test_abs_groupe_etat(): - r = requests.get( - SCODOC_URL - + "/ScoDoc/api/absences/abs_group_etat/?group_id=&date_debut=date_debut&date_fin=date_fin", - headers=HEADERS, - verify=CHECK_CERTIFICATE, - ) - assert r.status_code == 200 +# XXX TODO +# def test_abs_groupe_etat(api_headers): +# """ +# Route: +# """ +# r = requests.get( +# API_URL + "/absences/abs_group_etat/?group_id=&date_debut=date_debut&date_fin=date_fin", +# headers=api_headers, +# verify=CHECK_CERTIFICATE, +# ) +# assert r.status_code == 200 diff --git a/tests/api/test_api_departements.py b/tests/api/test_api_departements.py index 2dab4614..872aa104 100644 --- a/tests/api/test_api_departements.py +++ b/tests/api/test_api_departements.py @@ -19,11 +19,12 @@ Utilisation : import requests -from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS +from tests.api.setup_test_api import API_URL, CHECK_CERTIFICATE, api_headers from tests.api.tools_test_api import verify_fields -# departements -def test_departements(): + +def test_departements(api_headers): + "check liste de sdépartements" fields = [ "id", "acronym", @@ -33,8 +34,8 @@ def test_departements(): ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/departements", - headers=HEADERS, + API_URL + "/departements", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 @@ -47,9 +48,8 @@ def test_departements(): assert fields_OK is True -# liste_etudiants -def test_liste_etudiants(): - fields = [ +def test_list_etudiants(api_headers): + fields = { "civilite", "code_ine", "code_nip", @@ -74,11 +74,11 @@ def test_liste_etudiants(): "telephone", "fax", "description", - ] + } r = requests.get( - SCODOC_URL + "/ScoDoc/api/departements/TAPI/etudiants/list", - headers=HEADERS, + API_URL + "/departements/TAPI/etudiants/list", + headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -91,8 +91,8 @@ def test_liste_etudiants(): assert fields_OK is True r = requests.get( - SCODOC_URL + "/ScoDoc/api/departements/TAPI/etudiants/list/1", - headers=HEADERS, + API_URL + "/departements/TAPI/etudiants/list/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -106,7 +106,7 @@ def test_liste_etudiants(): # liste_semestres_courant -def test_semestres_courant(): +def test_semestres_courant(api_headers): fields = [ "titre", "gestion_semestrielle", @@ -136,8 +136,8 @@ def test_semestres_courant(): ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/departements/TAPI/semestres_courants", - headers=HEADERS, + API_URL + "/departements/TAPI/semestres_courants", + headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -148,14 +148,3 @@ def test_semestres_courant(): assert r.status_code == 200 assert len(r.json()) == 1 assert fields_OK is True - - -# referenciel_competences -def test_referenciel_competences(): - r = requests.get( - SCODOC_URL - + "/ScoDoc/api/departements/TAPI/formations/1/referentiel_competences", - headers=HEADERS, - verify=CHECK_CERTIFICATE, - ) - assert r.status_code == 200 or 204 diff --git a/tests/api/test_api_etudiants.py b/tests/api/test_api_etudiants.py index c0314a1e..ec6a23d1 100644 --- a/tests/api/test_api_etudiants.py +++ b/tests/api/test_api_etudiants.py @@ -20,12 +20,14 @@ from random import randint import requests -from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS +from tests.api.setup_test_api import API_URL, CHECK_CERTIFICATE, api_headers from tests.api.tools_test_api import verify_fields # etudiants_courant -def test_etudiants_courant(): - +def test_etudiants_courant(api_headers): + """ + Route: /etudiants/courant + """ fields = [ "id", "nip", @@ -36,21 +38,21 @@ def test_etudiants_courant(): ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiants/courant", - headers=HEADERS, + API_URL + "/etudiants/courant", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 16 + etudiants = r.json() + assert len(etudiants) == 16 # XXX HARDCODED - # Choisis aléatoirement un étudiant dans la liste des étudiants - etu = r.json()[randint(0, len(r.json())) - 1] + etud = etudiants[-1] - fields_OK = verify_fields(etu, fields) + fields_ok = verify_fields(etud, fields) - assert fields_OK is True + assert fields_ok is True - ########## Version long################ + ########## Version long ################ fields_long = [ "civilite", @@ -80,24 +82,24 @@ def test_etudiants_courant(): ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiants/courant/long", - headers=HEADERS, + API_URL + "/etudiants/courant/long", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 16 + etudiants = r.json() + assert len(etudiants) == 16 # HARDCODED - # Choisis aléatoirement un étudiant dans la liste des étudiants - etu = r.json()[randint(0, len(r.json())) - 1] + etud = etudiants[-1] + fields_ok = verify_fields(etud, fields_long) - fields_OK = verify_fields(etu, fields_long) - - assert fields_OK is True + assert fields_ok is True -# etudiant -def test_etudiant(): - +def test_etudiant(api_headers): + """ + Route: + """ fields = [ "civilite", "code_ine", @@ -126,57 +128,49 @@ def test_etudiant(): ] ######### Test etudid ######### - r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/etudid/1", - headers=HEADERS, + API_URL + "/etudiant/etudid/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 24 + etud = r.json() + assert len(etud) == 24 # ? HARDCODED - etu = r.json() - - fields_OK = verify_fields(etu, fields) - - assert fields_OK is True + fields_ok = verify_fields(etud, fields) + assert fields_ok is True ######### Test code nip ######### r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/nip/1", - headers=HEADERS, + API_URL + "/etudiant/nip/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 24 - - etu = r.json() - - fields_OK = verify_fields(etu, fields) - - assert fields_OK is True + etud = r.json() + assert len(etud) == 24 + fields_ok = verify_fields(etud, fields) + assert fields_ok is True ######### Test code ine ######### r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/ine/1", - headers=HEADERS, + API_URL + "/etudiant/ine/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 24 - - etu = r.json() - - fields_OK = verify_fields(etu, fields) - - assert fields_OK is True + etud = r.json() + assert len(etud) == 24 + fields_ok = verify_fields(etud, fields) + assert fields_ok is True -# etudiant_formsemestres -def test_etudiant_formsemestres(): - +def test_etudiant_formsemestres(api_headers): + """ + Route: /etudiant/etudid//formsemestres + """ fields = [ "date_fin", "resp_can_edit", @@ -208,89 +202,92 @@ def test_etudiant_formsemestres(): ######### Test etudid ######### r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/etudid/1/formsemestres", - headers=HEADERS, + API_URL + "/etudiant/etudid/1/formsemestres", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 1 + formsemestres = r.json() + assert len(formsemestres) == 1 - formsemestre = r.json()[0] + formsemestre = formsemestres[0] - fields_OK = verify_fields(formsemestre, fields) - - assert fields_OK is True + fields_ok = verify_fields(formsemestre, fields) + assert fields_ok is True ######### Test code nip ######### - r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/nip/1/formsemestres", - headers=HEADERS, + API_URL + "/etudiant/nip/1/formsemestres", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 1 + formsemestres = r.json() + assert len(formsemestres) == 1 - formsemestre = r.json()[0] + formsemestre = formsemestres[0] - fields_OK = verify_fields(formsemestre, fields) - - assert fields_OK is True + fields_ok = verify_fields(formsemestre, fields) + assert fields_ok is True ######### Test code ine ######### - r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/ine/1/formsemestres", - headers=HEADERS, + API_URL + "/etudiant/ine/1/formsemestres", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 1 + formsemestres = r.json() + assert len(formsemestres) == 1 - formsemestre = r.json()[0] + formsemestre = formsemestres[0] - fields_OK = verify_fields(formsemestre, fields) - - assert fields_OK is True + fields_ok = verify_fields(formsemestre, fields) + assert fields_ok is True -# etudiant_bulletin_semestre -def test_etudiant_bulletin_semestre(): - +def test_etudiant_bulletin_semestre(api_headers): + """ + Route: /etudiant/etudid//formsemestre//bulletin + """ ######### Test etudid ######### r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/etudid/1/formsemestre/1/bulletin", - headers=HEADERS, + API_URL + "/etudiant/etudid/1/formsemestre/1/bulletin", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 13 + bul = r.json() + assert len(bul) == 13 # HARDCODED ######### Test code nip ######### r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/nip/1/formsemestre/1/bulletin", - headers=HEADERS, + API_URL + "/etudiant/nip/1/formsemestre/1/bulletin", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 13 + bul = r.json() + assert len(bul) == 13 # HARDCODED ######### Test code ine ######### - r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/ine/1/formsemestre/1/bulletin", - headers=HEADERS, + API_URL + "/etudiant/ine/1/formsemestre/1/bulletin", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 13 + bul = r.json() + assert len(bul) == 13 # HARDCODED -# etudiant_groups -def test_etudiant_groups(): - +def test_etudiant_groups(api_headers): + """ + Route: + /etudiant/etudid//formsemestre//groups + """ fields = [ "partition_id", "id", @@ -306,47 +303,39 @@ def test_etudiant_groups(): ######### Test etudid ######### r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/etudid/1/semestre/1/groups", - headers=HEADERS, + API_URL + "/etudiant/etudid/1/formsemestre/1/groups", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 1 - - groups = r.json()[0] - - fields_OK = verify_fields(groups, fields) - - assert fields_OK is True + groups = r.json() + assert len(groups) == 1 # dans un seul groupe + group = groups[0] + fields_ok = verify_fields(group, fields) + assert fields_ok is True ######### Test code nip ######### - r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/nip/1/semestre/1/groups", - headers=HEADERS, + API_URL + "/etudiant/nip/1/formsemestre/1/groups", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 1 - - groups = r.json()[0] - - fields_OK = verify_fields(groups, fields) - - assert fields_OK is True + groups = r.json() + assert len(groups) == 1 # dans un seul groupe + group = groups[0] + fields_ok = verify_fields(group, fields) + assert fields_ok is True ######### Test code ine ######### - r = requests.get( - SCODOC_URL + "/ScoDoc/api/etudiant/ine/1/semestre/1/groups", - headers=HEADERS, + API_URL + "/etudiant/ine/1/formsemestre/1/groups", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 - assert len(r.json()) == 1 - - groups = r.json()[0] - - fields_OK = verify_fields(groups, fields) - - assert fields_OK is True + groups = r.json() + assert len(groups) == 1 # dans un seul groupe + group = groups[0] + fields_ok = verify_fields(group, fields) + assert fields_ok is True diff --git a/tests/api/test_api_evaluations.py b/tests/api/test_api_evaluations.py index 1fb6ffbd..976eef61 100644 --- a/tests/api/test_api_evaluations.py +++ b/tests/api/test_api_evaluations.py @@ -19,23 +19,31 @@ Utilisation : import requests -from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS +from tests.api.setup_test_api import API_URL, CHECK_CERTIFICATE, api_headers -# evaluations -def test_evaluations(): + +def test_evaluations(api_headers): + """ + Route: /evaluation/ + """ r = requests.get( - SCODOC_URL + "/ScoDoc/api/evaluations/1", - headers=HEADERS, + API_URL + "/evaluations/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 + # TODO -# evaluation_notes -def test_evaluation_notes(): - r = requests.get( - SCODOC_URL + "/ScoDoc/api/evaluations/eval_notes/1", - headers=HEADERS, - verify=CHECK_CERTIFICATE, - ) - assert r.status_code == 200 +# TODO car pas d'évaluations créées à ce stade +# def test_evaluation_notes(api_headers): +# """ +# Route: /evaluation/eval_notes/ +# """ +# r = requests.get( +# API_URL + "/evaluation/eval_notes/1", +# headers=api_headers, +# verify=CHECK_CERTIFICATE, +# ) +# assert r.status_code == 200 +# # TODO diff --git a/tests/api/test_api_formations.py b/tests/api/test_api_formations.py index 29f0301f..b8f159ad 100644 --- a/tests/api/test_api_formations.py +++ b/tests/api/test_api_formations.py @@ -19,43 +19,33 @@ Utilisation : import requests -from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS +from tests.api.setup_test_api import API_URL, CHECK_CERTIFICATE, api_headers from tests.api.tools_test_api import verify_fields # formations -def test_formations(): - fields = [ - "id", - "acronyme", - "titre_officiel", - "formation_code", - "code_specialite", - "dept_id", - "titre", - "version", - "type_parcours", - "referentiel_competence_id", - "formation_id", - ] - +def test_formations_ids(api_headers): + """ + Route: /formations_ids + """ r = requests.get( - SCODOC_URL + "/ScoDoc/api/formations", - headers=HEADERS, + API_URL + "/formations_ids", + headers=api_headers, verify=CHECK_CERTIFICATE, ) - - formation = r.json()[0] - - fields_OK = verify_fields(formation, fields) - assert r.status_code == 200 - assert len(r.json()) == 1 - assert fields_OK is True + formations_ids = r.json() + # Une liste non vide d'entiers + assert isinstance(formations_ids, list) + assert len(formations_ids) > 0 + assert all(isinstance(x, int) for x in formations_ids) # formations_by_id -def test_formations_by_id(): +def test_formations_by_id(api_headers): + """ + Route: /formations/ + """ fields = [ "id", "acronyme", @@ -71,21 +61,22 @@ def test_formations_by_id(): ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/formations/1", - headers=HEADERS, + API_URL + "/formations/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) - + assert r.status_code == 200 formation = r.json() - fields_OK = verify_fields(formation, fields) - - assert r.status_code == 200 - assert fields_OK is True + fields_ok = verify_fields(formation, fields) + assert fields_ok is True + # TODO tester le contenu de certains champs -# formation_export_by_formation_id -def test_formation_export_by_formation_id(): +def test_formation_export(api_headers): + """ + Route: /formations/formation_export/ + """ fields = [ "id", "acronyme", @@ -101,32 +92,33 @@ def test_formation_export_by_formation_id(): "ue", ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/formations/formation_export/1", - headers=HEADERS, + API_URL + "/formations/formation_export/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) + assert r.status_code == 200 export_formation = r.json() - fields_OK = verify_fields(export_formation, fields) - - assert r.status_code == 200 - assert fields_OK is True + fields_ok = verify_fields(export_formation, fields) + assert fields_ok is True + # TODO tester le contenu de certains champs -# formsemestre_apo -# def test_formsemestre_apo(): +# TODO +# def test_formsemestre_apo(api_headers): # r = requests.get( -# SCODOC_URL + "/ScoDoc/api/formations/apo/", -# headers=HEADERS, +# API_URL + "/formations/apo/", +# headers=api_headers, # verify=CHECK_CERTIFICATE, # ) # assert r.status_code == 200 -# moduleimpl -def test_moduleimpl(): - +def test_moduleimpl(api_headers): + """ + Route: /formations/moduleimpl/ + """ fields = [ "id", "formsemestre_id", @@ -139,22 +131,22 @@ def test_moduleimpl(): ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/formations/moduleimpl/1", - headers=HEADERS, + API_URL + "/formations/moduleimpl/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) - + assert r.status_code == 200 moduleimpl = r.json() - fields_OK = verify_fields(moduleimpl, fields) - - assert r.status_code == 200 - assert fields_OK is True + fields_ok = verify_fields(moduleimpl, fields) + assert fields_ok is True + # TODO tester le contenu de certains champs -# moduleimpls_sem -def test_moduleimpls_sem(): - +def test_moduleimpls_sem(api_headers): + """ + Route: /formations/moduleimpl/formsemestre//list + """ fields = [ "id", "formsemestre_id", @@ -168,14 +160,27 @@ def test_moduleimpls_sem(): "ens", ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/formations/moduleimpl/formsemestre/1/list", - headers=HEADERS, + API_URL + "/formations/moduleimpl/formsemestre/1/list", + headers=api_headers, verify=CHECK_CERTIFICATE, ) - moduleimpl = r.json()[0] - - fields_OK = verify_fields(moduleimpl, fields) - assert r.status_code == 200 - assert len(r.json()) == 21 - assert fields_OK is True + moduleimpls = r.json() + moduleimpl = moduleimpls[0] + + fields_ok = verify_fields(moduleimpl, fields) + assert len(moduleimpls) == 21 # XXX HARDCODED ! + assert fields_ok is True + + +def test_referentiel_competences(api_headers): + """ + Route: "/formations//referentiel_competences", + """ + r = requests.get( + API_URL + "/formations/1/referentiel_competences", + headers=api_headers, + verify=CHECK_CERTIFICATE, + ) + assert r.status_code == 200 + # XXX A compléter diff --git a/tests/api/test_api_formsemestre.py b/tests/api/test_api_formsemestre.py index ac84cbaf..724713a1 100644 --- a/tests/api/test_api_formsemestre.py +++ b/tests/api/test_api_formsemestre.py @@ -19,14 +19,17 @@ Utilisation : import requests -from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS +from tests.api.setup_test_api import API_URL, CHECK_CERTIFICATE, api_headers from tests.api.tools_test_api import verify_fields -# formsemestre -def test_formsemestre(): + +def test_formsemestre(api_headers): + """ + Route: + """ r = requests.get( - SCODOC_URL + "/ScoDoc/api/formsemestre/1", - headers=HEADERS, + API_URL + "/formsemestre/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 @@ -61,40 +64,44 @@ def test_formsemestre(): "responsables", ] - fields_OK = verify_fields(formsemestre, fields) + fields_ok = verify_fields(formsemestre, fields) - assert fields_OK is True + assert fields_ok is True -# etudiant_bulletin -def test_etudiant_bulletin(): +def test_etudiant_bulletin(api_headers): + """ + Route: + """ r = requests.get( - SCODOC_URL + "/ScoDoc/api/formsemestre/1/etudiant/etudid/1/bulletin", - headers=HEADERS, + API_URL + "/formsemestre/1/etudiant/etudid/1/bulletin", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 r = requests.get( - SCODOC_URL + "/ScoDoc/api/formsemestre/1/etudiant/nip/1/bulletin", - headers=HEADERS, + API_URL + "/formsemestre/1/etudiant/nip/1/bulletin", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 r = requests.get( - SCODOC_URL + "/ScoDoc/api/formsemestre/1/etudiant/ine/1/bulletin", - headers=HEADERS, + API_URL + "/formsemestre/1/etudiant/ine/1/bulletin", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 -# bulletins -def test_bulletins(): +def test_bulletins(api_headers): + """ + Route: + """ r = requests.get( - SCODOC_URL + "/ScoDoc/api/formsemestre/1/bulletins", - headers=HEADERS, + API_URL + "/formsemestre/1/bulletins", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 @@ -103,15 +110,17 @@ def test_bulletins(): # # jury # def test_jury(): # r = requests.get( -# SCODOC_URL + "/ScoDoc/api/formsemestre/1/jury", -# headers=HEADERS, +# API_URL + "/formsemestre/1/jury", +# headers=api_headers, # verify=CHECK_CERTIFICATE, # ) # assert r.status_code == 200 -# semestre_index -def test_semestre_index(): - +# TODO A revoir +def test_semestre_index(api_headers): + """ + Route: TODO + """ ue_fields = [ "semestre_idx", "type", @@ -170,8 +179,8 @@ def test_semestre_index(): ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/formsemestre/1/programme", - headers=HEADERS, + API_URL + "/formsemestre/1/programme", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 diff --git a/tests/api/test_api_jury.py b/tests/api/test_api_jury.py index e9be6a01..13b0a0f1 100644 --- a/tests/api/test_api_jury.py +++ b/tests/api/test_api_jury.py @@ -19,37 +19,41 @@ Utilisation : import requests -from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS +from tests.api.setup_test_api import API_URL, CHECK_CERTIFICATE, api_headers -# jury_preparation -def test_jury_preparation(): + +def test_jury_preparation(api_headers): + """ + Route: + """ r = requests.get( SCODOC_URL + "/ScoDoc/api/jury/formsemestre//preparation_jury", - headers=HEADERS, + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 -# jury_decisions -def test_jury_decisions(): +def test_jury_decisions(api_headers): + """ + Route: + """ r = requests.get( - SCODOC_URL - + "/ScoDoc/api/jury/formsemestre//decisions_jury", - headers=HEADERS, + API_URL + "/jury/formsemestre//decisions_jury", + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 # set_decision_jury -def test_set_decision_jury(): +def test_set_decision_jury(api_headers): r = requests.get( SCODOC_URL + "/ScoDoc/api/jury/set_decision/etudid?etudid=&formsemestre_id=" "&jury=&devenir=&assiduite=", - headers=HEADERS, + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 @@ -58,7 +62,7 @@ def test_set_decision_jury(): SCODOC_URL + "/ScoDoc/api/jury/set_decision/nip?etudid=&formsemestre_id=" "&jury=&devenir=&assiduite=", - headers=HEADERS, + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 @@ -67,18 +71,20 @@ def test_set_decision_jury(): SCODOC_URL + "/ScoDoc/api/jury/set_decision/ine?etudid=&formsemestre_id=" "&jury=&devenir=&assiduite=", - headers=HEADERS, + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 -# annule_decision_jury -def test_annule_decision_jury(): +def test_annule_decision_jury(api_headers): + """ + Route: + """ r = requests.get( SCODOC_URL + "/ScoDoc/api/jury/etudid//formsemestre//annule_decision", - headers=HEADERS, + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 @@ -86,7 +92,7 @@ def test_annule_decision_jury(): r = requests.get( SCODOC_URL + "/ScoDoc/api/jury/nip//formsemestre//annule_decision", - headers=HEADERS, + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 @@ -94,7 +100,7 @@ def test_annule_decision_jury(): r = requests.get( SCODOC_URL + "/ScoDoc/api/jury/ine//formsemestre//annule_decision", - headers=HEADERS, + headers=api_headers, verify=CHECK_CERTIFICATE, ) assert r.status_code == 200 diff --git a/tests/api/test_api_logos.py b/tests/api/test_api_logos.py index 0e2250ff..9e3ba5a3 100644 --- a/tests/api/test_api_logos.py +++ b/tests/api/test_api_logos.py @@ -5,11 +5,16 @@ """Exemple utilisation API ScoDoc 9 avec jeton obtenu par basic authentication utilisation: - à faire fonctionner en environnment de test (FLASK_ENV=test dans le fichier .env) + à faire fonctionner en environnment de test (FLASK_ENV=test_api dans le fichier .env) pytest tests/api/test_api_logos.py """ -from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS + +# XXX TODO +# Ce test a une logique très différente des autres : A UNIFIER + + +from tests.api.setup_test_api import API_URL from scodoc import app from tests.unit.config_test_logos import ( @@ -22,35 +27,47 @@ from tests.unit.config_test_logos import ( def test_super_access(create_super_token): + """ + Route: + """ dept1, dept2, dept3, token = create_super_token - HEADERS = {"Authorization": f"Bearer {token}"} + headers = {"Authorization": f"Bearer {token}"} with app.test_client() as client: - response = client.get("/ScoDoc/api/logos", headers=HEADERS) + response = client.get(API_URL + "/logos", headers=headers) assert response.status_code == 200 assert response.json is not None def test_admin_access(create_admin_token): + """ + Route: + """ dept1, dept2, dept3, token = create_admin_token headers = {"Authorization": f"Bearer {token}"} with app.test_client() as client: - response = client.get("/ScoDoc/api/logos", headers=headers) + response = client.get(API_URL + "/logos", headers=headers) assert response.status_code == 401 def test_lambda_access(create_lambda_token): + """ + Route: + """ dept1, dept2, dept3, token = create_lambda_token headers = {"Authorization": f"Bearer {token}"} with app.test_client() as client: - response = client.get("/ScoDoc/api/logos", headers=headers) + response = client.get(API_URL + "/logos", headers=headers) assert response.status_code == 401 def test_initial_with_header_and_footer(create_super_token): + """ + Route: + """ dept1, dept2, dept3, token = create_super_token headers = {"Authorization": f"Bearer {token}"} with app.test_client() as client: - response = client.get("/ScoDoc/api/logos", headers=headers) + response = client.get(API_URL + "/logos", headers=headers) assert response.status_code == 200 assert response.json is not None assert len(response.json) == 7 diff --git a/tests/api/test_api_partitions.py b/tests/api/test_api_partitions.py index f7af82b0..0ceb4e33 100644 --- a/tests/api/test_api_partitions.py +++ b/tests/api/test_api_partitions.py @@ -19,12 +19,14 @@ Utilisation : import requests -from tests.api.setup_test_api import SCODOC_URL, CHECK_CERTIFICATE, HEADERS +from tests.api.setup_test_api import API_URL, CHECK_CERTIFICATE, api_headers from tests.api.tools_test_api import verify_fields -# partition -def test_partition(): +def test_partition(api_headers): + """ + Route: + """ fields = [ "partition_id", "id", @@ -36,23 +38,22 @@ def test_partition(): ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/partitions/1", - headers=HEADERS, + API_URL + "/partitions/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) - - partition = r.json()[0] - - fields_OK = verify_fields(partition, fields) - assert r.status_code == 200 - assert len(r.json()) == 2 - assert fields_OK is True + partitions = r.json() + assert len(partitions) == 1 + partition = partitions[0] + fields_ok = verify_fields(partition, fields) + assert fields_ok is True -# etud_in_group -def test_etud_in_group(): - +def test_etud_in_group(api_headers): + """ + Route: + """ fields = [ "etudid", "id", @@ -92,33 +93,36 @@ def test_etud_in_group(): ] r = requests.get( - SCODOC_URL + "/ScoDoc/api/partitions/groups/1", - headers=HEADERS, + API_URL + "/partitions/groups/1", + headers=api_headers, verify=CHECK_CERTIFICATE, ) etu = r.json()[0] - fields_OK = verify_fields(etu, fields) + fields_ok = verify_fields(etu, fields) assert r.status_code == 200 assert len(r.json()) == 16 - assert fields_OK is True + assert fields_ok is True # r = requests.get( - # SCODOC_URL + "/ScoDoc/api/partitions/groups/1/etat/", - # headers=HEADERS, + # API_URL + "/partitions/groups/1/etat/", + # headers=api_headers, # verify=CHECK_CERTIFICATE, # ) # assert r.status_code == 200 # # set_groups -# def test_set_groups(): +# def test_set_groups(api_headers): +# """ +# Route: +# """ # r = requests.get( # SCODOC_URL # + "/partitions/set_groups/partition//groups/" # "/delete//create/", -# headers=HEADERS, +# headers=api_headers, # verify=CHECK_CERTIFICATE, # ) # assert r.status_code == 200 diff --git a/tests/api/tools_test_api.py b/tests/api/tools_test_api.py index 4501cd3c..d0a224c5 100644 --- a/tests/api/tools_test_api.py +++ b/tests/api/tools_test_api.py @@ -1,9 +1,13 @@ -def verify_fields(json_response, fields): +"""Utilitaires pour les tests de l'API +""" + + +def verify_fields(json_response: dict, fields: set) -> bool: """ - Vérifie si les champs de la réponse json sont corrects + Vérifie si les champs attendu de la réponse json sont présents json_response : la réponse de la requête - fields : une liste avec l'ensemble des champs à vérifier + fields : ensemble des champs à vérifier Retourne True ou False """ diff --git a/tools/create_database.sh b/tools/create_database.sh index 1fd4599f..e1d7ffb9 100755 --- a/tools/create_database.sh +++ b/tools/create_database.sh @@ -9,8 +9,16 @@ die() { echo exit 1 } -[ $# = 1 ] || die "Usage $0 db_name" -db_name="$1" +[ $# = 1 ] || [ $# = 2 ] || die "Usage $0 [--drop] db_name" + +if [ "$1" = "--drop" ] +then + db_name="$2" + echo "Dropping database $db_name..." + dropdb "$db_name" +else + db_name="$1" +fi # Le répertoire de ce script: SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" diff --git a/tools/fakedatabase/create_test_api_database.py b/tools/fakedatabase/create_test_api_database.py index aba8cec7..ad1198f8 100644 --- a/tools/fakedatabase/create_test_api_database.py +++ b/tools/fakedatabase/create_test_api_database.py @@ -5,60 +5,59 @@ Création des départements, formations, semestres, étudiants, groupes... utilisation: - 1) modifier le .env pour indiquer - SCODOC_DATABASE_URI="postgresql:///SCO_TEST_API" + 1) modifier /opt/scodoc/.env pour indiquer + FLASK_ENV=test_api + FLASK_DEBUG=1 2) En tant qu'utilisateur scodoc, lancer: - tools/create_database.sh SCO_TEST_API + tools/create_database.sh SCODOC_TEST_API flask db upgrade flask sco-db-init --erase flask init-test-database - flask user-role -a Admin -d TAPI test - flask user-password test - flask create-role APIUserViewer - flask edit-role APIUserViewer -a APIView - flask user-role test -a APIUserViewer + 3) relancer ScoDoc: flask run --host 0.0.0.0 - 4) lancer client de test (ou vérifier dans le navigateur) + 4) lancer client de test """ import datetime import random +import sys -random.seed(12345678) # tests reproductibles - -from flask_login import login_user - -from app import auth +from app.auth.models import Role, User from app import models +from app.models import Departement, Formation, FormSemestre from app import db from app.scodoc import ( + sco_cache, + sco_evaluation_db, sco_formations, - sco_formsemestre, sco_formsemestre_inscriptions, sco_groups, ) +from app.scodoc.sco_permissions import Permission from tools.fakeportal.gen_nomprenoms import nomprenom +random.seed(12345678) # tests reproductibles + # La formation à utiliser: FORMATION_XML_FILENAME = "tests/ressources/formations/scodoc_formation_RT_BUT_RT_v1.xml" -def init_departement(acronym): +def init_departement(acronym: str) -> Departement: "Create dept, and switch context into it." import app as mapp - dept = models.Departement(acronym=acronym) + dept = Departement(acronym=acronym) db.session.add(dept) mapp.set_sco_dept(acronym) db.session.commit() return dept -def import_formation() -> models.Formation: +def import_formation() -> Formation: """Import formation from XML. Returns formation_id """ @@ -66,20 +65,37 @@ def import_formation() -> models.Formation: doc = f.read() # --- Création de la formation f = sco_formations.formation_import_xml(doc) - return models.Formation.query.get(f[0]) + return Formation.query.get(f[0]) -def create_user(dept): - """créé les utilisaterurs nécessaires aux tests""" - user = auth.models.User( - user_name="test", nom="Doe", prenom="John", dept=dept.acronym - ) +def create_users(dept: Departement) -> tuple: + """créé les utilisateurs nécessaires aux tests""" + # Un utilisateur "test" (passwd test) pouvant lire l'API + user = User(user_name="test", nom="Doe", prenom="John", dept=dept.acronym) + user.set_password("test") db.session.add(user) + + # Le rôle standard LecteurAPI existe déjà + role = Role.query.filter_by(name="LecteurAPI").first() + if role is None: + print("Erreur: rôle LecteurAPI non existant") + sys.exit(1) + perm_api_view = Permission.get_by_name("APIView") + role.add_permission(perm_api_view) + db.session.add(role) + + user.add_role(role, None) + + # Un utilisateur "other" n'ayant aucune permission sur l'API + other = User(user_name="other", nom="Sans", prenom="Permission", dept=dept.acronym) + other.set_password("other") + db.session.add(other) + db.session.commit() - return user + return user, other -def create_fake_etud(dept): +def create_fake_etud(dept: Departement) -> models.Identite: """Créé un faux étudiant et l'insère dans la base""" civilite = random.choice(("M", "F", "X")) nom, prenom = nomprenom(civilite) @@ -100,14 +116,18 @@ def create_fake_etud(dept): return etud -def create_etuds(dept, nb=16): +def create_etuds(dept: Departement, nb=16) -> list: "create nb etuds" return [create_fake_etud(dept) for _ in range(nb)] -def create_formsemestre(formation, user, semestre_idx=1): - """Create formsemestre and moduleimpls""" - formsemestre = models.FormSemestre( +def create_formsemestre( + formation: Formation, responsable: User, semestre_idx=1 +) -> FormSemestre: + """Create formsemestre and moduleimpls + responsable: resp. du formsemestre + """ + formsemestre = FormSemestre( dept_id=formation.dept_id, semestre_id=semestre_idx, titre="Semestre test", @@ -121,7 +141,9 @@ def create_formsemestre(formation, user, semestre_idx=1): # Crée un modulimpl par module de ce semestre: for module in formation.modules.filter_by(semestre_id=semestre_idx): modimpl = models.ModuleImpl( - module_id=module.id, formsemestre_id=formsemestre.id, responsable_id=user.id + module_id=module.id, + formsemestre_id=formsemestre.id, + responsable_id=responsable.id, ) db.session.add(modimpl) db.session.commit() @@ -132,7 +154,7 @@ def create_formsemestre(formation, user, semestre_idx=1): return formsemestre -def inscrit_etudiants(etuds, formsemestre): +def inscrit_etudiants(etuds: list, formsemestre: FormSemestre): """Inscrit les etudiants aux semestres et à tous ses modules""" for etud in etuds: sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( @@ -144,14 +166,38 @@ def inscrit_etudiants(etuds, formsemestre): ) -def init_test_database(): +def create_evaluations(formsemestre: FormSemestre): + "creation d'une evaluation dans cahque modimpl du semestre" + for modimpl in formsemestre.modimpls: + args = { + "moduleimpl_id": modimpl.id, + "jour": None, + "heure_debut": "8h00", + "heure_fin": "9h00", + "description": None, + "note_max": 20, + "coefficient": 1.0, + "visibulletin": True, + "publish_incomplete": True, + "evaluation_type": None, + "numero": None, + } + evaluation_id = sco_evaluation_db.do_evaluation_create(**args) + +def init_test_database(): + """Appelé par la commande `flask init-test-database` + + Création d'un département et de son contenu pour les tests + """ dept = init_departement("TAPI") - user = create_user(dept) - etuds = create_etuds(dept) - formation = import_formation() - formsemestre = create_formsemestre(formation, user) - inscrit_etudiants(etuds, formsemestre) + user_lecteur, user_autre = create_users(dept) + with sco_cache.DeferredSemCacheManager(): + etuds = create_etuds(dept) + formation = import_formation() + formsemestre = create_formsemestre(formation, user_lecteur) + create_evaluations(formsemestre) + inscrit_etudiants(etuds, formsemestre) # à compléter # - groupes # - absences From 443eb72687e99edd6bf9ef7941005909beaf0054 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 4 May 2022 23:12:03 +0200 Subject: [PATCH 4/4] API: test des permissions de toutes les routes GET (sauf logos) --- tests/api/test_api_permissions.py | 98 +++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/api/test_api_permissions.py diff --git a/tests/api/test_api_permissions.py b/tests/api/test_api_permissions.py new file mode 100644 index 00000000..aa80f36f --- /dev/null +++ b/tests/api/test_api_permissions.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +"""Test permissions + + On a deux utilisateurs dans la base test API: + - "test", avec le rôle LecteurAPI qui a APIView, + - et "other", qui n'a aucune permission. + + + Lancer : + pytest tests/api/test_api_permissions.py +""" + +import requests + +import flask +from tests.api.setup_test_api import API_URL, SCODOC_URL, CHECK_CERTIFICATE, api_headers +from tests.api.tools_test_api import verify_fields + +from app import create_app +from config import RunningConfig + + +def test_permissions(api_headers): + """ + vérification de la permissions APIView et du non accès sans role + de toutes les routes de l'API + """ + # Ce test va récupérer toutes les routes de l'API + app = create_app(RunningConfig) + assert app + # Les routes de l'API avec GET, excluant les logos pour le momeent XXX + api_rules = [ + r + for r in app.url_map.iter_rules() + if str(r).startswith("/ScoDoc/api") + and not "logo" in str(r) # ignore logos + and "GET" in r.methods + ] + assert len(api_rules) > 0 + args = { + "etudid": 1, + # "date_debut": + # "date_fin": + "dept": "TAPI", + "etape_apo": "???", + "etat": "I", + "evaluation_id": 1, + "formation_id": 1, + "formsemestre_id": 1, + "group_id": 1, + "ine": "1", + "module_id": 1, + "moduleimpl_id": 1, + "nip": 1, + "partition_id": 1, + } + for rule in api_rules: + path = rule.build(args)[1] + if not "GET" in rule.methods: + # skip all POST routes + continue + r = requests.get( + SCODOC_URL + path, + headers=api_headers, + verify=CHECK_CERTIFICATE, + ) + assert r.status_code == 200 + + # Même chose sans le jeton: + for rule in api_rules: + path = rule.build(args)[1] + if not "GET" in rule.methods: + # skip all POST routes + continue + r = requests.get( + SCODOC_URL + path, + verify=CHECK_CERTIFICATE, + ) + assert r.status_code == 401 + + # Demande un jeton pour "other" + r = requests.post(API_URL + "/tokens", auth=("other", "other")) + assert r.status_code == 200 + token = r.json()["token"] + headers = {"Authorization": f"Bearer {token}"} + # Vérifie que tout est interdit + for rule in api_rules: + path = rule.build(args)[1] + if not "GET" in rule.methods: + # skip all POST routes + continue + r = requests.get( + SCODOC_URL + path, + headers=headers, + verify=CHECK_CERTIFICATE, + ) + assert r.status_code == 403