96 lines
4.0 KiB
Markdown
96 lines
4.0 KiB
Markdown
# Load test suite (k6)
|
|
|
|
This directory contains the production-rehearsal k6 load tests for the
|
|
boilerplate. They are the load-tier companion to the unit, integration, and
|
|
verifier layers — useful before a release cut, after a perf regression
|
|
suspicion, or when sizing a new staging tier.
|
|
|
|
The suite is **opt-in**. CI does not run it by default because it requires a
|
|
deployed target environment, a tenant API key, and a k6 binary on the
|
|
runner. `scripts/run-load-tests.mjs` is the safe wrapper: it SKIPs cleanly
|
|
when either prerequisite is missing.
|
|
|
|
## Install k6
|
|
|
|
k6 is a single Go binary — install it from the upstream packages:
|
|
|
|
- macOS: `brew install k6`
|
|
- Linux: see <https://k6.io/docs/getting-started/installation/>
|
|
- Container: `grafana/k6:latest` (mount this repo and run inside)
|
|
|
|
Verify the install with `k6 version`. The runner script checks the same.
|
|
|
|
## Scripts
|
|
|
|
| Script | Profile | Thresholds |
|
|
| --- | --- | --- |
|
|
| `login.js` | 50 VUs, 30s ramp + 30s hold against `POST /v1/auth/login` | `http_req_failed: rate<0.05`, `http_req_duration: p(99)<800ms`, `http_req_duration{name:login}: p(95)<400ms` |
|
|
| `api-read.js` | 100 VUs, 60s constant against `GET /v1/entities/<slug>/rows` | `http_req_duration: p(99)<300ms`, `http_reqs: rate>200/s` |
|
|
| `api-mutating.js` | 30 VUs, 30s constant against `POST /v1/entities/<slug>/rows` | `http_req_duration: p(99)<600ms` |
|
|
| `scenarios.js` | Composite — runs all three back-to-back | Per-suite thresholds tagged by `name:` |
|
|
|
|
Each per-script file is also runnable standalone — useful when isolating a
|
|
regression to one path.
|
|
|
|
## Threshold rationale
|
|
|
|
- `http_req_failed: rate<0.05` on login allows for 401s from the synthetic
|
|
account while still catching server-side 5xx storms.
|
|
- `http_req_duration: p(99)<800ms` on login covers password hashing + session
|
|
creation under realistic contention. Tighten as the auth path matures.
|
|
- `http_req_duration{name:login}: p(95)<400ms` keeps the typical login fast;
|
|
it is the user-facing budget, not the worst-case.
|
|
- `http_req_duration: p(99)<300ms` on the read path matches the
|
|
warm-cache-hit budget for the hottest API surface.
|
|
- `http_reqs: rate>200/s` is a throughput floor — percentile checks alone
|
|
miss regressions that quietly halve RPS under contention.
|
|
- `http_req_duration: p(99)<600ms` on the mutating path covers transactional
|
|
write + audit + queue enqueue.
|
|
|
|
If a threshold becomes too tight for a particular environment (e.g. a small
|
|
staging tier), override at invocation time with `k6 run --threshold` rather
|
|
than editing the script — keep the production budget in source.
|
|
|
|
## Running locally
|
|
|
|
```sh
|
|
# Single script
|
|
K6_TARGET_URL=http://localhost:3000 \
|
|
LOAD_TENANT_API_KEY=tnk_load_test_key \
|
|
k6 run tests/load/login.js
|
|
|
|
# Full suite via the safe runner (SKIPs if k6 is missing or target down)
|
|
K6_TARGET_URL=http://localhost:3000 \
|
|
LOAD_TENANT_API_KEY=tnk_load_test_key \
|
|
pnpm run verify:load
|
|
```
|
|
|
|
Required env vars:
|
|
|
|
- `K6_TARGET_URL` — base URL of the target environment (default
|
|
`http://localhost:3000`).
|
|
- `LOAD_TENANT_API_KEY` — tenant-scoped API key for the test tenant. The
|
|
read/mutating scripts default to a placeholder that will return 401 — fine
|
|
for SKIP-rehearsal but not for a real load run.
|
|
|
|
Optional env vars:
|
|
|
|
- `LOAD_LOGIN_EMAIL` / `LOAD_LOGIN_PASSWORD` — synthetic login credentials.
|
|
- `LOAD_ENTITY_SLUG` — entity slug to target on the read/mutating paths.
|
|
|
|
## Stress vs. smoke
|
|
|
|
To scale a smoke run down, pass `--vus 5 --duration 10s` to `k6 run`. To
|
|
scale a stress run up, increase the per-script VUs via the k6 CLI rather
|
|
than editing the file. The committed VU counts are the production-rehearsal
|
|
contract.
|
|
|
|
## Safety notes
|
|
|
|
- Never point a load test at production without an explicit human approval.
|
|
- Mutating runs append synthetic rows tagged with `load-test-row-*` so they
|
|
can be cleaned up by a downstream verifier. Pick a throwaway tenant.
|
|
- Load tests are part of the production-readiness ladder, not part of CI
|
|
Auto-Mode. Keep `verify:load` out of the default lane until a target
|
|
environment is wired up.
|