Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 2

build:
os: ubuntu-22.04
tools:
python: "3.12"

mkdocs:
configuration: mkdocs.yml
72 changes: 72 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# CLI Reference

## loadforge run

Run a load test from a scenario file.

```bash
loadforge run [scenario.yaml] [flags]
```

| Flag | Short | Description |
|------|-------|-------------|
| `--workers` | `-w` | Override worker count from config |
| `--duration` | `-d` | Override duration (e.g. `30s`, `2m`) |
| `--output` | `-o` | Save report to a JSON file |
| `--var` | | Set a variable (`key=value`) |
| `--env-file` | | Load variables from a `.env` file |
| `--no-ui` | | Plain text output instead of the terminal UI |
| `--verbose` | `-v` | Enable verbose logging |

### Examples

```bash
# Run with defaults from the file
loadforge run scenario.yaml

# Override workers and duration
loadforge run scenario.yaml --workers 50 --duration 2m

# Inject a variable
loadforge run scenario.yaml --var BASE_URL=https://staging.example.com

# Load variables from .env
loadforge run scenario.yaml --env-file .env
```

---

## loadforge validate

Validate a scenario file without running it.

```bash
loadforge validate [scenario.yaml]
```

---

## loadforge version

Print the installed version.

```bash
loadforge version
```

---

## loadforge --uninstall

Stop the web service and remove all LoadForge files from the system.

```bash
sudo loadforge --uninstall
```

This removes:

- `/usr/local/bin/loadforge`
- `/usr/local/bin/loadforge-web`
- `~/.loadforge/` (config, history, logs)
- The background service (systemd or launchd)
66 changes: 66 additions & 0 deletions docs/configuration/assertions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Assertions

Assertions define SLA thresholds that automatically mark a test as passed or failed.

## Configuration

```yaml
assertions:
- metric: p95_latency
operator: less_than
value: 500
enabled: true
```

## Available metrics

| Metric | Description |
|--------|-------------|
| `p50_latency` | 50th percentile latency (ms) |
| `p90_latency` | 90th percentile latency (ms) |
| `p95_latency` | 95th percentile latency (ms) |
| `p99_latency` | 99th percentile latency (ms) |
| `avg_latency` | Average latency (ms) |
| `max_latency` | Maximum latency (ms) |
| `rps` | Requests per second |
| `error_rate` | Percentage of failed requests |
| `success_rate` | Percentage of successful requests |
| `total_requests` | Total requests made |
| `total_errors` | Total failed requests |

## Available operators

| Operator | Meaning |
|----------|---------|
| `less_than` | metric < value |
| `less_than_or_equal` | metric <= value |
| `greater_than` | metric > value |
| `greater_than_or_equal` | metric >= value |
| `equal` | metric == value |

## Example

```yaml
assertions:
- metric: p95_latency
operator: less_than
value: 500
enabled: true

- metric: p99_latency
operator: less_than
value: 1000
enabled: true

- metric: error_rate
operator: less_than
value: 1
enabled: true

- metric: rps
operator: greater_than
value: 100
enabled: true
```

Use `enabled: false` to define an assertion without enforcing it — useful for tracking a metric without failing the test.
46 changes: 46 additions & 0 deletions docs/configuration/auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Auth

Authentication can be set per step in the scenario file.

## Basic auth

```yaml
steps:
- method: GET
url: /secure
auth:
basic:
username: admin
password: secret
```

## Bearer token

```yaml
steps:
- method: GET
url: /secure
auth:
bearer: your-token-here
```

## Custom header

```yaml
steps:
- method: GET
url: /secure
auth:
header:
key: X-API-Key
value: your-api-key
```

Or use it for any arbitrary header-based auth scheme:

```yaml
auth:
header:
key: Authorization
value: "Token abc123"
```
77 changes: 77 additions & 0 deletions docs/configuration/load-profiles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Load Profiles

A load profile controls how worker concurrency changes over time.

## constant

Fixed number of workers for the full duration. Use this for steady-state benchmarks.

```yaml
load:
profile: constant
workers: 20
duration: 60s
```

---

## ramp

Linearly increases workers from `start_workers` to `end_workers` over the ramp duration. Use this to find the degradation point without shocking the system.

```yaml
load:
profile: ramp
duration: 60s
ramp_up:
start_workers: 1
end_workers: 50
duration: 30s
```

---

## step

Adds workers in fixed increments at regular intervals. Use this to observe how latency changes as load increases in discrete steps.

```yaml
load:
profile: step
duration: 60s
step:
start_workers: 5
step_size: 5
step_duration: 10s
max_workers: 50
```

---

## spike

Runs a base level of workers with periodic traffic bursts. Use this to test how your system recovers after a sudden surge.

```yaml
load:
profile: spike
duration: 60s
spike:
base_workers: 10
spike_workers: 50
spike_duration: 5s
spike_every: 15s
```

---

## Stopping conditions

Use `duration` to run for a fixed time, or `max_requests` to stop after a total request count:

```yaml
load:
profile: constant
workers: 10
max_requests: 1000
```
88 changes: 88 additions & 0 deletions docs/configuration/scenario.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Scenario File

LoadForge scenarios are defined in YAML. A scenario file describes the requests to send, how to authenticate, and how much load to apply.

## Full reference

```yaml
name: Test Name
base_url: https://api.example.com

scenarios:
- name: Scenario Name
weight: 100 # Relative probability when multiple scenarios are defined
steps:
- name: Step Name
method: GET # GET, POST, PUT, PATCH, DELETE, HEAD
url: /path # Relative (uses base_url) or absolute URL

headers:
X-Custom-Header: value

body:
raw: "raw string body"
json:
key: value
form:
field: value

auth:
basic:
username: user
password: pass
bearer: your-token
header:
key: Authorization
value: Bearer your-token

options:
timeout: 10s
follow_redirects: true
tls_skip_verify: false
http2: true

think: 100ms # Pause after this step

load:
profile: constant # constant | ramp | step | spike
workers: 10
duration: 30s

assertions:
- metric: p95_latency
operator: less_than
value: 500
enabled: true
```

## Multiple scenarios

When multiple scenarios are defined, workers pick one at random weighted by the `weight` field.

```yaml
scenarios:
- name: Read path
weight: 80
steps:
- method: GET
url: /items

- name: Write path
weight: 20
steps:
- method: POST
url: /items
body:
json:
name: test
```

## Body types

Only one body type is used per step. Priority: `json` → `form` → `raw`.

| Type | Content-Type set automatically |
|------|-------------------------------|
| `json` | `application/json` |
| `form` | `application/x-www-form-urlencoded` |
| `raw` | none (set manually via `headers`) |
Loading
Loading