Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: locustio/locust
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2.32.8
Choose a base ref
...
head repository: locustio/locust
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2.32.9
Choose a head ref
  • 11 commits
  • 8 files changed
  • 5 contributors

Commits on Jan 8, 2025

  1. Copy the full SHA
    adc3240 View commit details

Commits on Jan 28, 2025

  1. update docs for stats.py file

    gabriel-check24 committed Jan 28, 2025
    Copy the full SHA
    957a3d0 View commit details

Commits on Jan 30, 2025

  1. changelog

    cyberw committed Jan 30, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f03faf3 View commit details

Commits on Jan 31, 2025

  1. fix error in example

    cyberw committed Jan 31, 2025
    Copy the full SHA
    2f192bd View commit details

Commits on Feb 4, 2025

  1. Merge pull request #3012 from timhovius/patch-1

    Fix issue where empty WebUI property is not parsed correctly
    cyberw authored Feb 4, 2025
    Copy the full SHA
    9821fb8 View commit details

Commits on Feb 7, 2025

  1. Merge pull request #3038 from gabriel-check24/master

    Update docs for stats.py file
    cyberw authored Feb 7, 2025
    Copy the full SHA
    79e689e View commit details
  2. Simplify .conf file examples in documentation

    cyberw committed Feb 7, 2025
    Copy the full SHA
    a31d1e9 View commit details

