Qu’est ce que le test de charge?
Le test de charge est un type de test qui permet d’observer le comportement d’une application selon des charges spécifiées. Pour simplifier, ce test permet de répondre à la question suivante :
Comment va se comporter mon application avec un nombre N d’utilisateurs connectés simultanément ?
Heureusement pour nous, il existe plusieurs outils open source qui permettent de réaliser ces tests :
Dans cet article nous allons voir comment utiliser Gatling pour effectuer des tests de charge sur un site Drupal. Évidemment ceci peut être adapté sur toute autre techno web.
Le code utilisé ci-dessous est disponible, librement, sur Gitlab: https://gitlab.com/symdrik/gatling-drupal-example
Étapes de déroulement d’un test de charge
- Mise en place des outils de monitoring.
- Définition des scénarios de test.
- Exécution des tests
- Interprétation des résultats.
Dans le contexte de cet article nous allons nous limiter aux 3 derniers points.
Installation de Gatling
Gatling étant notre outil de test de prédilection, deux options d’installation se présentent à nous: classique ou docker.
Dans un souci de simplicité, nous allons opter pour la deuxième option (Docker).
# Récupérer l’image de docker hub
docker pull denvazh/gatling
# Vérifier le fonctionnement
docker run -it --rm denvazh/gatling --help
Si tout s’est bien passé, nous devrions avoir l’affichage ci-dessous :
GATLING_HOME is set to /opt/gatling
Usage: compiler [options]
-h, --help
-sf, --simulations-folder <value>
-bf, --binaries-folder <value>
-eso, --extra-scalac-options <value>
Usage: gatling [options]
-h, --help Show help (this message) and exit
-nr, --no-reports Runs simulation but does not generate reports
-ro, --reports-only <directoryName>
Generates the reports for the simulation in <directoryName>
-rsf, --resources-folder <directoryPath>
Uses <directoryPath> as the absolute path of the directory where resources are stored
-rf, --results-folder <directoryPath>
Uses <directoryPath> as the absolute path of the directory where results are stored
-sf, --simulations-folder <directoryPath>
Uses <directoryPath> to discover simulations that could be run
-bf, --binaries-folder <directoryPath>
Uses <directoryPath> as the absolute path of the directory where Gatling should produce compiled binaries
-s, --simulation <className>
Runs <className> simulation
-rd, --run-description <description>
A short <description> of the run to include in the report
Scénario de test :
Notre scénario est assez simple :
- Aller à la page d’accueil et tester que nous avons bien une réponse http 200 et que cette réponse contient la chaîne de caractères “Welcome to Gatling”
- Aller à l’url de login, s’authentifier et tester que nous avons une réponse http 200 avec la présence d’une chaîne de caractères “Member For”.
- Aller sur une page inexistante du site et tester que nous recevons bien une réponse http 404.
Il est à noter que nous allons faire une simulation de ce scénario avec 10 utilisateurs en simultané.
Implémentation du test
Gatling utilise Scala comme langage pour écrire les simulations. Mais il n’est pas nécessaire de maîtriser ce langage car le Langage dédié utilisé est assez intuitif et couvre en général nos besoins.
Arborescence du projet
.
├── resultat <--- Dossier qui contient le rapport de test
└── simulation <--- Dossier qui contient les simulations
└── DrupalSimulation.scala
Le code final de notre simulation:
// Fichier: simulation/DrupalSimulation.scala
package drupalsimulation
import scala.concurrent.duration._
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class DrupalSimulation extends Simulation {
// Initialisation des requêtes HTTP.
val httpProtocol = http
.baseUrl("https://EXEMPLE_DE_SITE.com") // Remplacer par votre site
.acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
.doNotTrackHeader("1")
.acceptLanguageHeader("en-US,en;q=0.5")
.acceptEncodingHeader("gzip, deflate")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
// Définition du scénario.
val scn = scenario("Admin")
.exec(
http("Home_page")
// Aller à la page d'accueil.
.get("/")
// Tester le code et le contenu de la réponse HTTP.
.check(
status.is(200),
substring("Welcome to Gatling")
)
)
// Simuler une pause de 3 secondes
.pause(3)
.exec(
http("goto_login")
// Aller à la page de login.
.get("/user/login")
.check(
// Tester le code et le contenu de la réponse HTTP.
status.is(200),
// Récuperer les valeurs de form_build_id, form_id et op
// nécessaires pour exécuter la requête POST
substring("Log in"),
css("input[name=form_build_id]", "value").saveAs("form_build_id"),
css("input[name=form_id]", "value").saveAs("form_id"),
css("input[name=op]", "value").saveAs("op"),
)
)
// Simuler une pause de 5 secondes.
.pause(5)
.exec(
http("Login")
// Effectuer la requête de type POST
// en spécifiant les valeurs des champs du formulaire.
.post("/user/login")
.formParamSeq(
Seq(
("name", "LOGIN"), // Remplacer par votre login
("pass", "MOT_DE_PASSE"), // Remplacer par votre mdp
("form_build_id", "${form_build_id}"),
("form_id", "${form_id}"),
("op", "${op}")
)
)
// Tester le contenu de la réponse
.check(substring("Member for"))
)
.pause(3)
.exec(
http("404")
// Appeler une url inexistante.
.get("/not-found")
// Tester la réponse.
.check(
status.is(404),
)
)
// Lancer la simulation.
setUp(
scn
.inject(
atOnceUsers(10) // Simule 10 utilisateurs simultanés.
)
.protocols(httpProtocol)
)
}
Exécution de la simulation
docker run -it --rm \
-v $(pwd)/simulation:/opt/gatling/simulation \
-v $(pwd)/resultat:/opt/gatling/resultat \
denvazh/gatling -sf simulation -rd "Drupal simulation" -rf resultat
Rapport de test
Une fois le test exécuté, un rapport au format html sera généré dans le dossier “resultat”.
Exemple de rapport généré par Gatling