Automatise les tests unitaires de l'API

This commit is contained in:
Emmanuel Viennet 2022-12-07 13:22:11 +01:00
parent d36004abfe
commit 1ea782102b
8 changed files with 167 additions and 106 deletions

View File

@ -16,10 +16,10 @@ La version 9.0 s'efforce de reproduire presque à l'identique le fonctionnement
de ScoDoc7, avec des composants logiciels différents (Debian 11, Python 3,
Flask, SQLAlchemy, au lien de Python2/Zope dans les versions précédentes).
### État actuel (nov 22)
### État actuel (dec 22)
- 9.3.x est en production
- le prochain jalon est 9.4. Voir branches sur gitea.
- 9.4.x est en production
- le prochain jalon est 9.5. Voir branches sur gitea.
### Lignes de commandes

View File

@ -48,6 +48,7 @@ from app.scodoc.sco_permissions import Permission
@scodoc
@permission_required(Permission.ScoSuperAdmin)
def api_get_glob_logos():
"""Liste tous les logos"""
logos = list_logos()[None]
return jsonify(list(logos.keys()))

View File

@ -1,28 +1,44 @@
# Tests unitaires de l'API ScoDoc
Démarche générale:
## Lancement des tests
La première fois, copier le fichier `tests/api/dotenv_exemple` vers
`tests/api/.env`. Il est normalement inutile de modifier son contenu.
Dans un shell, lancer le script `start_api_server.py`, qui se charge
d'initialiser une base SQL de test et de lancer le serveur ScoDoc approprié.
```bash
tests/api/start_api_server.sh
```
Dans un autre shell, lancer les tests:
```bash
pytest tests/api
```
## Notes sur la démarche
1. On génère une base SQL de test: voir
`tools/fakedatabase/create_test_api_database.py`
1. modifier `/opt/scodoc/.env` pour indiquer
```bash
FLASK_ENV=test_api
FLASK_DEBUG=1
```
2. En tant qu'utilisateur scodoc, lancer:
1. En tant qu'utilisateur scodoc, lancer:
```bash
# evite de modifier /opt/scodoc/.env
export FLASK_ENV=test_api
export FLASK_DEBUG=1
tools/create_database.sh --drop SCODOC_TEST_API
flask db upgrade
flask sco-db-init --erase
flask init-test-database
```
en plus court: ```bash
tools/create_database.sh --drop SCODOC_TEST_API && flask db upgrade &&flask sco-db-init --erase && flask init-test-database
en plus court:
```bash
export FLASK_ENV=test_api && tools/create_database.sh --drop SCODOC_TEST_API && flask db upgrade &&flask sco-db-init --erase && flask init-test-database
```
2. On lance le serveur ScoDoc sur cette base

View File

@ -9,3 +9,6 @@ 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
API_USER="lecteur_api"
API_PASSWORD="azerty"

25
tests/api/start_api_server.sh Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash
# Script recreating the TEST API database and starting the serveur
set -e
# Le répertoire de ce script:
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# récupère API_USER et API_PASSWORD
source "$SCRIPT_DIR"/.env
export FLASK_ENV=test_api
export FLASK_DEBUG=1
tools/create_database.sh --drop SCODOC_TEST_API
flask db upgrade
flask sco-db-init --erase
flask init-test-database
flask user-create "$API_USER" LecteurAPI @all
flask user-password --password "$API_PASSWORD" "$API_USER"
flask edit-role LecteurAPI -a ScoView
flask user-role "$API_USER" -a LecteurAPI
flask run --host 0.0.0.0

View File

@ -76,7 +76,6 @@ def test_etudiants_courant(api_headers):
etud = etudiants[-1]
assert verify_fields(etud, fields) is True
assert etud["id"] == etud["etudid"]
assert isinstance(etud["id"], int)
assert isinstance(etud["code_nip"], str)
assert isinstance(etud["nom"], str)

View File

@ -13,8 +13,13 @@ utilisation:
# XXX TODO
# Ce test a une logique très différente des autres : A UNIFIER
from tests.api.setup_test_api import API_URL, api_admin_headers, api_headers
import requests
from tests.api.setup_test_api import (
API_URL,
api_admin_headers,
api_headers,
CHECK_CERTIFICATE,
)
from scodoc import app
from tests.unit.config_test_logos import (
@ -30,30 +35,24 @@ def test_super_access(api_admin_headers):
"""
Route: /logos
"""
headers = api_admin_headers
with app.test_client(api_admin_headers) as client:
response = client.get(API_URL + "/logos", headers=headers)
response = requests.get(
API_URL + "/logos",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.json is not None
def test_admin_access(api_headers):
"""
Route: /logos
"""
headers = api_headers
with app.test_client() as client:
response = client.get(API_URL + "/logos", headers=headers)
assert response.status_code == 401
assert response.json() is not None
def test_lambda_access(api_headers):
"""
Route: /logos
"""
headers = api_headers
with app.test_client() as client:
response = client.get(API_URL + "/logos", headers=headers)
response = requests.get(
API_URL + "/logos",
headers=api_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 401
@ -61,50 +60,58 @@ def test_global_logos(api_admin_headers):
"""
Route:
"""
headers = api_admin_headers
with app.test_client() as client:
response = client.get(API_URL + "/logos", headers=headers)
response = requests.get(
API_URL + "/logos",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.json is not None
assert "header" in response.json
assert "footer" in response.json
assert "B" in response.json
assert "C" in response.json
assert response.json() is not None
assert "header" in response.json()
assert "footer" in response.json()
assert "B" in response.json()
assert "C" in response.json()
def test_local_by_id_logos(api_admin_headers):
"""
Route: /departement/id/1/logos
"""
headers = api_admin_headers
with app.test_client() as client:
response = client.get(API_URL + "/departement/id/1/logos", headers=headers)
response = requests.get(
API_URL + "/departement/id/1/logos",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.json is not None
assert "A" in response.json
assert "D" in response.json
assert response.json() is not None
assert "A" in response.json()
assert "D" in response.json()
def test_local_by_name_logos(api_admin_headers):
"""
Route: /departement/TAPI/logos
"""
headers = api_admin_headers
with app.test_client() as client:
response = client.get(API_URL + "/departement/TAPI/logos", headers=headers)
response = requests.get(
API_URL + "/departement/TAPI/logos",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.json is not None
assert "A" in response.json
assert "D" in response.json
assert response.json() is not None
assert "A" in response.json()
assert "D" in response.json()
def test_local_png_by_id_logo(api_admin_headers):
"""
Route: /departement/id/1/logo/D
"""
headers = api_admin_headers
with app.test_client() as client:
response = client.get(API_URL + "/departement/id/1/logo/D", headers=headers)
response = requests.get(
API_URL + "/departement/id/1/logo/D",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.headers["Content-Type"] == "image/png"
assert response.headers["Content-Disposition"].startswith("inline")
@ -115,9 +122,11 @@ def test_global_png_logo(api_admin_headers):
"""
Route: /logo/C
"""
headers = api_admin_headers
with app.test_client() as client:
response = client.get(API_URL + "/logo/C", headers=headers)
response = requests.get(
API_URL + "/logo/C",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.headers["Content-Type"] == "image/png"
assert response.headers["Content-Disposition"].startswith("inline")
@ -128,9 +137,11 @@ def test_global_jpg_logo(api_admin_headers):
"""
Route: /logo/B
"""
headers = api_admin_headers
with app.test_client() as client:
response = client.get(API_URL + "/logo/B", headers=headers)
response = requests.get(
API_URL + "/logo/B",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.headers["Content-Type"] == "image/jpg"
assert response.headers["Content-Disposition"].startswith("inline")
@ -139,11 +150,13 @@ def test_global_jpg_logo(api_admin_headers):
def test_local_png_by_name_logo(api_admin_headers):
"""
Route: /departement/TAPI/logo/A
Route: /departement/TAPI/logo/D
"""
headers = api_admin_headers
with app.test_client() as client:
response = client.get(API_URL + "/departement/TAPI/logo/D", headers=headers)
response = requests.get(
API_URL + "/departement/TAPI/logo/D",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.headers["Content-Type"] == "image/png"
assert response.headers["Content-Disposition"].startswith("inline")
@ -152,11 +165,13 @@ def test_local_png_by_name_logo(api_admin_headers):
def test_local_jpg_by_id_logo(api_admin_headers):
"""
Route: /departement/id/1/logo/D
Route: /departement/id/1/logo/A
"""
headers = api_admin_headers
with app.test_client() as client:
response = client.get(API_URL + "/departement/id/1/logo/A", headers=headers)
response = requests.get(
API_URL + "/departement/id/1/logo/A",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.headers["Content-Type"] == "image/jpg"
assert response.headers["Content-Disposition"].startswith("inline")
@ -167,9 +182,11 @@ def test_local_jpg_by_name_logo(api_admin_headers):
"""
Route: /departement/TAPI/logo/A
"""
headers = api_admin_headers
with app.test_client() as client:
response = client.get(API_URL + "/departement/TAPI/logo/A", headers=headers)
response = requests.get(
API_URL + "/departement/TAPI/logo/A",
headers=api_admin_headers,
verify=CHECK_CERTIFICATE,
)
assert response.status_code == 200
assert response.headers["Content-Type"] == "image/jpg"
assert response.headers["Content-Disposition"].startswith("inline")

View File

@ -15,7 +15,7 @@ if [ "$1" = "--drop" ]
then
db_name="$2"
echo "Dropping database $db_name..."
dropdb "$db_name"
dropdb --if-exists "$db_name"
else
db_name="$1"
fi