From 1ea782102b55916c2cb8ef98cc63b582ecbe01cb Mon Sep 17 00:00:00 2001
From: Emmanuel Viennet <emmanuel.viennet@gmail.com>
Date: Wed, 7 Dec 2022 13:22:11 +0100
Subject: [PATCH] Automatise les tests unitaires de l'API
---
README.md | 6 +-
app/api/logos.py | 1 +
tests/api/README.md | 38 +++++--
tests/api/dotenv_exemple | 7 +-
tests/api/start_api_server.sh | 25 +++++
tests/api/test_api_etudiants.py | 1 -
tests/api/test_api_logos.py | 193 +++++++++++++++++---------------
tools/create_database.sh | 2 +-
8 files changed, 167 insertions(+), 106 deletions(-)
create mode 100755 tests/api/start_api_server.sh
diff --git a/README.md b/README.md
index 3cfbf39de..6c79f8bba 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/app/api/logos.py b/app/api/logos.py
index 49c0619c6..5c31ed758 100644
--- a/app/api/logos.py
+++ b/app/api/logos.py
@@ -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()))
diff --git a/tests/api/README.md b/tests/api/README.md
index 535b6cdee..c1b7b86e8 100644
--- a/tests/api/README.md
+++ b/tests/api/README.md
@@ -1,28 +1,44 @@
# Tests unitaires de l'API ScoDoc
-Démarche générale:
+## Lancement des tests
- 1. On génère une base SQL de test: voir
- `tools/fakedatabase/create_test_api_database.py`
+La première fois, copier le fichier `tests/api/dotenv_exemple` vers
+`tests/api/.env`. Il est normalement inutile de modifier son contenu.
- 1. modifier `/opt/scodoc/.env` pour indiquer
+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
- FLASK_ENV=test_api
- FLASK_DEBUG=1
- ```
+```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`
- 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
diff --git a/tests/api/dotenv_exemple b/tests/api/dotenv_exemple
index e1857bd81..e990d0c5c 100644
--- a/tests/api/dotenv_exemple
+++ b/tests/api/dotenv_exemple
@@ -4,8 +4,11 @@
# et à remplir.
# URL du serveur ScoDoc à interroger
-SCODOC_URL = "http://localhost:5000/"
+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
+CHECK_CERTIFICATE=False
+
+API_USER="lecteur_api"
+API_PASSWORD="azerty"
diff --git a/tests/api/start_api_server.sh b/tests/api/start_api_server.sh
new file mode 100755
index 000000000..67a3120a7
--- /dev/null
+++ b/tests/api/start_api_server.sh
@@ -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
\ No newline at end of file
diff --git a/tests/api/test_api_etudiants.py b/tests/api/test_api_etudiants.py
index 720090936..b4fc97f3b 100644
--- a/tests/api/test_api_etudiants.py
+++ b/tests/api/test_api_etudiants.py
@@ -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)
diff --git a/tests/api/test_api_logos.py b/tests/api/test_api_logos.py
index 9ae59e87f..8277c1840 100644
--- a/tests/api/test_api_logos.py
+++ b/tests/api/test_api_logos.py
@@ -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,147 +35,159 @@ 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)
- 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
+ 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_lambda_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
+ response = requests.get(
+ API_URL + "/logos",
+ headers=api_headers,
+ verify=CHECK_CERTIFICATE,
+ )
+ assert response.status_code == 401
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)
- 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
+ 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()
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)
- assert response.status_code == 200
- assert response.json is not None
- assert "A" in response.json
- assert "D" in response.json
+ 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()
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)
- assert response.status_code == 200
- assert response.json is not None
- assert "A" in response.json
- assert "D" in response.json
+ 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()
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)
- assert response.status_code == 200
- assert response.headers["Content-Type"] == "image/png"
- assert response.headers["Content-Disposition"].startswith("inline")
- assert "logo_D.png" in response.headers["Content-Disposition"]
+ 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")
+ assert "logo_D.png" in response.headers["Content-Disposition"]
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)
- assert response.status_code == 200
- assert response.headers["Content-Type"] == "image/png"
- assert response.headers["Content-Disposition"].startswith("inline")
- assert "logo_C.png" in response.headers["Content-Disposition"]
+ 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")
+ assert "logo_C.png" in response.headers["Content-Disposition"]
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)
- assert response.status_code == 200
- assert response.headers["Content-Type"] == "image/jpg"
- assert response.headers["Content-Disposition"].startswith("inline")
- assert "logo_B.jpg" in response.headers["Content-Disposition"]
+ 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")
+ assert "logo_B.jpg" in response.headers["Content-Disposition"]
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)
- assert response.status_code == 200
- assert response.headers["Content-Type"] == "image/png"
- assert response.headers["Content-Disposition"].startswith("inline")
- assert "logo_D.png" in response.headers["Content-Disposition"]
+ 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")
+ assert "logo_D.png" in response.headers["Content-Disposition"]
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)
- assert response.status_code == 200
- assert response.headers["Content-Type"] == "image/jpg"
- assert response.headers["Content-Disposition"].startswith("inline")
- assert "logo_A.jpg" in response.headers["Content-Disposition"]
+ 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")
+ assert "logo_A.jpg" in response.headers["Content-Disposition"]
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)
- assert response.status_code == 200
- assert response.headers["Content-Type"] == "image/jpg"
- assert response.headers["Content-Disposition"].startswith("inline")
- assert "logo_A.jpg" in response.headers["Content-Disposition"]
+ 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")
+ assert "logo_A.jpg" in response.headers["Content-Disposition"]
diff --git a/tools/create_database.sh b/tools/create_database.sh
index e1d7ffb95..6e9a939ed 100755
--- a/tools/create_database.sh
+++ b/tools/create_database.sh
@@ -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
--
GitLab