====== 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]]