Examples
34 runnable examples
Every one is a complete, valid test you can run with loadr run <file>. They ship in the examples/ folder of every download, or grab them here.
The smallest useful loadr test: 10 virtual users hammering one endpoint for 30 seconds, with checks and a pass/fail threshold. loadr run examples/01-quickstart.yaml
Classic ramp test: climb to 50 VUs, hold, ramp down — with think time between requests so VUs behave like humans.
Open-model load: start exactly 100 iterations per second regardless of how slowly the target responds. Watch `dropped_iterations` to spot saturation.
Spike test with a ramping arrival rate: calm baseline, sudden 10x spike, recovery. The abort threshold kills the run if errors explode.
Data-driven login: each iteration takes the next row from users.csv (shared cursor across all VUs, wrapping at EOF).
Correlation: extract values from earlier responses (regex, CSS selector, JSONPath, headers, boundary) and reuse them in later requests.
Several scenarios running concurrently with independent executors, start times and tags, plus groups and a custom metric.
Full JavaScript lifecycle: setup() fetches an auth token once, every iteration runs an exported function, beforeRequest/afterRequest hooks fire around YAML requests, teardown() cleans up.
WebSocket load: connect, exchange messages, assert on the conversation.
gRPC load: compile .proto files in-process (no protoc needed) or use server reflection, then call unary and streaming methods dynamically.
GraphQL over HTTP with variables; GraphQL `errors` are detected and the request is marked failed when no data comes back.
Raw socket load: TCP request/response and UDP datagrams, with hex payloads.
One test, many environments: `loadr run -e staging examples/13-environments.yaml` deep-merges the env block over the file. Secrets come from the process environment and are never printed.
Long soak test wired into observability: Prometheus scrape endpoint, JSONL archive, and StatsD — plus an abort threshold as a circuit breaker.
Distributed run: submit this to a controller and the load is partitioned across every connected agent (VUs split, arrival rates divided, percentiles merged centrally from HDR histograms — never averaged). loadr controller --bind 0.0.0.0:7625 & loadr agent --join controller-host:7625 --name agent-1 & loadr run --controller controller-host:6464 examples/15-distributed.yaml
Flow control: repeat, while, if/else and weighted random branches — the control flow from Gatling (repeat/during/doIf/randomSwitch) and the weighted-task model from Locust, in declarative YAML.
Feeder strategies (Gatling: sequential / random / shuffle, plus JSON feeders) and a global request-rate ceiling (Gatling throttle / reachRps).
Server-Sent Events load: open an event stream, read until a condition, assert on the last event.
Real-browser load test: drive headless Chrome over CDP and capture Navigation Timing + Web Vitals (FCP, LCP, DCL, load) for a page. Unlike the protocol-level `http` client, the `browser` protocol renders the page in a real Chrome tab — running JavaScript, fetching subresources, and firing the load/DOMContentLoaded events — so the timings reflect what a user actually experiences. Each VU keeps its own warm tab for the whole run. Requires headless Chrome/Chromium installed on the runner; it is launched lazily on the first browser request.
Advanced HTTP defaults: the "power features" of the HTTP client, all in one test. Exercises: - cache: true per-VU browser-style HTTP cache (fresh hits + ETag/Last-Modified revalidation) - hosts: pin a hostname to a fixed address (curl --resolve) - discard_response_bodies drop bodies after reading them (high throughput) - tracing: true inject a W3C `traceparent` header per request - tls.min_version/max_version pin the negotiated TLS version to 1.2..1.3 Run it, optionally dumping every request/response to the console: loadr run examples/21-http-advanced.yaml loadr run examples/21-http-advanced.yaml --http-debug
Scenario lifecycle hooks + a custom summary report. Each VU logs in once via the scenario `on_start` hook, runs its `exec` function every iteration, then logs out once via `on_stop` when it retires. After the run, the exported handleSummary(data) function prints a custom end-of-run report instead of the default console summary (k6-compatible).
Tagged scenarios for selective runs. Each scenario carries `tags` (a map of name → value); `loadr run` filters scenarios by their tag *values*. loadr run examples/23-tags.yaml # all four scenarios loadr run --tags smoke examples/23-tags.yaml # only smoke scenarios loadr run --tags read,write examples/23-tags.yaml # read OR write (any-match) loadr run --tags full --exclude-tags write examples/23-tags.yaml # full, but not writes --tags keeps a scenario when it carries at least one of the listed values. --exclude-tags drops a scenario when it carries any of the listed values, and always wins over --tags.
Time-series report demo: a ramp-up / spike / ramp-down profile that produces an interesting shape over time. Run it, export the summary, then render the self-contained HTML report — every metric is charted against elapsed time (throughput, latency p50/p95/p99, active VUs, error rate), not just shown as an end-of-run average. loadr run --summary-export results.json examples/24-timeseries-report.yaml loadr report results.json -o report.html open report.html # hover the charts to read off any point in the run The summary JSON carries a top-level `timeline` array (one point per snapshot interval) that drives the charts; the aggregate tables remain exact.
Fused check-chains: extract → coerce type → transform → validate → save, all in one declarative `extract:` step (Gatling-style). Chains live happily next to the classic `type:`-tagged extractors — mix them freely. Each `chain:` is the variable name to save. Pick exactly one source (jmespath / jsonpath / regex / header / css / xpath / left+right boundary), then optionally `as:` a type, run a `transform:` pipeline, `check:` the value and fall back to a `default:`.
Deliberately produces a MIX of failures so the web UI's failure breakdown panel has something to group: a healthy endpoint, 4xx and 5xx responses, a check that fails, and a JS step that throws an uncaught exception. Run it with the management UI and watch the "Failure breakdown" panel: docker compose -f examples/harness/docker-compose.yml up -d --build loadr run --ui examples/26-failure-breakdown.yaml (go-httpbin's /status/{code} endpoint returns the requested status code.)
PostgreSQL load test, driven by the `loadr-plugin-postgres` native protocol plugin. PostgreSQL support is NOT built into loadr core — it is a runtime-loadable plugin that ships the heavy `sqlx` Rust driver on its own (with ONLY the `postgres` feature, so it carries no `rsa` advisory). The plugin declares the `postgres://`/`postgresql://` URL schemes, so once it is installed a request to one of those URLs routes straight to it; no explicit `protocol:` needed. Each request runs one configured query as the "request"; loadr records query latency in `postgres_req_duration`, the number of rows returned (SELECT) or affected (INSERT/UPDATE/DELETE) in `postgres_rows`, and any database error fails the request (status 1 = ok, status 0 = DB/transport error). Positional parameters are bound safely by the driver with `$1, $2, ...` placeholders. Build + install the plugin, then run: cargo build -p loadr-plugin-postgres --release mkdir -p dist && cp plugins/loadr-plugin-postgres/plugin.toml dist/ \ && cp target/release/libloadr_plugin_postgres.so dist/ loadr plugin install dist loadr run examples/27-postgres.yaml Or point the plan's `plugins:` entry at the built artifact directly (below).
MongoDB load test, driven by the `loadr-plugin-mongo` native protocol plugin. MongoDB support is NOT built into loadr core — it is a runtime-loadable plugin that ships the heavy `mongodb` Rust driver on its own. The plugin declares the `mongodb://` (and `mongo://`) URL scheme, so once it is installed a request to a `mongodb://` URL routes straight to it; no explicit `protocol:` is needed. Each request runs one operation (insert/find/update/delete/aggregate/command) from its `plugin:` block. loadr records the operation latency in `mongo_req_duration`, the count of documents inserted/matched/modified/returned in `mongo_docs`, and any driver error fails the request (status 0 = error, status 1 = ok). Build + install the plugin, then run: cargo build -p loadr-plugin-mongo --release mkdir -p dist && cp plugins/loadr-plugin-mongo/plugin.toml dist/ \ && cp target/release/libloadr_plugin_mongo.so dist/ loadr plugin install dist loadr run examples/28-mongo.yaml Or point the plan's `plugins:` entry at the built artifact directly (below).
MySQL load test, driven by the `loadr-plugin-mysql` native protocol plugin. MySQL support is NOT built into loadr core — it is a runtime-loadable plugin that ships the heavy `sqlx` Rust driver on its own (with ONLY the `mysql` feature). The plugin declares the `mysql://` URL scheme, so once it is installed a request to such a URL routes straight to it; no explicit `protocol:` is needed. Each request runs one configured query as the "request"; loadr records query latency in `mysql_req_duration`, the number of rows returned (SELECT) or affected (INSERT/UPDATE/DELETE) in `mysql_rows`, and any database error fails the request (status 1 = ok, status 0 = DB/transport error). Positional parameters are bound safely by the driver with `?` placeholders. Build + install the plugin, then run: cargo build -p loadr-plugin-mysql --release mkdir -p dist && cp plugins/loadr-plugin-mysql/plugin.toml dist/ \ && cp target/release/libloadr_plugin_mysql.so dist/ loadr plugin install dist loadr run examples/29-mysql.yaml Or point the plan's `plugins:` entry at the built artifact directly (below).
Redis (RESP) load test, driven by the `loadr-plugin-redis` native protocol plugin. Redis is NOT built into loadr core — it is a runtime-loadable plugin that speaks RESP directly over TCP (no `redis` crate, no OpenSSL). The plugin declares the `redis://` (and `rediss://`) URL scheme, so once it is installed a request to a `redis://` URL routes straight to it; no explicit `protocol:` is needed. Each request runs one command from its `plugin.command` array (argv form). loadr records the command latency in `redis_req_duration` and counts requests in `redis_reqs`. A successful reply is status 0; a RESP error reply is status 1 and fails the request. Build + install the plugin, then run: cargo build -p loadr-plugin-redis --release mkdir -p dist && cp plugins/loadr-plugin-redis/plugin.toml dist/ \ && cp target/release/libloadr_plugin_redis.so dist/ loadr plugin install dist loadr run examples/30-redis.yaml Or point the plan's `plugins:` entry at the built artifact directly (below).
Apache Kafka load test, driven by the `loadr-plugin-kafka` native protocol plugin. Kafka support is NOT built into loadr core — it is a runtime-loadable plugin that ships its own Kafka client. That client is `rskafka`, a PURE-RUST client (no librdkafka / C toolchain), so the plugin cross-compiles to every release target. The plugin declares the `kafka://` URL scheme, so once it is installed a request to a `kafka://` URL routes straight to it; no explicit `protocol:` is needed. The broker is the URL authority and the topic is the URL path (`kafka://broker:9092/topic`). Each request runs one operation (produce/fetch) from its `plugin:` block. loadr records the operation latency in `kafka_req_duration`, the count of messages produced/fetched in `kafka_msgs`, and any client error fails the request (status 1 = ok, status 0 = client/transport error). Build + install the plugin, then run: cargo build -p loadr-plugin-kafka --release mkdir -p dist && cp plugins/loadr-plugin-kafka/plugin.toml dist/ \ && cp target/release/libloadr_plugin_kafka.so dist/ loadr plugin install dist loadr run examples/31-kafka.yaml Or point the plan's `plugins:` entry at the built artifact directly (below).
RabbitMQ load test, driven by the `loadr-plugin-rabbitmq` native protocol plugin. RabbitMQ support is NOT built into loadr core — it is a runtime-loadable plugin that ships the pure-Rust `lapin` AMQP 0.9.1 client on its own. The plugin declares the `amqp://` / `amqps://` (and `rabbitmq://`) URL schemes, so once it is installed a request to one of those URLs routes straight to it; no explicit `protocol:` is needed. Each request runs one operation (publish/get) from its `plugin:` block. loadr records the operation latency in `rabbitmq_req_duration`, the count of messages published/consumed in `rabbitmq_msgs`, and any broker error fails the request (status 1 = ok, status 0 = AMQP/transport error). Build + install the plugin, then run: cargo build -p loadr-plugin-rabbitmq --release mkdir -p dist && cp plugins/loadr-plugin-rabbitmq/plugin.toml dist/ \ && cp target/release/libloadr_plugin_rabbitmq.so dist/ loadr plugin install dist loadr run examples/32-rabbitmq.yaml Or point the plan's `plugins:` entry at the built artifact directly (below).
Elasticsearch load test, driven by the `loadr-plugin-elasticsearch` native protocol plugin. Elasticsearch support is NOT built into loadr core — it is a runtime-loadable plugin. Elasticsearch's API is plain HTTP/JSON, so the plugin talks to it over loadr's own hyper + hyper-rustls stack (pure-Rust TLS, no system OpenSSL); it does not pull in the heavy official `elasticsearch` crate. The plugin declares the `elasticsearch://` (and `es://`) URL schemes — both mapped onto `http://` internally — so once it is installed a request to one of those URLs routes straight to it; no explicit `protocol:` is needed. A plain `http(s)://` URL works too. Each request runs one operation (index/get/search/bulk) from its `plugin:` block. loadr records the operation latency in `elasticsearch_req_duration`, the count of documents written (index = 1, bulk = items succeeded) in `elasticsearch_docs`, and any HTTP/cluster error fails the request (status 1 = ok, status 0 = error). Build + install the plugin, then run: cargo build -p loadr-plugin-elasticsearch --release mkdir -p dist && cp plugins/loadr-plugin-elasticsearch/plugin.toml dist/ \ && cp target/release/libloadr_plugin_elasticsearch.so dist/ loadr plugin install dist loadr run examples/33-elasticsearch.yaml Or point the plan's `plugins:` entry at the built artifact directly (below).
A protocol plugin written in plain C, loaded over loadr's frozen C ABI. Unlike the Rust native plugins (mongo/redis/...), `c-echo` is a C shared library exporting four `extern "C"` symbols — proving loadr plugins can be authored in non-Rust languages. The host auto-detects the C ABI at load time. It serves the `cecho://` scheme and echoes each request body back, status 200. Build + install the plugin, then run: make -C examples/plugins/c-echo mkdir -p dist && cp examples/plugins/c-echo/plugin.toml dist/ \ && cp examples/plugins/c-echo/libloadr_plugin_cecho.so dist/ loadr plugin install dist loadr run examples/34-c-echo.yaml Or point the plan's `plugins:` entry at the built artifact directly: plugins: - { name: cecho, path: examples/plugins/c-echo/libloadr_plugin_cecho.so }
A protocol plugin written in Go, loaded over loadr's frozen C ABI. Like the c-echo example, go-echo is NOT a Rust plugin: it's a Go shared library (`go build -buildmode=c-shared`) exporting the four `extern "C"` symbols of loadr's C ABI — proving loadr plugins can be authored in Go. The host auto-detects the C ABI at load time. It serves the `goecho://` scheme and echoes each request body back, status 200. Build + install the plugin, then run: make -C examples/plugins/go-echo mkdir -p dist && cp examples/plugins/go-echo/plugin.toml dist/ \ && cp examples/plugins/go-echo/libloadr_plugin_goecho.so dist/ loadr plugin install dist loadr run examples/35-go-echo.yaml Or point the plan's `plugins:` entry at the built artifact directly: plugins: - { name: goecho, path: examples/plugins/go-echo/libloadr_plugin_goecho.so }