DEV Community

Cover image for The Death of XML: Why We Built LocustPilot — A Modern Control Plane for Distributed Load Testing
Hakan GÜL
Hakan GÜL

Posted on Originally published at hakangul.lovable.app

The Death of XML: Why We Built LocustPilot — A Modern Control Plane for Distributed Load Testing

TL;DR: GUI-based load testing tools like JMeter create painful Git merge conflicts with massive XML files, while standard Locust lacks persistent run history and out-of-the-box team dashboards. LocustPilot bridges this gap by combining Python's code-as-test power with a modern Streamlit control center, dynamic test registries, ReportPortal observability, and instant Docker/Kubernetes deployment.

Why Is Traditional Performance Testing Broken?

Every test automation engineer who has prepared for a major traffic event (Black Friday, product launches, or high-volume campaigns) has faced the dreaded .jmx file conflict.

It is 6:00 PM. Two engineers update a JMeter test plan simultaneously. They commit their changes, and Git screams with a 4,000-line XML merge conflict. You cannot easily read it, you cannot safely merge it in a text editor, and one wrong closing tag corrupts the entire test suite.

For decades, performance testing was trapped in GUI-heavy, XML-driven tools. When Locust arrived, it revolutionized the industry by introducing Performance Testing as Code in pure Python.

Suddenly, your load tests were version-controlled, readable, and could leverage the entire Python ecosystem.

from locust import HttpUser, task, between

class QuickOrderUser(HttpUser):
    wait_time = between(1, 2)

    @task
    def checkout(self):
        self.client.post("/api/v1/orders", json={"item_id": 42, "quantity": 1})
Enter fullscreen mode Exit fullscreen mode

What Was Missing in Vanilla Locust?

While Locust's core execution engine is lightweight and lightning-fast, scaling it across an enterprise engineering team reveals immediate operational friction:

  1. No Out-of-the-Box Test Registry: You have to remember command-line paths (locust -f locustfiles/checkout_flow.py) or manage messy bash wrapper scripts.
  2. Ephemeral Run History: The default Locust web UI is purely session-based. Once you stop the test or restart the container, all charts, response times, and failure logs vanish forever.
  3. Disconnected Reporting: Sharing past test runs with backend developers requires manually downloading CSVs or hunting through local log files.
  4. Lack of Enterprise Quality Gates: Teams need automated test thresholds (e.g., Fail if 99th percentile exceeds 250ms) and centralized observability dashboards like ReportPortal.

Modern Developer Workspace
Photo by Glenn Carstens-Peters on Unsplash


Introducing LocustPilot: The Modern Control Plane

We built LocustPilot to turn standalone Locust scripts into a collaborative, production-grade load testing platform.

Instead of wrestling with CLI flags or losing past test metrics, LocustPilot provides an interactive Streamlit Command Center that automatically manages test discovery, execution, real-time log streaming, and persistent reporting.

Key Architectural Highlights:

  • 🧪 Smart Test Discovery (AST Scanner): Automatically parses your test directory using Python's Abstract Syntax Tree (ast), detects all HttpUser / FastHttpUser classes, and exposes them in a clean dropdown menu.
  • 📊 Persistent History & Plotly Charts: Every run is automatically archived with detailed latency percentiles (P50, P90, P95, P99), throughput graphs, and downloadable HTML/CSV bundles.
  • 🔌 Native ReportPortal Integration: Streams live endpoint metrics and unique failure logs directly into ReportPortal with zero manual setup.
  • ☁️ Cloud-Native Deployment: Ready for production with pre-configured Docker images and Kubernetes Helm charts (helm/locust).

Feature Matrix: How LocustPilot Compares

Capability Apache JMeter Vanilla Locust LocustPilot
Test Definition XML / Proprietary GUI Pure Python Code Pure Python Code
Version Control & Diffs ❌ Painful XML conflicts ✅ Clean Python Git diffs ✅ Clean Python Git diffs
Test Selection UI ❌ Manual file opening ❌ CLI arguments only Dropdown Test Registry
Run History ⚠️ Complex DB setups ❌ Session only (lost on stop) Persistent CSV/HTML/ZIP
Enterprise Telemetry ⚠️ Heavy plugins ❌ Basic web UI Built-in ReportPortal & Plotly
K8s & CI/CD Ready ❌ Heavy JVM overhead ⚠️ Manual worker setup Helm Chart & Docker Ready

How to Get Started in 30 Seconds

LocustPilot is completely open-source under the MIT license. You can launch the entire platform locally with a single Docker command:

# Clone the repository
git clone https://github.com/hakanngul/LocustPilot.git
cd LocustPilot

# Build and launch with Docker
docker build -t locust-pilot .
docker run -p 8501:8501 locust-pilot
Enter fullscreen mode Exit fullscreen mode

Open your browser at http://localhost:8501, pick your target test from the dropdown, configure your user count, and hit Start Test.


What Is Next in This Series?

This is Part 1 of our 5-part LocustPilot deep dive. Over the next parts, we will explore:

  • Part 2: Under the hood of the dynamic AST Python test scanner and non-blocking log streamer.
  • Part 3: Enterprise observability: Streaming 99th percentile latencies to ReportPortal with Gevent.
  • Part 4: Scaling to 100,000 RPS on Kubernetes using Helm and distributed workers.
  • Part 5: Shift-Left performance testing: Enforcing automated build quality gates in CI/CD.

👉 Star and Explore LocustPilot on GitHub


FAQ

Why choose Python-based Locust over JMeter?

Python-based load testing allows developers and SDETs to treat performance tests as first-class software code. You can write reusable modules, use native Git diffs, debug directly in your IDE, and eliminate fragile XML files.

Does LocustPilot modify standard Locust scripts?

No. Any standard Locust script (HttpUser, FastHttpUser, @task) runs seamlessly in LocustPilot without requiring any code modifications or vendor lock-in.

Can I run LocustPilot in headless CI/CD pipelines?

Yes. LocustPilot supports both the interactive Streamlit UI for ad-hoc load runs and fully headless execution inside GitHub Actions, Bitbucket Pipelines, or Jenkins.

Top comments (0)