====== Locust ======
Is a load testing tool in which you define user behaviour and the system launches a lot of non-real users accessing your web page.
* Docs: [[http://docs.locust.io/en/latest/]]
===== Basic things =====
==== Install ====
$ pip install locustio
==== Basic things in Locust ====
We define several tasks (functions that take one argument, a Locus class instance). We set them on a ''TaskSet'' class, using the ''tasks'' attribute. This class defines the user behaviour. The engine which move all of this is the ''Locust'' class, it indicates the "limits" (of time, with min_wait and max_wait) for the user. \\
''HttpLocust'' is a ''Locust'' class that allows HTTP requests.
The ''Locust'' class represents a user then, the system, will create a lot of locust instances (one for each user simulated). It contains...
* ''task_set'' attribute, which will be set with a ''TaskSet'' instance that defines the user behaviour.
* ''min_wait'' and ''max_wait'' attributes, milliseconds that a simulated user will wait between executing each task. If they are not set, locust will wait a second to execute it again (both have 1000 as default).
* ''host'', you can specify it on the command line using the –host option. It tells the host to be loaded.
* ''weight'' tells the frequency of use, for example, ''WebUserLocust'' will be executed three times ''MobileUserLocust''.
class WebUserLocust(Locust):
weight = 3
....
class MobileUserLocust(Locust):
weight = 1
....
The ''TaskSet'' represents the user behaviour. It's a collection of tasks (actions). If we were loadtesting an auction website this tasks would be like “loading the start page”, “searching for some product” and “making a bid”.
In a load test, each TaskSet will pick one of it’s tasks and call it. It will then wait a number of milliseconds, chosen at random between min_wait and max_wait attributes. Then it will again pick a new task which will be called, then wait again, and so on.
=== Examples ===
This...
from locust import HttpLocust, TaskSet
def login(l):
l.client.post("/login", {"username":"ellen_key", "password":"education"})
def index(l):
l.client.get("/")
def profile(l):
l.client.get("/profile")
class UserBehavior(TaskSet):
tasks = {index:2, profile:1}
def on_start(self):
login(self)
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait=5000
max_wait=9000
Is the same than...
from locust import HttpLocust, TaskSet, task
class UserBehavior(TaskSet):
def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """
self.login()
def login(self):
self.client.post("/login", {"username":"ellen_key", "password":"education"})
@task(2)
def index(self):
self.client.get("/")
@task(1)
def profile(self):
self.client.get("/profile")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait=5000
max_wait=9000
==== Executing Locust ====
In the same path than the locust file:
locust
Or in different path:
locust -f ../locust_files/my_locust_file.py
Running two locust in the same file (weight attribute will define the frequency of calling).
locust -f locust_file.py WebUserLocust MobileUserLocust
=== Running multiple processes ===
* It's recommended to install zeromq: ''$ pip install pyzmq''
* You can find more about this subject [[http://docs.locust.io/en/latest/running-locust-distributed.html|here]].
You'll need a master:
locust -f ../locust_files/my_locust_file.py --master
And an arbitrary number of slave processes:
locust -f ../locust_files/my_locust_file.py --slave
Or with multiple machines:
locust -f ../locust_files/my_locust_file.py --slave --master-host=192.168.0.100
==== Accessing to the web interface ====
You only need to access the url: [[http://127.0.0.1:8089]]
===== More things... =====
==== The TaskSet class ====
=== Declaring tasks with the task decorator ===
from locust import Locust, TaskSet, task
class MyTaskSet(TaskSet):
@task
def my_task(self):
print "Locust instance (%r) executing my_task" % (self.locust)
class MyLocust(Locust):
task_set = MyTaskSet
Or defining weight (task2 will be executed twice than task):
from locust import Locust, TaskSet, task
class MyTaskSet(TaskSet):
min_wait = 5000
max_wait = 15000
@task(3)
def task1(self):
pass
@task(6)
def task2(self):
pass
class MyLocust(Locust):
task_set = MyTaskSet
=== Set an dictionary to tasks attribute ===
The next dictionary will assign two tasks, each one with their weight.
class MyTaskSet(TaskSet):
tasks = {my_task: 3, another_task:1}
=== The on_start function ===
A TaskSet class can declare an on_start function. That function is called when a simulated user starts executing tasks in that TaskSet.
=== Nesting TaskSets ===
We can define a ''TaskSet'' as a task. Then it will represent a group of sub-task which are executed in that way.
It could be useful to represent a user that makes actions over the web (like enter in a web, then browse films and watch one, then navigate in the blog and comment and comment again, then navigate again, then browse films...).
A nested class set could call the ''self.interrupt()'' function. It interrupts the action in that class set.
=== Nested sub-tasks examples ===
class ForumPage(TaskSet):
@task(20)
def read_thread(self):
pass
@task(1)
def new_thread(self):
pass
@task(5)
def stop(self):
self.interrupt()
class UserBehaviour(TaskSet):
tasks = {ForumPage:10}
@task
def index(self):
pass
class MyTaskSet(TaskSet):
@task
class SubTaskSet(TaskSet):
@task
def my_task(self):
pass
==== Hacer nuestro propio cliente ====
Haremos un cliente "específico" para la tarea de deseemos. Este heredará de la clase ''Locust'' y usará el código que deseemos. Luego, para definir las acciones del test de carga heredaremos de esa clase; esta contendrá el taskset. Ver [[http://docs.locust.io/en/latest/testing-other-systems.html|aquí]], donde tenemos un código ''XmlRpcClient'' y una clase ''Locust'' que lo usa, la ''XmlRpcLocust''.
==== The HTTPClient ====
* [[http://docs.locust.io/en/latest/writing-a-locustfile.html#using-the-http-client]]