Commits on Feb 8, 2025

  1. Add iter_lines Method to FastHttpSession Class (#3024)

    ---------
    
    Co-authored-by: MasterX <153791429+MsterKey-Pro@users.noreply.github.com>
    MasterKey-Pro and MasterKey-Pro authored Feb 8, 2025
    Copy the full SHA
    41f2863 View commit details
  2. Api docs: Add FastHttpSession, move HttpSession closer to HttpUser

    cyberw committed Feb 8, 2025
    Copy the full SHA
    47c997e View commit details
  3. Type-hint FastHttpSession.iter_lines

    cyberw committed Feb 8, 2025
    Copy the full SHA
    a0caf46 View commit details

Commits on Feb 10, 2025

  1. changelog for 2.32.9

    cyberw committed Feb 10, 2025
    Copy the full SHA
    5d78a24 View commit details
Showing with 159 additions and 54 deletions.
  1. +13 βˆ’7 docs/api.rst
  2. +9 βˆ’0 docs/changelog.rst
  3. +28 βˆ’40 docs/configuration.rst
  4. +1 βˆ’1 examples/custom_messages.py
  5. +11 βˆ’0 locust/contrib/fasthttp.py
  6. +39 βˆ’0 locust/test/test_fasthttp.py
  7. +56 βˆ’4 locust/test/test_web.py
  8. +2 βˆ’2 locust/web.py
20 changes: 13 additions & 7 deletions docs/api.rst
Original file line number Diff line number Diff line change
@@ -15,13 +15,25 @@ HttpUser class
.. autoclass:: locust.HttpUser
:members: wait_time, tasks, client, abstract

HttpSession class
=================

.. autoclass:: locust.clients.HttpSession
:members: __init__, request, get, post, delete, put, head, options, patch

FastHttpUser class
==================

.. autoclass:: locust.contrib.fasthttp.FastHttpUser
:members: wait_time, tasks, client, abstract, rest
:noindex:

FastHttpSession class
=====================

.. autoclass:: locust.contrib.fasthttp.FastHttpSession
:members: __init__, request, get, post, delete, put, head, options, patch, iter_lines

PostgresUser class
==================

@@ -33,7 +45,7 @@ MongoDBUser class
=================

.. autoclass:: locust.contrib.mongodb.MongoDBUser
:members: wait_time, tasks, client, abstract, rest
:members: wait_time, tasks, client, abstract
:noindex:

TaskSet class
@@ -67,12 +79,6 @@ Built in wait_time functions
.. automodule:: locust.wait_time
:members: between, constant, constant_pacing, constant_throughput

HttpSession class
=================

.. autoclass:: locust.clients.HttpSession
:members: __init__, request, get, post, delete, put, head, options, patch

Response class
==============

9 changes: 9 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -4,6 +4,15 @@ Changelog Highlights

For full details of changes, please see https://github.com/locustio/locust/releases or https://github.com/locustio/locust/blob/master/CHANGELOG.md

2.32.9
======
* Fix issue where empty WebUI property is not parsed correctly https://github.com/locustio/locust/pull/3012
* Add iter_lines method to FastHttpSession https://github.com/locustio/locust/pull/3024

2.32.8
======
* Fix a single broken link in the UI

2.32.7
======
* Fix readme image ref links by @changchaishi in https://github.com/locustio/locust/pull/3031
68 changes: 28 additions & 40 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
@@ -55,23 +55,7 @@ You can specify an additional file using the ``--config`` flag.
$ locust --config custom_config.conf
Here's a minimalistic example of the configuration file supported by Locust:

Have a look later in this article for `All available configuration options`_

locust.conf
--------------

.. code-block:: ini
locustfile = locust_files/my_locust_file.py
headless = true
host = https://target-system
run-time = 1m
spawn-rate =
users = 1
Here's a quick example of the configuration files supported by Locust:
Here's an example:

locust.conf
--------------
@@ -88,6 +72,8 @@ locust.conf
run-time = 10m
tags = [Critical, Normal]
Have a look later in this page for `All available configuration options`_

pyproject.toml
--------------

@@ -109,9 +95,9 @@ When using a TOML file, configuration options should be defined within the ``[to
.. note::

Configuration values are read (and overridden) in the following order:

.. code-block:: console
~/.locust.conf -> ./locust.conf -> ./pyproject.toml -> (file specified using --conf) -> env vars -> cmd args
@@ -245,7 +231,7 @@ To configure multiple users you pass multiple arguments to ``--config-users``, o
When using this way to configure your users, you can set any attribute.

.. note::

``--config-users`` is a somewhat experimental feature and the json format may change even between minor Locust revisions.

Custom arguments
@@ -269,26 +255,28 @@ It can be done directly in Locust file or extracted to separate file for common

The list of statistics parameters that can be modified is:

+-------------------------------------------+--------------------------------------------------------------------------------------+
| Parameter name | Purpose |
+-------------------------------------------+--------------------------------------------------------------------------------------+
| STATS_NAME_WIDTH | Width of column for request name in console output |
+-------------------------------------------+--------------------------------------------------------------------------------------+
| STATS_TYPE_WIDTH | Width of column for request type in console output |
+-------------------------------------------+--------------------------------------------------------------------------------------+
| CSV_STATS_INTERVAL_SEC | Interval for how frequently the CSV file is written if this option is configured |
+-------------------------------------------+--------------------------------------------------------------------------------------+
| CONSOLE_STATS_INTERVAL_SEC | Interval for how frequently results are written to console |
+-------------------------------------------+--------------------------------------------------------------------------------------+
| CURRENT_RESPONSE_TIME_PERCENTILE_WINDOW | Window size/resolution - in seconds - when calculating the current response |
| | time percentile |
+-------------------------------------------+--------------------------------------------------------------------------------------+
| PERCENTILES_TO_REPORT | List of response time percentiles to be calculated & reported |
+-------------------------------------------+--------------------------------------------------------------------------------------+
| PERCENTILES_TO_CHART | List of response time percentiles in the screen of chart for UI |
+-------------------------------------------+--------------------------------------------------------------------------------------+
| PERCENTILES_TO_STATISTICS | List of response time percentiles in the screen of statistics for UI |
+-------------------------------------------+--------------------------------------------------------------------------------------+
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| Parameter name | Purpose | Default value |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| STATS_NAME_WIDTH | Width of column for request name in console output | terminal size or 80 |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| STATS_TYPE_WIDTH | Width of column for request type in console output | 8 |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| CSV_STATS_INTERVAL_SEC | Interval for how frequently the CSV file is written if this option is configured | 1 |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| CONSOLE_STATS_INTERVAL_SEC | Interval for how frequently results are written to console / chart UI | 2 |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| HISTORY_STATS_INTERVAL_SEC | Interval for how frequently results are written to history | 5 |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| CURRENT_RESPONSE_TIME_PERCENTILE_WINDOW | Window size/resolution - in seconds - when calculating the current response | 10 |
| | time percentile | |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| PERCENTILES_TO_REPORT | List of response time percentiles to be calculated & reported | [0.50, 0.66, 0.75, 0.80, 0.90, 0.95, 0.98, 0.99, 0.999, 0.9999, 1.0] |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| PERCENTILES_TO_STATISTICS | List of response time percentiles in the screen of statistics for UI | [0.95, 0.99] |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+
| PERCENTILES_TO_CHART | List of response time percentiles in the screen of chart for UI | [0.5, 0.95] |
+-----------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------+

Customization of additional static variables
============================================
2 changes: 1 addition & 1 deletion examples/custom_messages.py
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ def on_test_start(environment, **_kwargs):
if isinstance(environment.runner, LocalRunner):
workers = [environment.runner]
else:
workers = [environment.runner.clients]
workers = environment.runner.clients

for i, worker in enumerate(workers):
start_index = i * chunk_size
11 changes: 11 additions & 0 deletions locust/contrib/fasthttp.py
Original file line number Diff line number Diff line change
@@ -298,6 +298,17 @@ def get(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager
"""Sends a GET request"""
return self.request("GET", url, **kwargs)

def iter_lines(self, url: str, method: str = "GET", **kwargs) -> Generator[str]:
"""Sends a iter_lines request"""
response = self.request(method, url, stream=True, **kwargs)
response.raise_for_status()
buffer = ""
for chunk in response.iter_content(chunk_size=1024, decode_content=True):
buffer += chunk.decode("utf-8")
while "\n" in buffer:
line, buffer = buffer.split("\n", 1)
yield line

def head(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager | FastResponse:
"""Sends a HEAD request"""
return self.request("HEAD", url, **kwargs)
39 changes: 39 additions & 0 deletions locust/test/test_fasthttp.py
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
import socket
import time
from tempfile import NamedTemporaryFile
from unittest.mock import MagicMock

import gevent
from geventhttpclient.client import HTTPClientPool
@@ -106,6 +107,44 @@ def test_streaming_response_catch_response(self):
self.assertGreaterEqual(stats.avg_response_time, 0)
self.assertLess(stats.avg_response_time, 250)

def test_iter_lines(self):
session = self.get_client()

url = "/streaming/10"

response_mock = MagicMock()
response_mock.iter_content = MagicMock(
return_value=iter(
[
b"<span>0</span>\n",
b"<span>1</span>\n",
b"<span>2</span>\n",
b"<span>3</span>\n",
b"<span>4</span>\n",
b"<span>5</span>\n",
b"<span>6</span>\n",
b"<span>7</span>\n",
b"<span>8</span>\n",
b"<span>9</span>\n",
]
)
)
response_mock.raise_for_status = MagicMock()

session.request = MagicMock(return_value=response_mock)

lines = list(session.iter_lines(url, method="POST"))

expected_lines = [f"<span>{i}</span>" for i in range(10)]

self.assertEqual(lines, expected_lines)

session.request.assert_called_once_with(
"POST",
url,
stream=True,
)

def test_slow_redirect(self):
s = self.get_client()
url = "/redirect?url=/redirect&delay=0.5"
60 changes: 56 additions & 4 deletions locust/test/test_web.py
Original file line number Diff line number Diff line change
@@ -759,7 +759,7 @@ def tick(self):
response = requests.get("http://127.0.0.1:%i/stop" % self.web_port)
self.assertEqual(response.json()["message"], "Test stopped")

def test_swarm_custom_argument(self):
def test_swarm_custom_argument_without_default_value(self):
my_dict = {}

class MyUser(User):
@@ -771,10 +771,10 @@ def my_task(self):
my_dict["val"] = self.environment.parsed_options.my_argument

@locust.events.init_command_line_parser.add_listener
def _(parser, **kw):
def _(parser):
parser.add_argument("--my-argument", type=int, help="Give me a number")

parsed_options = parse_options(args=["--my-argument", "42"])
parsed_options = parse_options()
self.environment.user_classes = [MyUser]
self.environment.parsed_options = parsed_options
self.environment.web_ui.parsed_options = parsed_options
@@ -783,7 +783,59 @@ def _(parser, **kw):
data={"user_count": 1, "spawn_rate": 1, "host": "", "my_argument": "42"},
)
self.assertEqual(200, response.status_code)
self.assertEqual(my_dict["val"], 42)
self.assertEqual("42", my_dict["val"])

def test_swarm_custom_argument_with_default_value(self):
my_dict = {}

class MyUser(User):
host = "http://example.com"
wait_time = constant(1)

@task(1)
def my_task(self):
my_dict["val"] = self.environment.parsed_options.my_argument

@locust.events.init_command_line_parser.add_listener
def _(parser):
parser.add_argument("--my-argument", type=int, help="Give me a number", default=24)

parsed_options = parse_options()
self.environment.user_classes = [MyUser]
self.environment.parsed_options = parsed_options
self.environment.web_ui.parsed_options = parsed_options
response = requests.post(
"http://127.0.0.1:%i/swarm" % self.web_port,
data={"user_count": 1, "spawn_rate": 1, "host": "", "my_argument": "42"},
)
self.assertEqual(200, response.status_code)
self.assertEqual(42, my_dict["val"])

def test_swarm_override_command_line_argument(self):
my_dict = {}

class MyUser(User):
host = "http://example.com"
wait_time = constant(1)

@task(1)
def my_task(self):
my_dict["val"] = self.environment.parsed_options.my_argument

@locust.events.init_command_line_parser.add_listener
def _(parser):
parser.add_argument("--my-argument", type=int, help="Give me a number")

parsed_options = parse_options(args=["--my-argument", "24"])
self.environment.user_classes = [MyUser]
self.environment.parsed_options = parsed_options
self.environment.web_ui.parsed_options = parsed_options
response = requests.post(
"http://127.0.0.1:%i/swarm" % self.web_port,
data={"user_count": 1, "spawn_rate": 1, "host": "", "my_argument": "42"},
)
self.assertEqual(200, response.status_code)
self.assertEqual(42, my_dict["val"])

def test_swarm_host_value_not_specified(self):
class MyUser(User):
4 changes: 2 additions & 2 deletions locust/web.py
Original file line number Diff line number Diff line change
@@ -284,9 +284,9 @@ def swarm() -> Response:
if isinstance(parsed_options_value, bool):
parsed_options_dict[key] = value == "true"
elif parsed_options_value is None:
parsed_options_dict[key] = parsed_options_value
parsed_options_dict[key] = value
else:
parsed_options_dict[key] = type(parsed_options_dict[key])(value)
parsed_options_dict[key] = type(parsed_options_value)(value)

if environment.shape_class and environment.runner is not None:
environment.runner.start_shape()