La mise au point de scénarios sur des pages dynamiques est beaucoup plus complexe que sur les pages statiques. En effet, il faut fournir des données dans les formulaires, qui sont parfois variables, et avec des aléas comme les « nonces » pour que le serveur accepte nos requêtes.
WordPress est un bon exemple de serveur qui utilise des « nonces » pour contrôler la légitimité des requêtes.
Lorsque vous affichez un formulaire, comme la page des Articles, WordPress place des champs cachés contenant des nombre aléatoires, les « nonces », qu’il faut obligatoirement fournir lorsqu’on envoie, on poste, les champs du formulaire sans quoi, on reçoit un message « Forbidden 403 » qui indique de WordPress refuse notre requête.
Il faut donc passer obligatoirement par l’affichage des formulaires avant de lancer une requête avec les données du formulaire afin de récupérer le bon « nonce ». Et des fois, on s’aperçoit que le « nonce » a été fourni quelques pages auparavant et pas juste dans la requête précédente !
Il faut démarrer le scénario en se connectant sur le backoffice WordPress avec des identifiants. Ce sera la première partie du scénario.
Pour démarrer, on va enregistrer le login sur le backoffice avec le Recorder, comme on l’a fait pour les pages statiques dans l’article Les tests de charge avec JMeter
On arrête l’enregistrement dès qu’on est loggé. On peut rejouer le scénario et voici de qu’on obtient :
On constate qu’on a plus d’une dizaine d’URL rien que pour le login !
On a également deux erreurs sur les URL Ajax lorsqu’on rejoue le scénario. Mais pour le login, ça fonctionne. Si on regarde de plus près ce qu’on envoie sur le formulaire de login :
On voit que le login et le mot de passe sont effectivement transmis sur le formulaire. On note que l’URL contient deux variables ${scheme}://${host}/wp-admin
Ces variables sont déclarées dans l’item « User Defined Variables » et sont utilisé par la suite par JMeter. Ces variables permettent par exemple de lancer le même scénario sur un serveur en HTTP et en HTTPS ou sur un port comme le 6081 pour avoir directement Varnish ou 8080 pour avoir directement Apache. On pourra ainsi comparer les performances selon l’architecture
Maintenant si on s’intéresse aux erreurs sur les requêtes Ajax, on voit le code de retour « 403 Forbidden »
Si on regarde les données de la requête POST, on voit un « _wpnonce »
On retrouve ce « nonce » dans notre scénario
Comme ce « nonce » a une valeur fixe dans notre scénario et que WordPress génère des valeurs aléatoires à chaque login, cette requête Ajax ne va pas fonctionner si on ne lui transmet pas le bon « nonce ».
Pour trouver le bon « nonce », il faut chercher dans le « View Result Tree » du « Test Script Recorder » qui a été généré lorsqu’on a enregistré le scénario ! En effet, le « nonce » a été fourni par une page précédente et a été utilisé ensuite dans l’Ajax. Une fois qu’on rejoue le scénario, le « nonce » présenté n’est plus le même. Et comme WordPress en place une bonne dizaine, il n’est pas simple de retrouver le bon. Il faut donc faire une recherche de la chaîne "fc5858da59"
dans le « View Result Tree » du « Test Script Recorder »
Le « nonce » est généré sur la page 053 - /wp/admin/
On va essayer de récupérer sa valeur par une extraction sur le corps de la page HTML, qu’on voit si on affiche l’onglet « Response Body » et qu’on fait une recherche de la chaine "fc5858da59"
on trouve la ligne
1 2 3 |
<script> var SiteHealth = {"screen":"dashboard","nonce":{"site_status":"33e44d2192","site_status_result":"fc5858da59"},"site_status":{"direct":[],"async":[],"issues":{"good":"15","recommended":"4","critical":"1"}}}; </script> |
que nous allons utiliser pour récupérer un « nonce » qui changera à chaque login.
On va ajouter un post processeur sur la page 052 - /wp-login/
pour faire une extraction de cette valeur et la stocker dans une variable, qu’on appellera site_status_nonce
. On n’utilise pas 053- /wp/admin/
, car la page est grisée, c’est le résultat de la redirection du login. C’est la requête 052 - /wp-login/
qui fournira le « nonce » !
On va remplir les champs avec l’expression régulière : "site_status_result":"([^"]+)"
qui signifie tout ce qui se trouve entre ″ et ″ et qui ne contient pas de ″.
On pourrait utiliser l’expression régulière "site_status_result":"(.+?)"
qui signifie n’importe quoi jusqu’à la première ″ rencontrée. Le ? permet d’avoir une expression « non greedy », sinon le moteur d’expression prend tout ce qu’il trouve jusqu’à la dernière ″ du fichier !
Pour plus d’informations, il faut regarder la documentation : https://jmeter.apache.org/usermanual/regular_expressions.html
On peut également tester les expressions régulières dans JMeter. Dans le « View Result Tree », on affiche la page 052 - /wp-login/
et dans la combo box au dessus, on choisit « Regexp Tester ». On peut alors saisir une expression régulière dans le panneau de droite, qui va s’appliquer au « Request Body » de la page 052 - /wp-login/
. On peut vérifier ici, qu’on récupère le « nonce » f9d0db48be
Maintenant qu’on sait récupérer le « nonce », il faut l’utiliser. Il faut modifier les 2 pages Ajax 109 - /wp-admin/admin-ajax.php
et110 - /wp-admin/admin-ajax.php
pour mettre la variable ${site_status_nonce}
dans les paramètres de la requête
Désormais, les requêtes Ajax fonctionnent et renvoient un code 200 !
A ce stade, on a un login qui fonctionne. On pourrait faire un scénario sans lancer ces requêtes Ajax qui ont pour principal objectif de montrer comment récupérer un « nonce » dans une page Web.
Dernière étape du login, on peut nettoyer les requêtes qui sont grisées. En effet, ce sont des requêtes implicites, qui proviennent de redirection des requêtes précédentes.
Par exemple, l’appel de « 024 – wp-admin » déclenche les redirections suivantes, qu’on peut voir du coté du navigateur :
L’enchaînement est le suivant
- https://alain.arditi.fr/wp-admin
- http://alain.arditi.fr/wp-admin/
- https://alain.arditi.fr/wp-admin/
- https://alain.arditi.fr/wp-login.php?redirect_to=https%3A%2F%2Falain.arditi.fr%2Fwp-admin%2F&reauth=1
Les lecteurs perspicaces verront une optimisation qui consiste à ne pas repasser en HTTP à l’étape 2 puis repasser en HTTPS à l’étape 3. C’est une optimisation qui supprime un aller/retour entre le client et le serveur. 31 ms d’après la trace du « Waterfall ». Cette redirection est faite au niveau d’Apache par les rewrites ajoutés par le plugin WP Fastest Cache. Dans le cas présent, je laisse, l’enjeu étant faible, et surtout à la prochaine mise à jour du plugin je perdrais mes modifications.
Comme JMeter suit les redirections par défaut, il va lancer les 4 requêtes à partir de la première. C’est la raison qui fait que dans notre scénario, on retrouve 3 requêtes grisées. Elle ne sont pas jouées par défaut. On peut donc supprimer toutes les requêtes grisées pour alléger. On retrouve notre scénario de login final :
Dans l’article suivant on va continuer notre scénario. On va créer un article, renseigner du contenu et le mettre à la corbeille. En effet, sans la mise à la corbeille, un scénario qui générerait 1000 créations d’articles, nous obligerait à les supprimer par la suite, sans quoi on se retrouverait avec un site rempli d’article de test ! Dans ces requêtes on va être obligés de trouver les « nonces », sans quoi, impossible de créer, publier ou supprimer un article.
A noter que la bonne manière de procéder pour les tests de charge voudrait qu’on réinitialise les données après chaque test. On remet le site comme d’origine. On pourrait très bien ne pas supprimer les articles si on restaure les données. Avec WordPress, il suffit de restaurer la base de données.
Site officiel de JMeter : https://jmeter.apache.org/