Main Content
A side-by-side image of the Drupal 8 and Locust logos.

Drupal 8 Load Testing with Locust

Load-testing is an essential best practice for Drupal 8 development. Quantifying how much traffic a site can sustain is critical information both during development and prior to launch. 

The reasons for doing so are significant and wide-ranging:

  • Determine hosting needs
  • Identify under-performing code
  • Test the efficiency of candidate contributed modules
  • Quantify how performance is impacted as content grows
  • Document pre-launch performance to facilitate future troubleshooting

 

Locust as a Load-testing Solution

Locust is a web-based, open-source tool. It was created to be easy-to-use via its user interface, while also being customizable via Python test scripts. For example, it allows for the ability to simulate multiple users concurrently submitting a Drupal webform multiple times. It can also run distributed tests with instances running on multiple machines.

 

Installing Locust

python3 -m pip install locustio

Install the "Beautiful Soup" python library to facilitate user login

python3 -m pip install bs4

 

Example Test Script

from locust import HttpLocust, TaskSet, between
from bs4 import BeautifulSoup

def index(self):
    self.client.get("/")

def about(self):
    self.client.get("/about")

def drupalLogin(self):
    # Get form build ID to pass back to Drupal on login.
    response = self.client.get("/user")
    content = BeautifulSoup(response.content)
    build_id = content.body.find('input', {'name': 'form_build_id'})['value']
    self.client.post("/user/login", {
        "name": "testusername",
        "pass": "testpassword",
        "form_id": "user_login_form",
        "form_build_id": build_id,
        "op": "Log in"
    })

def drupalLogout(self):
    self.client.get("/user/logout")

class UserBehavior(TaskSet):
    tasks = {index: 1, about: 1}

    def on_start(self):
        drupalLogin(self);

    def on_stop(self):
        drupalLogout(self)

class WebsiteUser(HttpLocust):
    task_set = UserBehavior
    wait_time = between(5.0, 9.0)

In this example, 5 users log in to Drupal and then each user accesses either the front page or the / about page every 5-9 seconds. The "Hatch rate" of 1 adds an additional use each second until a total of 5 concurrent users are actively running the script. This helps to simulate a more natural increase in traffic.  Finally, all users log out of Drupal when testing ends.

 

Running a Test

locust -f ./locust_test.py

Here is the UI form for initializing the test:

The UI form for initializing the test

Here is a screenshot of the data table this test produced:

Screen shot of the data the test produced

Here are PNG graph images generated by Locust during this test:

Graph showing the number of requests per second.

Graph showing response times.

PNG graph images generated by Locust during the test

Tests can also be run without the UI. This is useful for automation or for running tests in a remote environment:

locust -f ./locust_test.py --no-web -c 5 -r 1 -H https://target.domain

This approach has successfully been tested in a CentOS 7 environment.

 

Load-Testing in the Development Cycle

Since tests are fairly straightforward to write and run, it is feasible to perform load-testing throughout the development process.

Early in the development phase, tests could be more simple and generic. For example, visiting the front page, logging in, and logging out. These initial tests could be site-agnostic for reuse across multiple projects. Then, more site-specific tests can be added as the project takes shape,.

An approach for this might include load-testing directions within pull requests or, potentially, automation could kick off tests following a PR merge so a snapshot of performance is captured with each code change.

 

Next Steps

Locust is a simple yet flexible open-source tool for quantifying performance throughout the development cycle. Interested in load-testing or test-driven development for your Drupal 8 site?  Contact us today.

Resources