torks 0.9.3

Fast HTTP load testing CLI built in Rust
<p align="center">
  <img src="Logo/torks_logo_new.svg" alt="Torks Logo" width="200" />
</p>

<p align="center">
  <strong>Fast HTTP load testing CLI built in Rust</strong>
</p>

<p align="center">
  <a href="https://crates.io/crates/torks"><img src="https://img.shields.io/crates/v/torks.svg" alt="crates.io" /></a>
  <a href="https://github.com/Armonika-dz/torks/blob/main/LICENSE"><img src="https://img.shields.io/crates/l/torks.svg" alt="license" /></a>
</p>

---

Torks is a lightweight, high-performance HTTP load testing tool with a real-time TUI dashboard, interactive mode, and CI-friendly output. Built with Rust and Tokio for maximum throughput.

## Features

- Real-time TUI dashboard with RPS & latency charts
- Interactive quick mode — just run `torks quick` and follow the prompts
- Dual HTTP engine: `reqwest` (full-featured) or `hyper` (raw speed)
- Configurable worker threads via `--threads`
- TOML-based scenario files with multi-step flows
- HDR Histogram for accurate percentile tracking
- Variable extraction from JSON responses
- Weighted scenario selection
- Ramp-up scheduling
- JSON & CSV report export
- CI/CD threshold checks (p99, error rate, min RPS)
- Quiet mode for headless environments

## Installation

```bash
cargo install torks
```

## Quick Start

### Interactive Mode

Run `torks quick` with no arguments to launch the interactive wizard:

```bash
torks quick
```

You'll be guided through:
- HTTP engine selection (reqwest or hyper)
- Worker threads (auto or custom count)
- Target URL & path
- HTTP method (arrow-key selection)
- Headers (add as many as needed)
- Request body (for POST/PUT/PATCH)
- Concurrent users, ramp-up, duration, timeout
- Summary & confirmation before launch

### One-liner Mode

```bash
# GET request with 50 users for 30 seconds
torks quick https://api.example.com/health -u 50 -d 30s

# POST with 100 users, 5s ramp-up
torks quick https://api.example.com/data -m POST -u 100 -d 1m -r 5s

# Quiet mode (no TUI, for CI)
torks quick https://api.example.com/health -u 10 -d 10s -q

# Use hyper engine for raw speed
torks quick https://api.example.com/health -u 100 -d 30s --engine hyper

# Control worker threads (default: CPU core count)
torks --threads 4 quick https://api.example.com/health -u 200 -d 1m
```

### Scenario File

```bash
# Run a scenario file
torks run scenario.toml

# With JSON and CSV reports
torks run scenario.toml --json report.json --csv report.csv

# Quiet mode
torks run scenario.toml --quiet
```

### Validate Config

```bash
torks validate scenario.toml
```

## Commands

| Command | Description |
|---------|-------------|
| `torks` | Show banner with usage info |
| `torks quick` | Interactive load test wizard |
| `torks quick <URL>` | Quick load test with flags |
| `torks run <FILE>` | Run a TOML scenario file |
| `torks validate <FILE>` | Validate a scenario file without running |
| `torks --help` | Show all options |

### Global Flags

| Flag | Default | Description |
|------|---------|-------------|
| `--threads` | CPU core count | Number of tokio worker threads |

### `torks quick` Flags

| Flag | Short | Default | Description |
|------|-------|---------|-------------|
| `--users` | `-u` | `10` | Number of concurrent users |
| `--duration` | `-d` | `10s` | Test duration (`30s`, `5m`, `1h`) |
| `--method` | `-m` | `GET` | HTTP method |
| `--ramp-up` | `-r` | `0s` | Ramp-up time |
| `--engine` | | `reqwest` | HTTP engine: `reqwest` (full-featured) or `hyper` (raw speed) |
| `--quiet` | `-q` | `false` | Disable TUI dashboard |

### `torks run` Flags

