diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst index a780da8..c5c7161 100644 --- a/docs/source/glossary.rst +++ b/docs/source/glossary.rst @@ -39,6 +39,7 @@ Glossary The agent isn't sending itself the queries, it creates a worker which does it instead. + users virtual users When running a test, you can chose the number of users you want to have in parallel. This is called the number of virtual users. diff --git a/docs/source/guide.rst b/docs/source/guide.rst index db4aecd..62f5a16 100644 --- a/docs/source/guide.rst +++ b/docs/source/guide.rst @@ -204,3 +204,60 @@ the test is successful:: At the end of the test, you will be able to know how many times the counter was incremented. + +.. _randomness-section: + +Testing random actions +---------------------- + +Since your test method will be called several times per :term:`user`s +(See :ref:`users and hits `), you may want to introduce +some entropy in order to simulate the behaviour of a real user. + +A good practice is to rely on randomness to control the distribution of the +test actions:: + + import random + from loads.case import TestCase + + WRITE_PERCENTAGE = 30 + + class TestAction(TestCase): + + def test_api(self): + if random.randint(0, 100) < WRITE_PERCENTAGE: + self.test_write() + else: + self.test_read() + + +.. _authenticating-session-section: + +Authenticated sessions +---------------------- + +If you want to map :term:`virtual users` to actual users on your remote server, +you shall perform authentication during the test initialization. + +For example, using *Requests*:: + + import uuid + from requests import auth as requests_auth + from loads.case import TestCase + + class TestAuthenticatedAction(TestCase): + + def __init__(self, *args, **kwargs): + super(TestAuthenticatedAction, self).__init__(*args, **kwargs) + + random_user = uuid.uuid4().hex + random_pwd = uuid.uuid4().hex + + # Create the user on your remote server + # ... + + self.auth = requests_auth.HTTPBasicAuth(random_user, random_pwd) + + def test_api(self): + res = self.session.get('http://localhost:8000', auth=self.auth) + self.assertEqual(res.status_code, 200) diff --git a/docs/source/internals.rst b/docs/source/internals.rst index 40cbdfc..2f3033b 100644 --- a/docs/source/internals.rst +++ b/docs/source/internals.rst @@ -15,6 +15,27 @@ to smoke test your service - or simply because you don't need to send a huge load. That's the *non-distributed* mode. +.. _users-hits-section: + +About users and hits +==================== + +Loads will *instantiate* your test class as many times as *users* specified. +Hence, any operations related to test suite initialization, such as +:ref:`authenticating the session ` or creating +initial test data, shall be performed in the test ``__init__`` method. + +Loads will then *run* your test method as many times as *hits* specified. +Unless your goal is to test the same specific usage scenario in parallel, +:ref:`relying on randomness ` to execute various different +actions might become relevant. + +.. note:: + + Loads test methods are executed using *gevent*. Therefore the order of + execution of each hit is basically asynchronous and not deterministic. + + What happens during a non-distributed run ========================================= @@ -24,7 +45,9 @@ What happens during a non-distributed run 2. A `loads.case.TestResult` object is created. This object is a data collector, it is passed to the test suite (`TestCase`), the loads `Session` object and the websocket manager. Its very purpose is to collect the data - from these sources. You can read more in the section named `TestResult` below. + from these sources. + + You can read more in the :ref:`TestResult section `. 3. We create any number of outputs (standard output, html output, etc.) in the runner and register them to the test_result object. @@ -37,11 +60,11 @@ What happens during a non-distributed run 6. During the tests, both the requests' `Session`, the test case itself and the websocket objects report their progress in real time to test_result. When - there is a need to disambiguate the calls, a loads_status object is passed - along. + there is a need to disambiguate the calls, a ``loads_status`` attribute is + available on the session object. - It contains data about the hits, the total number of users, the current - user and the current hit. + It is a tuple containing respectively the hits, the total number of users, + the current user and the current hit. 7. Each time a call is made to the test_result object to add data, it notifies its list of observers to be sure they are up to date. This is helpful to @@ -83,6 +106,8 @@ In more details: can get them. +.. _testresult-section: + The TestResult object =====================