jeudi 26 mars 2020

Serveur ESP32 : tests automatisés (2ème partie)


 Serveur ESP32 : tests automatisés

(2ème partie)


Ceci est la suite et fin des six articles précédents :
Serveur ESP32 : implémentation
Serveur ESP32 : implémentation (2ème partie)
Serveur ESP32 : implémentation (3eme-partie)
Serveur ESP32 : implémentation (4eme-partie)
Serveur ESP32 : implémentation (5eme-partie)
Serveur ESP32 : tests automatisés

Le but de cette dernière évolution est :
  • ajouter la délivrance d'un service aux abonnés
  • améliorer le serveur 
  • tester certains cas nominaux ou non nominaux
  • tests particuliers
  • tests interactifs
Rappel : comme vu dans la 4ème partie seul l'ESP32 pourra offrir une possibilité de partitionnement entre SPIFFS et FAT.
Pour un ESP8266 il faudra forcément utiliser une SD.

1. Evolutions

1.1. Service aux abonnés

Ce service va être simple, afin de rajouter aussi peu de matériel que possible :
  • un bouton-poussoir
  • une LED (la LED de la carte ESP32)
L'abonné présente sa carte et appuie sur le bouton poussoir.
Si l'abonné n'est pas enregistré la LED clignote 1 fois.
Si l'abonné est désactivé la LED clignote 3 fois.
Si l'abonné a un crédit nul la LED clignote 6 fois.
S'il a du crédit la LED s'allume 10 secondes et son crédit est décompté.

On pourrait imaginer beaucoup de solutions hardware :
  • écran LCD alphanumérique
  • écran tactile
  • gâche électrique
  • vanne de distribution de boisson
  • distributeur de barres vitaminées
  • imprimante de tickets
  • etc.
Le but final de cet exercice sera d'ouvrir une porte. Le bouton-poussoir disparaîtra à terme. La notion de crédit ne sera pas nécessaire non plus, mais cela peut servir pour d'autres applications.

1.2. Historique

L'historique fonctionne maintenant à l'envers. Il est plus pratique d'avoir les dernières opérations affichées en premier.
L'affichage de l'historique est maintenant limité à 20 lignes et un lien "More history ..." permet de visualiser le fichier complet.

Une nouvelle ligne a été ajoutée : la date d'enregistrement de l'abonné.

1.3. Les détails

Le changement d'heure
Comme le changement d'heure est intervenu cette nuit (29 mars), le serveur est en retard d'une heure.

L'heure était configurée comme ceci :

  configTime(3600, 0, ntpServer);

Aujourd'hui il faudrait la configurer avec une heure de plus :

  configTime(7200, 0, ntpServer);

Mais il y a moyen de faire cela automatiquement, avec une "timezone string" :

  configTzTime("CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00", ntpServer);

Le changement d'heure sera donc automatique le dernier dimanche de mars et octobre.
Les explications ici : https://www.di-mgt.com.au/wclock/tz.html

Les image et logos
Les deux pages HTML affichent maintenant un petit logo (un cadenas) et l'icône favori (favicon.ico) a également été ajouté :

Ceci pour démontrer qu'il ne suffit pas d'écrire <img src="/lock.jpg"> dans une page pour que l'image s'affiche.
Cela n'est pas forcément une évidence lorsque l'on a l'habitude de travailler sur un serveur Apache, mais avec un ESP32 et la librairie AsyncWebServer, il faut servir cette image.

Mémoire libre
Une URL supplémentaire a été ajoutée afin de pouvoir afficher la mémoire dynamique libre :
/freeram.html

La quantité de mémoire RAM libre est également affichée dans la boîte de dialogue "About ...".

2. Tests

2.1. Cas nominaux et non nominaux

Quelques tests nominaux ont été ajoutés :
  • recherche par nom
  • recherche par UID
Ces tests ont permis de corriger un bug.

Dans tout développement sérieux il ne suffit pas de tester quelques cas nominaux. Il faut aussi tester les cas d'erreurs :
  • carte non lue
  • abonné inexistant
  • abonné désactivé
  • crédit nul
Pour tous ces cas, du code a été écrit. Il serait assez peu judicieux de faire confiance au code écrit sans le tester, car en dehors d'assurer une fonctionnalité, tout cas d'utilisation, nominal ou non, est susceptible de produire un crash du logiciel.
Tant que l'on n'a pas testé le plus de cas possible rien ne permet d'affirmer que le logiciel fonctionne correctement.

Ces tests paraissent simples. Vérifier que le serveur affiche bien "Subscriber NOT FOUND !!!" si l'abonné n'existe pas ne devrait poser aucune difficulté.

Pour rappel cette suite de test s'exécute comme ceci :

$ python3 test.py AutomatedTest

2.2. Cas particuliers

Partition pleine
Un test en particulier est absolument indispensable : le test de remplissage de la partition FAT.Pour tester ce cas, il va être difficile de créer un abonné ou plusieurs et de réaliser un grand nombre d'actions (ajout de crédit par exemple) jusqu'à remplir la partition de 1.44 méga-octets. Chaque ligne d'historique faisant environ 30 octets. Cela nous obligerait à réaliser 48059 actions.

Faire ce test en automatique sera long également. Même si chaque opération ne dure que 500ms, il nous faudrait tout de même 24000 secondes soit plus de 6 heures !

Une astuce consiste à remplir artificiellement la partition de fichiers de taille assez importante.
La serveur se voit donc ajouter une nouvelle URL /create.html permettant de créer un fichier X de taille donnée. La durée du test sera nettement raccourcie.
Une deuxième URL /freebytes.html est ajoutée afin que le logiciel de test puisse récupérer l'espace disponible.

