From 831fb93783c0ee4ff322f229c793d7bb7cc1dde7 Mon Sep 17 00:00:00 2001 From: Fred Date: Sun, 28 Mar 2021 17:44:41 +0200 Subject: [PATCH] Working on tests --- source/images/diagrams/architecture.png | Bin 25586 -> 38900 bytes .../diagrams/infrastructure-base.drawio | 1 + .../part-1-workspace/environment/_index.adoc | 66 ++++++++++++++++-- source/part-2-deployment/_main.adoc | 57 ++++++++++----- 4 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 source/images/diagrams/infrastructure-base.drawio diff --git a/source/images/diagrams/architecture.png b/source/images/diagrams/architecture.png index cef440cd692883397facd03ef470bf34fe09f4f6..0cbc3cc75abdffad994c0e19079533d97e2f49a8 100644 GIT binary patch literal 38900 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 S5BM*SM{3GiO4SNB(f3Vpbc6s2EP41TJ/CIC42foydy2mbdjJNb6cvGRlkUI9AHiF8ya8/EkgGLF8b23H6kqAFLdLuft/uClveKFs8MjhNf6ExIpbrxAvLu7Nc1w9c8VcKlrUg8LxakDAc1yLQCF7wG1JCR0lLHKOi8yCnlHA87Qojmuco4h0ZZIzOu49NKOm+dQoTZAheIkhM6V845mktDd1+I/+CcJLqN4PeoL6TQf2w2kmRwpjOWyLv3vJGjFJeX2WLESLSdtou9byHLXdXC2Mo54dM+JPd/EhBePPzP0/BY3r37NCfyA1Q7in4Uu8YxcIAakgZT2lCc0juG+kwKtkMSa1ADBgt87gaOWJUfEM8StWtZvYTpVMl/BdxvlR+hiWnQpTyjKi7aIH531KXHQRq+LUaDvTwbqFeVQ2WrcEzYjhDHDEtyzlb1sr6gR5/bd9sdFUjraw2ibTDVlMrUUFLFqEd9g1UyEKWIL7LD94qIgSSEBX7YEsxkSECOZ51FwJVTCer51ZTnykWS3QdBT83UMGn0Ad8p6uiXpia1QSPuGgtoxFVIXVEeKntzyAp1RbMcCNEYFmGlQDIVAojQkuhdDhPMUcvU1gZeC7YpRsqTeCB9cBTb0WMo8VuF5oW15brdy2nUTxvSABoWdoigNDZ7qOOdY81pSbEli1TziUL3krF7oNt29eF5RPCqH8gjIKdPnVsxwFdPCij/leY6UfoZFKgsyCovx9BU7kYxO5nwqyFhoNONtKRMSzSlVdbDio4o9/QiBIqKTOnuQyICSZEiyzX8z3f9yV7wmJa59cJXkhlQwLHiDzTAnNMcwlblFfcO5S4wyKDPq09MKac06z1wC3BibzBZUANoRqt9NCSE5yL9enM7rRIIlskst6wZ7PYnqPx61im+mraFl5wTsMLYI1Rfdd2A4Magg3M4AV2cCZuGHw2amil+U6WPz7Jn5BkwgNJpr+PZIKw/8lYJjQC6A+OCS4gRyUzQkdjsMzIbcTpOzDfComNaD9vjl+DsmemeG8Djntny/BgP9d3YbinQjq1vfy1YrK/wWBhz7TYCgCnN1nwGXgN7Ga1pk35qC4FeAdSH/A3B8jBzPY+b3v7AWKUKdNWwlC9RiuHtJ1nFCDbi6hCYA7nye9VWHhCgLPqHEH/v8NZIrZI8Fj8hZE0zWuMGZJsKezwMBHXc0iIXcyS87cyTtjFrb+J6HRx0gZucC7cuoP/EW5BB7UNiC+AW/9Q3A4+FLe+gdtfE5wvriu7gUG4KuV107+hJNhY2p8NJ9d7PPfu/AYuiJPe58BJz8DJSyny1wwXlMXXhRYPrBfPngGV8KJQ6V0pVI5ocE8Z8ocemW3pZi8T8a55vPUb4lT2nI418qxbES09IpY/HAtRL5FX5IdyR28qjVc1oXtqu/V+NMNxXIUEQwV+g+NKn/RJdbpW7TsYWsHdLvSob1BqsrU6M277b0fs7jhS8F1/7eBSRfs7vw8Axx50zypuXGD33a6e8507gAOONz+2KHDXPgOEJs31LklzwDyquTKLeWsWG3y0xczT0ccyxxFl+ZVZzt+fUi9qOfeAz3dGv90ykEmdBg3rvnlCc65SKXC39dFvJUNySwnKEYNi+Q8vsjiK0OsXBAlPL9JNe30gPyd3HKW1tBtqYIfhBX2lFbd89aAOGQyfic1z67gvQUp0eBrdhJ0dBdYJHON6g26KDM3mzd8AH/d4l4hh87uNOhc2P37x7r8D \ No newline at end of file diff --git a/source/part-1-workspace/environment/_index.adoc b/source/part-1-workspace/environment/_index.adoc index 783d809..4ba087c 100644 --- a/source/part-1-workspace/environment/_index.adoc +++ b/source/part-1-workspace/environment/_index.adoc @@ -321,27 +321,79 @@ Comme tout bon *framework* qui se respecte, Django embarque tout un environnemen ---- from django.test import TestCase + class TestModel(TestCase): def test_str(self): raise NotImplementedError('Not implemented yet') ---- -Idéalement, chaque fonction ou méthode doit être testée afin de bien en valider le fonctionnement, indépendamment du reste des composants. Cela permet d'isoler chaque bloc de manière unitaire, et permet de ne pas rencontrer de régression lors de l'ajout d'une nouvelle fonctionnalité ou de la modification d'une existante. Il existe plusieurs types de tests (intégration, comportement, ...); on ne parlera ici que des tests unitaires. +Idéalement, chaque fonction ou méthode doit être testée afin de bien en valider le fonctionnement, indépendamment du reste des composants. Cela permet d'isoler chaque bloc de manière unitaire, et permet de ne pas rencontrer de régression lors de l'ajout d'une nouvelle fonctionnalité ou de la modification d'une existante. +Il existe plusieurs types de tests (intégration, comportement, ...); on ne parlera ici que des tests unitaires. -Avoir des tests, c'est bien. S'assurer que tout est testé, c'est mieux. C'est là qu'il est utile d'avoir le pourcentage de code couvert par les différents tests, pour savoir ce qui peut être amélioré. +Avoir des tests, c'est bien. +S'assurer que tout est testé, c'est mieux. +C'est là qu'il est utile d'avoir le pourcentage de code couvert par les différents tests, pour savoir ce qui peut être amélioré. -TODO: Vérifier comment les applications sont construites. Type DRF, Django Social Auth, tout ça. +Comme indiqué ci-dessus, Django propose son propre cadre de tests, au travers du package `django.tests`. +Une bonne pratique (parfois discutée) consiste cependant à switcher vers `pytest`, qui présente quelques avantages: + +* Une syntaxe plus concise (au prix de https://docs.pytest.org/en/reorganize-docs/new-docs/user/naming_conventions.html[quelques conventions], même si elles restent configurables): un test est une fonction, et ne doit pas obligatoirement faire partie d'une classe héritant de `TestCase` - la seule nécessité étant que cette fonction fasse partie d'un module commençant ou finissant par "test" (`test_example.py` ou `example_test.py`). +* Une compatibilité avec du code Python "classique" - vous ne devrez donc retenir qu'un seul ensemble de commandes ;-) +* Des _fixtures_ faciles à réutiliser entre vos différents composants +* Une compatibilité avec le reste de l'écosystème, dont la couverture de code présentée ci-dessous. + +Ainsi, après installation, il nous suffit de créer notre module `test_models.py`, dans lequel nous allons simplement tester l'addition d'un nombre et d'une chaîne de caractères (oui, c'est complètement biesse; on est sur la partie théorique ici): + +[source,python] +---- +def test_add(): + assert 1 + 1 == "argh" +---- + +Forcément, cela va planter. +Pour nous en assurer (dès fois que quelqu'un en doute), il nous suffit de démarrer la commande `pytest`: + +[source,bash] +---- +λ pytest +============================= test session starts ==================================== +platform ... +rootdir: ... +plugins: django-4.1.0 +collected 1 item + +gwift\test_models.py F [100%] + +================================== FAILURES ========================================== +_______________________________ test_basic_add _______________________________________ + + def test_basic_add(): +> assert 1 + 1 == "argh" +E AssertionError: assert (1 + 1) == 'argh' + +gwift\test_models.py:2: AssertionError + +=========================== short test summary info ================================== +FAILED gwift/test_models.py::test_basic_add - AssertionError: assert (1 + 1) == 'argh' +============================== 1 failed in 0.10s ===================================== +---- ==== Couverture de code -La couverture de code est une analyse qui donne un pourcentage lié à la quantité de code couvert par les tests. Attention qu'il ne s'agit pas de vérifier que le code est **bien** testé, mais juste de vérifier **quelle partie** du code est testée. En Python, il existe le paquet https://pypi.python.org/pypi/coverage/[coverage], qui se charge d'évaluer le pourcentage de code couvert par les tests. Ajoutez-le dans le fichier `requirements/base.txt`, et lancez une couverture de code grâce à la commande `coverage`. La configuration peut se faire dans un fichier `.coveragerc` que vous placerez à la racine de votre projet, et qui sera lu lors de l'exécution. +La couverture de code est une analyse qui donne un pourcentage lié à la quantité de code couvert par les tests. +Attention qu'il ne s'agit pas de vérifier que le code est **bien** testé, mais juste de vérifier **quelle partie** du code est testée. +Le paquet `coverage` se charge d'évaluer le pourcentage de code couvert par les tests. + +Avec `pytest`, il convient d'utiliser le paquet https://pypi.org/project/pytest-cov/[`pytest-cov`], suivi de la commande `pytest --cov=gwift tests/`. + +Si vous préférez rester avec le cadre de tests de Django, vous pouvez passer par le paquet https://pypi.org/project/django-coverage-plugin/[django-coverage-plugin] Ajoutez-le dans le fichier `requirements/base.txt`, et lancez une couverture de code grâce à la commande `coverage`. +La configuration peut se faire dans un fichier `.coveragerc` que vous placerez à la racine de votre projet, et qui sera lu lors de l'exécution. [source,bash] ---- # requirements/base.text [...] -coverage django_coverage_plugin ---- @@ -386,6 +438,8 @@ $ coverage report $ coverage html ---- +<--- / partie obsolète ---> + Ceci vous affichera non seulement la couverture de code estimée, et générera également vos fichiers sources avec les branches non couvertes. @@ -402,7 +456,7 @@ L'outil le plus connu est https://tox.readthedocs.io/en/latest/[Tox], qui consis ---- # content of: tox.ini , put in same dir as setup.py [tox] -envlist = py27,py36 +envlist = py36,py37,py38,py39 [testenv] deps = diff --git a/source/part-2-deployment/_main.adoc b/source/part-2-deployment/_main.adoc index 60167ae..547b156 100644 --- a/source/part-2-deployment/_main.adoc +++ b/source/part-2-deployment/_main.adoc @@ -6,9 +6,9 @@ Il est du coup probable d'oublier une partie des désidérata, de zapper une fon Aborder le déploiement dès le début permet également de rédiger dès le début les procédures d'installation, de mises à jour et de sauvegardes. Déploier une nouvelle version sera aussi simple que de récupérer la dernière archive depuis le dépôt, la placer dans le bon répertoire, appliquer des actions spécifiques (et souvent identiques entre deux versions), puis redémarrer les services adéquats, et la procédure complète se résumera à quelques lignes d'un script bash. - Le serveur que django met à notre disposition _via_ la commande `runserver` est extrêmement pratique, mais il est uniquement prévu pour la phase développement: en production, il est inutile de passer par du code Python pour charger des fichiers statiques (feuilles de style, fichiers JavaScript, images, ...). -De même, Django propose par défaut une base de données SQLite, qui fonctionne parfaitement dès lors que l'on connait ses limites et que l'on se limite à un utilisateur à la fois. En production, il est légitime que la base de donnée soit capable de supporter plusieurs utilisateurs et connexions simultanément... En restant avec les paramètres par défaut, il est plus que probable que vous rencontriez rapidement des erreurs de verrou parce qu'un autre processus a déjà pris la main pour écrire ses données. +De même, Django propose par défaut une base de données SQLite, qui fonctionne parfaitement dès lors que l'on connait ses limites et que l'on se limite à un utilisateur à la fois. En production, il est légitime que la base de donnée soit capable de supporter plusieurs utilisateurs et connexions simultanément... +En restant avec les paramètres par défaut, il est plus que probable que vous rencontriez rapidement des erreurs de verrou parce qu'un autre processus a déjà pris la main pour écrire ses données. En bref, vous avez quelque chose qui fonctionne, mais qui ressemble de très loin à ce dont vous aurez besoin au final. Dans cette partie, nous aborderons les points suivants: @@ -18,20 +18,48 @@ Dans cette partie, nous aborderons les points suivants: * Configurer les outils nécessaires à la bonne exécution de ce code et de ses fonctionnalités: les différentes méthodes de supervision de l'application, comment analyser les fichiers de logs, comment intercepter correctement une erreur si elle se présente et comment remonter l'information. * Rendre notre application accessible depuis l'extérieur. -== Infrastructure +== Infrastructure & composants -Si on schématise l'infrastructure et le chemin parcouru par une éventuelle requête, nous devrions arriver à quelque chose de synthéthique: +Pour une mise ne production, le standard _de facto_ est le suivant: -. l'utilisateur fait une requête via son navigateur (Firefox ou Chrome) -. le navigateur envoie une requête http, sa version, un verbe (GET, POST, ...), un port et éventuellement du contenu -. le firewall du serveur (Debian GNU/Linux, CentOS, ...) vérifie si la requête peut être prise en compte -. la requête est transmise à l'application qui écoute sur le port (probablement 80 ou 443; et _a priori_ Nginx) -. elle est ensuite transmise par socket et est prise en compte par Gunicorn -. qui la transmet ensuite à l'un de ses _workers_ (= un processus Python) -. après exécution, une réponse est renvoyée à l'utilisateur. + * Nginx comme reverse proxy + * HAProxy pour la distribution de charge + * Gunicorn ou Uvicorn comme serveur d'application + * Supervisor pour le monitoring + * PostgreSQL ou MariaDB comme base de données. + * Celery et RabbitMQ pour l'exécution de tâches asynchrones + * Redis / Memcache pour la mise à en cache (et pour les sessions ? A vérifier). + +Si nous schématisons l'infrastructure et le chemin parcouru par une requête, nous pourrions arriver à la synthèse suivante: + +. L'utilisateur fait une requête via son navigateur (Firefox ou Chrome) +. Le navigateur envoie une requête http, sa version, un verbe (GET, POST, ...), un port et éventuellement du contenu +. Le firewall du serveur (Debian GNU/Linux, CentOS, ...) vérifie si la requête peut être prise en compte +. La requête est transmise à l'application qui écoute sur le port (probablement 80 ou 443; et _a priori_ Nginx) +. Elle est ensuite transmise par socket et est prise en compte par un des _workers_ (= un processus Python) instancié par Gunicorn. Si l'un de ces travailleurs venait à planter, il serait automatiquement réinstancié par Supervisord. +. Qui la transmet ensuite à l'un de ses _workers_ (= un processus Python). +. Après exécution, une réponse est renvoyée à l'utilisateur. image::images/diagrams/architecture.png[] +=== Reverse proxy + +Le principe du *proxy inverse* est de pouvoir rediriger du trafic entrant vers une application hébergée sur le système. +Il serait tout à fait possible de rendre notre application directement accessible depuis l'extérieur, mais le proxy a aussi l'intérêt de pouvoir élever la sécurité du serveur (SSL) et décharger le serveur applicatif grâce à un mécanisme de cache ou en compressant certains résultats footnote:[https://fr.wikipedia.org/wiki/Proxy_inverse] + + +=== Load balancer + +=== Workers + +=== Supervision des processus + +=== Base de données + +=== Tâches asynchrones + +=== Mise en cache + == Code source Au niveau logiciel (la partie mise en subrillance ci-dessus), la requête arrive dans les mains du processus Python, qui doit encore @@ -47,14 +75,7 @@ Il est possible de démarrer petit, et de suivre l'évolution des besoins en fon == Outils de supervision et de mise à disposition -Pour une mise ne production, le standard _de facto_ est le suivant: - * Nginx comme reverse proxy - * Gunicorn ou Uvicorn comme serveur d'application - * Supervisorctl pour le monitoring - * PostgreSQL ou MariaDB comme base de données. - * Celery et RabbitMQ pour l'exécution de tâches asynchrones - * Redis / Memcache pour la mise à en cache (et pour les sessions ? A vérifier). == Méthode de déploiement