Skip to content

First run

This guide assumes you want the fastest path to proof that test-scale works on your machine. Later sections explain how to aim workers at your own API.

Requirement Why
Go 1.26.5+ Builds control plane, worker, and aggregator images during make quickstart
Docker Compose v2 Runs Postgres, NATS, Prometheus, Grafana, workers
curl, jq, Git Health checks and smoke script

Ensure the Docker daemon is running before you start.

Step 1 — First success (make quickstart)

Section titled “Step 1 — First success (make quickstart)”
Terminal window
git clone https://github.com/MohamedBenTaher/test-scale.git
cd test-scale
make quickstart

What this does, in order:

  1. Preflight — checks docker, curl, jq, and go.
  2. Build — rebuilds ctrl-plane, worker, and aggregator images from your checkout (avoids stale auth/payload bugs).
  3. Start stack — Postgres, NATS, mock target, Prometheus, Grafana, autoscaler.
  4. Health wait — control plane /ping and dependencies.
  5. Smoke — submits examples/smoke.yaml (~10 RPS, 1 worker, bundled mock target).

Success looks like:

PASS: run run-0711-2042-abcd completed with 1 worker(s), 10 RPS, 0 errors
First run complete.
UI: http://localhost:8080
Grafana: http://localhost:3001

If host ports 8080 or 3001 are busy, test-scale picks free ports and writes them to deploy/docker/.ports.env. Always use the URLs printed at the end, or run source deploy/docker/scripts/ports.sh before using the CLI directly.

After quickstart succeeds:

Terminal window
make docker-open

The embedded UI lets you submit plans, watch runs, compare baselines, and open Grafana without YAML. Full walkthrough: Web UI.

Terminal window
make docker-run PLAN=examples/http-post.yaml
make docker-open

make docker-run loads the API URL, API key, and ports for you. When calling the CLI yourself:

Terminal window
source deploy/docker/scripts/ports.sh
./bin/test-scale run -f examples/smoke.yaml

Workers run inside Docker. localhost inside a container is the container itself, not your Mac or Linux host.

Target location target_url host
Bundled mock (Compose network) http://mock-target
App on your machine http://host.docker.internal:<port>
Remote staging/prod Normal hostname or IP

Example:

target_url: http://host.docker.internal:8000/health
target_rps: 20
duration_sec: 10

Your app must listen on an interface reachable from Docker (not only 127.0.0.1 in some setups).

Never commit live tokens. Plan files support ${ENV_VAR} expansion when the CLI parses YAML (before the plan is stored).

Terminal window
export TOURBA_JWT='eyJ...'
make docker-run PLAN=examples/http-auth-jwt.yaml
method: GET
auth:
type: jwt
token: ${TOURBA_JWT}
Auth type Effect
bearer / jwt Sets Authorization: Bearer <token>
session / cookie Sets Cookie: <name>=<value>
header Sets a custom header name/value

Debug 401s: use curl with the same header first. “Credentials not provided” means the worker did not send auth (stale worker image or plan not re-submitted). “Invalid token” means auth arrived but the target rejected it.

Plans persist resolved headers in the database. Restrict who can read plans and rotate test credentials.

Structured JSON (preferred):

method: POST
json:
query: health
limit: 10
expected_statuses: [200, 202]

Raw body:

method: POST
body: '{"query":"health"}'
headers:
Content-Type: application/json

Do not set both json and body.

target_rps is the total throughput for the run, not per worker.

Default worker count:

ceil(target_rps / autoscaler.per_worker_rps)

Default capacity is 500 RPS per worker. Example: target_rps: 2000 → 4 workers.

Override when you want more connections at a lower rate per worker:

target_rps: 40
worker_count: 4

That splits ~10 RPS per worker; it does not mean 40 RPS each.

Docker workers still share one host. For multi-node generators, use Kubernetes + KEDA.

Field Meaning
rps Achieved aggregate throughput
p50_ms, p95_ms, p99_ms Latency percentiles (histogram-merged)
error_count Timeouts, connection failures, statuses outside expected_statuses
worker_count Workers assigned to the run

completed with error_count > 0 still finished — treat errors as a failed test for gates.

Terminal window
make docker-down # stop stack, keep Postgres volume
make docker-up # restart and rebuild app images
make docker-reset # destroy volumes and all run history (local only)

Schema upgrades use versioned SQL migrations; you should not need docker-reset after a version bump.

Symptom What to do
Docker daemon not reachable Start Docker Desktop/Engine
Missing jq, curl, or Go Install the tool named in the error
valid Test Scale API key is required Use make docker-run or source deploy/docker/scripts/ports.sh
Control plane unreachable make docker-up; use printed URL
Host target connection refused host.docker.internal; check bind address
All requests 401 Verify token with curl; make docker-up to rebuild workers; submit a new plan
failed to create plan after upgrade Check ctrl-plane logs; restart so migrations run
RPS below target Check errors and CPU; add workers or lower per_worker_rps

Diagnostic acceptance run:

Terminal window
make docker-verify

Next: Example plans and the CLI.