-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1505 from max-rocket-internet/loadtest_shaper
Adding ability to generate any custom load shape with LoadTestShape class
- Loading branch information
Showing
15 changed files
with
457 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
.. _generating-custom-load-shape: | ||
|
||
================================= | ||
Generating a custom load shape using a `LoadTestShape` class | ||
================================= | ||
|
||
Sometimes a completely custom shaped load test is required that cannot be achieved by simply setting or changing the user count and hatch rate. For example, generating a spike during a test or ramping up and down at custom times. In these cases using the `LoadTestShape` class can give complete control over the user count and hatch rate at all times. | ||
|
||
How does a `LoadTestShape` class work? | ||
--------------------------------------------- | ||
|
||
Define your class inheriting the `LoadTestShape` class in your locust file. If this type of class is found then it will be automatically used by Locust. Add a `tick()` method to return either a tuple containing the user count and hatch rate or `None` to stop the load test. Locust will call the `tick()` method every second and update the load test with new settings or stop the test. | ||
|
||
Examples | ||
--------------------------------------------- | ||
|
||
There are also some [examples on github](https://github.com/locustio/locust/tree/master/examples/custom_shape) including: | ||
|
||
- Generating a double wave shape | ||
- Time based stages like K6 | ||
- Step load pattern like Visual Studio | ||
|
||
Here is a simple example that will increase user count in blocks of 100 then stop the load test after 10 minutes: | ||
|
||
```python | ||
class MyCustomShape(LoadTestShape): | ||
time_limit = 600 | ||
hatch_rate = 20 | ||
def tick(self): | ||
run_time = self.get_run_time() | ||
if run_time < self.time_limit: | ||
user_count = round(run_time, -2) | ||
return (user_count, hatch_rate) | ||
return None | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import math | ||
from locust import HttpUser, TaskSet, task, constant | ||
from locust import LoadTestShape | ||
|
||
|
||
class UserTasks(TaskSet): | ||
@task | ||
def get_root(self): | ||
self.client.get("/") | ||
|
||
|
||
class WebsiteUser(HttpUser): | ||
wait_time = constant(0.5) | ||
tasks = [UserTasks] | ||
|
||
|
||
class DoubleWave(LoadTestShape): | ||
""" | ||
A shape to immitate some specific user behaviour. In this example, midday | ||
and evening meal times. | ||
Settings: | ||
min_users -- minimum users | ||
peak_one_users -- users in first peak | ||
peak_two_users -- users in second peak | ||
time_limit -- total length of test | ||
""" | ||
|
||
min_users = 20 | ||
peak_one_users = 60 | ||
peak_two_users = 40 | ||
time_limit = 600 | ||
|
||
def tick(self): | ||
run_time = round(self.get_run_time()) | ||
|
||
if run_time < self.time_limit: | ||
user_count = ((self.peak_one_users - self.min_users) * math.e ** -((run_time/(self.time_limit/10*2/3))-5) ** 2 | ||
+ (self.peak_two_users - self.min_users) * math.e ** - ((run_time/(self.time_limit/10*2/3))-10) ** 2 | ||
+ self.min_users) | ||
return (round(user_count), round(user_count)) | ||
else: | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
from locust import HttpUser, TaskSet, task, constant | ||
from locust import LoadTestShape | ||
|
||
|
||
class UserTasks(TaskSet): | ||
@task | ||
def get_root(self): | ||
self.client.get("/") | ||
|
||
|
||
class WebsiteUser(HttpUser): | ||
wait_time = constant(0.5) | ||
tasks = [UserTasks] | ||
|
||
|
||
class StagesShape(LoadTestShape): | ||
""" | ||
A simply load test shape class that has different user and hatch_rate at | ||
different stages. | ||
Keyword arguments: | ||
stages -- A list of dicts, each representing a stage with the following keys: | ||
duration -- When this many seconds pass the test is advanced to the next stage | ||
users -- Total user count | ||
hatch_rate -- Hatch rate | ||
stop -- A boolean that can stop that test at a specific stage | ||
stop_at_end -- Can be set to stop once all stages have run. | ||
""" | ||
|
||
stages = [ | ||
{'duration': 60, 'users': 10, 'hatch_rate': 10}, | ||
{'duration': 100, 'users': 50, 'hatch_rate': 10}, | ||
{'duration': 180, 'users': 100, 'hatch_rate': 10}, | ||
{'duration': 220, 'users': 30, 'hatch_rate': 10}, | ||
{'duration': 230, 'users': 10, 'hatch_rate': 10}, | ||
{'duration': 240, 'users': 1, 'hatch_rate': 1}, | ||
] | ||
|
||
def tick(self): | ||
run_time = self.get_run_time() | ||
|
||
for stage in self.stages: | ||
if run_time < stage["duration"]: | ||
tick_data = (stage["users"], stage["hatch_rate"]) | ||
return tick_data | ||
|
||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import math | ||
from locust import HttpUser, TaskSet, task, constant | ||
from locust import LoadTestShape | ||
|
||
|
||
class UserTasks(TaskSet): | ||
@task | ||
def get_root(self): | ||
self.client.get("/") | ||
|
||
|
||
class WebsiteUser(HttpUser): | ||
wait_time = constant(0.5) | ||
tasks = [UserTasks] | ||
|
||
|
||
class StepLoadShape(LoadTestShape): | ||
""" | ||
A step load shape | ||
Keyword arguments: | ||
step_time -- Time between steps | ||
step_load -- User increase amount at each step | ||
hatch_rate -- Hatch rate to use at every step | ||
time_limit -- Time limit in seconds | ||
""" | ||
|
||
step_time = 30 | ||
step_load = 10 | ||
hatch_rate = 10 | ||
time_limit = 600 | ||
|
||
def tick(self): | ||
run_time = self.get_run_time() | ||
|
||
if run_time > self.time_limit: | ||
return None | ||
|
||
current_step = math.floor(run_time / self.step_time) + 1 | ||
return (current_step * self.step_load, self.hatch_rate) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.