Skip to content

Commit

Permalink
Use python-requests lib (partly discussed in locustio#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
heyman committed Oct 25, 2012
1 parent 953935b commit d0782d1
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 373 deletions.
10 changes: 7 additions & 3 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ Locust class

.. autoclass:: locust.core.Locust
:members: tasks, min_wait, max_wait, schedule_task, client

.. autoattribute:: locust.core.LocustBase.min_wait
.. autoattribute:: locust.core.LocustBase.max_wait
.. autoattribute:: locust.core.LocustBase.tasks


HttpBrowser class
HttpSession class
=================

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

HttpResponse class
==================
Expand Down
96 changes: 90 additions & 6 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,21 +1,105 @@
==========
##########
Changelog
==========
##########

0.6
===

Improvements and bug fixes
--------------------------

* Scheduled task callabled can now take keyword arguments.
.. warning::

This version comes with non backward compatible changes to the API.
Anyone who is currently using existing locust scripts and want to upgrade to 0.6
is adviced to read through these changes. It's nothing major, and the upgrade
should be possible without too much pain.


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

class MyWebUser(Locust):
def on_start(self):
self.client.headers = {"Accept-Encoding":""}


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 :py:meth:`get <locust.clients.HttpSession.get>`, :py:meth:`post <locust.clients.HttpSession.post>`,
:py:meth:`put <locust.clients.HttpSession.put>`, :py:meth:`delete <locust.clients.HttpSession.delete>` and
:py:meth:`head <locust.clients.HttpSession.head>` methods, the :py:class:`HttpSession <locust.clients.HttpSession>` class
now also has :py:meth:`patch <locust.clients.HttpSession.patch>` and :py:meth:`options <locust.clients.HttpSession.options>` methods.

* 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::
client.get("/path", {"User-Agent":"locust"}) # this will no longer work
And should now be specified like::
client.get("/path", headers={"User-Agent":"locust"})

* 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 <http://python-requests.org>`_ for more details.

* The new :py:class:`HttpSession <locust.clients.HttpSession>` class' methods now return python-request
:py:class:`Response <requests.Response>` objects. This means that accessing 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 method now returns a CatchedResponse
object which is a context manager that can be used to manually deciding if the request should be reported
as successful or as a failure, in the Locust statistics.

.. autoclass:: locust.clients.CatchedResponse
:members: response, request, success, failure
:noindex:

* 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::
client.get("/does/not/exist", allow_http_error=True)
Can instead now be written like:

with client.get("does/not/exist", catch_response=True) as catched:
catched.success()


Other improvements and bug fixes
--------------------------------

* Scheduled task callables can now take keyword arguments.
* SubLocust classes that are scheduled using :func:`locust.core.Locust.schedule_task` can now take
arguments and keyword arguments (available in *self.args* and *self.kwargs*).



API Changes
-----------

* HttpBrowser has been removed in favor of python requests library.
* Changed signature of :func:`locust.core.Locust.schedule_task`. Previously all extra arguments that
was given to the method was passed on to the 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
Expand Down
7 changes: 6 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ["sphinx.ext.autodoc"]
extensions = ["sphinx.ext.autodoc", "sphinx.ext.intersphinx"]

# autoclass options
#autoclass_content = "both"
Expand All @@ -32,6 +32,11 @@
project = 'Locust'
#copyright = ''

# Intersphinx config
intersphinx_mapping = {
'requests': ('http://requests.readthedocs.org/en/latest/', None),
}

# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
#
Expand Down
33 changes: 14 additions & 19 deletions docs/writing-a-locustfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,32 +132,27 @@ and **/** will be requested twice the amount of times than **/about/**.
Using the HTTP client
======================

Each instance of Locust has an instance of HttpBrowser in the *client* attribute.
Each instance of Locust has an instance of HttpSession in the *client* attribute.

.. autoclass:: locust.clients.HttpBrowser
:members: __init__, get, post
.. autoclass:: locust.clients.HttpSession
:members: __init__, get, post, request
:noindex:

By default, requests are marked as failed requests unless the HTTP response code is ok (2xx).
However, one can mark requests as failed, even when the response code is okay, by using the
*catch_response* argument with a with statement::

from locust import ResponseError
client = HttpBrowser("http://example.com")
with client.get("/", catch_response=True) as response:
if response.data != "Success":
raise ResponseError("Got wrong response")

Just as one can mark requests with OK response codes as failures, one can also make requests that
results in an HTTP error code still result in a success in the statistics::

client = HttpBrowser("http://example.com")
response = client.get("/does_not_exist/", allow_http_error=True)
if response.exception:
print "We got an HTTPError exception, but the request will still be marked as OK"
Also, *catch_response* and *allow_http_error* can be used together.
with client.get("/", catch_response=True) as catched:
if catched.response.content != "Success":
catched.failure("Got wrong response")

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

with client.get("/does_not_exist/", catch_response=True) as catched:
if catched.response.status_code == 404:
catched.success()


The on_start function
Expand Down
6 changes: 5 additions & 1 deletion examples/basic.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from locust import Locust, require_once
from locust import Locust, require_once, task
import random

def login(l):
Expand All @@ -20,3 +20,7 @@ class WebsiteUser(Locust):
tasks = [index, stats]
min_wait=2000
max_wait=5000

@task
def page404(self):
self.client.get("/does_not_exist")
Loading

0 comments on commit d0782d1

Please sign in to comment.