Skip to content

Repository files navigation

Load Testing Platform

Go-based load-test authoring and execution platform backed by PostgreSQL. The repository contains the API, scheduler, worker runtime, local process deployer, Kubernetes Job deployer, SQLC data layer, and execution documentation.

The current backend supports the local authoring-to-execution path. A frontend can integrate with the existing project, test-spec, environment, run, worker, summary, and cancellation APIs. Cloud observability, advanced authorization, and production operations remain separate follow-up work.

Architecture

HTTP API
  -> application services
  -> SQLC-generated queries
  -> PostgreSQL

API -> execution_queue -> scheduler -> ProcessDeployer or KubernetesDeployer
                                      -> worker runtime
                                      -> authenticated callbacks

The API, scheduler, and worker are separate processes:

  • app: HTTP API and project/run services.
  • app/scheduler: queue consumer, capacity planner, and deployer.
  • app/worker: immutable run-snapshot executor and lifecycle callback client.

Runs copy the validated test-spec version and environment target URL when they are created. Workers execute that run snapshot and do not read mutable project authoring tables.

Requirements

  • Go 1.26 or newer.
  • Docker and Docker Compose.
  • PostgreSQL 16, if running without Docker.
  • Kubernetes access only when using LOAD_TEST_DEPLOYER=kubernetes.

Quick Start

Start PostgreSQL and apply migrations to a new Docker volume:

make db-up

Run the API in local development mode. Authentication is deliberately disabled only for this trusted local setup:

AUTH_MODE=disabled \
DATABASE_URL='postgres://postgres:postgres@localhost:5432/load_testing?sslmode=disable' \
HTTP_ADDR=':8080' \
LOAD_TEST_WORKER_TOKEN='replace-with-a-random-shared-token' \
go run ./app

Build all application binaries:

make build
make build-scheduler
make build-worker

Start the scheduler in another terminal after the API is running:

AUTH_MODE=disabled \
DATABASE_URL='postgres://postgres:postgres@localhost:5432/load_testing?sslmode=disable' \
LOAD_TEST_API_URL='http://localhost:8080/api/v1' \
LOAD_TEST_WORKER_BINARY='./bin/load-test-worker' \
LOAD_TEST_WORKER_TOKEN='replace-with-a-random-shared-token' \
LOAD_TEST_HEARTBEAT_INTERVAL='15s' \
LOAD_TEST_ARTIFACT_DIR='./var/artifacts' \
go run ./app/scheduler

The worker is normally launched by the scheduler. It requires the API URL, run ID, worker ID, and shared callback token. The scheduler passes only the explicit worker environment, not its complete host environment.

Authentication

Production API access uses provider-neutral OIDC/JWT validation. Configure:

AUTH_MODE=oidc
AUTH_ISSUER=https://issuer.example.com/
AUTH_AUDIENCE=load-testing-api
AUTH_JWKS_URL=https://issuer.example.com/.well-known/jwks.json

JWT sub, email, name, and preferred_username claims are used to identify the caller. Project membership roles are viewer, operator, editor, and owner. The first authenticated user creating a project becomes its owner.

AUTH_MODE=disabled is a local-development escape hatch and must not be used for a shared or production deployment. Worker callbacks use the separate LOAD_TEST_WORKER_TOKEN bearer credential.

Core API

The API base path is /api/v1.

POST /projects
GET  /projects
GET  /projects/{projectID}
POST /projects/{projectID}/routes
POST /projects/{projectID}/flows
POST /projects/{projectID}/flows/{flowID}/steps
POST /projects/{projectID}/test-specs
POST /projects/{projectID}/test-specs/{testSpecID}/versions
POST /projects/{projectID}/environments
POST /projects/{projectID}/test-specs/{testSpecID}/runs
GET  /projects/{projectID}/runs
GET  /runs/{runID}
GET  /runs/{runID}/workers
POST /runs/{runID}/cancel

Successful responses use a data wrapper. Run creation requires an Idempotency-Key header and an environment_id; it returns 202 Accepted. The selected environment URL is snapshotted onto the run.

Internal worker callbacks are authenticated and include:

POST /internal/v1/runs/{runID}/workers/{workerID}/started
POST /internal/v1/runs/{runID}/workers/{workerID}/heartbeat
POST /internal/v1/runs/{runID}/workers/{workerID}/completed
POST /internal/v1/runs/{runID}/workers/{workerID}/failed

Secrets And Artifacts

Request configurations contain secret reference names, not secret values:

{
  "secret_refs": ["storefront-token"],
  "secret_headers": {
    "Authorization": "storefront-token"
  }
}

The local worker can resolve references from a JSON file configured with LOAD_TEST_SECRET_FILE:

{
  "storefront-token": "Bearer local-value"
}

When LOAD_TEST_ARTIFACT_DIR is configured, workers atomically write protected summary artifacts to:

<artifact-dir>/<run-id>/<worker-id>.json

Metrics Aggregation

The execution path must not write one PostgreSQL row per request. The intended aggregation flow is:

Worker counters and fixed duration histograms
  -> bounded metric batches
  -> authenticated collector
  -> Prometheus-compatible time-series backend
  -> stable metrics API
  -> UI

In the target architecture, PostgreSQL stores run state, final summaries, threshold results, and batch-level durable metadata. Prometheus-compatible storage handles live and historical request rate, error rate, latency histograms, active users, and bounded flow or route dimensions. Batch IDs make ingestion idempotent, and fixed histogram buckets allow p50/p95/p99 calculations to merge across workers without averaging worker percentiles.

The detailed contract and acceptance criteria are in docs/METRICS_AGGREGATION_DESIGN.md.

Database And Migrations

Migrations are mounted into PostgreSQL's initialization directory and run only when the database volume is first created. The current migration chain includes projects, test specs, runs, environments, worker summaries, heartbeats, identity/memberships, and metric batches.

Regenerate SQLC code after changing SQL:

make sqlc

To recreate the local database from all migrations, destroying local data:

make db-reset

Do not use make db-reset against a shared or production database.

Kubernetes

Use the Kubernetes Job deployer from the scheduler:

LOAD_TEST_DEPLOYER=kubernetes
KUBERNETES_NAMESPACE=default
KUBECONFIG=/path/to/kubeconfig

Jobs use deterministic names and run/worker labels. Repeated deployments adopt existing Jobs rather than creating duplicates. Terminal or stopping runs are cleaned up, and idle scheduler passes reconcile active Jobs.

Verification

Run the complete local checks:

go test ./...
go test -race ./...
go vet ./...
go build ./app ./app/scheduler ./app/worker
make sqlc

Useful project documents:

Current Production Gaps

  • Complete the worker metric-batch collector and UI-facing metric query endpoints.
  • Persist and expose threshold-result and artifact metadata resources.
  • Add heartbeat-timeout enforcement and local-process restart reconciliation.
  • Add callback event IDs, attempt fencing, and fully atomic worker/run transitions.
  • Add readiness checks, queue dead-letter policy, quotas, audit events, and operational dashboards.
  • Add cloud secret, metrics, and artifact adapters.

The backend is suitable for beginning a trusted internal UI against the current authoring and run APIs. The production gaps above should be closed before exposing it to multiple teams or untrusted users.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages