Load Testing HTTP with Locust

In this blog post I will share some examples of basic load testing against web services.
I will describe a few examples which easily can be configured to match additional needs and requirements.

Locust is an open source load testing tool, it is fairly simple to setup and run basic HTTP tests. It is intended for load testing web sites (or other systems) and to figure out how many concurrent users a system can handle.

You define the behavior of each test user in python code and the test process is monitored from a Web UI in Real Time.

Statistics

 

Charts from Locust in Real Time

 

Feature overview

  • Scalable and Distributed
    • Locust can be set up in a Master / Slave distributed model and supports hundreds of thousands of users
  • Write user test scenarios based on Python
  • Web-based UI
  • Can test any system
    • Locust is web-oriented, but you can write your own client for what ever you wish to test

Install Locust

Linux/Unix

pip install locustio

Mac OS X

brew install libev

Then run:

pip install locustio

Or

easy_install locustio

 

Test Scenario

These test scenarios are only done to demonstrate Locust (Tested with version 0.8a4).
The JuiceShop web service (JSON Application) runs as a Docker Container on Ubuntu 16.04.

Test Scenario 1 – example of automated load test against a Juiceshop login form delivered via JSON.

Test Scenario 2 – Both default web site and login form is tested against. Citrix NetScaler is used as a reverse proxy, fronting Juiceshop.
Rate Limiting is configured to limit HTTP Requests and dropping traffic when Rate Limit trigger is hit .

Scenario 1 – Login Test

In this scenario I execute 100 random logins from a specific user against a fictive Juiceshop (OWASP).

Shell script to start Locust test against target host (start-locust-load-juiceshop.sh):

locust -f locust_http_test-juiceshop.py –host=https://juiceshop.xxxx.com:3000

Access Locust Web UI from:
127.0.0.1:8089

Locust configuration

Simple Locust python script (locust_http_test-juiceshop.py) to generate a user login in JSON enabled web application :

from locust import HttpLocust, TaskSet, web
import json

payload = {“email”:”user1@test.com”, “password”:”password01″}

headers = {“Content-Type”:”application/json”,”User-Agent”:”locust”}

def login(l):
l.client.post(“/rest/user/login”, data=json.dumps(payload), headers=headers)

class UserBehavior(TaskSet):
tasks = {login: 1}

class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000

 

Graphing Test 1 Statistics with Excel

Insert Chart in Excel based on Statistics from Locust Test:

After import of CSV use Text2Columns under Data menu, now insert chart based on values from locust test:

 

 

 

Scenario 2 – Rate Limit Test

In this scenario I run 100 users against a fictive Juiceshop (OWASP) but fronted by NetScaler as a Application Delivery Controller / Reverse Proxy configured with Rate Limiting.

Locust configuration

 

from locust import HttpLocust, TaskSet, web
import json

payload = {“email”:”user1@test.com”, “password”:”password01″}

headers = {“Content-Type”:”application/json”,”User-Agent”:”locust”,”Accept-Encoding”: “”}

def login(l):
l.client.post(“/rest/user/login”, data=json.dumps(payload), headers=headers)

def index(l):
l.client.get(“/”, headers={“User-Agent”:”locust”})

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

class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000

 

Graphing Test 2 Statistics with Excel

Failure occuring because of Rate Limit on NetScaler:

 

Connection Reset by Peer (NetScaler dropping the connection)

 

RateLimit config example:

add stream selector limit_selector_client_ip_locust client.ip.src

add ns limitIdentifier limit_id_client_ip_locust -threshold 2 -timeSlice 10000 -selectorName limit_selector_client_ip_locust

NetScaler Responder bound to JuiceShop Load Balancing virtual server:

add responder policy resp-pol-locust-ratelimit-test “HTTP.REQ.HEADER(\”User-Agent\”).CONTAINS(\”locust\”) && SYS.CHECK_LIMIT(\”limit_id_client_ip_locust\”)” DROP

 

 

Additional Locust tips

Get Response code from HTTP Request:

response = self.client.get(“/about”)
print “Response status code:”, response.status_code
print “Response content:”, response.content

Add addtional page in Locust Web UI:

from locust import web

@web.app.route(“/added_page”)
def my_added_page():
return “Another page”

Reference links

Listed here are some reference links to Locust.

Main Site
http://locust.io

Documentation
http://docs.locust.io/en/latest/

Source code
http://github.com/locustio/locust

Leave a Reply