forked from ScoDoc/ScoDoc
466 lines
13 KiB
Python
466 lines
13 KiB
Python
"""
|
|
Test de l'api Assiduité
|
|
|
|
Ecrit par HARTMANN Matthias
|
|
|
|
"""
|
|
|
|
import datetime
|
|
from random import randint
|
|
import re
|
|
from types import NoneType
|
|
|
|
from app.scodoc import sco_utils as scu
|
|
from tests.api.setup_test_api import (
|
|
GET,
|
|
POST,
|
|
DEPT_ACRONYM,
|
|
APIError,
|
|
api_headers,
|
|
api_admin_headers,
|
|
check_failure_get,
|
|
check_failure_post,
|
|
check_fields,
|
|
)
|
|
|
|
ETUDID = 1
|
|
FAUX = 42069
|
|
FORMSEMESTREID = 1
|
|
MODULE = 1
|
|
|
|
|
|
ASSIDUITES_FIELDS = {
|
|
"assiduite_id": int,
|
|
"etudid": int,
|
|
"code_nip": str,
|
|
"moduleimpl_id": int,
|
|
"date_debut": str,
|
|
"date_fin": str,
|
|
"etat": str,
|
|
"desc": str,
|
|
"entry_date": str,
|
|
"user_id": (int, NoneType),
|
|
"user_name": (str, NoneType),
|
|
"user_nom_complet": (str, NoneType),
|
|
"est_just": bool,
|
|
"external_data": dict,
|
|
}
|
|
|
|
ASSIDUITES_EVALUATIONS_FIELDS = {"evaluation_id": int, "assiduites": list}
|
|
|
|
CREATE_FIELD = {"assiduite_id": int}
|
|
BATCH_FIELD = {"errors": list, "success": list}
|
|
|
|
COUNT_FIELDS = {"compte": int, "journee": int, "demi": int, "heure": int | float}
|
|
|
|
TO_REMOVE = []
|
|
|
|
|
|
def create_data(etat: str, day: str, module: int = None, desc: str = None):
|
|
"""
|
|
Permet de créer un dictionnaire assiduité
|
|
|
|
Args:
|
|
etat (str): l'état de l'assiduité (PRESENT,ABSENT,RETARD)
|
|
day (str): Le jour de l'assiduité
|
|
module (int, optional): Le moduleimpl_id associé
|
|
desc (str, optional): Une description de l'assiduité (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 module is not None:
|
|
data["moduleimpl_id"] = module
|
|
if desc is not None:
|
|
data["desc"] = desc
|
|
|
|
return data
|
|
|
|
|
|
def test_route_assiduite(api_headers):
|
|
"""test de la route /assiduite/<assiduite_id:int>"""
|
|
|
|
# Bon fonctionnement == id connu
|
|
data = GET(path="/assiduite/1", headers=api_headers, dept=DEPT_ACRONYM)
|
|
check_fields(data, fields=ASSIDUITES_FIELDS)
|
|
|
|
# Mauvais Fonctionnement == id inconnu
|
|
|
|
check_failure_get(
|
|
f"/assiduite/{FAUX}",
|
|
api_headers,
|
|
)
|
|
|
|
|
|
def test_route_assiduites_count(api_headers):
|
|
"""test de la route /assiduites/<etudid:int>/count"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
data = GET(
|
|
path=f"/assiduites/{ETUDID}/count", headers=api_headers, dept=DEPT_ACRONYM
|
|
)
|
|
check_fields(data, COUNT_FIELDS)
|
|
|
|
metrics = {"heure", "compte"}
|
|
data = GET(
|
|
path=f"/assiduites/{ETUDID}/count/query?metric={','.join(metrics)}",
|
|
headers=api_headers,
|
|
dept=DEPT_ACRONYM,
|
|
)
|
|
|
|
assert set(data.keys()) == metrics
|
|
|
|
# Mauvais fonctionnement
|
|
|
|
check_failure_get(f"/assiduites/{FAUX}/count", api_headers)
|
|
|
|
|
|
def test_route_assiduites(api_headers):
|
|
"""test de la route /assiduites/<etudid:int>"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
data = GET(path=f"/assiduites/{ETUDID}", headers=api_headers, dept=DEPT_ACRONYM)
|
|
assert isinstance(data, list)
|
|
for ass in data:
|
|
check_fields(ass, ASSIDUITES_FIELDS)
|
|
|
|
data = GET(
|
|
path=f"/assiduites/{ETUDID}/query?", headers=api_headers, dept=DEPT_ACRONYM
|
|
)
|
|
assert isinstance(data, list)
|
|
for ass in data:
|
|
check_fields(ass, ASSIDUITES_FIELDS)
|
|
|
|
# Mauvais fonctionnement
|
|
check_failure_get(f"/assiduites/{FAUX}", api_headers)
|
|
check_failure_get(f"/assiduites/{FAUX}/query?", api_headers)
|
|
|
|
|
|
def test_route_assiduites_evaluations(api_headers):
|
|
"""test de la route /assiduites/<etudid:int>/evaluations"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
data = GET(
|
|
path=f"/assiduites/{ETUDID}/evaluations", headers=api_headers, dept=DEPT_ACRONYM
|
|
)
|
|
assert isinstance(data, list)
|
|
for evals in data:
|
|
check_fields(evals, ASSIDUITES_EVALUATIONS_FIELDS)
|
|
for assi in evals["assiduites"]:
|
|
check_fields(assi, ASSIDUITES_FIELDS)
|
|
|
|
# Mauvais fonctionnement
|
|
check_failure_get(f"/assiduites/{FAUX}/evaluations", api_headers)
|
|
|
|
|
|
def test_route_evaluations_assiduites(api_headers):
|
|
"""test de la route /evaluation/<int:evaluation_id>/assiduites"""
|
|
|
|
# Bon fonctionnement
|
|
evaluation_id = 1
|
|
data = GET(
|
|
path=f"/evaluation/{evaluation_id}/assiduites",
|
|
headers=api_headers,
|
|
dept=DEPT_ACRONYM,
|
|
)
|
|
assert isinstance(data, dict)
|
|
for key, val in data.items():
|
|
assert isinstance(key, str), "Erreur les clés ne sont pas des strings"
|
|
assert isinstance(val, list), "Erreur, les valeurs ne sont pas des listes"
|
|
|
|
for assi in val:
|
|
check_fields(assi, ASSIDUITES_FIELDS)
|
|
|
|
# Mauvais fonctionnement
|
|
check_failure_get(f"/evaluation/{FAUX}/assiduites", api_headers)
|
|
|
|
|
|
def test_route_formsemestre_assiduites(api_headers):
|
|
"""test de la route /assiduites/formsemestre/<formsemestre_id:int>"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
data = GET(
|
|
path=f"/assiduites/formsemestre/{FORMSEMESTREID}",
|
|
headers=api_headers,
|
|
dept=DEPT_ACRONYM,
|
|
)
|
|
assert isinstance(data, list)
|
|
for ass in data:
|
|
check_fields(ass, ASSIDUITES_FIELDS)
|
|
|
|
data = GET(
|
|
path=f"/assiduites/formsemestre/{FORMSEMESTREID}/query?",
|
|
headers=api_headers,
|
|
dept=DEPT_ACRONYM,
|
|
)
|
|
assert isinstance(data, list)
|
|
for ass in data:
|
|
check_fields(ass, ASSIDUITES_FIELDS)
|
|
|
|
# Mauvais fonctionnement
|
|
check_failure_get(
|
|
f"/assiduites/formsemestre/{FAUX}",
|
|
api_headers,
|
|
err="le paramètre 'formsemestre_id' n'existe pas",
|
|
)
|
|
check_failure_get(
|
|
f"/assiduites/formsemestre/{FAUX}/query?",
|
|
api_headers,
|
|
err="le paramètre 'formsemestre_id' n'existe pas",
|
|
)
|
|
|
|
|
|
def test_route_count_formsemestre_assiduites(api_headers):
|
|
"""test de la route /assiduites/formsemestre/<formsemestre_id:int>/count"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
data = GET(
|
|
path=f"/assiduites/formsemestre/{FORMSEMESTREID}/count",
|
|
headers=api_headers,
|
|
dept=DEPT_ACRONYM,
|
|
)
|
|
|
|
print("data: ", data)
|
|
|
|
check_fields(data, COUNT_FIELDS)
|
|
metrics = {"heure", "compte"}
|
|
data = GET(
|
|
path=f"/assiduites/formsemestre/{FORMSEMESTREID}/count/query?metric={','.join(metrics)}",
|
|
headers=api_headers,
|
|
dept=DEPT_ACRONYM,
|
|
)
|
|
assert set(data.keys()) == metrics
|
|
|
|
# Mauvais fonctionnement
|
|
check_failure_get(
|
|
f"/assiduites/formsemestre/{FAUX}/count",
|
|
api_headers,
|
|
err="le paramètre 'formsemestre_id' n'existe pas",
|
|
)
|
|
check_failure_get(
|
|
f"/assiduites/formsemestre/{FAUX}/count/query?",
|
|
api_headers,
|
|
err="le paramètre 'formsemestre_id' n'existe pas",
|
|
)
|
|
|
|
|
|
def test_route_create(api_admin_headers):
|
|
"""test de la route /assiduite/<etudid:int>/create"""
|
|
|
|
# -== Unique ==-
|
|
|
|
# Bon fonctionnement
|
|
data = create_data("present", "03")
|
|
|
|
res = POST(
|
|
f"/assiduite/{ETUDID}/create", [data], api_admin_headers, dept=DEPT_ACRONYM
|
|
)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["success"]) == 1
|
|
TO_REMOVE.append(res["success"][0]["message"]["assiduite_id"])
|
|
data_get = GET(
|
|
path=f'/assiduite/{res["success"][0]["message"]["assiduite_id"]}',
|
|
headers=api_admin_headers,
|
|
dept=DEPT_ACRONYM,
|
|
)
|
|
check_fields(data_get, fields=ASSIDUITES_FIELDS)
|
|
# la date de début est sans fournie sans timezone, mais celle renvoyé avec.
|
|
# Compare en ajoutant la timezone serveur:
|
|
assert scu.localize_datetime(
|
|
datetime.datetime.fromisoformat(data["date_debut"])
|
|
) == datetime.datetime.fromisoformat(data_get["date_debut"])
|
|
|
|
# Création avec timezone (comme le fait assiduite.js)
|
|
data["date_debut"] = "2024-10-28T10:00:00.000Z"
|
|
data["date_fin"] = "2024-10-28T12:00:00.000Z"
|
|
res = POST(
|
|
f"/assiduite/{ETUDID}/create", [data], api_admin_headers, dept=DEPT_ACRONYM
|
|
)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["success"]) == 1
|
|
TO_REMOVE.append(res["success"][0]["message"]["assiduite_id"])
|
|
data_get = GET(
|
|
path=f'/assiduite/{res["success"][0]["message"]["assiduite_id"]}',
|
|
headers=api_admin_headers,
|
|
dept=DEPT_ACRONYM,
|
|
)
|
|
check_fields(data_get, fields=ASSIDUITES_FIELDS)
|
|
assert scu.localize_datetime(
|
|
datetime.datetime.fromisoformat(data["date_debut"])
|
|
) == datetime.datetime.fromisoformat(data_get["date_debut"])
|
|
|
|
# Absence avec module
|
|
data2 = create_data("absent", "04", MODULE, "desc")
|
|
res = POST(
|
|
f"/assiduite/{ETUDID}/create", [data2], api_admin_headers, dept=DEPT_ACRONYM
|
|
)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["success"]) == 1
|
|
|
|
TO_REMOVE.append(res["success"][0]["message"]["assiduite_id"])
|
|
|
|
# Mauvais fonctionnement
|
|
check_failure_post(f"/assiduite/{FAUX}/create", api_admin_headers, [data])
|
|
|
|
res = POST(
|
|
f"/assiduite/{ETUDID}/create", [data], api_admin_headers, dept=DEPT_ACRONYM
|
|
)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["errors"]) == 1
|
|
assert (
|
|
res["errors"][0]["message"]
|
|
== "Duplication: la période rentre en conflit avec une plage enregistrée"
|
|
)
|
|
|
|
res = POST(
|
|
f"/assiduite/{ETUDID}/create",
|
|
[create_data("absent", "05", FAUX)],
|
|
api_admin_headers,
|
|
dept=DEPT_ACRONYM,
|
|
)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["errors"]) == 1
|
|
assert res["errors"][0]["message"] == "param 'moduleimpl_id': invalide"
|
|
|
|
# -== Multiple ==-
|
|
|
|
# Bon Fonctionnement
|
|
|
|
etats = ["present", "absent", "retard"]
|
|
data = [
|
|
create_data(etats[d % 3], 10 + d, MODULE if d % 2 else None)
|
|
for d in range(randint(2, 4))
|
|
]
|
|
|
|
res = POST(
|
|
f"/assiduite/{ETUDID}/create", data, api_admin_headers, dept=DEPT_ACRONYM
|
|
)
|
|
check_fields(res, BATCH_FIELD)
|
|
for dat in res["success"]:
|
|
check_fields(dat["message"], CREATE_FIELD)
|
|
TO_REMOVE.append(dat["message"]["assiduite_id"])
|
|
|
|
# Mauvais Fonctionnement
|
|
|
|
data2 = [
|
|
create_data("present", "03"),
|
|
create_data("present", "25", FAUX),
|
|
create_data("blabla", 26),
|
|
create_data("absent", 32),
|
|
create_data("absent", "01"),
|
|
]
|
|
|
|
res = POST(
|
|
f"/assiduite/{ETUDID}/create", data2, api_admin_headers, dept=DEPT_ACRONYM
|
|
)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["errors"]) == 5
|
|
|
|
assert (
|
|
res["errors"][0]["message"]
|
|
== "Duplication: la période rentre en conflit avec une plage enregistrée"
|
|
)
|
|
assert res["errors"][1]["message"] == "param 'moduleimpl_id': invalide"
|
|
assert res["errors"][2]["message"] == "param 'etat': invalide"
|
|
assert (
|
|
res["errors"][3]["message"]
|
|
== "param 'date_debut': format invalide, param 'date_fin': format invalide"
|
|
)
|
|
assert res["errors"][4]["message"] == "La date de début n'est pas un jour travaillé"
|
|
|
|
|
|
def test_route_edit(api_admin_headers):
|
|
"""test de la route /assiduite/<assiduite_id:int>/edit"""
|
|
|
|
# Bon fonctionnement
|
|
|
|
data = {"etat": "retard", "moduleimpl_id": MODULE}
|
|
res = POST(
|
|
f"/assiduite/{TO_REMOVE[0]}/edit", data, api_admin_headers, dept=DEPT_ACRONYM
|
|
)
|
|
assert res == {"OK": True}
|
|
|
|
data["moduleimpl_id"] = None
|
|
res = POST(
|
|
f"/assiduite/{TO_REMOVE[1]}/edit", data, api_admin_headers, dept=DEPT_ACRONYM
|
|
)
|
|
assert res == {"OK": True}
|
|
|
|
# Mauvais fonctionnement
|
|
|
|
check_failure_post(f"/assiduite/{FAUX}/edit", api_admin_headers, data)
|
|
data["etat"] = "blabla"
|
|
check_failure_post(
|
|
f"/assiduite/{TO_REMOVE[2]}/edit",
|
|
api_admin_headers,
|
|
data,
|
|
err="param 'etat': invalide",
|
|
)
|
|
|
|
|
|
def test_route_delete(api_admin_headers):
|
|
"""test de la route /assiduite/delete"""
|
|
# -== Unique ==-
|
|
|
|
# Bon fonctionnement
|
|
data = TO_REMOVE[0]
|
|
|
|
res = POST("/assiduite/delete", [data], api_admin_headers, dept=DEPT_ACRONYM)
|
|
check_fields(res, BATCH_FIELD)
|
|
for dat in res["success"]:
|
|
assert dat["message"] == "OK"
|
|
|
|
# Mauvais fonctionnement
|
|
res = POST("/assiduite/delete", [data], api_admin_headers, dept=DEPT_ACRONYM)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["errors"]) == 1
|
|
|
|
# -== Multiple ==-
|
|
|
|
# Bon Fonctionnement
|
|
|
|
data = TO_REMOVE[1:]
|
|
|
|
res = POST("/assiduite/delete", data, api_admin_headers, dept=DEPT_ACRONYM)
|
|
check_fields(res, BATCH_FIELD)
|
|
for dat in res["success"]:
|
|
assert dat["message"] == "OK"
|
|
|
|
# Mauvais Fonctionnement
|
|
|
|
data2 = [
|
|
FAUX,
|
|
FAUX + 1,
|
|
FAUX + 2,
|
|
]
|
|
|
|
res = POST("/assiduite/delete", data2, api_admin_headers, dept=DEPT_ACRONYM)
|
|
check_fields(res, BATCH_FIELD)
|
|
assert len(res["errors"]) == 3
|
|
|
|
assert all(i["message"] == "Assiduite non existante" for i in res["errors"])
|
|
|
|
|
|
def test_date_time_offset(api_headers):
|
|
"""test de la route /assiduites/date_time_offset"""
|
|
|
|
reply = GET(
|
|
path="/assiduite/date_time_offset/2024-10-29",
|
|
headers=api_headers,
|
|
dept=DEPT_ACRONYM,
|
|
raw=True,
|
|
)
|
|
# offset ISO 8601 de la forme +/-hh:mm
|
|
assert re.match(r"^(Z|[+-]\d{2}:\d{2})$", reply.text)
|