Locust Performance Testing
Contents
1
Getting started 3
1.1
What is Locust?.......................................................................................................................... 3
1.1.1
Features......................................................................................................................... 3
1.1.2
Background.................................................................................................................. 4
1.1.3
Authors......................................................................................................................... 4
1.1.4
License.......................................................................................................................... 4
1.2
Installation................................................................................................................................... 4
1.2.1
Supported Python
Versions......................................................................................... 5
1.2.2
Installing Locust
on Windows..................................................................................... 5
1.2.3
Installing Locust
on macOS........................................................................................ 5
1.2.4
Increasing Maximum
Number of Open
Files Limit.................................................. 5
1.3
Quick start................................................................................................................................... 6
1.3.1
Example locustfile.py.................................................................................................. 6
1.3.1.1
Let’s break
it down:....................................................................................... 6
1.3.2
Start Locust................................................................................................................... 7
1.3.3
Open up Locust’s web interface.................................................................................. 8
2
Writing Locust
tests 11
2.1
Writing a locustfile................................................................................................................... 11
2.1.1
The Locust
class......................................................................................................... 11
2.1.1.1
The
wait_time attribute............................................................................... 11
2.1.1.2
The
weight attribute.................................................................................... 12
2.1.1.3
The
host attribute......................................................................................... 12
2.1.1.4
The
tasks attribute....................................................................................... 12
2.1.2
Tasks........................................................................................................................... 12
2.1.2.1
Declaring tasks............................................................................................ 13
2.1.2.2
tasks attribute............................................................................................... 13
2.1.3
TaskSet class.............................................................................................................. 14
2.1.3.1
Interrupting a TaskSet................................................................................. 15
2.1.3.2
Differences between
tasks in TaskSet
and Locust classes........................ 15
2.1.3.3
Referencing the Locust instance, or the parent
TaskSet instance............ 16
2.1.4
TaskSequence class................................................................................................... 16
2.1.5
Setups, Teardowns, on_start, and on_stop............................................................... 16
2.1.5.1
Setups and Teardowns................................................................................ 16
2.1.5.2
The on_start
and on_stop methods............................................................. 16
2.1.5.3
Order of events............................................................................................ 16
2.1.6
Making HTTP requests.............................................................................................. 17
2.1.6.1
Using the HTTP client................................................................................ 17
2.1.6.2
Safe mode.................................................................................................... 18
2.1.6.3
Manually controlling if a request
should be considered successful or a failure........................................................................................................... 18
2.1.6.4
Grouping requests
to URLs with dynamic parameters............................. 18
2.1.6.5
HTTP Proxy
settings................................................................................... 19
2.1.7
How to structure your
test code................................................................................ 19
3
Running your Locust tests 21
3.1
Running Locust
distributed...................................................................................................... 21
3.1.1
Example...................................................................................................................... 21
3.1.2
Options....................................................................................................................... 22
3.1.2.1
--master.................................................................................................. 22
3.1.2.2
--worker.................................................................................................. 22
3.1.2.3
--master-host=X.X.X.X.................................................................. 22
3.1.2.4 --master-port=5557......................................................................... 22
3.1.2.5
--master-bind-host=X.X.X.X..................................................... 22
3.1.2.6
--master-bind-port=5557............................................................. 22
3.1.2.7
--expect-workers=X......................................................................... 22
3.1.3
Running distributed with Docker.............................................................................. 22
3.1.4
Running Locust
distributed without the web UI...................................................... 22
3.1.5
Running Locust
distributed in Step
Load mode...................................................... 23
3.1.6
Increase Locust’s
performance................................................................................. 23
3.2
Running Locust
with Docker................................................................................................... 23
3.2.1
Environment Variables.............................................................................................. 23
3.2.2
Running your tests..................................................................................................... 23
3.3
Running Locust
without the web UI....................................................................................... 24
3.3.1
Setting a time limit
for the test.................................................................................. 24
3.3.2
Allow tasks
to finish their
iteration on shutdown.................................................... 24
3.3.3
Running Locust
distributed without the web UI...................................................... 24
3.4
Increase Locust’s
performance with a faster HTTP client.................................................... 24
3.4.1
How to use FastHttpLocust....................................................................................... 25
3.4.2
API.............................................................................................................................. 25
3.4.2.1
FastHttpLocust class................................................................................... 25
3.4.2.2
FastHttpSession class.................................................................................. 25
4.1
Running Locust
in Step Load
Mode....................................................................................... 29
4.1.1
Options....................................................................................................................... 29
4.1.1.1
--step-load........................................................................................... 29
4.1.1.2
--step-clients................................................................................... 29
4.1.1.3
--step-time........................................................................................... 29
4.1.1.4
Running Locust
in step load mode without
the web UI............................ 29
4.1.1.5
Running Locust
distributed in step load mode.......................................... 30
4.2
Retrieve test statistics in CSV format..................................................................................... 30
4.3
Testing other
systems using custom
clients............................................................................ 30
4.3.1
Sample XML-RPC
Locust client.............................................................................. 31
4.4
Extending Locust...................................................................................................................... 32
4.4.1
Adding Web Routes................................................................................................... 33
4.5
Logging..................................................................................................................................... 33
4.5.1
Options....................................................................................................................... 33
4.5.1.1
--skip-log-setup.............................................................................. 33
4.5.1.2
--loglevel............................................................................................. 33
4.5.1.3
--logfile................................................................................................ 33
Locust as a library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
34 |
||||
|
|
35 |
|||
API . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
35 |
|||
|
Locust class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
35 |
|||
|
HttpLocust class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
36 |
|||
|
TaskSet class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
36 |
|||
|
task decorator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
37 |
|||
|
TaskSequence class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
37 |
|||
|
seq_task decorator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
38 |
|||
|
Built in wait_time functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
39 |
|||
|
HttpSession class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
39 |
|||
|
Response class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
42 |
|||
|
ResponseContextManager class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
44 |
|||
|
InterruptTaskSet Exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
44 |
|||
|
Environment class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
44 |
|||
|
Event hooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
45 |
|||
|
|
5.1.13.1 EventHook class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
47 |
||
49 |
|||||
|
6.1 Third party tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
49 |
|||
|
6.1.1 Support for other sampler protocols, reporting etc . . . . . . . . . . . . . . . . . . . . . . . |
49 |
|||
|
6.1.2 Automate distributed runs with no manual steps . . . . . . . . . . . . . . . . . . . . . . . . |
49 |
|||
|
6.1.3 Using other
languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
49 |
|||
|
6.1.3.1 Golang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
49 |
|||
|
6.1.3.2 Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
49 |
|||
|
6.1.4 Configuration Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
50 |
|||
51 |
|||||
|
7.1 Changelog Highlights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
51 |
|||
|
7.1.1 In development (master) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
51 |
|||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
51 |
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
51 |
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
51 |
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
51 |
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
52 |
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
52 |
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
52 |
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
52 |
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
53 |
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
53 |
||||
0.9.0 . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
53 |
|||
0.8.1 . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
53 |
|||
0.8 . . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
53 |
|||
0.7.5 . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
54 |
|||
0.7.4 . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
54 |
|||
0.7.3 . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
54 |
|||
0.7.2 . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
54 |
|||
0.7.1 . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
54 |
|||
0.7 . . |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
55 |
|||
|
HTTP client
functionality moved to HttpLocust . . . . . . . . . . . . . . . . . . . |
55 |
|||
|
msgpack for serializing master/slave data . . . . . . . . . . . . . . . . . . . . . . . |
55 |
|||
|
requests updated
to version 2.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
55 |
|||
|
gevent updated to version 1.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
55 |
|||
|
7.1.20.5 Big refactoring of request statistics code
. . . . . . . . . . . . . . . . . . . . . . . |
55 |
7.1.20.6 Removed support for avg_wait . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
56 |
|
7.1.20.7 Removed support for ramping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
56 |
|
7.1.20.8 Locust
Event hooks now takes keyword
argument . . . . . . . . . . . . . . . . . . |
56 |
|
7.1.20.9 Other
changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
56 |
|
0.6.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
57 |
|
0.6.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
57 |
|
0.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
57 |
|
|
7.1.23.1
SubLocust replaced by TaskSet and Locust class behaviour changed . . . . |
57 |
|
7.1.23.2 Locust
now uses Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
58 |
|
7.1.23.3 Other
improvements and bug fixes . . . . . . . . . . . . . . . . . . . . . . . . . . |
60 |
|
7.1.23.4 Smaller API Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
60 |
0.5.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
60 |
|
0.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
60 |
|
|
7.1.25.1 API changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
60 |
|
7.1.25.2 Improvements and bug fixes
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
61 |
0.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
61 |
|
|
7.1.26.1 API changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
61 |
|
7.1.26.2 Improvements and bug fixes
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
61 |
63 |
||
|
65 |
Locust, Release
0.14.5
Everything you need to know about Locust
Getting started
1.1 What is Locust?
Locust is an easy-to-use, distributed, user load testing
tool. It is intended for load-testing web sites (or other systems) and figuring out how many concurrent users a system
can handle.
The idea is that during a test, a swarm of locusts will attack your website. The behavior of each locust (or test user if you will) is defined by you and the
swarming process is monitored from a web UI in real-time. This will help you battle test and identify bottlenecks in your code before letting
real users in.
Locust is completely event-based, and therefore it’s
possible to support thousands of concurrent users on a single machine. In contrast to many other
event-based apps it doesn’t use callbacks. Instead it uses light-weight
processes, through gevent. Each locust swarming your site is
actually running inside its own process (or greenlet, to be correct). This
allows you to write very expressive scenarios in Python without
complicating your code with callbacks.
1.1.1
Features
• Write user test scenarios in plain-old Python
No need for clunky UIs or bloated
XML—just code as you normally
would. Based on coroutines instead
of callbacks, your code looks and behaves
like normal, blocking
Python code.
• Distributed & Scalable
- supports hundreds
of thousands of users
Locust supports running load tests distributed over
multiple machines. Being event-based, even one Lo- cust node can handle thousands of users in a single process.
Part of the reason behind this is that even if
you simulate that many users, not all are actively hitting your system.
Often, users are idle figuring out what to do next. Requests per second != number of users online.
• Web-based UI
Locust has a neat HTML+JS user interface that shows
relevant test details in real-time. And since the UI is web-based, it’s cross-platform and easily extendable.
• Can test any system
Even though Locust
is web-oriented, it can be used to test almost any system.
Just write a client for what ever you wish to test and swarm it with locusts! It’s super easy!
•
Hackable
Locust is small
and very hackable
and we intend to keep it that way. All heavy-lifting of evented I/O and coroutines are delegated to gevent. The
brittleness of alternative testing tools was the reason we created Locust.
1.1.2 Background
Locust was created
because we were fed up with existing
solutions. None of them are solving the right problem
and to me, they are missing the point. We’ve tried both Apache JMeter
and Tsung. Both tools are quite OK to use; we’ve used the former
many times benchmarking stuff at work. JMeter comes
with a UI, which you might think for a second is a good thing. But you soon realize it’s a PITA to “code”
your testing scenarios through some point-and-click interface. Secondly,
JMeter is thread-bound. This means
for every user you want to simulate, you need a separate thread. Needless to say, benchmarking thousands of users on a single machine
just isn’t feasible.
Tsung, on the other hand, does not have these thread issues
as it’s written
in Erlang. It can make use of the light-weight processes offered by BEAM itself and happily scale up. But when it comes to defining the test scenarios, Tsung is as limited as JMeter. It offers an XML-based DSL to define how a user should behave when testing. I guess you can
imagine the horror of “coding” this. Displaying
any sorts of graphs or reports when completed requires you to post-process the log files generated from the test. Only then can you get an understanding of how the test went.
Anyway, we’ve tried to address these issues when
creating Locust. Hopefully none of the above pain points should exist.
I guess you could say we’re really just trying to scratch
our own itch here. We hope others will find it as useful as we do.
1.1.3 Authors
•
Jonatan Heyman (@jonatanheyman on Twitter)
•
Carl Byström (@cgbystrom on Twitter)
•
Joakim Hamrén (@Jahaaja on Twitter)
•
Hugo Heyman (@hugoheyman on Twitter)
1.1.4
License
Open source licensed
under the MIT license (see LICENSE file for details).
1.2 Installation
Locust is available on PyPI
and can be installed with pip.
If you want the bleeding edge version, you can use pip to install directly from our Git repository. For example, to install the master branch
using Python 3:
Once
Locust is installed, a locust command
should be available in your shell. (if you’re not using virtualenv—which you should—make sure your python
script directory is on your path).
To see available options, run:
1.2.1 Supported Python Versions
Locust is supported on Python 3.6, 3.7 and 3.8.
1.2.2 Installing
Locust on Windows
On Windows, running
pip install
locustio should work.
However, if it doesn’t, chances
are that it can be fixed by first installing the pre built binary packages
for pyzmq, gevent
and greenlet.
You can find an unofficial collection of pre built python
packages for windows
here: http://www.lfd.uci.edu/~gohlke/ pythonlibs/
When you’ve downloaded a pre-built .whl file, you can install it with:
Once you’ve
done that you should be able to just pip install
locustio.
Note: Running Locust
on Windows should work fine for developing and testing your load testing
scripts. However, when running
large scale tests, it’s recommended that you do that on Linux machines, since
gevent’s performance under Windows
is poor.
1.2.3 Installing
Locust on macOS
Make sure you have a working installation of Python 3.6
or higher and follow the above instructions. Homebrew can be used to install Python
on macOS.
1.2.4 Increasing Maximum Number
of Open Files
Limit
Every HTTP connection on a machine opens a new file
(technically a file descriptor). Operating systems may set a low limit for the maximum number of files
that can be open. If the limit is less than the number of simulated users in a test, failures
will occur.
Increase the operating system’s default maximum number
of files limit to a number higher than the number of simu- lated
users you’ll want to run. How to do this depends on the operating
system in use.
1.3 Quick start
1.3.1 Example locustfile.py
When using Locust
you define the behaviour of users in Python code,
and then you have the ability to simulate any number of those users while gathering
request statistic. The entrypoint for
defining the user behaviour is the locustfile.py.
Note: The locustfile.py is a normal
Python file that will get imported by Locust. Within
it you can import modules just as you would in any python
code.
The file can be named something
else and specified
with the -f flag to the locust command.
Below is a quick little example
of a simple locustfile.py:
1.3.1.1 Let’s break it down:
Here we define a class for the users that we will be simulating. It inherits from HttpLocust which gives each user a
client
attribute, which is an
instance of HttpSession, that can be used to make HTTP requests to the
target system that we want to
load test. When a test starts locust will create an instance of this class for
every user that it simulates, and each of these users will start running within their own green gevent
thread.
Our class defines
a wait_time function that will make the simulated users
wait between 5 and 9 seconds after
each task is executed.
@task(2) def index(self):
(continues on next page)
(continued from previous page)
We’ve also declared two tasks by decorating two methods with @task and given them different weights
(2 and 1). When a simulated user of this type runs it’ll pick one of either index or view_post - with twice the chance
of picking index -
call that method and then pick a duration uniformly between 5 and 9 and just
sleep for that duration. After it’s wait time it’ll
pick a new task and keep repeating
that.
In the view_post task we load a dynamic
URL by using a query parameter that is a number picked
at random between 1 and 10000. In order to not get 10k entries in Locust’s statistics - since the stats is grouped on the URL - we use the name parameter to group all those requests under an entry named "/post?id=[post-id]" instead.
Additionally we’ve declared a on_start
method. A method
with this name will be called for each simulated
user when they start. For more info see Setups, Teardowns, on_start, and on_stop.
1.3.2
Start Locust
To run Locust with the above Locust file, if it was named locustfile.py and located in the current working directory, we could run:
If
the Locust file is located
under a subdirectory and/or named different than locustfile.py, specify it using -f:
To run Locust distributed across multiple processes we would start a master
process by specifying --master:
and
then we would
start an arbitrary number of worker
processes:
If we want to run Locust distributed on multiple machines
we would also have to specify the master host when starting
the workers (this
is not needed when running
Locust distributed on a single
machine, since the master host defaults to 127.0.0.1):
Parameters can also be set in a config file (locust.conf or ~/.locust.conf) or in env vars, prefixed
by LOCUST_ For example: (this will do the same thing as the previous
command)
Note: To see all available options
type: locust
--help
1.3.3 Open up Locust’s
web interface
Once you’ve started
Locust using one of the above command lines, you should open up a browser and point it to http://127.0.0.1:8089 (if you are running
Locust locally). Then you should
be greeted with something like this:
If you run Locust in Step Load Mode, then you should
be greeted with Locust UI like this:
Writing Locust
tests
2.1 Writing a locustfile
A locustfile is a normal python file. The only
requirement is that it declares at least one class— let’s call it the locust class—that inherits from the class Locust.
2.1.1 The Locust class
A locust class represents one user (or a swarming locust
if you will). Locust will spawn (hatch) one instance of the locust class for each user that is being simulated. There are a few attributes that a locust
class should typically define.
2.1.1.1 The wait_time attribute
In addition to the task_set attribute, one should also declare a wait_time method. It’s used to determine for how long a simulated user will wait
between executing tasks. Locust comes with a few built in functions that return
a few common wait_time methods.
The most common one is between. It’s used to make the simulated
users wait a random time between a min and max value after
each task execution. Other built in wait time functions are constant and constant_pacing.
With the following
locustfile, each user would wait between 5 and 15 seconds between
tasks:
The wait_time
method should return a number of seconds (or fraction
of a second) and can also be declared on a TaskSet
class, in which case it will only be used for that TaskSet.
It’s also possible to declare your own wait_time method directly on a Locust or TaskSet class. The following locust
class would start
sleeping for one second and then one, two, three,
etc.
If more than one locust class exists
in the file, and no locusts are specified on the command
line, each new spawn will
choose randomly from the existing
locusts. Otherwise, you can specify
which locusts to use from the same file like so:
If you wish to make one of these locusts execute
more often you can set a weight attribute on those classes.
Say for example, web users
are three times more likely
than mobile users:
The host attribute is a URL prefix (i.e. “http://google.com”) to the host that is to be
loaded. Usually, this is specified in Locust’s web UI or on the command line, using the --host option,
when locust is started.
If one declares a host
attribute in the locust class, it will be used in the case when no --host is specified on the command line or in the web request.
A Locust class can have tasks
declared as methods under it using the @task decorator, but one can also specify tasks using the tasks attribute which is descibed
in more details
below.
2.1.2 Tasks
When a load test is started, an instance of a Locust
class will be created for each simulated user and they will start running within their own green thread.
When these users run they pick tasks that they execute, sleeps for awhile, and then picks a new task and so on.
The tasks are normal python callables and — if we were
load-testing an auction website — they could do stuff like “loading
the start page”,
“searching for some product”, “making
a bid”, etc.
2.1.2.1 Declaring tasks
The typical way of declaring tasks for a Locust class (or a TaskSet) it to use the task decorator. Here is an example:
@task takes an optional
weight argument that can be used to specify the task’s execution
ratio. In the following example
task2 will have twice the chance
of being picked
as task1:
2.1.2.2 tasks attribute
Using the @task decorator to declare tasks is a convenience, and
usually the best way to do it. However,
it’s also possible to define the tasks
of a
Locust or TaskSet by setting the tasks
attribute (using the @task decorator will actually just populate the tasks attribute).
The tasks attribute
is either a list of Task, or a <Task :
int> dict, where Task is either a python callable or a TaskSet class (more on that below). If the task is a normal
python function they receive a single argument
which is the Locust instance that is executing the task.
Here is an example of a locust
task declared as a normal
python function:
If the tasks
attribute is specified as a list, each time a task is to be performed, it will be randomly chosen
from the tasks attribute. If however, tasks is a dict — with callables as keys
and ints as values — the task that is to be executed will be chosen at random but with the int as ratio. So with a tasks that looks like this:
my_task
would be 3 times
more likely to be executed
than another_task.
Internally the above dict will actually
be expanded into a list (and the tasks attribute is updated)
that looks like this:
and then Python’s
random.choice() is used pick tasks from the list.
2.1.3
TaskSet class
Since real websites
are usually built up in an hierarchical way, with multiple
sub-sections, locust has the TaskSet
class. A locust task can not
only be a Python callable, but also a TaskSet class. A TaskSet is a collection of locust tasks that will be executed much like the tasks declared directly on a
Locust class, with the user sleeping in between task executions. Here’s a short example
of a locustfile that has a TaskSet:
A
TaskSet can also be inlined
directly under a Locust/TaskSet class using the @task decorator:
The tasks of a TaskSet class can be other TaskSet
classes, allowing them to be nested any number of levels. This allows
us to define a behaviour that simulates users in a more realistic way. For
example we could define TaskSets with the following structure:
- Main user behaviour - Index page - Forum page - Read thread - Reply
(continues on next page)
(continued from previous page)
When a running Locust thread
picks a TaskSet class for execution an instance of this class will be created
and execution will then go into this TaskSet. What happens then is that one of the
TaskSet’s tasks will be picked and executed, and then the thread will sleep for a duration
specified by the Locust’s wait_time
function (unless a wait_time function
has been declared
directly on the TaskSet class,
in which case it’ll use that function
instead), then pick a new task from the TaskSet’s
tasks, wait again,
and so on.
2.1.3.1 Interrupting
a TaskSet
One important thing to know about TaskSets
is that they will never stop executing
their tasks, and hand over execution back to their parent Locust/TaskSet, by
themselves. This has to be done by the developer by calling the TaskSet. interrupt() method.
interrupt(self, reschedule=True)
Interrupt the TaskSet and hand over execution control
back to the parent TaskSet.
If reschedule is
True (default), the parent Locust
will immediately re-schedule, and execute, a new task
This method
should not be called by the root TaskSet (the one that is immediately, attached to the Locust class’
task_set attribute), but rather
in nested TaskSet
classes further down the hierarchy.
In the following example, if we didn’t
have the stop task that calls self.interrupt(), the simulated user would never stop running
tasks from the Forum taskset
once it has went into it:
Using the interrupt function, we can — together with
task weighting — define how likely it is that a simulated user leaves the forum.
2.1.3.2 Differences
between tasks in TaskSet and Locust classes
One difference for tasks residing under a TaskSet, compared to tasks
residing directly under a Locust, is that the
argument that they are passed when executed (self for tasks declared
as methods with the @task decorator) is a
reference to the TaskSet instance, instead of the Locust user instance. The Locust instance can be accessed from within a TaskSet instance
through the TaskSet.locust. TaskSets also contains a convenience client attribute that refers
to the client attribute on the Locust
instance.
2.1.3.3 Referencing
the Locust instance, or the parent
TaskSet instance
A TaskSet instance
will have the attribute locust point to its Locust instance, and the attribute
parent point to its parent TaskSet instance.
2.1.4 TaskSequence class
TaskSequence class is a TaskSet but its tasks will be executed in order. To define this order you should do the following:
In the above example, the order is defined to execute first_task, then second_task and lastly the third_task for 10 times.
As you can see, you can compose
@seq_task with @task decorator, and of course you can also nest TaskSets
within TaskSequences and vice versa.
2.1.5 Setups, Teardowns, on_start,
and on_stop
Locust optionally supports Locust level setup
and teardown, TaskSet level setup and teardown, and
TaskSet on_start and on_stop
2.1.5.1 Setups and Teardowns
setup
and teardown, whether it’s run on Locust or TaskSet, are methods
that are run only once.
setup is run
before tasks start running, while teardown
is run after all tasks have
finished and Locust is exiting. This enables you to perform some preparation before
tasks start running
(like creating a database) and to clean up before
the Locust quits
(like deleting the database).
To use, simply declare
a setup and/or teardown on the Locust or TaskSet class. These methods
will be run for you.
2.1.5.2 The on_start and on_stop methods
A TaskSet class can declare an
on_start
method or an on_stop method. The on_start method is called when a simulated user starts executing
that TaskSet class,
while the on_stop <locust.core.TaskSet.on_stop() method is called when the TaskSet
is stopped.
2.1.5.3 Order of events
Since many setup
and cleanup operations are dependent on each other,
here is the order which
they are run:
1.
Locust setup (once)
2. TaskSet setup (once)
3. TaskSet on_start
(every time a user starts
executing a new TaskSet)
4. TaskSet tasks. . .
5. TaskSet on_stop
(every time a user stops executing a TaskSet, either
to run a different one or at shutdown)
6. TaskSet teardown
(once)
7. Locust teardown
(once)
In general, the setup and teardown methods
should be complementary.
2.1.6 Making HTTP requests
So far, we’ve only covered
the task scheduling part of a Locust user. In order
to actually load test a system we need to make HTTP requests.
To help us do this, the HttpLocust class exists. When
using this class, each instance gets a client attribute which will be an instance
of HttpSession which can be used to make HTTP requests.
class HttpLocust(*args, **kwargs)
Represents an HTTP “user” which is to be hatched
and attack the system that is to be load tested.
The behaviour of this user is defined
by it’s tasks. Tasks can be declared
either directly on the class by using the
@task decorator on the methods, or by setting
the tasks attribute.
This class creates a client attribute on instantiation which is an HTTP client with support for keeping a user session between
requests.
client = None
Instance of HttpSession that is created
upon instantiation of Locust. The client support
cookies, and therefore keeps the session
between HTTP requests.
When inheriting from the HttpLocust class, we can use its
client attribute to make HTTP requests against the server. Here is an example of a locust file that can be used to load test a site with two URLs; / and
/about/:
Using the above Locust class,
each simulated user will wait between 5 and 15 seconds between
the requests, and / will be requested twice
as much as /about/.
2.1.6.1 Using the HTTP client
Each instance of HttpLocust has an instance
of HttpSession
in the client attribute. The HttpSession class is actually a subclass of requests.Session
and can be used to make HTTP
requests, that will be reported to Locust’s statistics, using the get, post, put, delete, head, patch
and options
methods. The
HttpSession instance will preserve
cookies between requests
so that it can be used to log in to websites
and keep a session between
requests.
The client attribute can also be referenced from the Locust instance’s TaskSet
instances so that it’s easy to retrieve
the client and make HTTP requests from within your tasks.
Here’s a simple example
that makes a GET request
to the /about path
(in this case we assume self is an instance of a
TaskSet or HttpLocust class:
And
here’s an example
making a POST request:
2.1.6.2 Safe mode
The HTTP client is configured to run in safe_mode. What
this does is that any request that fails due to a connection error, timeout, or similar will not raise an exception, but rather return an empty dummy Response
object. The request
will be reported as a failure in Locust’s statistics. The returned dummy Response’s content attribute will be set to None, and its status_code
will be 0.
2.1.6.3 Manually controlling if a request
should be considered successful or a failure
By default, requests
are marked as failed requests
unless the HTTP response code is OK (<400). Most of the time, this default
is what you want. Sometimes however—for example when testing a URL endpoint
that you expect to return 404, or
testing a badly designed system that might return 200 OK even though an error occurred—there’s a need for manually
controlling if locust
should consider a request as a success
or a failure.
One can mark requests as failed, even when the response code
is OK, by using the catch_response argument
and a with statement:
Just as one can mark requests
with OK response codes as failures, one can also use catch_response argument together with a with statement to make requests
that resulted in an HTTP error code still be reported as a success
in the statistics:
2.1.6.4 Grouping requests to URLs with dynamic parameters
It’s very common for websites to have pages whose URLs
contain some kind of dynamic parameter(s). Often
it makes sense to group these URLs together in Locust’s statistics. This can be done by passing a name argument to the HttpSession's different request
methods.
Example:
2.1.6.5 HTTP Proxy settings
To improve performance, we configure requests to not look for HTTP
proxy settings in the environment by setting
requests.Session’s trust_env attribute to False. If you don’t want this you can manually
set locust_instance. client.trust_env to True. For further details,
refer to the documentation of requests.
2.1.7 How to structure your test code
It’s important to remember that the locustfile.py is
just an ordinary Python module that is imported by Locust. From this module you’re free to import other
python code just as you normally would in any Python program. The current working
directory is automatically added to python’s
sys.path, so any python
file/module/packages that resides
in the working directory
can be imported using the python import statement.
For small tests, keeping all
of the test code in a single locustfile.py should work fine, but for larger test
suites, you’ll probably
want to split the code into multiple
files and directories.
How you structure
the test source
code is ofcourse entirely up to you, but we recommend that you follow Python best practices. Here’s an example
file structure of an imaginary
Locust project:
•
Project root
– common/
*
init .py
*
auth.py
*
config.py
– locustfile.py
– requirements.txt (External Python dependencies is often kept in a requirements.txt) A project with multiple
different locustfiles could also keep them in a separate
subdirectory:
•
Project root
– common/
*
init .py
*
auth.py
*
config.py
– locustfiles/
*
api.py
*
website.py
– requirements.txt
With any of the above
project structure, your locustfile can import common
libraries using:
Running your Locust tests
3.1 Running Locust distributed
Once a single
machine isn’t enough
to simulate the number of users that you need,
Locust supports running
load tests distributed across multiple machines.
To do this, you start one
instance of Locust in master mode using the --master flag. This is the instance that will be
running Locust’s web interface where you start
the test and see live statistics. The master node doesn’t simulate any users
itself. Instead you have to start one or —most likely—multiple worker Locust
nodes using the --worker flag, together with the --master-host (to specify the IP/hostname of the master node).
A common set up is to run a single master on one machine,
and then run one worker instance
per processor core on the worker machines.
Note: Both the master and each worker machine,
must have a copy of the locust test scripts
when running Locust
distributed.
Note: It’s
recommended that you start a number of simulated users that are greater than number
of locust classes * number of workers when running Locust distributed.
Otherwise - due to the current implementation - you might end up with a distribution of the Locust
classes that doesn’t
correspond to the Locust classes’ weight attribute. And if the hatch rate is lower than the number of worker nodes,
the hatching would occur in “bursts” where all
worker node would hatch a single user and then sleep for multiple seconds,
hatch another user,
sleep and repeat.
3.1.1 Example
To start locust in master mode:
And then on each worker (replace
192.168.0.14 with IP of the master
machine):
3.1.2
Options
3.1.2.1 --master
Sets locust
in master mode. The web interface will run on this node.
3.1.2.2 --worker
Sets locust
in worker mode.
3.1.2.3 --master-host=X.X.X.X
Optionally used together
with --worker to set the hostname/IP of the master
node (defaults to 127.0.0.1)
3.1.2.4 --master-port=5557
Optionally used together
with --worker to set the port number
of the master node (defaults to 5557).
3.1.2.5 --master-bind-host=X.X.X.X
Optionally used together
with --master. Determines what network interface
that the master node will bind to. Defaults to * (all available interfaces).
3.1.2.6 --master-bind-port=5557
Optionally used together with --master. Determines
what network ports that the master node will listen to. Defaults
to 5557.
3.1.2.7 --expect-workers=X
Used when starting
the master node with --no-web. The master node will then wait until X worker
nodes has connected before the test is started.
3.1.3 Running distributed with Docker
See Running Locust with Docker
3.1.4 Running Locust distributed without the web UI
3.1.5
Running Locust
distributed in Step Load mode
See Running Locust in Step Load Mode
3.1.6 Increase Locust’s performance
If you’re
planning to run large-scale load tests you might be interested to use the alternative HTTP client that’s shipped with
Locust. You can read more about it here: Increase Locust’s performance with a faster
HTTP client
3.2 Running Locust with Docker
To keep things simple
we provide a single Docker
image that can run standalone, as a master,
or as a worker.
3.2.1 Environment Variables
•
LOCUST_MODE
One of ‘standalone’, ‘master’, or ‘worker’. Defaults
to ‘standalone’.
•
LOCUSTFILE_PATH
The path inside the container to the locustfile. Defaults to ‘/locustfile.py’
•
LOCUST_MASTER_HOST
The hostname
of the master.
•
LOCUST_MASTER_PORT
The port used to communicate with the master. Defaults to 5557.
•
LOCUST_OPTS
Additional options
to pass to locust. Defaults
to ‘’
3.2.2 Running your tests
The easiest way to get your tests running is to build an image with your test file built in. Once you’ve written your locustfile you can bake it into a Docker
image with a simple Dockerfile:
You’ll need to push the built image to a Docker
repository such as Dockerhub, AWS ECR, or GCR in order for dis- tributed
infrastructure to be able to pull the image. See your chosen
repository’s documentation on how to authenticate with the repository to pull the image.
For debugging locally
you can run a container and pass your locustfile in as a volume:
To run in standalone mode without the web UI, you can use the LOCUST_OPTS environment variable to add the required options:
If you are Kubernetes user, you can use the Helm chart to scale
and run locust.
3.3 Running Locust without
the web UI
You can run locust without the web UI - for example if you want to run it in some automated flow, like a CI server - by using the --no-web flag
together with -c and -r:
-c specifies the number
of Locust users to spawn,
and -r specifies the hatch rate (number
of users to spawn per second).
3.3.1 Setting a time limit for the test
If you want to specify the run time for a test, you can do that with --run-time or -t:
Locust will shutdown once the time is up.
3.3.2 Allow tasks to finish their iteration on shutdown
By default, locust will stop your tasks immediately. If you want to allow your tasks to finish their iteration,
you can use --stop-timeout <seconds>.
3.3.3 Running Locust distributed without the web UI
If you want to run Locust distributed without
the web UI, you should specify the --expect-workers option when starting the master node, to specify the
number of worker nodes that are expected to connect. It will then wait until that many worker
nodes have connected before starting the test.
3.4
Increase Locust’s
performance with a faster HTTP client
Locust’s default HTTP client
uses python-requests. The reason
for this is that requests is a very well-maintained python package, that provides a really
nice API, that many python developers are familiar with. Therefore, in many
cases, we recommend that you use the default HttpLocust which uses requests. However, if you’re planning to
run really large scale tests, Locust comes with an alternative HTTP client, FastHttpLocust which uses geventhttpclient instead of requests. This client is significantly faster,
and we’ve seen 5x-6x performance increases for making
HTTP- requests. This does
not necessarily mean that the number of users one can simulate per CPU core
will automatically increase 5x-6x,
since it also depends on what else the load testing script does. However, if your locust scripts are spending
most of their CPU time in making HTTP-requests, you are likely to see signifant performance gains.
3.4.1
How to use FastHttpLocust
Subclass FastHttpLocust instead
of HttpLocust:
Note: FastHttpLocust
uses a whole other HTTP client implementation, with a different API, compared
to the de- fault HttpLocust that uses
python-requests. Therefore
FastHttpLocust might not work as a drop-in replacement for HttpLocust, depending on how the HttpClient is used.
3.4.2
API
3.4.2.1 FastHttpLocust class
class FastHttpLocust(environment)
FastHttpLocust uses a different HTTP client (geventhttpclient) compared to HttpLocust (python-requests). It’s significantly faster, but not as capable.
The behaviour of this user is defined
by it’s tasks. Tasks can be declared
either directly on the class by using the
@task decorator on the methods, or by setting
the tasks attribute.
This class creates a client attribute on instantiation which is an HTTP client with support for keeping a user session between
requests.
connection_timeout = 60.0
Parameter passed to FastHttpSession
insecure = True
Parameter passed to FastHttpSession. Default
True, meaning no SSL verification.
max_redirects = 5
Parameter passed to FastHttpSession. Default 5, meaning
4 redirects.
max_retries = 1
Parameter passed to FastHttpSession. Default 1, meaning
zero retries.
network_timeout = 60.0
Parameter passed to FastHttpSession
3.4.2.2 FastHttpSession class
class FastHttpSession(environment: locust.env.Environment, base_url: str,
**kwargs)
get(path, **kwargs)
Sends a GET request
Sends a HEAD request
options(path, **kwargs)
Sends a OPTIONS
request
patch(path, data=None, **kwargs)
Sends a POST request
post(path, data=None, **kwargs)
Sends a POST request
put(path, data=None, **kwargs)
Sends a PUT request
request(method: str, path: str,
name: str
= None, data: str = None, catch_response: bool = False, stream: bool = False, headers: dict = None, auth=None, json: dict = None,
**kwargs)
Send and HTTP request Returns locust.contrib.fasthttp.FastResponse object.
Parameters
• method – method for the new Request object.
• path – Path that will be concatenated with the base host URL that has been specified. Can also be a full URL, in which case the full URL will be requested, and the base host is ignored.
• name – (optional) An argument that can
be specified to use as label in Locust’s statistics instead of the URL path. This can be used to group different URL’s that are requested into a single
entry in Locust’s
statistics.
•
catch_response – (optional)
Boolean argument that, if set, can be used to make a request return
a context manager
to work as argument to a with statement. This will allow the request
to be marked as a fail based on the content of the response, even if the response code is ok (2xx). The opposite also
works, one can use catch_response to catch a request and then mark it as successful even if the response code was not (i.e 500 or 404).
• data – (optional) String/bytes to send in the body of the request.
•
json –
(optional) Dictionary to send in the body of the request. Automatically sets Content-Type and Accept headers
to “application/json”. Only used if data is not set.
• headers – (optional) Dictionary of HTTP Headers
to send with the request.
• auth – (optional) Auth (username, password)
tuple to enable Basic HTTP Auth.
•
stream – (optional) If set to true the response body will not be consumed
immediately and
can instead be consumed by accessing the stream attribute on the Response
object. Another side effect of setting stream
to True is that the time for downloading the response content will not be accounted for in the request time that is reported by Locust.
class
FastResponse(ghc_response, request=None, sent_request=None)
content
Unzips if necessary
and buffers the received body. Careful with large files!
headers = None
Dict like object
containing the response
headers
→
json() dict
Parses the response
as json and returns a dict
text
Returns the text content of the response
as a decoded string
Other functionalities
4.1 Running Locust in Step Load Mode
If you want to monitor
your service performance with different user load and probe the max
tps that can be achieved, you can run Locust with Step Load enabled with --step-load:
4.1.1
Options
4.1.1.1 --step-load
Enable Step Load mode to monitor
how performance metrics
varies when user load increases.
4.1.1.2 --step-clients
Client count
to increase by step in Step Load mode. Only used together
with --step-load.
4.1.1.3 --step-time
Step duration
in Step Load mode, e.g. (300s, 20m, 3h, 1h30m,
etc.). Only used together with --step-load.
4.1.1.4 Running Locust in step load mode without
the web UI
If you want to run Locust in step load mode without the web UI, you can do that with --step-clients and
--step-time:
29
Locust will swarm
the clients by step and shutdown once the time is up.
4.1.1.5 Running Locust distributed in step load mode
If you want to run Locust distributed in step load mode, you should
specify the --step-load option when starting
the master node,
to swarm locusts
by step. It will then show the --step-clients option and --step-time option
in Locust UI.
4.2 Retrieve test statistics in CSV format
You may wish to consume your Locust results
via a CSV file. In this case, there are two ways to do this. First,
when running Locust with the web UI, you can retrieve CSV files under the Download
Data tab.
Secondly, you can run Locust with a flag which will periodically save two CSV files. This is particularly useful if you plan on running Locust in an automated
way with the --no-web flag:
The files will be named example_response_times.csv and example_stats.csv (when using
--csv=example) and mirror Locust’s
built in stat pages.
You can also customize how frequently this is written
if you desire faster (or slower) writing:
This data will write two files with _response_times.csv and _stats.csv added to the name you give:
and:
4.3 Testing other systems
using custom clients
Locust was built with HTTP as its main target. However,
it can easily be extended
to load test any request/response based system, by writing a custom client that triggers request_success and request_failure events.
4.3.1 Sample XML-RPC Locust
client
Here is an example of a Locust class, XmlRpcLocust, which provides an XML-RPC client,
XmlRpcClient, and tracks all requests made:
import time
from xmlrpc.client import ServerProxy, Fault
from locust import Locust, task, between
class XmlRpcClient(ServerProxy):
"""
Simple, sample XML RPC client implementation that wraps xmlrpclib.ServerProxy and fires
locust events on request_success and request_failure, so that all requests gets tracked in locust's statistics.
"""
_locust_environment
= None def getattr (self, name):
func = ServerProxy. getattr (self, name)
def wrapper(*args, **kwargs): start_time
= time.time() try:
result = func(*args, **kwargs)
except Fault as e:
total_time = int((time.time()
- start_time) * 1000) self._locust_environment.events.request_failure.fire(request_type=
˓→"xmlrpc", name=name, response_time=total_time, exception=e)
else:
total_time = int((time.time()
- start_time) * 1000) self._locust_environment.events.request_success.fire(request_type=
˓→"xmlrpc", name=name, response_time=total_time, response_length=0)
# In this example,
I've hardcoded response_length=0. If we would want
˓→the response length to be
# reported correctly in the statistics, we would probably
need to
˓→hook in at a lower level
return wrapper
class XmlRpcLocust(Locust):
"""
This is the abstract Locust
class which should
be subclassed. It provides an XML-
˓→RPC client
that can be used to make XML-RPC requests
that will be tracked in Locust's
˓→statistics.
"""
abstract = True
def init (self, *args, **kwargs): super(XmlRpcLocust, self).
init
(*args, **kwargs) self.client = XmlRpcClient(self.host) self.client._locust_environment =
self.environment
class ApiUser(XmlRpcLocust):
host = "http://127.0.0.1:8877/"
(continues on next page)
4.3. Testing
other systems using custom clients 31
(continued from previous page)
If you’ve written Locust tests before,
you’ll recognize the class called ApiUser which is a normal Locust class that has
a couple of tasks declared. However,
the ApiUser inherits from XmlRpcLocust that you can see right above ApiUser. The XmlRpcLocust is marked as abstract using abstract = True which
means that Locust till not try to
create simulated users from that class (only of classes that extends it). XmlRpcLocust provides an instance of XmlRpcClient under the client attribute.
The XmlRpcClient is a wrapper around the standard
library’s xmlrpc.client.ServerProxy. It ba-
sically just proxies
the function calls, but with the important
addition of firing locust.event.Events. request_success and locust.event.Events.request_failure
events, which will record all calls in Locust’s statistics.
Here’s an implementation of an XML-RPC
server that would work as a server for the code above:
4.4 Extending Locust
Locust comes with a number
of events hooks
that can be used to extend Locust
in different ways.
Event hooks live on the Environment
instance under the events attribute. However,
since the Environment instance hasn’t
been created when locustfiles are imported, the events object can also be
accessed at the module level of the locustfile through
the locust.events variable.
Here’s an example
on how to set up an event listener:
from locust import events @events.request_success.add_listener
(continues on next page)
(continued from previous page)
Note: It’s highly recommended that you add a wildcard keyword argument
in your listeners (the **kw in the code above),
to prevent your code from breaking if new arguments
are added in a future
version.
See also:
To see all available event, please see Event hooks.
4.4.1 Adding Web Routes
Locust uses Flask to serve the web UI and therefore it is easy to add web end-points to the web UI. By listening to the
init
event, we can retrieve a reference
to the Flask app instance
and use that to set up a new route:
You should
now be able to start locust and browse to http://127.0.0.1:8089/added_page
4.5 Logging
Locust comes with a basic logging
configuration that optionally takes --loglevel and/or --logfile to modify the configuration. If you want to control the logging configuration you
can supply the --skip-log-setup flag, which ignores
the other parameters.
4.5.1
Options
4.5.1.1 --skip-log-setup
Disable Locust’s
logging setup. Instead,
the configuration is provided by the Locust test or Python defaults.
4.5.1.2 --loglevel
Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default
is INFO. The short-hand version
is -L.
4.5.1.3 --logfile
Path to log file. If not set, log will go to stdout/stderr.
4.6 Using Locust as a library
It’s possible to use Locust as a library
instead of running
Locust by invoking
the locust command.
Here’s an example:
API
Represents a “user” which is to be hatched and attack the system that is to be load tested.
The behaviour of this user is defined
by it’s tasks. Tasks can be declared
either directly on the class by using the
@task decorator on the methods, or by setting
the tasks attribute.
This class should usually be subclassed by a class that defines some kind of client. For example when load testing an HTTP system, you probably want to use the HttpLocust class.
abstract = True
If abstract is True it the class is meant to be subclassed (users
of this class itself will not be spawned during
a test)
tasks = []
Collection of python callables and/or
TaskSet classes that the Locust user(s) will run. If tasks is a list, the task to be performed will be picked randomly.
If tasks is a (callable,int) list
of two-tuples, or a {callable:int} dict, the task to be performed will be picked
randomly, but each task will be weighted according to it’s corresponding
int value. So in the following case ThreadPage
will be fifteen
times more likely to be picked than write_post:
Method that returns
the time (in seconds) between
the execution of locust tasks. Can be overridden for individual TaskSets.
Example:
weight = 10
Probability of locust
being chosen. The higher the weight, the greater is the chance
of it being chosen.
class HttpLocust(*args, **kwargs)
Represents an HTTP “user” which is to be hatched
and attack the system that is to be load tested.
The behaviour of this user is defined
by it’s tasks. Tasks can be declared
either directly on the class by using the
@task decorator on the methods, or by setting
the tasks attribute.
This class creates a client
attribute on instantiation which is an HTTP client with support for keeping
a user session between requests.
abstract = True
If abstract is True it the class is meant to be subclassed (users
of this class itself will not be spawned during
a test)
client = None
Instance of HttpSession that is created
upon instantiation of Locust. The client support
cookies, and therefore keeps the session
between HTTP requests.
Class defining a set of tasks that a Locust
user will execute.
When a TaskSet starts running, it will pick a task from
the tasks attribute, execute it, and
then sleep for the number of seconds returned by it’s wait_time function. If no wait_time
method has been declared on the TaskSet, it’ll call the wait_time
function on the Locust by default. It will then schedule another
task for execution
and so on.
TaskSets can be nested, which means that a TaskSet’s tasks attribute can contain another
TaskSet. If the nested TaskSet it scheduled to be executed, it
will be instantiated and called from the current executing TaskSet. Ex- ecution in the currently running TaskSet will then be handed over to the nested TaskSet which will continue to run
until it throws an InterruptTaskSet exception, which is done when TaskSet.interrupt()
is called. (execution will then continue
in the first TaskSet).
client
Reference to the client attribute of the root Locust
instance.
interrupt(reschedule=True)
Interrupt the TaskSet
and hand over execution control
back to the parent TaskSet.
If reschedule is
True (default), the parent Locust
will immediately re-schedule, and execute, a new task
This method should not be called by the root TaskSet (the one that
is immediately, attached to the Locust class’ task_set attribute), but rather in nested TaskSet
classes further down the hierarchy.
locust = None
Will refer to the root Locust
class instance when the TaskSet
has been instantiated
Will refer to the parent
TaskSet, or Locust, class instance when the TaskSet has been instantiated. Useful for nested
TaskSet classes.
schedule_task(task_callable, args=None, kwargs=None, first=False)
Add a task to the Locust’s task execution queue.
Arguments:
•
task_callable: Locust task to schedule
•
args: Arguments that will be passed to the task callable
•
kwargs: Dict of keyword arguments
that will be passed to the task callable.
•
first: Optional keyword
argument. If True, the task will be put first in the queue.
tasks = []
Collection of python callables and/or
TaskSet classes that the Locust user(s) will run. If tasks is a list, the task to be performed will be picked randomly.
If tasks is a (callable,int) list
of two-tuples, or a {callable:int} dict, the task to be performed will be picked
randomly, but each task will be weighted according to it’s corresponding
int value. So in the following case ThreadPage
will be fifteen
times more likely to be picked than write_post:
wait_time()
Method that returns
the time (in seconds) between
the execution of tasks. Example:
Used as a convenience decorator to be able to declare tasks for a Locust or a TaskSet inline in the class. Example:
class TaskSequence(parent)
Class defining a sequence of tasks that a Locust
user will execute.
When a TaskSequence starts running, it will pick the task in index from
the tasks attribute, execute it, and call its wait_function which will define
a time to sleep for. This defaults
to a uniformly distributed random
number
between min_wait and max_wait milliseconds. It will then schedule the index + 1 % len(tasks) task for
execution and so on.
TaskSequence can be nested with TaskSet, which means
that a TaskSequence’s tasks attribute
can contain TaskSet instances
as well as other TaskSequence instances. If the nested TaskSet
is scheduled to be executed, it will be
instantiated and called from the current executing TaskSet. Execution in the
currently running TaskSet will then
be handed over to the nested TaskSet which will continue to run until it throws
an InterruptTaskSet exception, which is done when TaskSet.interrupt()
is called. (execution will then continue in the first TaskSet).
In this class,
tasks should be defined as a list, or simply
define the tasks with the @seq_task decorator
client
Reference to the client
attribute of the root Locust instance.
interrupt(reschedule=True)
Interrupt the TaskSet
and hand over execution control
back to the parent TaskSet.
If reschedule is
True (default), the parent Locust
will immediately re-schedule, and execute, a new task
This method should not be called by the root TaskSet (the one that
is immediately, attached to the Locust class’ task_set attribute), but rather in nested TaskSet
classes further down the hierarchy.
schedule_task(task_callable, args=None, kwargs=None, first=False)
Add a task to the Locust’s task execution queue.
Arguments:
•
task_callable: Locust task to schedule
•
args: Arguments that will be passed to the task callable
•
kwargs: Dict of keyword arguments
that will be passed to the task callable.
•
first: Optional keyword
argument. If True, the task will be put first in the queue.
wait_time()
Method that returns the time (in seconds) between
the execution of tasks. Example:
Used as a convenience decorator
to be able to declare
tasks for a TaskSequence inline
in the class. Example:
class NormalUser(TaskSequence): @seq_task(1) def login_first(self): pass @seq_task(2) @task(25) # You can
also set the
weight in order to execute the
task for ˓→`weight` times one after another. def then_read_thread(self): pass
(continues on next page)
(continued from previous page)
5.1.7 Built in wait_time functions
Returns a function that will return
a random number
between min_wait and max_wait. Example:
Returns a function that just returns
the number specified
by the wait_time argument Example:
Returns a function
that will track the run time of the tasks,
and for each time it’s called it will return a wait time that
will try to make the total time between task execution equal to the time specified by the wait_time argument.
In the following example the task will always
be executed once every second,
no matter the task execution time:
If a task execution exceeds
the specified wait_time, the wait will be 0 before starting
the next task.
class HttpSession(base_url, request_success, request_failure, *args, **kwargs)
Class for performing web requests and holding (session-) cookies between requests
(in order to be able to log in and out of websites). Each request is logged so that locust
can display statistics.
This is a slightly extended
version of python-request’s requests.Session
class and mostly this class works exactly the same. However
the methods for making requests
(get, post, delete,
put, head, options,
patch, request) can now take a url argument that’s only the path part of the URL, in which case the host part of the URL will be prepended with the HttpSession.base_url which is normally
inherited from a Locust class’
host property.
Each of the methods for making requests
also takes two additional optional
arguments which are Locust specific
and doesn’t exist
in python-requests. These are:
Parameters
• name – (optional) An argument that can
be specified to use as label in Locust’s statistics instead of the URL path. This can be used to group different URL’s that
are requested into a single
entry in Locust’s
statistics.
•
catch_response – (optional)
Boolean argument that, if set, can be used to make a re- quest return a context manager to work as argument to
a with statement. This will allow the request to be marked
as a fail based on the content
of the response, even if the response
code is ok (2xx). The opposite also works, one can use catch_response to
catch a request and then mark it as successful even if the response code was not (i.e 500 or 404).
init (base_url, request_success, request_failure, *args, **kwargs)
Initialize self. See help(type(self)) for accurate signature.
delete(url, **kwargs)
Sends a DELETE request.
Returns Response object.
Parameters
•
url – URL for the new Request
object.
•
**kwargs – Optional
arguments that request
takes.
Return type requests.Response
get(url, **kwargs)
Sends a GET request.
Returns Response object.
Parameters
•
url – URL for the new Request
object.
•
**kwargs – Optional
arguments that request
takes.
Return type requests.Response
head(url, **kwargs)
Sends a HEAD request.
Returns Response object.
Parameters
•
url – URL for the new Request
object.
•
**kwargs – Optional
arguments that request
takes.
Return type requests.Response
options(url, **kwargs)
Sends a OPTIONS request.
Returns Response object.
Parameters
•
url – URL for the new Request
object.
•
**kwargs – Optional
arguments that request
takes.
Return type requests.Response
patch(url, data=None, **kwargs)
Sends a PATCH request.
Returns Response object.
Parameters
•
url – URL for the new Request
object.
•
data – (optional) Dictionary, list of tuples,
bytes, or file-like object to send in the body of the Request.
• **kwargs – Optional arguments that request takes.
Return type requests.Response
post(url, data=None, json=None, **kwargs)
Sends a POST request.
Returns Response object.
Parameters
•
url – URL for the new Request
object.
•
data – (optional) Dictionary, list of tuples,
bytes, or file-like object to send in the body of the Request.
•
json – (optional) json to send in the body of the Request.
•
**kwargs – Optional
arguments that request
takes.
Return type requests.Response
put(url, data=None, **kwargs)
Sends a PUT request.
Returns Response object.
Parameters
•
url – URL for the new Request
object.
•
data – (optional) Dictionary, list of tuples,
bytes, or file-like object to send in the body of the Request.
•
**kwargs – Optional
arguments that request
takes.
Return type requests.Response
request(method, url,
name=None, catch_response=False, **kwargs)
Constructs and sends a requests.Request. Returns requests.Response object.
Parameters
• method – method for the new Request object.
• url – URL for the new Request object.
• name – (optional) An argument that can
be specified to use as label in Locust’s statistics instead of the URL path. This can be used to group different URL’s that are requested into a single
entry in Locust’s
statistics.
•
catch_response – (optional)
Boolean argument that, if set, can be used to make a request return
a context manager
to work as argument to a with statement. This will allow the request
to be marked as a fail based on the content of the response, even if the response code is ok (2xx). The opposite also
works, one can use catch_response to catch a request and then mark it as successful even if the response code was not (i.e 500 or 404).
•
params – (optional) Dictionary or bytes to be sent in the query string for the Request.
•
data – (optional) Dictionary or bytes
to send in the body of the Request.
•
headers – (optional) Dictionary of HTTP Headers to send with the Request.
•
cookies – (optional) Dict or CookieJar object to send with the Request.
•
files – (optional) Dictionary of 'filename': file-like-objects for multi-
part encoding upload.
•
auth – (optional) Auth tuple or callable to enable Basic/Digest/Custom HTTP Auth.
•
timeout (float or tuple) – (optional) How long in seconds to wait for the server
to send data before giving up, as a float,
or a (connect timeout, read timeout) tuple.
•
allow_redirects (bool) – (optional) Set to True by default.
•
proxies – (optional) Dictionary mapping protocol
to the URL of the proxy.
• stream – (optional) whether
to immediately download
the response content.
Defaults to
False.
•
verify – (optional) if True,
the SSL cert will be verified. A CA_BUNDLE path can also be provided.
•
cert – (optional) if String, path to ssl client cert file (.pem).
If Tuple, (‘cert’,
‘key’) pair.
This class actually
resides in the python-requests library, since
that’s what Locust
is using to make HTTP requests, but it’s
included in the API docs for locust since it’s so central when writing locust
load tests. You can also look at the Response class at the requests documentation.
class Response
The Response object, which contains
a server’s response
to an HTTP request.
apparent_encoding
The apparent encoding, provided by the chardet library.
close()
Releases the connection back to the pool. Once this method
has been called the underlying raw object
must not be accessed again.
Note: Should not normally need to be called explicitly.
content
Content of the response, in bytes.
cookies = None
A CookieJar of Cookies the server sent back.
elapsed = None
The amount of time elapsed between sending the request
and the arrival of the response (as a timedelta). This property specifically measures the time taken between
sending the first byte of the request
and finish- ing parsing the headers. It is therefore
unaffected by consuming the response content or the value of the stream keyword argument.
encoding = None
Encoding to decode
with when accessing r.text.
headers = None
Case-insensitive Dictionary
of Response Headers. For example, headers['content-encoding']
will return
the value of a 'Content-Encoding' response header.
history = None
A list of Response objects from the history of the Request. Any redirect responses will end up here. The list is sorted
from the oldest
to the most recent request.
is_permanent_redirect
True if this Response one of the permanent versions
of redirect.
is_redirect
True if this Response is a well-formed HTTP redirect that could have been processed
automatically (by
Session.resolve_redirects()).
iter_content(chunk_size=1, decode_unicode=False)
Iterates over the response data. When stream=True is set on the request,
this avoids reading
the content at once
into memory for large responses. The chunk size is the number of bytes it
should read into memory. This is not necessarily the length of each item returned as decoding can take place.
chunk_size must be of type int or None. A value of None will function differently
depending on the value of stream.
stream=True will read data as it arrives in whatever size the chunks are
received. If stream=False, data is returned as a single
chunk.
If decode_unicode is True, content will be decoded using the best available encoding based on the response.
iter_lines(chunk_size=512, decode_unicode=False, delimiter=None)
Iterates over the response data, one line at a time. When stream=True is set on the request,
this avoids reading the content at once into memory for large responses.
Note: This method is not reentrant
safe.
json(**kwargs)
Returns the json-encoded content of a response, if any.
Parameters **kwargs – Optional
arguments that json.loads takes.
Raises ValueError – If the response body does not contain valid json.
links
Returns the parsed header links of the response, if any.
next
Returns a PreparedRequest for the next request in a redirect
chain, if there is one.
ok
Returns True if status_code is less than 400, False if not.
This attribute checks if the status code of the response
is between 400 and 600 to see if there was a client error or a server error.
If the status code is between 200 and 400, this will return True. This is not a check
to see if the response
code is 200 OK.
raise_for_status()
Raises stored HTTPError, if one occurred.
raw = None
File-like object representation of response (for advanced usage). Use of raw requires that stream=True
be set on the request.
This requirement does not apply for use internally to Requests.
reason = None
Textual reason of responded HTTP Status, e.g. “Not Found” or “OK”.
request = None
The PreparedRequest object
to which this is a response.
status_code = None
Integer Code of responded HTTP Status, e.g. 404 or 200.
text
Content of the response, in unicode.
If Response.encoding is None, encoding
will be guessed
using chardet.
The encoding of the response content is determined based
solely on HTTP headers, following RFC 2616 to
the letter. If you can take advantage of non-HTTP knowledge to make a better
guess at the encoding, you should set r.encoding appropriately before accessing
this property.
Final URL location
of Response.
5.1.10 ResponseContextManager class
class ResponseContextManager(response, request_success, request_failure)
A Response class that also acts as a context manager that provides the ability to manually control if an HTTP request
should be marked
as successful or a failure
in Locust’s statistics
This class is a subclass
of Response with two additional methods:
success and failure.
failure(exc)
Report the response
as a failure.
exc can be either a python exception, or a string in which case it will be wrapped inside a CatchRespon- seError.
Example:
Report the response as successful Example:
5.1.11 InterruptTaskSet Exception
exception InterruptTaskSet(reschedule=True)
Exception that will interrupt a Locust when thrown inside
a task
class Environment(events=None, options=None, host=None, reset_stats=False, step_load=False, stop_timeout=None)
Event hooks used by Locust internally, as well as to extend Locust’s functionality See Event hooks for available events.
host = None
Base URL of the target
system
master_bind_host = '*'
Hostname/interfaces
that the master
node should expect
workers to connect
to. Defaults to ‘*’ which
means all interfaces.
master_bind_port = 5557
Port that the master node should listen
to and expect workers to connect to. Defaults to 5557.
Hostname of master
node that the worker should
connect to
master_port = 5557
Port of master
node that the worker should
connect to. Defaults
to 5557.
options = None
Parsed command line options
reset_stats = False
Determines if stats
should be reset
once all simulated users have been spawned
runner = None
Reference to the LocustRunner instance
step_load = False
Determines if we’re running in step load mode
stop_timeout = None
If set, the runner will try to stop the runnning users
gracefully and wait this many seconds before killing them hard.
web_ui = None
Reference to the WebUI instance
Locust provide event hooks that can be used to extend Locus in various
ways.
The following event
hooks are available under Environment.events, and there’s also a reference to these events
under locust.events that can be used at the module level of locust scripts (since the
Environment instance hasn’t been created when the locustfile is imported).
class
Events
hatch_complete
hatch_complete is fired
when all locust
users has been spawned. Event
is fire with the following
arguments:
•
user_count:
Number of users that was hatched alias of EventHook
init
init is fired when Locust is started, once the Environment instance and
locust runner instance have been created.
This hook can be used by end-users’ code to run code that requires access to
the Envirionment. For example
to register listeners
to request_success, request_failure or other events.
Event is fired with following arguments:
•
environment:
Environment instance alias of EventHook
init_command_line_parser
Event that can be used to add command line options to Locust
Event is fired with the following arguments: * parser:
ArgumentParser instance alias
of EventHook
locust_error is fired when an exception occurs
inside the execution
of a Locust class. Event
is fired with the following
arguments:
• locust_instance: Locust class instance
where the exception
occurred
•
exception: Exception
that was thrown
•
tb: Traceback
object (from sys.exc_info()[2]) alias of EventHook
locust_start_hatching
locust_start_hatching is fired when we initiate the hatching process
on any locust worker. alias
of EventHook
locust_stop_hatching
locust_stop_hatching is fired when terminate
the hatching process
on any locust worker. alias
of EventHook
master_start_hatching
master_start_hatching is fired when we initiate the hatching process on the master. This event is especially useful
to detect when the ‘start’
button is clicked
on the web ui. alias
of EventHook
master_stop_hatching
master_stop_hatching is fired when terminate the hatching process
on the master.
This event is especially useful
to detect when the ‘stop’
button is clicked
on the web ui. alias
of EventHook
quitting
quitting is fired when the locust
process is exiting
alias of EventHook
report_to_master
report_to_master is used when Locust is running
in –worker mode.
It can be used to attach data to the dicts that are regularly
sent to the master. It’s fired regularly when a report
is to be sent to the master server.
Note that the keys “stats”
and “errors” are used by Locust and shouldn’t be overridden. Event
is fired with the following
arguments:
• client_id: The client id of the running locust process.
•
data: Data dict that can be modified in order to attach data that should
be sent to the master.
alias of EventHook
request_failure
request_failure is fired when a request fails Event is fired with the following
arguments:
• request_type: Request type method
used
•
name: Path to the URL that was called
(or override name if it was used in the call to the client)
•
response_time: Time in milliseconds until exception was thrown
•
response_length: Content-length of the response
• exception: Exception
instance that was thrown alias of EventHook
request_success
request_success is fired when a request is completed successfully. Listeners should take the following
arguments:
• request_type: Request type method
used
•
name: Path to the URL that was called
(or override name if it was used in the call to the client)
•
response_time: Response
time in milliseconds
•
response_length: Content-length of the response
alias of EventHook
worker_report
worker_report is used when Locust is running in –master mode and is fired when the master server receives
a report from a Locust
worker server.
This event can be used to aggregate
data from the locust worker servers. Event
is fired with following arguments:
• client_id: Client id of the reporting
worker
•
data: Data dict with the data from the worker node
alias of EventHook
The event hooks are instances of the locust.events.EventHook class:
class EventHook
Simple event class used to provide
hooks for different types of events
in Locust. Here’s
how to use the EventHook
class:
If reverse
is True, then the handlers
will run in the reverse
order that they were inserted
Note: It’s highly recommended that you add a wildcard
keyword argument in your event listeners to prevent your code from breaking if new arguments are added in a future
version.
6.1.1 Support for other sampler
protocols, reporting etc
6.1.2 Automate distributed runs with no manual steps
A Locust master and a Locust worker communicate by
exchanging msgpack messages, which is supported by
many languages. So, you can write
your Locust tasks in any languages you like. For convenience, some libraries do
the job as a worker runner. They run your Locust
tasks, and report
to master regularly.
• Boomer
• Locust4j
•
Swarm
6.1.4 Configuration Management
Deploying Locust
is easy, but here and there some tools can still provide
a measure of convenience.
tinx.locust is an Ansible role to install, configure
and control Locust as a systemd service,
or to build Locust docker
images using ansible-container. Also manages locustfiles and accompanying test data.
For full details of the Locust
changelog, please see https://github.com/locustio/locust/blob/master/CHANGELOG.md
7.1.1
In development (master) 7.1.2 0.14.0
• Drop Python
2 and Python 3.5 support!
•
Continuously measure CPU usage and emit a warning if we get a five second average
above 90%
•
Show CPU usage
of slave nodes
in the Web UI
•
Fixed issue when running
Locust distributed and new slave nodes connected during the hatching/ramp-up phase (https://github.com/locustio/locust/issues/1168)
Various minor fixes, mainly
regarding FastHttpLocust.
Identical to previous version,
but now built
& deployed to Pypi using
Travis.
•
Unable to properly
connect multiple slaves - https://github.com/locustio/locust/issues/1176
•
Zero exit code on exception - https://github.com/locustio/locust/issues/1172
•
–stop-timeout is not respected when changing number
of running Users
in distributed mode - https://github.com/ locustio/locust/issues/1162
•
Fixed bug that broke the Web UI’s repsonse time graph
•
Fixed crash bug on Python
3.8.0
•
Various other bug fixes and improvements.
•
New API for specifying wait time - https://github.com/locustio/locust/pull/1118 Example of the new API:
There are three built in wait time functions: between, constant and constant_pacing.
•
FastHttpLocust: Accept self signed SSL certificates, ignore
host checks. Improved
response code handling
•
Add current working
dir to sys.path - https://github.com/locustio/locust/pull/484
•
Web UI improvements: Added 90th percentile to table, failure
per seconds as a series
in the chart
•
Ability to specify
host in web ui
•
Added response_length to request_failure event
- https://github.com/locustio/locust/pull/1144
•
Added p99.9 and p99.99 to request stats distribution csv - https://github.com/locustio/locust/pull/1125
•
Various other bug fixes and improvements.
•
Added –skip-log-setup to disable Locust’s
default logging setup.
•
Added –stop-timeout to allow tasks to finish running
their iteration before stopping
•
Added 99.9 and 99.99 percentile response times to csv output
•
Allow custom clients to set request response time to None. Those requests
will be excluded when calculating median, average, min, max and percentile response
times.
•
Renamed the last row in statistics
table from “Total”
to “Aggregated” (since the values aren’t a sum of the individual table rows).
•
Some visual improvements to the web UI.
•
Fixed issue with simulating fewer number of locust users than the number of slave/worker nodes.
•
Fixed bugs in the web UI related
to the fact that the stats table is truncated at 500 entries.
• Various other bug fixes and improvements.
•
Added new FastHttpLocust class that uses a faster
HTTP client, which should be 5-6 times faster than the normal
HttpLocust class. For more info see the documentation on increasing performance.
•
Added ability to set the exit code of the locust
process when exceptions has occurred within
the user code,
using the --exit-code-on-error parameter.
•
Added TCP keep alive to master/slave communication sockets to avoid broken connections in some environ-
ments.
•
Dropped support for Python 3.4
•
Numerous other bug fixes and improvements.
•
Python 3.7 support
•
Added a status page to the web UI when running
Locust distributed showing
the status of slave nodes and detect
down slaves using
heartbeats
•
Numerous bugfixes/documentation updates
(see detailed changelog)
•
Added detailed changelog (https://github.com/locustio/locust/blob/master/CHANGELOG.md)
•
Numerous bugfixes (see detailed changelog)
•
Added sequential task support - https://github.com/locustio/locust/pull/827
•
Added support for user-defined wait_function - https://github.com/locustio/locust/pull/785
• By default, Locust
no
longer
resets
the
statistics when
the
hatching is
complete. Therefore
--no-reset-stats has been deprected
(since it’s now the default
behaviour), and instead
a new
--reset-stats option has been added.
•
Dropped support for Python 3.3
•
Updated documentation
•
Updated pyzmq version, and changed so that we don’t pin a specific version. This makes it easier to install Locust
on Windows.
•
Python 3 support
•
Dropped support for Python 2.6
•
Added --no-reset-stats option for controling if the statistics should be reset
once the hatching
is com- plete
•
Added charts to the web UI for requests per second, average
response time, and number of simulated users.
•
Updated the design of the web UI.
•
Added ability to write a CSV file for results
via command line flag
•
Added the URL of the host that is currently
being tested to the web UI.
•
We now also
apply gevent’s monkey patching of threads. This fixes an issue when using
Locust to test Cassandra (https://github.com/locustio/locust/issues/569).
•
Various bug fixes and improvements
•
Use version 1.1.1 of gevent.
Fixes an install
issue on certain
versions of python.
•
Use a newer version
of requests, which fixed
an issue for users with older versions
of requests getting
Connec- tionErrors (https://github.com/locustio/locust/issues/273).
•
Various fixes to documentation.
•
Fixed bug where POST requests (and
other methods as well) got incorrectly reported as GET requests, if the request
resulted in a redirect.
•
Added ability to download
exceptions in CSV format. Download links has also been moved to it’s own tab in the web UI.
•
Locust now returns
an exit code of 1 when any failed requests
were reported.
•
When making an HTTP request to an endpoint
that responds with a redirect, the original URL that was requested is now used as the name for that entry in the statistics (unless
an explicit override
is specified through
the name argument). Previously, the last URL in the redirect chain was used to label
the request(s) in the statistics.
• Fixed bug which caused
only the time of the last request
in a redirect chain to be included
in the reported time.
• Fixed bug which caused the download
time of the request body not to be included
in the reported response time.
•
Fixed bug that occurred on some
linux dists that were tampering with the python-requests system package (removing dependencies which requests is
bundling). This bug only occured when
installing Locust in the python system
packages, and not when using virtualenv.
• Various minor fixes and improvements.
• Exceptions that occurs within
TaskSets are now catched by default.
•
Fixed bug which caused Min response
time to always be 0 after all locusts had been hatched and the statistics had been reset.
• Minor UI improvements in the web interface.
•
Handle messages from “zombie” slaves
by ignoring the message and making a log entry
in the master process.
7.1.20.1 HTTP client functionality moved to HttpLocust
Previously, the Locust class instantiated a HttpSession under the client
attribute that was used to
make HTTP requests. This funcionality has now been moved into the HttpLocust class, in an effort to make it more obvious
how one can use Locust
to load test non-HTTP
systems.
To make existing locust scripts compatible with the new
version you should make your locust classes inherit from HttpLocust instead of the base Locust class.
7.1.20.2 msgpack for serializing master/slave data
Locust now uses msgpack for
serializing data that is sent between a master node and it’s slaves. This adresses a possible attack that can be used to execute code remote, if one
has access to the internal locust ports that are used for master-slave communication. The reason
for this exploit
was due to the fact that pickle was used.
Anyone who uses
the report_to_master and slave_report events,
needs to make sure that any data that is attached to the slave
reports is serializable by msgpack.
7.1.20.3 requests updated
to version 2.2
Locust updated
requests to the latest
major release.
Note: Requests 1.0 introduced
some major API changes (and 2.0 just a few). Please check if you are using any internal features and check the documentation: Migrating to 1.x and Migrationg to 2.x
7.1.20.4 gevent updated
to version 1.0
gevent 1.0 has now been released
and Locust has been updated
accordingly.
7.1.20.5 Big refactoring of request statistics code
Refactored RequestStats.
•
Created StatsEntry which represents a single stats entry (URL).
Previously the RequestStats was actually
doing two different
things:
•
It was holding
track of the aggregated stats
from all requests
•
It was holding
the stats for single stats entries.
Now RequestStats should be instantiated and holds the
global stats, as well as a dict of StatsEntry instances which holds the stats
for single stats
entries (URLs)
7.1.20.6 Removed support
for avg_wait
Previously one could specify avg_wait to TaskSet and
Locust that Locust would try to strive to. However this can be sufficiently accomplished by using min_wait
and max_wait for most use-cases. Therefore we’ve decided
to remove the avg_wait as it’s use-case
is not clear or just too narrow to be in the Locust core.
7.1.20.7 Removed support
for ramping
Previously one could tell Locust, using the –ramp
option, to try to find a stable client count that the target host could handle, but it’s been broken and
undocumented for quite a while so we’ve decided to remove it from the locust
core and perhaps have it reappear as a plugin
in the future.
7.1.20.8 Locust Event
hooks now takes keyword argument
When Extending
Locust by listening to Event hooks, the listener functions
should now expect the arguments to be passed in as keyword
arguments. It’s also highly recommended to add an extra wildcard
keyword arguments to listener functions, since they’re then less likely
to break if extra arguments are added to that event in some future version.
For example:
The method and path arguments to request_success and request_failure are now called request_type and
name, since it’s less HTTP specific.
• You can now specify
the port on which to run the web host
•
Various code cleanups
•
Updated gevent/zmq libraries
•
Switched to unittest2
discovery
•
Added option –only-summary to only output the summary to the console, thus disabling the periodic stats output.
•
Locust will now make sure to spawn all the specified
locusts in distributed mode, not just a multiple
of the number of slaves.
•
Fixed the broken
Vagrant example.
•
Fixed the broken
events example (events.py).
•
Fixed issue where
the request column
was not sortable
in the web-ui.
•
Minor styling of the statistics table in the web-ui.
•
Added options to specify host and ports in distributed mode using –master-host, –master-port for the slaves,
–master-bind-host, –master-bind-port for the master.
• Removed previously deprecated and obsolete
classes WebLocust and SubLocust.
•
Fixed so that also failed
requests count, when specifying a maximum number
of requests on the command
line
•
Made Locust compatible with gevent 1.0rc2.
This allows user to step around a problem with running Locust
under some versions
of CentOS, that can be fixed by upgrading gevent
to 1.0.
•
Added parent attribute to TaskSet class that refers to the parent TaskSet,
or Locust, instance.
Contributed by Aaron Daubman.
•
Fixed bug that was causing problems
when setting a maximum number of requests
using the -n or –num-request
command line parameter.
7.1.23.1 SubLocust replaced by TaskSet and Locust class behaviour changed
Locust classes does no longer control task scheduling and
execution. Therefore, you no longer
define tasks within Locust classes,
instead the Locust class has a task_set attribute which should point to a TaskSet class. Tasks should now be defined
in TaskSet classes,
in the same way that was previously done in Locust and SubLocust
classes. TaskSets can be nested
just like SubLocust classes could.
So the following code for 0.5.1:
class User(Locust): min_wait = 10000 max_wait = 120000 @task(10) def index(self): self.client.get("/") @task(2) class AboutPage(SubLocust): min_wait = 10000 max_wait = 120000 def on_init(self): self.client.get("/about/") @task def team_page(self): self.client.get("/about/team/") @task
(continues on next page)
(continued from previous page)
Should now be written like:
Each TaskSet instance
gets a locust attribute, which refers
to the Locust class.
7.1.23.2 Locust now uses Requests
Locust’s own HttpBrowser class (which was typically accessed
through self.client from within
a locust class)
has been replaced by a thin wrapper around the
requests library (http://python-requests.org). This comes with a number of advantages. Users can now take advantage
of a well documented, well written, fully
fledged library for making HTTP requests.
However, it also comes with some small API changes wich will require users to
update their existing load testing scripts.
Gzip encoding
turned on by default
The HTTP client now sends headers for accepting gzip
encoding by default. The –gzip command
line argument has been removed and if
someone want to disable the Accept-Encoding
that the HTTP client uses, or any other HTTP headers you can do:
Improved HTTP client
Because of the switch
to using python-requests in the HTTP client, the API for the client
has also gotten
a few changes.
• Additionally to the get, post, put, delete and head methods, the HttpSession class now also has
•
All arguments to the HTTP request methods,
except for url and
data should now be specified as keyword arguments. For example, previously one could specify
headers using:
And
should now be specified like:
•
In general the whole HTTP client is
now more powerful since it leverages on python-requests. Features that we’re
now able to use in Locust includes file upload, SSL, connection keep-alive, and
more. See the python- requests documentation for more details.
• The new HttpSession
class’ methods now return python-request Response objects. This means that ac- cessing the content
of the response is no longer made using the data attribute, but instead the content
attribute. The HTTP response code is now accessed through
the status_code attribute, instead
of the code attribute.
HttpSession methods’ catch_response argument improved and allow_http_error argument
removed
• When doing HTTP
requests using the catch_response argument,
the context manager that is returned now provides two functions, success and failure that can be used to manually
control what the request should
be reported
as in Locust’s statistics.
class ResponseContextManager(response, request_success, request_failure)
A Response class that also acts as a context manager that provides the ability to manually control if an HTTP request
should be marked as successful or a failure
in Locust’s statistics
This class is a subclass
of Response with two additional methods:
success and failure.
failure(exc)
Report the response
as a failure.
exc can be either a python exception, or a string in which case it will be wrapped inside a CatchRe-
sponseError.
Example:
success()
Report the response
as successful Example:
•
The allow_http_error argument of the HTTP client’s
methods has been removed. Instead
one can use the
catch_response argument to get a context manager,
which can be used together
with a with statement. The following code in the previous Locust
version:
Can instead now be written
like:
7.1.23.3 Other improvements and bug fixes
• Scheduled task callables can now take keyword arguments
and not only normal function
arguments.
•
SubLocust classes
that are scheduled
using locust.core.Locust.schedule_task()
can now take arguments and keyword arguments
(available in self.args and
self.kwargs).
•
Fixed bug where the average content
size would be zero when doing requests
against a server
that didn’t set the content-length header (i.e. server that uses Transfer-Encoding: chunked)
•
The require_once decorator has been removed. It was an old legacy
function that no longer fit into the current
way of writing Locust tests, where tasks are either
methods under a Locust class or SubLocust classes containing task methods.
•
Changed signature of locust.core.Locust.schedule_task(). Previously all extra arguments that was given to the method was passed on to
the task when it was called. It no longer accepts extra arguments. Instead, it takes an args argument (list) and a kwargs
argument (dict) which are be passed to the task when it’s called.
• Arguments for request_success event hook has been changed. Previously it took an HTTP Response instance as
argument, but this has been changed to take the content-length of the response
instead. This makes it easier
to write custom
clients for Locust.
•
Fixed bug which caused –logfile and
–loglevel command line parameters to not be respected when running locust without zeromq.
• Web inteface
is now turned on by default. The –web command line option has been replaced
by –no-web.
•
locust.events.request_success() and locust.events.request_failure() now gets the HTTP method as the first argument.
7.1.25.2 Improvements and bug fixes
•
Removed –show-task-ratio-confluence and added a –show-task-ratio-json option instead. The –show-task- ratio-json will output JSON data containing the task execution
ratio for the locust “brain”.
•
The HTTP method
used when a client requests
a URL is now displayed
in the web UI
•
Some fixes and improvements in the stats
exporting:
•
A file name is now set (using
content-disposition header) when downloading stats.
•
The order of the column
headers for request
stats was wrong.
•
Thanks Benjamin W. Smith,
Jussi Kuosa and Samuele Pedroni!
•
WebLocust class has been deprecated and is now called just Locust. The class that was previously called Locust is now called
LocustBase.
•
The catch_http_error argument to HttpClient.get() and HttpClient.post() has been renamed
to allow_http_error.
7.1.26.2 Improvements and bug fixes
• Locust now uses python’s
logging module for all logging
•
Added the ability to change the number of spawned users when a test is running, without
having to restart the test.
•
Experimental support for automatically ramping up and down the number of locust to find a maximum number
of concurrent users (based on some parameters like response times and acceptable failure rate).
•
Added support for failing requests
based on the response data, even if the HTTP response was OK.
•
Improved master node performance in order to not get bottlenecked when using enough
slaves (>100)
•
Minor improvements in web interface.
•
Fixed missing template
dir in MANIFEST file causing
locust installed with “setup.py install”
not to work.
init () (HttpSession method), 40
A
abstract
(HttpLocust attribute), 36
abstract
(Locust attribute), 35
B
between() (in module locust.wait_time), 39
C
client (HttpLocust attribute), 36 client (TaskSequence attribute), 38 client (TaskSet attribute), 36
connection_timeout (FastHttpLocust attribute), 25 constant() (in module locust.wait_time),
39 constant_pacing() (in module locust.wait_time),
content (FastResponse attribute), 26
D
delete() (HttpSession method), 40
E
Environment (class in locust.env), 44 EventHook
(class in locust.event), 47 Events
(class
in locust.event), 45 events (Environment attribute), 44
F
failure() (ResponseContextManager method), 44 FastHttpLocust (class in locust.contrib.fasthttp), 25 FastHttpSession (class in locust.contrib.fasthttp),
FastResponse (class in locust.contrib.fasthttp), 26
G
get() (FastHttpSession method), 25
get() (HttpSession method), 40
H
hatch_complete (Events attribute), 45 head()
(FastHttpSession
method), 25 head() (HttpSession method), 40 headers
(FastResponse
attribute), 26 host (Environment
attribute), 44 HttpLocust (class in locust.core),
36 HttpSession (class in locust.clients), 39
I
init (Events attribute), 45
init_command_line_parser (Events attribute), 45
insecure (FastHttpLocust attribute), 25 interrupt() (TaskSequence method), 38 interrupt() (TaskSet method), 36 InterruptTaskSet, 44
J
json() (FastResponse method), 26
L
Locust (class in locust.core), 35 locust
(TaskSet
attribute), 36 locust.wait_time (module), 39 locust_error (Events attribute), 45
locust_start_hatching (Events attribute), 46
locust_stop_hatching (Events attribute), 46
M
master_bind_host (Environment attribute), 44 master_bind_port
(Environment attribute), 44 master_host (Environment attribute), 44
master_port (Environment
attribute), 45 master_start_hatching
(Events attribute), 46 master_stop_hatching (Events attribute), 46 max_redirects (FastHttpLocust attribute), 25
max_retries (FastHttpLocust attribute), 25
N
network_timeout (FastHttpLocust attribute), 25
O
options (Environment attribute), 45
options() (FastHttpSession method), 26 options() (HttpSession
method), 40
P
parent (TaskSet attribute), 36
patch() (FastHttpSession method), 26 patch() (HttpSession method), 40 post() (FastHttpSession method), 26 post()
(HttpSession
method), 41 put() (FastHttpSession method), 26 put() (HttpSession method), 41
Q
quitting (Events attribute), 46
R
report_to_master (Events attribute), 46 request() (FastHttpSession method), 26 request()
(HttpSession method),
41 request_failure (Events attribute),
46 request_success (Events attribute), 47 reset_stats
(Environment
attribute), 45 ResponseContextManager (class in locust.clients),
runner (Environment attribute), 45
S
schedule_task() (TaskSequence method), 38 schedule_task()
(TaskSet
method), 37 seq_task() (in module locust.core), 38 step_load
(Environment
attribute), 45 stop_timeout (Environment
attribute), 45 success() (ResponseContextManager method), 44
T
task()
(in module
locust.core), 37 tasks
(Locust
attribute), 35 tasks (TaskSet attribute), 37
TaskSequence (class in locust.core), 37
TaskSet
(class in locust.core), 36
text (FastResponse attribute), 26
W
wait_time (Locust attribute),
35 wait_time() (TaskSequence method), 38 wait_time() (TaskSet method), 37
web_ui (Environment attribute), 45
weight (Locust attribute),
36 worker_report (Events attribute), 47
66 Index
Comments
Post a Comment