Le logiciel de test va donc demander au serveur de créer N fichiers de 100Ko jusqu'à ce que l'espace soit presque plein.On ne peut pas simplement diviser l'espace disponible au départ par 100Ko et créer N fichiers. L'allocation des secteurs par le système de fichiers n'est pas prédictible.

La taille restante sera d'environ 4096 octets, la taille d'un secteur de la FLASH.
En dessous de cette valeur la méthode FFat.freeBytes() utilisée pour déterminer l'espace disponible retourne ZÉRO, ce qui ne nous arrange pas car on ne saurait quand s'arrêter.

Il ne nous restera plus qu'à effectuer une centaine d'opérations pour remplir le dernier secteur.

Test intensif
Ce test enchaîne 5000 ajouts de crédit.
Cela m'a permis de m'apercevoir qu'après l'ajout de 5000 lignes dans le fichier historique, lorsque l'on utilise la fonction explorer,  la lecture du fichier historique échoue. L'ESP32 n'a plus assez de mémoire.
Donc les fichiers sont affichés par page de 200 lignes avec un lien "More ...".
Les lignes sont maintenant numérotées.

Cette suite de test s'exécute comme ceci :

$ python3 test.py SpecialTest

2.3. Tests interactifs

Deux tests interactifs ont été également ajoutés :
  • ajout d'un abonné
  • débit
Le test d'ajout d'un abonné demande au testeur de passer par la page "Nouvel abonné" d'entrer un nom et de présenter une carte.

Le test de débit nécessite la présentation de la carte et l'appui sur le bouton-poussoir.

Il est à noter que chacun de ces test, s'il est effectué un peu avant le passage à la minute suivante, échouerait, d'où une petite attente, afin de laisser au testeur le temps de réaliser les opérations manuellement :

    def wait_minute_00(self) :
        dt = datetime.now()
        if dt.second < 30:
            return
        print("wait %s seconds please" % (60 - dt.second))
        time.sleep(60 - dt.second)


Cette suite de test interactifs s'exécute comme ceci :

$ python3 test.py InteractiveTest

3. La suite de test

Celle-ci est disponible ici :
https://bitbucket.org/henri_bachetti/webserver-form/src/v2.3/esp32-subscriber/test/test.py

On voit donc de nouveaux tests apparaître :
  • remise à ZÉRO du crédit
  • désactivation de l'abonné
  • réactivation de l'abonné
  • test de remplissage de la partition
Une nouvelle classe de base apparaît : BaseTest. Elle contient les méthodes de base qui seront utilisées par les classes qui en hériteront :
  • setUp() et tearDown() : voir article précédent
  • nettoyage du serveur
  • remplissage de la partition
  • récuparation de l'heure
La récupération de l'heure comporte une petite astuce particulière : elle fait une pause de 2 secondes au moment où les secondes arrivent à 59 afin d'éviter les problèmes de comparaison d'heure dans les tests.
Le PC peut en effet demander au serveur d'effectuer une opération qu'il effectuera à 10:44:59, et il est probable que le logiciel de test récupère ensuite une heure légèrement différente : 10:45:00. La comparaison échouerait.

L'heure du PC et de l'ESP32 ne sont pas parfaitement synchronisées à la seconde près. C'est pour cette raison que l'on évite généralement de contrôler des heures à la seconde près.

Le test de remplissage de la partition est situé dans une classe à part SpecialTest afin de permettre son exécution séparément des autre tests, car son exécution prend pas mal de temps : 2 minutes.

$ python3 test.py SpecialTest
.
----------------------------------------------------------------------
Ran 1 test in 122.269s

OK


L'exécution des tests nominaux est plus courte : 10 secondes.

$ python3 test.py AutomatedTest
......
----------------------------------------------------------------------
Ran 7 tests in 10.686s

OK


4. Téléchargement

Cette version est disponible ici :
https://bitbucket.org/henri_bachetti/webserver-form/src/v2.3/esp32-subscriber/

5. Liens utiles

La suite :
Serveur ESP32 : implémentation (6eme-partie)


6. Conclusion

Une fois de plus le test automatisé permet de fiabiliser le logiciel. Sans test automatisé il m'aurait été impossible de m'apercevoir de ce que j'ai observé en test intensif (voir 2.2).

On voit également que souvent le code à tester évolue au fur et à mesure que les tests sont écrits, ce qui est parfaitement normal dans une démarche de test automatisé.

Il existe même une méthode dite "Test-driven development" (Développement piloté par les tests) qui préconise l'écriture des tests avant l'écriture du code.

Bien entendu la suite de tests n'est pas totalement terminée, mais cela ne justifie pas un article de plus.Les suppléments seront ajoutés dans celui-ci.

Pour conclure, je dirais que le test automatisé nécessite une investissement non négligeable, certes, mais cet investissement est largement compensé par le temps gagné par rapport à des tests effectués manuellement, surtout si on les répète souvent.
En fait on s'aperçoit très vite que l'on a tendance à lancer les tests après chaque journée ou semaine de travail, avant le commit (partage de son travail). Lorsque l'on travaille en équipe cela permet de ne pas perturber le travail des autres membres de l'équipe.
J'ai tellement pris goût à ces méthodes que même quand je travaillais seul, je continuais à faire de même.

J'espère que cette suite d'articles vous aura éclairé quant à la manière de concevoir un serveur ESP32, et surtout de le tester.


Cordialement
Henri

7. Mises à jour

27/03/2020 : ajout de tests
                     corrections
29/03/2020 : 1.3. Les détails / le changement d'heure

Aucun commentaire:

Enregistrer un commentaire