From 4182134547e2030b8e82309949e4cdc4b793b110 Mon Sep 17 00:00:00 2001 From: Jean-Marie PLACE Date: Sun, 14 Aug 2022 11:36:24 +0200 Subject: [PATCH] ajout utilitaire make_samples --- tests/api/make_samples.py | 177 ++++++++++++++++++++++++++++++++++++++ tests/api/samples.csv | 77 +++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 tests/api/make_samples.py create mode 100644 tests/api/samples.csv diff --git a/tests/api/make_samples.py b/tests/api/make_samples.py new file mode 100644 index 000000000..fbb198283 --- /dev/null +++ b/tests/api/make_samples.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# -*- mode: python -*- +# -*- coding: utf-8 -*- + +"""Construction des fichiers exemples pour la documentation. + + Usage: + cd /opt/scodoc/tests/api + python make_samples.py + +doit être exécutée immédiatement apres une initialisation de la base pour test API! (car dépendant des identifiants générés lors de la création des objets) + cd /opt/scodoc/tests/api + tools/create_database.sh --drop SCODOC_TEST_API && flask db upgrade &&flask sco-db-init --erase && flask init-test-database + +Créer éventuellement un fichier `.env` dans /opt/scodoc/tests/api +avec la config du client API: +``` + SCODOC_URL = "http://localhost:5000/" +``` + +Cet utilitaire prend en donnée le fichier de nom `samples.csv` contenant la description des exemples (séparés par une tabulation (\t), une ligne par exemple) +* Le nom de l'exemple donne le nom du fichier généré (nom_exemple => nom_exemple.json.md). plusieurs lignes peuvent partager le même nom. dans ce cas le fichier contiendra chacun des exemples +* l'url utilisée +* la permission nécessaire (par défaut ScoView) +* la méthode GET,POST à utiliser (si commence par #, la ligne est ignorée) +* les arguments éventuel (en cas de POST): une chaîne de caractère selon json + +Implémentation: +Le code complète une structure de données (Samples) qui est un dictionnaire de set (indicé par le nom des exemple. +Chacun des éléments du set est un exemple (Sample) +Quand la structure est complète, on génére tous les fichiers textes +- nom de l exemple +- un ou plusieurs exemples avec pour chaucn + - l url utilisée + - les arguments éventuels + - le résultat +Le tout mis en forme au format markdown et rangé dans le répertoire DATA_DIR (/tmp/samples) qui est créé ou écrasé si déjà existant + +TODO: ajouter un argument au script permettant de ne générer qu'un seul fichier (exemple: `python make_samples.py nom_exemple`) + +""" +import os +import shutil +from collections import defaultdict +from pprint import pprint as pp +from pprint import pformat as pf + +import urllib3 +import json +from setup_test_api import ( + API_PASSWORD, + API_URL, + API_USER, + APIError, + CHECK_CERTIFICATE, + get_auth_headers, + GET, + POST_JSON, + SCODOC_URL, +) + +DATA_DIR = "/tmp/samples/" + + +class Sample: + def __init__(self, url, method="GET", permission="ScoView", content=None): + self.content = content + self.permission = permission + self.url = url + self.method = method + self.result = None + if permission == "ScoView": + HEADERS = get_auth_headers("test", "test") + elif permission == "ScoSuperAdmin": + HEADERS = get_auth_headers("admin_api", "admin_api") + elif permission == "ScoUsersAdmin": + HEADERS = get_auth_headers("admin_api", "admin_api") + else: + raise Exception(f"Bad permission : {permission}") + if self.method == "GET": + self.result = GET(self.url, HEADERS) + elif self.method == "POST": + if self.content == "": + self.result = POST_JSON(self.url, headers=HEADERS) + else: + HEADERS["Content-Type"] = "application/json ; charset=utf-8" + self.result = POST_JSON(self.url, json.loads(self.content), HEADERS) + elif self.method[0] != "#": + raise Exception(f"Bad method : {self.method}") + else: # method begin with # => comment + print(" pass") + self.shorten() + file = open(f"sample_TEST.json.md", "tw") + self.dump(file) + file.close() + + def _shorten(self, item): + if isinstance(item, list): + return [self._shorten(child) for child in item[:2]] + return item + + def shorten(self): + self.result = self._shorten(self.result) + + def pp(self): + print(f"------ url: {self.url}") + print(f"method: {self.method}") + print(f"content: {self.content}") + print(f"permission: {self.permission}") + pp(self.result, indent=4) + + def dump(self, file): + file.write(f"#### {self.method} {self.url}\n") + if len(self.content) > 0: + file.write(f"> `Content-Type: application/json`\n") + file.write(f"> \n") + file.write(f"> `{self.content}`\n\n") + + file.write("```json\n") + file.write(json.dumps(self.result, indent=4)) + file.write("\n```\n\n") + + +class Samples: + def __init__(self): + self.entries = defaultdict(lambda: set()) + + def add_sample(self, entry, url, method="GET", permission="ScoView", content=None): + show_content = "" if content == "" else f": '{content}'" + print(f"{entry:50} {method:5} {url:50} {show_content}") + sample = Sample(url, method, permission, content) + self.entries[entry].add(sample) + + def pp(self): + for entry, samples in self.entries.items(): + print(f"=== {entry}") + for sample in samples: + sample.pp() + + def dump(self): + for entry, samples in self.entries.items(): + file = open(f"{DATA_DIR}sample_{entry}.json.md", "tw") + file.write(f"### {entry}\n\n") + for sample in samples: + sample.dump(file) + file.close() + + +def make_samples(): + if os.path.exists(DATA_DIR): + if not os.path.isdir(DATA_DIR): + raise f"{DATA_DIR} existe déjà et n'est pas un répertoire" + else: + # DATA_DIR existe déjà - effacer et recréer + shutil.rmtree(DATA_DIR) + os.mkdir(DATA_DIR) + else: + os.mkdir("/tmp/samples") + + samples = Samples() + # samples.pp() + with open("samples.csv") as f: + L = [x[:-1].split("\t") for x in f] + for line in L[1:]: + entry_name = line[0] + url = line[1] + permission = line[2] if line[2] != "" else "ScoView" + method = line[3] if line[3] != "" else "GET" + content = line[4] + samples.add_sample(entry_name, url, method, permission, content) + samples.dump() + return samples + + +if not CHECK_CERTIFICATE: + urllib3.disable_warnings() +make_samples() diff --git a/tests/api/samples.csv b/tests/api/samples.csv new file mode 100644 index 000000000..341bda1e8 --- /dev/null +++ b/tests/api/samples.csv @@ -0,0 +1,77 @@ +reference url permission method content +departements /departements GET +departements-ids /departements_ids GET +departement /departement/TAPI GET +departement /departement/id/1 GET +departement-etudiants /departement/TAPI/etudiants GET +departement-etudiants /departement/id/1/etudiants GET +departement-formsemestres_ids /departement/TAPI/formsemestres_ids GET +departement-formsemestres_ids /departement/id/1/formsemestres_ids GET +departement-formsemestres-courants /departement/TAPI/formsemestres_courants GET +departement-formsemestres-courants /departement/id/1/formsemestres_courants GET +departement-create /departement/create ScoSuperAdmin POST {"acronym": "NEWONE" , "visible": true} +departement-edit /departement/NEWONE/edit ScoSuperAdmin POST {"visible": false} +departement-delete /departement/NEWONE/delete ScoSuperAdmin POST +etudiants-courants /etudiants/courants GET +etudiants-courants /etudiants/courants/long GET +etudiant /etudiant/etudid/11 GET +etudiant /etudiant/nip/11 GET +etudiant /etudiant/ine/INE11 GET +etudiants-clef /etudiants/etudid/11 GET +etudiants-clef /etudiants/ine/INE11 GET +etudiants-clef /etudiants/nip/11 GET +etudiant-formsemestres /etudiant/etudid/11/formsemestres GET +etudiant-formsemestres /etudiant/ine/INE11/formsemestres GET +etudiant_formsemestres /etudiant/nip/11/formsemestres GET +etudiant-formsemestre-bulletin /etudiant/etudid/11/formsemestre/1/bulletin GET +etudiant-formsemestre-bulletin /etudiant/ine/INE11/formsemestre/1/bulletin GET +etudiant-formsemestre-bulletin /etudiant/nip/11/formsemestre/1/bulletin GET +etudiant-formsemestre-groups /etudiant/etudid/11/formsemestre/1/groups GET +formations /formations GET +formations_ids /formations_ids GET +formation /formation/1 GET +formation-export /formation/1/export GET +formation-export /formation/1/export_with_ids GET +formation-referentiel_competences /formation/1/referentiel_competences GET +moduleimpl /moduleimpl/1 GET +formsemestre /formsemestre/1 GET +formsemestres-query /formsemestres/query?annee_scolaire=2022&etape_apo=A2 GET +formsemestre-bulletins /formsemestre/1/bulletins GET +formsemestre-programme /formsemestre/1/programme GET +formsemestre-etudiants /formsemestre/1/etudiants GET +formsemestre-etudiants-query /formsemestre/1/etudiants/query?etat=D GET +formsemestre-etat_evals /formsemestre/1/etat_evals GET +formsemestre-resultats /formsemestre/1/resultats GET +formsemestre-decisions_jury /formsemestre/1/decisions_jury GET +formsemestre-partitions /formsemestre/1/partitions GET +partition /partition/1 GET +group-etudiants /group/1/etudiants GET +group-etudiants-query /group/1/etudiants/query?etat=D GET +moduleimpl-evaluations /moduleimpl/1/evaluations GET +evaluation-notes /evaluation/1/notes GET +user /user/1 GET +users-query /users/query?starts_with=u_ GET +permissions /permissions GET +roles /roles GET +role /role/Observateur GET +group-set_etudiant /group/1/set_etudiant/10 ScoSuperAdmin POST +group-remove_etudiant /group/1/remove_etudiant/10 ScoSuperAdmin POST +partition-group-create /partition/1/group/create ScoSuperAdmin POST {"group_name": "NEW_GROUP"} +group-edit /group/2/edit ScoSuperAdmin POST {"group_name": "NEW_GROUP2"} +group-delete /group/2/delete ScoSuperAdmin POST +formsemestre-partition-create /formsemestre/1/partition/create ScoSuperAdmin POST {"partition_name": "PART"} +formsemestre-partitions-order /formsemestre/1/partitions/order ScoSuperAdmin POST [ 1 ] +partition-edit /partition/1/edit ScoSuperAdmin POST {"partition_name":"P2BIS", "numero":3,"bul_show_rank":true,"show_in_lists":false, "groups_editable":true} +partition-remove_etudiant /partition/2/remove_etudiant/10 ScoSuperAdmin POST +partition-groups-order /partition/1/groups/order ScoSuperAdmin POST [ 1 ] +partition-delete /partition/2/delete ScoSuperAdmin POST +user-create /user/create ScoSuperAdmin POST {"user_name": "alain", "dept": null, "nom": "alain", "prenom": "bruno", "active": true } +user-edit /user/10/edit ScoSuperAdmin POST { "dept": "TAPI", "nom": "alain2", "prenom": "bruno2", "active": false } +user-role-add /user/10/role/Observateur/add ScoSuperAdmin POST +user-role-remove /user/10/role/Observateur/remove ScoSuperAdmin POST +role-create /role/create/customRole ScoSuperAdmin POST {"permissions": ["ScoView", "ScoUsersView"]} +role-remove_permission /role/customRole/remove_permission/ScoUsersView ScoSuperAdmin POST +role-add_permission /role/customRole/add_permission/ScoUsersView ScoSuperAdmin POST +role-edit /role/customRole/edit ScoSuperAdmin POST { "name" : "LaveurDeVitres", "permissions" : [ "ScoView", "APIView" ] } +role-edit /role/customRole/edit ScoSuperAdmin POST { "name" : "LaveurDeVitres", "permissions" : [ "ScoView", "APIView" ] } +role-delete /role/customRole/delete ScoSuperAdmin POST