Metadata-Version: 2.4
Name: loadtester
Version: 0.1.4
Summary: Reusable high-performance HTTP load testing library
Author: Samarth Sikotara
License-Expression: MIT
Project-URL: Homepage, https://github.com/samarthsikotara/loadtester
Project-URL: Source, https://github.com/samarthsikotara/loadtester
Project-URL: Issues, https://github.com/samarthsikotara/loadtester/issues
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests
Dynamic: license-file

# loadtester

**loadtester** is a high‑performance, configurable HTTP load testing library written in Python. It is designed to be simple to use, highly flexible, and suitable for both local testing and large‑scale API load simulations.

The library supports **GET and POST APIs**, rate‑limited execution, retries with exponential backoff, concurrent request execution, real‑time progress logging, and CSV‑based result reporting.

---

## 🚀 Features

- ✅ Supports **GET** and **POST** HTTP methods
- ✅ Rate‑limited traffic using a sliding time window
- ✅ Thread‑pooled concurrent execution
- ✅ Automatic retries with exponential backoff
- ✅ Real‑time progress logging (request ID, status, latency)
- ✅ CSV export of load‑test results
- ✅ Fully customizable headers, request body, and query parameters
- ✅ Easy integration into existing Python projects

---

## Installation

Install directly from PyPI:

```bash
pip install loadtester
```

---

## Quick Start

### Example 1: GET API Load Test

Use this example for APIs that accept query parameters.

```python
from loadtester import LoadTestConfig, LoadTester


def make_headers(x_req_uid):
    return {
        "Authorization": "Basic XXXXX",
        "X-REQ-UID": x_req_uid,
        "Content-Type": "application/json",
    }


def build_params(entity_id):
    return {
        "entityId": entity_id
    }


config = LoadTestConfig(
    url="https://happydaysarebackagainin/api/test",
    http_method="GET",
    total_requests=1000,
    concurrency_window_ms=5,
    rp_values=[50, 100],
    make_headers=make_headers,
    build_params=build_params,
    verbose=True,
)

LoadTester(config).run()
```

✅ **Use this when:**
- HTTP method is GET
- API expects query parameters
- No JSON request body is required

---

### Example 2: POST API Load Test

Use this example when the API expects a JSON request body.

```python
from loadtester import LoadTestConfig, LoadTester


def make_headers(x_req_uid):
    return {
        "Authorization": "Basic XXXXX",
        "X-REQ-UID": x_req_uid,
        "Content-Type": "application/json",
    }


def build_body(entity_id):
    return {
        "authenticationDetails": {
            "authenticationType": 3,
            "authenticationValue": "111111"
        },
        "entityDetails": {
            "entityIdentity": {
                "entityId": entity_id,
                "entityIdType": 1
            }
        }
    }


config = LoadTestConfig(
    url="https://happydaysarebackagainin/api/submit",
    http_method="POST",
    total_requests=1000,
    concurrency_window_ms=5,
    rp_values=[50, 51],
    make_headers=make_headers,
    build_body=build_body,
    verbose=True,
)

LoadTester(config).run()
```

✅ **Use this when:**
- HTTP method is POST
- API expects a JSON payload
- Request body must be dynamically generated

---

## Configuration Parameters

### `LoadTestConfig`

| Parameter | Description |
|-----------|-------------|
| `url` | Target API endpoint |
| `http_method` | `"GET"` or `"POST"` |
| `total_requests` | Total number of requests to send |
| `concurrency_window_ms` | Time window (in milliseconds) used for rate limiting |
| `rp_values` | List of concurrency levels to test |
| `make_headers` | Function that generates request headers |
| `build_params` | Function to generate query parameters (GET only) |
| `build_body` | Function to generate JSON body (POST only) |
| `verbose` | Enables request‑level progress logging |

---

## Output & Metrics

At the end of each run, a summary table is printed to the console:

```
RP    RPS      Total(ms)   Avg(ms)   p95(ms)   p99(ms)   OK   FAIL
-----------------------------------------------------------------
50    10000    4200.12     1580.33   2984.21   3254.11   920  80
100   20000    6870.44     1764.50   3520.19   3822.07   890  110
```

Additionally:
- A CSV file named `load_test_results.csv` is generated automatically
- Each row corresponds to one concurrency level

---

## Real‑Time Logging

When `verbose=True`, the library prints live request logs:

```
[REQ 120] req_id=ab92fd... method=GET status=200 latency=143.52ms OK
```

This ensures long‑running load tests never feel "silent".

---

## Retry & Failure Handling

Automatic retries are triggered for the following transient failure codes:

- `429`, `500`, `502`, `503`, `504`

Retries use **exponential backoff with jitter**. All failures are fully counted and included in summary statistics.

---

## Project Layout

```
loadtester/
├── loadtester/
│   ├── config.py
│   ├── runner.py
│   ├── engine.py
│   ├── summary.py
│   └── types.py
├── examples/
│   └── basic_run.py
└── README.md
```

---

## Extensibility

The current design allows easy future extensions such as:

- PUT / DELETE support
- Mixed GET + POST workloads
- YAML‑based configuration
- Prometheus / Grafana metrics output

---

## License

MIT License © Samarth Sikotara

---

## Project Links

- **GitHub:** [https://github.com/samarthsikotara/loadtester](https://github.com/samarthsikotara/loadtester)
- **PyPI:** [https://pypi.org/project/loadtester](https://pypi.org/project/loadtester)
