Load tests (Locust)

Table of contents

  1. Introduction
  2. Load-testing one feature
  3. Stopping it
  4. Writing a locustfile
  5. Advanced
  6. Reference

Introduction

splent locust starts a Locust load test inside your product’s web container, which already has the framework and every feature installed. splent locust:stop stops it. Both need a selected product (SPLENT_APP) that is running.

splent locust
Command: docker exec -d -e WORKING_DIR=/workspace my_first_app_web sh -c ...
Locust is running at http://localhost:8089
Stop it with: splent locust:stop

Open the URL and start the swarm. Each product publishes Locust on 8089 plus its port offset, like its web and database ports, so several products can run it at once.


Load-testing one feature

splent locust notes

Without an argument it runs every feature’s locustfile. The short name, the package (splent_feature_notes) and the pyproject form (splent-io/splent_feature_notes@v1.2.0) all work.


Stopping it

splent locust:stop

It prints Locust stopped., or No Locust process was running. when there was nothing to stop.


Writing a locustfile

Each feature keeps its load test in tests/load/locustfile.py, outside the default pytest run. feature:create scaffolds one that requests the feature’s own route and counts 200 and 302, the login redirect, as success.

from locust import HttpUser, TaskSet, between, task
from splent_framework.environment.host import get_host_for_locust_testing


class NotesBehavior(TaskSet):
    @task
    def index(self):
        with self.client.get("/notes", allow_redirects=False, catch_response=True) as response:
            if response.status_code in (200, 302):
                response.success()
            else:
                response.failure(f"Notes index returned {response.status_code}")


class NotesUser(HttpUser):
    tasks = [NotesBehavior]
    wait_time = between(5, 9)
    host = get_host_for_locust_testing()
  • Use wait_time. Locust 2.x ignores min_wait and max_wait.
  • get_host_for_locust_testing() returns http://localhost:5000, the dev server next to Locust. Set LOCUST_TARGET_URL to aim elsewhere.
  • splent_framework.locust.common gives you get_csrf_token(response), which reads a form’s hidden csrf_token, and fake, a Faker instance.

Advanced

The framework module splent_framework.bootstraps.locustfile_bootstrap finds every locustfile.py under the product’s features/ folder, following its links, and imports each under its own module name. A locustfile that fails to import is skipped with a logged exception. SPLENT_LOCUSTFILES replaces that search with comma-separated glob patterns, relative to WORKING_DIR unless absolute.


Reference

Argument Description
FEATURE Load-test only this feature

Before it starts, it runs locust --list in the container, which imports every locustfile. Then it starts Locust detached, logging to /tmp/locust.log, and checks two seconds later that it is still alive.

Message What to do
Container '<product>_web' is not running. Start the product with splent product:up
locust is not installed in '<product>_web'. Add "locust" to [project.optional-dependencies].dev and run splent product:derive, or docker exec <product>_web pip install locust once
No locustfile found for feature '<feature>' Put it where the message says it looked, usually tests/load/locustfile.py
Locust could not load the locustfiles, so it was not started. Fix the error in Locust’s output below it
Locust exited right after it started. Read the last lines of the log it prints. A busy port is a common cause
Locust is already running in the product container. Stop it first with splent locust:stop
... does not publish port 8089. Add "<host port>:8089" to the web service’s ports and recreate the container

All but the last two exit 1. Locust already running starts nothing, and a missing port only warns.


Back to top

splent. Distributed by an LGPL license v3. Contact us: drorganvidez@us.es