forked from ScoDoc/ScoDoc
494 lines
14 KiB
Python
494 lines
14 KiB
Python
"""
|
|
Test de l'api justificatif
|
|
|
|
Ecrit par HARTMANN Matthias
|
|
|
|
"""
|
|
|
|
from random import randint
|
|
|
|
import requests
|
|
from tests.api.setup_test_api import (
|
|
API_URL,
|
|
CHECK_CERTIFICATE,
|
|
GET,
|
|
POST_JSON,
|
|
APIError,
|
|
api_headers,
|
|
api_admin_headers,
|
|
)
|
|
|
|
ETUDID = 1
|
|
FAUX = 42069
|
|
|
|
|
|
JUSTIFICATIFS_FIELDS = {
|
|
"justif_id": int,
|
|
"etudid": int,
|
|
"code_nip": str,
|
|
"date_debut": str,
|
|
"date_fin": str,
|
|
"etat": str,
|
|
"raison": str,
|
|
"entry_date": str,
|
|
"fichier": str,
|
|
"user_id": int,
|
|
"external_data": dict,
|
|
}
|
|
|
|
CREATE_FIELD = {"justif_id": int, "couverture": list}
|
|
BATCH_FIELD = {"errors": list, "success": list}
|
|
|
|
TO_REMOVE = []
|
|
|
|
|
|
def check_fields(data, fields: dict = None):
|
|
"""
|
|
Cette fonction permet de vérifier que le dictionnaire data
|
|
contient les bonnes clés et les bons types de valeurs.
|
|
|
|
Args:
|
|
data (dict): un dictionnaire (json de retour de l'api)
|
|
fields (dict, optional): Un dictionnaire représentant les clés et les types d'une réponse.
|
|
"""
|
|
if fields is None:
|
|
fields = JUSTIFICATIFS_FIELDS
|
|
assert set(data.keys()) == set(fields.keys())
|
|
for key in data:
|
|
if key in ("raison", "fichier", "user_id", "external_data"):
|
|
assert (
|
|
isinstance(data[key], fields[key]) or data[key] is None
|
|
), f"error [{key}:{type(data[key])}, {data[key]}, {fields[key]}]"
|
|
else:
|
|
assert isinstance(
|
|
data[key], fields[key]
|
|
), f"error [{key}:{type(data[key])}, {data[key]}, {fields[key]}]"
|
|
|
|
|
|
def check_failure_get(path, headers, err=None):
|
|
"""
|
|
Cette fonction vérifiée que la requête GET renvoie bien un 404
|
|
|
|
Args:
|
|
path (str): la route de l'api
|
|
headers (dict): le token d'auth de l'api
|
|
err (str, optional): L'erreur qui est sensée être fournie par l'api.
|
|
|
|
Raises:
|
|
APIError: Une erreur car la requête a fonctionné (mauvais comportement)
|
|
"""
|
|
try:
|
|
GET(path=path, headers=headers)
|
|
# ^ Renvoi un 404
|
|
except APIError as api_err:
|
|
if err is not None:
|
|
assert api_err.payload["message"] == err
|
|
else:
|
|
raise APIError("Le GET n'aurait pas du fonctionner")
|
|
|
|
|
|
def check_failure_post(path, headers, data, err=None):
|
|
"""
|
|
Cette fonction vérifiée que la requête POST renvoie bien un 404
|
|
|
|
Args:
|
|
path (str): la route de l'api
|
|
headers (dict): le token d'auth
|
|
data (dict): un dictionnaire (json) à envoyer
|
|
err (str, optional): L'erreur qui est sensée être fournie par l'api.
|
|
|
|
Raises:
|
|
APIError: Une erreur car la requête a fonctionné (mauvais comportement)
|
|
"""
|
|
try:
|
|
data = POST_JSON(path=path, headers=headers, data=data)
|
|
# ^ Renvoi un 404
|
|
except APIError as api_err:
|
|
if err is not None:
|
|
assert api_err.payload["message"] == err
|
|
else:
|
|
raise APIError("Le POST n'aurait pas du fonctionner")
|
|
|
|
|
|
def create_data(etat: str, day: str, raison: str = None):
|
|
"""
|
|
Permet de créer un dictionnaire assiduité
|
|
|
|
Args:
|
|
etat (str): l'état du justificatif (VALIDE,NON_VALIDE,MODIFIE, ATTENTE)
|
|
day (str): Le jour du justificatif
|
|
raison (str, optional): Une description du justificatif (eg: motif retard )
|
|
|
|
Returns:
|
|
dict: la représentation d'une assiduité
|
|
"""
|
|
data = {
|
|
"date_debut": f"2022-01-{day}T08:00",
|
|
"date_fin": f"2022-01-{day}T10:00",
|
|
"etat": etat,
|
|
}
|
|
if raison is not None:
|
|
data["desc"] = raison
|
|
|
|
return data
|
|
|
|
|
|
def test_route_justificatif(api_headers):
|
|
"""test de la route /justificatif/<justif_id:int>"""
|
|
|
|
# Bon fonctionnement == id connu
|
|
data = GET(path="/justificatif/1", headers=api_headers)
|
|
check_fields(data)
|
|
|
|
# Mauvais Fonctionnement == id inconnu
|
|
|
|
check_failure_get(
|
|
f"/justificatif/{FAUX}",
|
|
api_headers,
|
|
)
|
|
|
|
|
|
def test_route_justificatifs(api_headers):
|
|
"""test de la route /justificatifs/<etudid:int>"""
|
|
# Bon fonctionnement
|
|
|
|
data = GET(path=f"/justificatifs/{ETUDID}", headers=api_headers)
|
|
assert isinstance(data, list)
|
|
for just in data:
|
|
check_fields(just, JUSTIFICATIFS_FIELDS)
|
|
|
|
data = GET(path=f"/justificatifs/{ETUDID}/query?", headers=api_headers)
|
|
assert isinstance(data, list)
|
|
for just in data:
|
|
check_fields(just, JUSTIFICATIFS_FIELDS)
|
|
|
|
# Mauvais fonctionnement
|
|
check_failure_get(f"/justificatifs/{FAUX}", api_headers)
|
|
check_failure_get(f"/justificatifs/{FAUX}/query?", api_headers)
|
|
|
|
|
|
def test_route_create(api_admin_headers):
|
|
"""test de la route /justificatif/<justif_id:int>/create"""
|
|
# -== Unique ==-
|
|
|
|
# Bon fonctionnement
|
|
data = create_data("valide", "01")
|
|
|
|
res = POST_JSON(f"/justificatif/{ETUDID}/create", [data], api_admin_headers)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["success"]) == 1
|
|
|
|
TO_REMOVE.append(res["success"][0]["message"]["justif_id"])
|
|
|
|
data2 = create_data("modifie", "02", "raison")
|
|
res = POST_JSON(f"/justificatif/{ETUDID}/create", [data2], api_admin_headers)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["success"]) == 1
|
|
|
|
TO_REMOVE.append(res["success"][0]["message"]["justif_id"])
|
|
|
|
# Mauvais fonctionnement
|
|
check_failure_post(f"/justificatif/{FAUX}/create", api_admin_headers, [data])
|
|
|
|
res = POST_JSON(
|
|
f"/justificatif/{ETUDID}/create",
|
|
[create_data("absent", "03")],
|
|
api_admin_headers,
|
|
)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["errors"]) == 1
|
|
assert res["errors"][0]["message"] == "param 'etat': invalide"
|
|
|
|
# -== Multiple ==-
|
|
|
|
# Bon Fonctionnement
|
|
|
|
etats = ["valide", "modifie", "non_valide", "attente"]
|
|
data = [
|
|
create_data(etats[d % 4], 10 + d, "raison" if d % 2 else None)
|
|
for d in range(randint(3, 5))
|
|
]
|
|
|
|
res = POST_JSON(f"/justificatif/{ETUDID}/create", data, api_admin_headers)
|
|
check_fields(res, BATCH_FIELD)
|
|
for dat in res["success"]:
|
|
check_fields(dat["message"], CREATE_FIELD)
|
|
TO_REMOVE.append(dat["message"]["justif_id"])
|
|
|
|
# Mauvais Fonctionnement
|
|
|
|
data2 = [
|
|
create_data(None, "25"),
|
|
create_data("blabla", 26),
|
|
create_data("valide", 32),
|
|
]
|
|
|
|
res = POST_JSON(f"/justificatif/{ETUDID}/create", data2, api_admin_headers)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["errors"]) == 3
|
|
|
|
assert res["errors"][0]["message"] == "param 'etat': manquant"
|
|
assert res["errors"][1]["message"] == "param 'etat': invalide"
|
|
assert (
|
|
res["errors"][2]["message"]
|
|
== "param 'date_debut': format invalide, param 'date_fin': format invalide"
|
|
)
|
|
|
|
|
|
def test_route_edit(api_admin_headers):
|
|
"""test de la route /justificatif/<justif_id:int>/edit"""
|
|
# Bon fonctionnement
|
|
|
|
data = {"etat": "modifie", "raison": "test"}
|
|
res = POST_JSON(f"/justificatif/{TO_REMOVE[0]}/edit", data, api_admin_headers)
|
|
assert isinstance(res, dict) and "couverture" in res.keys()
|
|
|
|
data["raison"] = None
|
|
res = POST_JSON(f"/justificatif/{TO_REMOVE[1]}/edit", data, api_admin_headers)
|
|
assert isinstance(res, dict) and "couverture" in res.keys()
|
|
|
|
# Mauvais fonctionnement
|
|
|
|
check_failure_post(f"/justificatif/{FAUX}/edit", api_admin_headers, data)
|
|
data["etat"] = "blabla"
|
|
check_failure_post(
|
|
f"/justificatif/{TO_REMOVE[2]}/edit",
|
|
api_admin_headers,
|
|
data,
|
|
err="param 'etat': invalide",
|
|
)
|
|
|
|
|
|
def test_route_delete(api_admin_headers):
|
|
"""test de la route /justificatif/delete"""
|
|
# -== Unique ==-
|
|
|
|
# Bon fonctionnement
|
|
data = TO_REMOVE[0]
|
|
|
|
res = POST_JSON("/justificatif/delete", [data], api_admin_headers)
|
|
check_fields(res, BATCH_FIELD)
|
|
for dat in res["success"]:
|
|
assert dat["message"] == "OK"
|
|
|
|
# Mauvais fonctionnement
|
|
res = POST_JSON("/justificatif/delete", [data], api_admin_headers)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["errors"]) == 1
|
|
|
|
# -== Multiple ==-
|
|
|
|
# Bon Fonctionnement
|
|
|
|
data = TO_REMOVE[1:]
|
|
|
|
res = POST_JSON("/justificatif/delete", data, api_admin_headers)
|
|
check_fields(res, BATCH_FIELD)
|
|
for dat in res["success"]:
|
|
assert dat["message"] == "OK"
|
|
|
|
# Mauvais Fonctionnement
|
|
|
|
data2 = [
|
|
FAUX,
|
|
FAUX + 1,
|
|
FAUX + 2,
|
|
]
|
|
|
|
res = POST_JSON("/justificatif/delete", data2, api_admin_headers)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["errors"]) == 3
|
|
|
|
assert all(i["message"] == "Justificatif non existant" for i in res["errors"])
|
|
|
|
|
|
# Gestion de l'archivage
|
|
|
|
|
|
def _send_file(justif_id: int, filename: str, headers):
|
|
"""
|
|
Envoi un fichier vers la route d'importation
|
|
"""
|
|
with open(filename, "rb") as file:
|
|
url: str = API_URL + f"/justificatif/{justif_id}/import"
|
|
req = requests.post(
|
|
url,
|
|
files={filename: file},
|
|
headers=headers,
|
|
verify=CHECK_CERTIFICATE,
|
|
timeout=30,
|
|
)
|
|
|
|
if req.status_code != 200:
|
|
raise APIError(f"erreur status={req.status_code} !", req.json())
|
|
|
|
return req.json()
|
|
|
|
|
|
def _check_failure_send(
|
|
justif_id: int,
|
|
headers,
|
|
filename: str = "tests/api/test_api_justificatif.txt",
|
|
err: str = None,
|
|
):
|
|
"""
|
|
Vérifie si l'envoie d'un fichier renvoie bien un 404
|
|
|
|
Args:
|
|
justif_id (int): l'id du justificatif
|
|
headers (dict): token d'auth de l'api
|
|
filename (str, optional): le chemin vers le fichier.
|
|
Defaults to "tests/api/test_api_justificatif.txt".
|
|
err (str, optional): l'erreur attendue.
|
|
|
|
Raises:
|
|
APIError: Si l'envoie fonction (mauvais comportement)
|
|
"""
|
|
try:
|
|
_send_file(justif_id, filename, headers)
|
|
# ^ Renvoi un 404
|
|
except APIError as api_err:
|
|
if err is not None:
|
|
assert api_err.payload["message"] == err
|
|
else:
|
|
raise APIError("Le POST n'aurait pas du fonctionner")
|
|
|
|
|
|
def test_import_justificatif(api_admin_headers):
|
|
"""test de la route /justificatif/<justif_id:int>/import"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
filename: str = "tests/api/test_api_justificatif.txt"
|
|
|
|
resp: dict = _send_file(1, filename, api_admin_headers)
|
|
assert "filename" in resp
|
|
assert resp["filename"] == "test_api_justificatif.txt"
|
|
|
|
filename: str = "tests/api/test_api_justificatif2.txt"
|
|
resp: dict = _send_file(1, filename, api_admin_headers)
|
|
assert "filename" in resp
|
|
assert resp["filename"] == "test_api_justificatif2.txt"
|
|
|
|
# Mauvais fonctionnement
|
|
|
|
_check_failure_send(FAUX, api_admin_headers)
|
|
|
|
|
|
def test_list_justificatifs(api_admin_headers):
|
|
"""test de la route /justificatif/<justif_id:int>/list"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
res: list = GET("/justificatif/1/list", api_admin_headers)
|
|
|
|
assert isinstance(res, dict)
|
|
assert len(res["filenames"]) == 2
|
|
assert res["total"] == 2
|
|
|
|
res: list = GET("/justificatif/2/list", api_admin_headers)
|
|
|
|
assert isinstance(res, dict)
|
|
assert len(res["filenames"]) == 0
|
|
assert res["total"] == 0
|
|
|
|
# Mauvais fonctionnement
|
|
|
|
check_failure_get(f"/justificatif/{FAUX}/list", api_admin_headers)
|
|
|
|
|
|
def _post_export(justif_id: int, fname: str, api_headers):
|
|
"""
|
|
Envoie une requête poste sans data et la retourne
|
|
|
|
Args:
|
|
id (int): justif_id
|
|
fname (str): nom du fichier (coté serv)
|
|
api_headers (dict): token auth de l'api
|
|
|
|
Returns:
|
|
request: la réponse de l'api
|
|
"""
|
|
url: str = API_URL + f"/justificatif/{justif_id}/export/{fname}"
|
|
res = requests.post(url, headers=api_headers)
|
|
return res
|
|
|
|
|
|
def test_export(api_admin_headers):
|
|
"""test de la route /justificatif/<justif_id:int>/export/<filename:str>"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
assert (
|
|
_post_export(1, "test_api_justificatif.txt", api_admin_headers).status_code
|
|
== 200
|
|
)
|
|
|
|
# Mauvais fonctionnement
|
|
assert (
|
|
_post_export(FAUX, "test_api_justificatif.txt", api_admin_headers).status_code
|
|
== 404
|
|
)
|
|
assert _post_export(1, "blabla.txt", api_admin_headers).status_code == 404
|
|
assert _post_export(2, "blabla.txt", api_admin_headers).status_code == 404
|
|
|
|
|
|
def test_remove_justificatif(api_admin_headers):
|
|
"""test de la route /justificatif/<justif_id:int>/remove"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
filename: str = "tests/api/test_api_justificatif.txt"
|
|
_send_file(2, filename, api_admin_headers)
|
|
filename: str = "tests/api/test_api_justificatif2.txt"
|
|
_send_file(2, filename, api_admin_headers)
|
|
|
|
res: dict = POST_JSON(
|
|
"/justificatif/1/remove", {"remove": "all"}, api_admin_headers
|
|
)
|
|
assert res == {"response": "removed"}
|
|
l = GET("/justificatif/1/list", api_admin_headers)
|
|
assert isinstance(l, dict)
|
|
assert l["total"] == 0
|
|
|
|
res: dict = POST_JSON(
|
|
"/justificatif/2/remove",
|
|
{"remove": "list", "filenames": ["test_api_justificatif2.txt"]},
|
|
api_admin_headers,
|
|
)
|
|
assert res == {"response": "removed"}
|
|
l = GET("/justificatif/2/list", api_admin_headers)
|
|
assert isinstance(l, dict)
|
|
assert l["total"] == 1
|
|
|
|
res: dict = POST_JSON(
|
|
"/justificatif/2/remove",
|
|
{"remove": "list", "filenames": ["test_api_justificatif.txt"]},
|
|
api_admin_headers,
|
|
)
|
|
assert res == {"response": "removed"}
|
|
l = GET("/justificatif/2/list", api_admin_headers)
|
|
assert isinstance(l, dict)
|
|
assert l["total"] == 0
|
|
|
|
# Mauvais fonctionnement
|
|
|
|
check_failure_post("/justificatif/2/remove", api_admin_headers, {})
|
|
check_failure_post(
|
|
f"/justificatif/{FAUX}/remove", api_admin_headers, {"remove": "all"}
|
|
)
|
|
check_failure_post("/justificatif/1/remove", api_admin_headers, {"remove": "all"})
|
|
|
|
|
|
def test_justifies(api_admin_headers):
|
|
"""test la route /justificatif/<justif_id:int>/justifies"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
res: list = GET("/justificatif/1/justifies", api_admin_headers)
|
|
assert isinstance(res, list)
|
|
|
|
# Mauvais fonctionnement
|
|
|
|
check_failure_get(f"/justificatif/{FAUX}/justifies", api_admin_headers)
|