A simple, fast HTTP load testing tool written in Go.
# From source (in project directory)
go install ./cmd/maestro
# Or directly from GitHub
go install github.com/Mulder90/maestro/cmd/maestro@latest- Create a config file
test.yaml:
workflow:
name: "My API Test"
steps:
- name: "health"
method: GET
url: "https://api.example.com/health"- Run the test:
maestro --config=test.yaml --actors=10 --duration=30s- See results:
Maestro - Load Test Results
==============================
Duration: 30s
Total Requests: 4,523
Success Rate: 99.2% (4,487 / 4,523)
Requests/sec: 150.8
Response Times:
Min: 12ms
Avg: 65ms
P95: 120ms
P99: 180ms
Max: 312ms
| Flag | Default | Description |
|---|---|---|
--config |
required | Path to YAML config |
--actors |
5 | Number of concurrent actors |
--duration |
10s | Test duration |
--max-iterations |
0 | Stop after N iterations per actor (0 = unlimited) |
--warmup |
0 | Warmup iterations excluded from metrics |
--output |
text | Output format: text or json |
--quiet |
false | Suppress progress output |
--verbose |
false | Log requests/responses |
workflow:
name: "API Test"
steps:
- name: "login"
method: POST
url: "${env:API_BASE}/auth/login"
headers:
Content-Type: "application/json"
body: '{"user": "test", "pass": "secret"}'
extract:
token: "$.auth.token"
- name: "get_profile"
method: GET
url: "${env:API_BASE}/users/me"
headers:
Authorization: "Bearer ${token}"Variables use ${var} syntax. Extract values from JSON responses with $.path (JSONPath).
Environment variables use ${env:VAR}. Built-in functions: ${uuid()}, ${random(1,100)}, ${random_string(8)}, ${timestamp()}, ${date(2006-01-02)}.
Load test data from CSV or JSON files:
workflow:
name: "Parameterized Test"
data:
users:
file: "users.csv" # CSV with headers: username,password
mode: sequential # iterate in order (default)
products:
file: "products.json" # JSON array of objects
mode: random # pick random row each time
steps:
- name: "login"
method: POST
url: "https://api.example.com/login"
body: '{"user": "${data.users.username}", "pass": "${data.users.password}"}'Access data fields as ${data.sourcename.fieldname}. File paths are relative to the config file.
Fail the test if metrics exceed limits:
workflow:
name: "API Test"
steps:
- name: "health"
method: GET
url: "https://api.example.com/health"
thresholds:
http_req_duration:
p95: 200ms
p99: 500ms
http_req_failed:
rate: 1%Exit codes: 0 = passed, 1 = threshold failed, 2 = error
Define phases for ramp-up/down patterns:
workflow:
name: "Load Test"
steps:
- name: "api"
method: GET
url: "https://api.example.com/data"
loadProfile:
phases:
- name: "ramp_up"
duration: 30s
startActors: 1
endActors: 50
- name: "steady"
duration: 2m
actors: 50
rps: 100 # rate limit (optional)
- name: "ramp_down"
duration: 30s
startActors: 50
endActors: 0Run exact iterations for deterministic tests:
execution:
max_iterations: 100 # each actor runs exactly 100 iterations
warmup_iterations: 10 # first 10 excluded from metricsOr via CLI: --max-iterations=100 --warmup=10
See the examples/ folder for ready-to-run configs:
# Start test server (optional, for local testing)
go run ./cmd/testserver &
# Simple tests
maestro --config=examples/local/health-check.yaml --duration=10s
# Load profiles
maestro --config=examples/profiles/ramp-up-down.yaml
# Thresholds
maestro --config=examples/thresholds/passing.yaml- Contributing - Development setup, running tests
- Architecture - Design and internals
- Roadmap - Future plans
MIT