Arborescence des pages

Installer Jmeter

https://jmeter.apache.org/download_jmeter.cgi

Lancer Jmeter avec son interface

JVM_ARGS="-Xms8192m -Xmx8192m" ./apache-jmeter-5.5/bin/jmeter

Pour lancer directement le script en ligne de commande : https://jmeter.apache.org/usermanual/get-started.html#non_gui

jmeter -n -t my_test.jmx -l log.jtl 

Le plan de test

Le plan de test est un fichier JMeter (extension .jmx) contient plusieurs scénarios de test et les paramétrages qui permettent de les lancer. Un scénario est une suite de requêtes lancées par l'outil. Pour bâtir ces scénarios JMeter permet d'enregistrer une navigation web et se comporte alors comme un serveur proxy et enregistre toutes les requêtes appelée  https://jmeter.apache.org/usermanual/get-started.html#template

Le plan de test fournit propose plusieurs scénarios :

  • Navigation anonyme, c'est à dire une navigation sans authentification
  • Authentification, c'est à dire affichage de la page d'accueil puis authentification
  • Accès à l'emploi du temps, c'est à dire authentification puis accès au service "Emploi du temps"
  • Navigation authentifiée, c'est à dire authentification puis accès à plusieurs services

Configuration

Le plan de test se configure dans le composant User Defined Variables grâce aux variables suivantes :

  • host : Adresse de la PWA
  • host-back : Adresse du back-end
  • scheme : http/https
  • user : Identifiant
  • password : Mot de passe
  • authToken : token obtenu après authentification. Il est renseigné par le script (voir le paragraphe dédié à l'authentification)
  • serviceTicket : Service Ticket CAS. Il est renseigné par le script (voir le paragraphe dédié à l'authentification)
  • currentDate : forcer une date du jour pour avoir des données significatives pour les emplois du temps. (voir le paragraphe dédié au test de l'EDT)
  • asUser : login d'un utilisateur à forcer pour les EDT.(voir le paragraphe dédié au test de l'EDT)
  • host-directus Adresse du CMS Headless pour récupérer les assets directement
  • directus-key : Clé du CMS Headless (ne sert pas ?)
  • user-file : Fichier csv qui liste des identifiants utilisateurs pour tester la charge avec des utilisateurs différents (voir le paragraphe dédié à l'utilisation d'un fichier de logins)
  • log-root : Chemin où seront déversés les logs

L'authentification

Pour jouer l'authentification l'appel de la route /auth dans les scripts on force dans le body de la requête l'utilisation du ${user} et ${password}

{"username":"${user}","password":"${password}"}

Ensuite l'utilisation d'un composant JSON Extractor permet d'extraire de TGT CAS reçu en retour et de le positionner dans la variable ${authToken}

On peut utiliser ce TGT pour demander des ST CAS (afin d'éviter à un utilisateur de se ré-authentifier lorsqu'il est redirigé vers un service CAS) en appelant la route /sso-service-token

{"service":"${scheme}://mdw.univ-lorraine.fr/login/cas","authToken":"${authToken}"}

Ensuite l'utilisation d'un composant Regular Expression Extractor permet d'extraire de ST CAS reçu en retour et de le positionner dans la variable ${serviceTicket}

On peut enfin rédiriger vers le service en utilisant la variable ${serviceTicket} comme dans l'exemple suivant

Test de l'emploi du temps

Le service emploi du temps s'appelle sur la route /schedule.

Pour permettre des tests de charge représentatifs des paramêtres ont été ajouté. On peut donc passer en POST le body suivant

{"authToken":"${authToken}","startDate":"${startDate}","endDate":"${endDate}","asUser":"${asUser}"}

${startDate} et ${endDate} permettent de positionner une dans de début et une date de fin et où ${asUser} permet d'indiquer l'identifiant d'un autre utilisateur que celui connecté.

${asUser} est indiqué dans les User Defined Variables et les ${startDate} et ${endDate} sont calculées à partir de ${currentDate} également déclaré dans User Defined Variables grâce au script Pré-Processeur BeanShell situé à la racine du projet.

Ce script propose d'autres variables comme ${schedulStarMonth} et ${schedulEndMonth} qui peuvent être utilisée pour tester la vue "mois" et des ${scheduleStartDatePlusx} pour tester la navigation dans l'EDT.

import java.text.SimpleDateFormat;
import java.text.DateFormat;
import java.util.Calendar;


SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

String currentDateStr = vars.get("currentDate");
Date currentDate = null;

if (currentDateStr == null || "".equals(currentDateStr)) {
	currentDate = new Date();
	vars.put("currentDate", sdf.format(currentDate));
} else {
	currentDate = sdf.parse(currentDateStr);
}

Calendar calendar = Calendar.getInstance();  
calendar.setTime(currentDate);

calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
vars.put("scheduleStartDate", sdf.format(calendar.getTime()));

calendar.add(Calendar.DATE, 6);
vars.put("scheduleEndDate", sdf.format(calendar.getTime()));

calendar.add(Calendar.DATE, 1);
vars.put("scheduleStartDatePlus1", sdf.format(calendar.getTime()));

calendar.add(Calendar.DATE, 6);
vars.put("scheduleEndDatePlus1", sdf.format(calendar.getTime()));

calendar.add(Calendar.DATE, 1);
vars.put("scheduleStartDatePlus2", sdf.format(calendar.getTime()));

calendar.add(Calendar.DATE, 6);
vars.put("scheduleEndDatePlus2", sdf.format(calendar.getTime()));

calendar.add(Calendar.DATE, 1);
vars.put("scheduleStartDatePlus3", sdf.format(calendar.getTime()));

calendar.add(Calendar.DATE, 6);
vars.put("scheduleEndDatePlus3", sdf.format(calendar.getTime()));

calendar.add(Calendar.DATE, 1);
vars.put("scheduleStartDatePlus4", sdf.format(calendar.getTime()));

calendar.add(Calendar.DATE, 6);
vars.put("scheduleEndDatePlus4", sdf.format(calendar.getTime()));

calendar.setTime(currentDate);
calendar.set(Calendar.DATE, calendar.getActualMinimum(Calendar.DATE));
vars.put("scheduleStartMonth", sdf.format(calendar.getTime()));

calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
vars.put("scheduleEndMonth", sdf.format(calendar.getTime()));


calendar.setTime(currentDate);
calendar.add(Calendar.DATE, -12);
vars.put("startDate", sdf.format(calendar.getTime()));

calendar.setTime(currentDate);
calendar.add(Calendar.DATE, 9);
vars.put("endDate", sdf.format(calendar.getTime()));


Utilisation d'un fichier de logins

Pour faire des tests de charge réalistes avec des utilisateurs différents il est possible d'utiliser un fichier CSV qui contiendra une liste de login. Dans l'exemple fournit ces comptes doivent avoir un mot de passe identique mais il est possible de l'adapter pour utiliser un fichier contenant login et mot de passe.

Le chemin vers le fichier doit être indiqué dans la variable ${user-file} de User Defined Variables

Ensuite il faut activer le composant CSV Data Set Config situé à la racine du projet JMeter

Dans cet exemple, les valeurs de login trouvées dans le CSV surchargeront la variable ${user} et écraseront la valeur positionnée dansUser Defined Variables

Si on voulait également insérer les mot de passe via le fichier CSV il faudrait mettre une seconde colonne et "user, password" dans le champs Variable Names.

Lancement d'un test

Pour lancer un test, activer (clique droit Enable) le composant Thread Group correspondant.

Les paramétrages du test se trouvent à ce niveau et se configurent comme suit :

Pour plus d'explication :

https://jmeter.apache.org/usermanual/component_reference.html#Thread_Group 

https://dev.to/rusydy/thread-group-in-jmeter-understanding-its-components-and-use-cases-42be

Lancer le test à l'aide du bouton "Play" situé dans la barre supérieur

Les résultats s'afficheront dans les composants :

  • Summary Report : Rapport consolidé
  • Agregate Graph : Graphique agrégé
  • Graph Results : Graphique de résultats

Pour aller plus loin...

... et créer ou compléter le script.

Préparer l'enregistrement

Dans JMeter un scenario est une suite d'appel d'URL et peut être créé automatiquement à partir d'une navigation sur l'application dans une navigateur. Pour cela, JMeter doit faire office de serveur proxy et le navigateur doit utiliser ce proxy.

Dans JMeter, utiliser un composant HTTP(S) Test Script Recorder qui va permettre de lancer le mode Proxy ainsi qu'un composant Recording Controller qui récupèrera les appels successifs. Le premier composant référencera le second.

Dans Firefox on déclarer le proxy dans Réglages > Général > Paramètres réseau en choisissant une configuration manuelle pointant vers localhost:8888

Le navigateur devra utiliser le certificat JMeter : https://jmeter.apache.org/usermanual/component_reference.html#HTTP%28S%29_Test_Script_Recorder

Dans Réglages > Vie privée... > Certificats > Importer... charger le fichier ApacheJMeterTemporaryRootCA.crt qui se trouve à la racine du répertoire JMeter.

Désactiver le cache du navigateur dans Outils de développement > Réseau en cochant "désactiver le cache".

Pour plus de détails consulter : https://jmeter.apache.org/usermanual/jmeter_proxy_step_by_step.html#script-recorder

Lancer l'enregistrement

Lancer le serveur en cliquant sur le bouton "Play" vert, une fenêtre s'ouvre et reste en premier plan.

Naviguer et jouer le scénario

Faire "Stop" sur la fenêtre en premier plan.

Les requêtes enregistrées se trouvent dans le composant Recording Controller

Créer, rendre paramétrable le scénario

Créer à la racine un nouveau composant Thread Group

Couper/coller les requêtes du composant Recording Controller dans le composant Thread Group fraîchement créé.

Toutes les variables, c'est à dire les éléments que l'on souhaite pouvoir changer facilement lors de l'exécution d'un test de charge doivent figurer dans un composant User Defined Variables.

Au moment, de l'enregistrement si JMeter rencontre une valeur qui se trouve dans une variable déclarée dans le User Defined Variables il remplace automatiqueme la valeur par la variable ce qui est hyper pratique.

Par exemple, s'il rencontre un appel sur l'URL :

mobile-back.univ-lorraine.fr/auth/login-page-content

Mais qu'il connait la variable host-back

qui donne dans le JMX...
		<elementProp name="host" elementType="Argument">
            <stringProp name="Argument.name">host</stringProp>
            <stringProp name="Argument.value">mobile.univ-lorraine.fr</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>

Il remplacera automatiquement par la variable ${host-back}

Néanmoins pour pourras souhaiter paramétrer l'authentification ou d'autres éléments

Astuce

Le fichier .jmx du projet jMeter est un fichier XML. Il peut donc être édité avec un simple éditeur de texte pour des remplacements de masse.

Les appels peuvent être regroupés dans des Transaction Group qui permettront d'agréger les résultat des requêtes de ce groupe.

Une fois le scénario prêt, ajouter à minima un composant Summary Report pour avoir et logguer les résultat du test de charge. Pour en savoir plus : https://jmeter.apache.org/usermanual/component_reference.html#listeners

Lancer le test de charge en paramètrant le Thread group comme expliqué plus haut



  • Aucune étiquette