Skip to content

Commit

Permalink
Add response object to request event. Update documentation. Relates a…
Browse files Browse the repository at this point in the history
… little bit to the discussion in #1750
  • Loading branch information
cyberw committed May 3, 2021
1 parent 76ac755 commit a19a14d
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 15 deletions.
4 changes: 2 additions & 2 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ For full details of the Locust changelog, please see https://github.com/locustio
1.5.0
=====

* Add new event called request. Is called on every request successful or not. request_success and request_failure are still available but are deprecated
* Add parameter context to the request event. Can be used to forward information when calling a request, things like user information, tags etc
* Unify request_success/request_failure into a single event called request (the old ones are deprecated but still work) https://github.com/locustio/locust/issues/1724
* Add the response object and context as parameters to the request event. context is used to forward information to the request event handler (can be used for things like username, tags etc)

1.4.4
=====
Expand Down
10 changes: 7 additions & 3 deletions docs/extending-locust.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@ Here's an example on how to set up an event listener::
from locust import events
@events.request.add_listener
def my_request_handler(request_type, name, response_time, response_length, context, exception, **kw):
def my_request_handler(request_type, name, response_time, response_length, response,
context, exception, **kw):
if exception:
print(f"Request to {name} failed with exception {exception}")
else:
print(f"Successfully made a request to: {name})


.. 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.

Note that it is entirely possible to implement a client that does not support all parameters
(some non-HTTP protocols might not have a concept of `response_length` or `response` object).

.. _request_context:

Request context
==================
Expand Down Expand Up @@ -60,7 +64,7 @@ Context from User class::
self.client.post("/login", json={"username": self.username})

@events.request.add_listener
def on_request(self, context, **kwargs):
def on_request(context, **kwargs):
print(context["username"])


Expand Down
1 change: 1 addition & 0 deletions locust/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def request(self, method, url, name=None, catch_response=False, context={}, **kw
"response_time": (time.monotonic() - start_time) * 1000,
"name": name or (response.history and response.history[0] or response).request.path_url,
"context": context,
"response": response,
"exception": None,
}

Expand Down
1 change: 1 addition & 0 deletions locust/contrib/fasthttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ def request(

# send request, and catch any exceptions
response = self._send_request_safe_mode(method, url, payload=data, headers=headers, **kwargs)
request_meta["response"] = response

if not allow_redirects:
self.client.redirect_resonse_codes = old_redirect_response_codes
Expand Down
5 changes: 3 additions & 2 deletions locust/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ class Events:
:param name: Path to the URL that was called (or override name if it was used in the call to the client)
:param response_time: Time in milliseconds until exception was thrown
:param response_length: Content-length of the response
:param exception: Exception instance that was thrown. None if no exception
:param context: Dict with context values specified when performing request
:param response: Response object (e.g. a :py:class:`requests.Response`)
:param context: :ref:`User/request context <request_context>`
:param exception: Exception instance that was thrown. None if request was successful.
"""

request_success: DeprecatedEventHook
Expand Down
8 changes: 6 additions & 2 deletions locust/test/test_fasthttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ class MyUser(FastHttpUser):
host = "http://127.0.0.1:%i" % self.port

def context(self):
return {"user": self}
return {"user": self.username}

kwargs = {}

Expand All @@ -264,8 +264,12 @@ def on_request(**kw):

self.environment.events.request.add_listener(on_request)
user = MyUser(self.environment)
user.username = "foo"
user.client.request("get", "/request_method")
self.assertDictEqual({"user": user}, kwargs["context"])
self.assertDictEqual({"user": "foo"}, kwargs["context"])
self.assertEqual("GET", kwargs["response"].text)
user.client.request("get", "/request_method", context={"user": "bar"})
self.assertDictEqual({"user": "bar"}, kwargs["context"])

def test_get_request(self):
self.response = ""
Expand Down
21 changes: 19 additions & 2 deletions locust/test/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,19 @@ def on_request(exception, **kw):
s.request("get", "/request_method", context={"foo": "bar"})
self.assertDictEqual({"foo": "bar"}, kwargs["context"])

def test_response_parameter(self):
s = self.get_client()
kwargs = {}

def on_request(**kw):
kwargs.update(kw)

self.environment.events.request.add_listener(on_request)
s.request("get", "/request_method")
self.assertEqual("GET", kwargs["response"].text)
s.request("get", "/wrong_url")
self.assertEqual("Not Found", kwargs["response"].text)

def test_deprecated_request_events(self):
s = self.get_client()
status = {"success_amount": 0, "failure_amount": 0}
Expand Down Expand Up @@ -246,7 +259,7 @@ class TestUser(HttpUser):
host = "http://localhost"

def context(self):
return {"user": self}
return {"user": self.username}

kwargs = {}

Expand All @@ -256,5 +269,9 @@ def on_request(**kw):
self.environment.events.request.add_listener(on_request)

user = TestUser(self.environment)
user.username = "foo"
user.client.request("get", "/request_method")
self.assertDictEqual({"user": user}, kwargs["context"])
self.assertDictEqual({"user": "foo"}, kwargs["context"])
self.assertEqual("GET", kwargs["response"].text)
user.client.request("get", "/request_method", context={"user": "bar"}) # override User context
self.assertDictEqual({"user": "bar"}, kwargs["context"])
5 changes: 1 addition & 4 deletions locust/user/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,7 @@ def stop(self, force=False):

def context(self) -> Dict:
"""
Returns user specific context. Override this method to customize data to be forwarded in request event.
:return: Context data
:rtype: Dict
Adds the returned value (a dict) to the context for :ref:`request event <request_context>`
"""
return {}

Expand Down

0 comments on commit a19a14d

Please sign in to comment.