# Running Tests

## Setup

```bash
uv sync --extra dev
```

## Unit tests

```bash
# Run all tests
uv run pytest

# Verbose output
uv run pytest -v

# Stop on first failure
uv run pytest -x

# Run a specific file
uv run pytest tests/test_middleware.py

# Run a specific test
uv run pytest tests/test_middleware.py::test_in_flight_returns_to_zero_after_request

# Show print output (useful for debugging)
uv run pytest -s
```

## Load tests

### Self-contained async script (no separate server needed)

**Burst mode** — fire N requests at once, watch the in-flight bar chart:
```bash
# Default: 50 concurrent requests, 1.5s simulated delay
uv run examples/load_test.py

# Crank it up
uv run examples/load_test.py --requests 200 --delay 2.0
```

**Sweep mode** — find your saturation point and recommended autoscaling threshold:
```bash
# Async I/O workload (won't saturate — prints Little's Law formula instead)
uv run examples/load_test.py --mode sweep

# CPU-bound workload (will saturate — prints recommended threshold)
uv run examples/load_test.py --mode sweep --workload cpu

# Tune the sweep range and work duration
uv run examples/load_test.py --mode sweep --workload cpu --max-concurrency 128 --duration-ms 200
```

### Locust (web UI + realistic ramp-up)

Start the example app first, then locust in a second terminal:

```bash
# Terminal 1 — start the app
uv run uvicorn examples.app:app --port 8000

# Terminal 2 — start locust
uv run locust -f examples/locustfile.py --host http://localhost:8000
```

Open **http://localhost:8089**, set user count and ramp rate, then start.

**Headless mode** (no browser needed):

```bash
# 100 users, ramp 10/s, run for 60 seconds
uv run locust -f examples/locustfile.py --host http://localhost:8000 \
    --headless -u 100 -r 10 -t 60s
```

**Watch the autoscaling metric live** while locust runs:

```bash
# Terminal 3
watch -n1 'curl -s localhost:8000/metrics | grep "^runway_requests_in_flight "'
```
