Python : Locust (Tests de charge)
Présentation vite fait
Locust est une lib python servant à effectuer des tests de charge sur du web. Celle-ci simule des requêtes utilisateur en se basant sur des locustfiles, des scripts en Python. À l'utilisation, celle-ci se base sur une commande et propose ses résultats sous la forme d'une interface web sympa.
Installation, utilisation simple
Install
Le plus simple est de passer par un venv
python3 -m pip venv myvenv source myvenv/bin/activate pip install locust
Locust est installé. Une fois en place, il passe par des locustfiles.
Locustfile basique
Créer un locustfile. Un locustfile nommé locustfile.py sera automatiquement pris en compte par la commande, mais on peut les nommer comme on veut et les passer à la commade locust avec l'argument -f.
Le locustfile suivant est détaillé et explique le principe. <source lang="python"> import time from locust import HttpUser, task, between
- Un locustfile est simplement un module Python
- il peut utiliser code venu d'autres fichiers / packages
- On définit une classe pour simuler un utilisateur.
- On hérite de la classe HttpUser; celle-ci donne a chaque user un attribut
- nommé client, qui est une instance de HttpSession, utilisée pour faire des
- requêtes http. Lors du test, Locust va créer une instance de cette classe
- pour chaque client, chaque client ayant son thread.
- Unn locustfile doit avoir au moins une classe héritant de User.
class QuickstartUser(HttpUser):
#Chaque utilisateur attendra entre 1 et 5 secondes après chaque tâche. #https://docs.locust.io/en/stable/writing-a-locustfile.html#wait-time
wait_time = between(1, 5)
#Les méthodes décorées avec @task sont au coeur du locustfile. #Pour chaque user, Locust va générer un greenlet (un micro-thread) #qui appellera ces méthodes #Une méthode non décorée ne sera pas une tâche; ainsi, #on peut créer nos méthodes "helper" en interne #qui pourront être appellées par des tasks
#Les tâches sont appellées au hasard, mais leur poids #est pris en compte.
#Première tâche: un simple get, poids 1 par défaut #HttpUser n'est pas un vrai Browser; il ne lit pas le code html #par contre il gère les cookies @task def hello_world(self): #On appelle le client de notre classe, dont on a hérité self.client.get("/", auth=("squip", "blaaaah"))
#Deuxième tâche, avec un poids de 3 #Elle a trois fois plus de chances de se produire @task(3) def view_items(self): articles = [ "1662725871", "1658325104", "1658313746" ] for article in articles: #Ici, on fait un get en boucle avec note= un id de note #Le name=machin sert à regrouper toutes ces requêtes #sous le nom "/readmode" dans les résultats Locust self.client.get(f"/readmode?note={article}", name="/readmode", auth=("squip", "blaaaah")) time.sleep(1)
#Toute méthode nommée "on_start" sera appellée par chaque utlisateur à #son démarrage #Ici on s'authentifie une fois au démarrage, juste pour l'exemple def on_start(self): self.client.get("/", auth=("squip", "blaaaah"))
</source>
Lancement
Une fois mon locustfile créé, je peux lancer le process:
locust -f monlocustfile.py
Bien lire ses retours : le mien essaye de monter le nombre de file descriptors de mon système à 10000 parce qu'il n'en a pas assez, mais il n'as pas les droits pour le faire. Bref.
Il ouvre alors une interface web sur http://localhost:8089/. On peut y renseigner l'URL à matraquer, la quantité d'utilisateurs, etc. Le tout est assez explicite.