| Flag | Short | Default | Description |
|------|-------|---------|-------------|
| `--json` | | | Output JSON report to file |
| `--csv` | | | Output CSV report to file |
| `--quiet` | `-q` | `false` | Disable TUI dashboard |

## Scenario File Format

Scenario files use TOML format:

```toml
[target]
base_url = "https://api.example.com"
timeout_ms = 30000

[target.headers]
Authorization = "Bearer your-token"
Content-Type = "application/json"

[[scenarios]]
name = "browse-api"
weight = 70

[[scenarios.steps]]
method = "GET"
path = "/users"

[[scenarios.steps]]
method = "GET"
path = "/users/{{user_id}}/posts"

[[scenarios]]
name = "create-post"
weight = 30

[[scenarios.steps]]
method = "GET"
path = "/users"
expect_status = 200

[scenarios.steps.extract]
user_id = "$.data[0].id"

[[scenarios.steps]]
method = "POST"
path = "/users/{{user_id}}/posts"
body = '{"title": "Load Test", "content": "Hello"}'

[scenarios.steps.headers]
Content-Type = "application/json"

[load]
users = 100
ramp_up = "10s"
duration = "2m"

[thresholds]
p99_ms = 500
error_rate = 5.0
min_rps = 100.0
```

### Config Reference

#### `[target]`

| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `base_url` | Yes | | Base URL for all requests |
| `timeout_ms` | No | `30000` | Request timeout in milliseconds |
| `headers` | No | `{}` | Default headers for all requests |

#### `[[scenarios]]`

| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `name` | Yes | | Scenario name |
| `weight` | No | `100` | Weight for random selection |
| `steps` | Yes | | List of HTTP steps |

#### `[[scenarios.steps]]`

| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `method` | Yes | | HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) |
| `path` | Yes | | URL path (appended to base_url) |
| `headers` | No | `{}` | Step-specific headers |
| `body` | No | | Request body |
| `extract` | No | `{}` | Extract variables from JSON response |
| `expect_status` | No | `< 400` | Expected HTTP status code |

#### `[load]`

| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `users` | Yes | | Number of concurrent virtual users |
| `duration` | Yes | | Test duration (`30s`, `5m`, `1h`) |
| `ramp_up` | No | `0s` | Time to ramp up to full users |

#### `[thresholds]`

| Field | Required | Description |
|-------|----------|-------------|
| `p99_ms` | No | Max p99 latency (ms) — exits with code 1 if exceeded |
| `error_rate` | No | Max error rate (%) — exits with code 1 if exceeded |
| `min_rps` | No | Min requests/sec — exits with code 1 if below |

## Variable Extraction

Chain requests by extracting values from JSON responses:

```toml
[[scenarios.steps]]
method = "POST"
path = "/auth/login"
body = '{"email": "test@example.com", "password": "secret"}'

[scenarios.steps.extract]
token = "$.data.access_token"

[[scenarios.steps]]
method = "GET"
path = "/api/profile"

[scenarios.steps.headers]
Authorization = "Bearer {{token}}"
```

## HTTP Engines

Torks ships with two HTTP engines:

| Engine | Flag | Best For |
|--------|------|----------|
| **reqwest** (default) | `--engine reqwest` | Full-featured tests: cookies, JSON, TLS, headers, multi-step scenarios |
| **hyper** | `--engine hyper` | Raw throughput benchmarks: minimal overhead, maximum RPS |

```bash
# Default engine (reqwest) — full feature support
torks quick https://api.example.com/health -u 100 -d 30s

# Hyper engine — raw speed, ~2x RPS
torks quick https://api.example.com/health -u 100 -d 30s --engine hyper
```

## CI/CD Integration

Use `--quiet` mode and thresholds for CI pipelines:

```yaml
# GitHub Actions example
- name: Load Test
  run: |
    cargo install torks
    torks run load-test.toml --quiet --json results.json
```

Torks exits with code `1` if any threshold is exceeded, making it easy to gate deployments.

## License

Apache-2.0

## Author

Built by [Armonika](https://github.com/Armonika-dz)