Zerohand
May 3, 2026 · View on GitHub
A simple and efficient load testing tool for Web APIs built with Go.
Overview
Zerohand is a simple load testing tool designed to help developers and DevOps engineers quickly assess API performance and capacity. With a focus on spike tests, load tests, and stress tests, Zerohand provides:
- Simple CLI interface for quick load testing
- RPS (requests per second) control
- Detailed response time metrics and statistics
- Support for various HTTP methods and custom headers
- Real-time progress tracking and graceful shutdown
Whether you're validating capacity before a product launch, testing autoscaling behavior, or finding performance bottlenecks, Zerohand makes it easy to generate controlled load and analyze results.
Features
- Configurable RPS: Control requests per second to generate desired load
- Multiple HTTP Methods: Support for GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
- Custom Headers & Body: Add custom headers and request body
- Response Time Metrics: Measure average, median, P95, P99, min, and max response times
- Success/Failure Tracking: Track request outcomes and error types
- Progress Display: Real-time progress bar during test execution
- JSON Export: Save detailed results to JSON file
- Graceful Shutdown: Ctrl+C support with partial results display
Installation
Download Pre-built Binaries (Recommended)
Download the latest release for your platform from the GitHub Releases page.
Linux / macOS
# Download the binary (replace VERSION, OS, and ARCH with your values)
# Example for Linux amd64:
curl -LO https://github.com/nilpoona/zerohand/releases/download/v0.1.0/zerohand_0.1.0_linux_amd64.tar.gz
# Extract the archive
tar -xzf zerohand_0.1.0_linux_amd64.tar.gz
# Move to a directory in your PATH
sudo mv zerohand /usr/local/bin/
# Verify installation
zerohand --help
Windows
- Download the
.zipfile for Windows from the releases page - Extract the archive
- Add the
zerohand.exeto your PATH or run it directly
Build from Source
Prerequisites
- Go 1.25 or later
Steps
# Clone the repository
git clone https://github.com/nilpoona/zerohand.git
cd zerohand
# Install dependencies
go mod tidy
# Build the CLI binary
go build -o zerohand cmd/zerohand/main.go
Usage
Basic GET Request
./zerohand run --url https://httpbin.org/get --rps 10 --duration 5
POST Request with Body and Headers
./zerohand run \
--url https://httpbin.org/post \
--method POST \
--rps 20 \
--duration 10 \
--body '{"name":"test","value":123}' \
--headers "Content-Type:application/json,Authorization:Bearer token"
Save Results to JSON
./zerohand run \
--url https://api.example.com/endpoint \
--rps 50 \
--duration 30 \
--output results.json
Test with Custom Timeout
./zerohand run \
--url https://httpbin.org/delay/15 \
--rps 5 \
--duration 10 \
--timeout 2
Command-Line Options
| Flag | Description | Default | Required |
|---|---|---|---|
--url | Target URL to test | - | Yes |
--method | HTTP method (GET, POST, PUT, etc.) | GET | No |
--rps | Requests per second | 10 | No |
--duration | Test duration in seconds | 10 | No |
--body | Request body (for POST, PUT, etc.) | "" | No |
--headers | Custom headers (format: key:value,key:value) | "" | No |
--timeout | Request timeout in seconds | 10 | No |
--output | Save results to JSON file | "" | No |
Output Format
Terminal Output Example
=== Load Test Configuration ===
Test ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Target: https://httpbin.org/get
Method: GET
RPS: 10
Duration: 5 seconds
Timeout: 10 seconds
===============================
Starting load test...
Running... [========================================] 100.0% (50/50)
Load test completed
Results:
Total Requests: 50
Success: 50 (100.00%)
Failure: 0 (0.00%)
Response Time:
Average: 123.45ms
Min: 89.12ms
Median: 120.34ms
P95: 156.78ms
P99: 178.90ms
Max: 189.01ms
Status Codes:
200: 50
JSON Output Structure
When using --output flag, results are saved in the following format:
[
{
"timestamp": "2025-01-15T10:30:00.123456Z",
"status_code": 200,
"duration_us": 123456,
"error": ""
},
{
"timestamp": "2025-01-15T10:30:00.234567Z",
"status_code": 500,
"duration_us": 234567,
"error": ""
},
{
"timestamp": "2025-01-15T10:30:00.345678Z",
"status_code": 0,
"duration_us": 0,
"error": "timeout"
}
]
Use Cases
Spike Testing
Test how your API handles sudden traffic spikes (5-10 minutes):
./zerohand run --url https://api.example.com/endpoint --rps 1000 --duration 600
Load Testing
Verify stable operation under expected traffic (20-30 minutes):
./zerohand run --url https://api.example.com/endpoint --rps 200 --duration 1800
Stress Testing
Find system limits by gradually increasing load:
# Phase 1: Baseline
./zerohand run --url https://api.example.com/endpoint --rps 100 --duration 300
# Phase 2: Increased load
./zerohand run --url https://api.example.com/endpoint --rps 500 --duration 300
# Phase 3: High load
./zerohand run --url https://api.example.com/endpoint --rps 1000 --duration 300
Error Classification
Errors are automatically classified into the following categories:
timeout: Request or connection timeoutdns_error: DNS resolution failureconnection_error: Connection refused or failedtls_error: TLS/SSL certificate errornetwork_error: Other network-related errorscanceled: Request canceled (e.g., Ctrl+C)unknown_error: Unclassified errors
Performance Notes
Performance Goals:
- RPS Accuracy: ±5% of requested RPS
- Efficient memory usage for up to 1000 concurrent requests
- Low CPU overhead at moderate load levels
Testing
Running Tests
# Run all unit tests
go test ./...
# Run with coverage
go test -cover ./...
# Run integration tests (E2E tests with actual binary)
go test -v ./test/integration/... -timeout 5m
# Run integration tests in short mode (skips network tests)
go test -v ./test/integration/... -short
For more details on integration tests, see test/integration/README.md.
Testing Recommendations
Test Against Public APIs
- httpbin.org: Great for testing various HTTP methods and responses
- jsonplaceholder.typicode.com: REST API for testing
Start with Low RPS
Begin with low RPS (10-50) to avoid overwhelming the target server.
Example test sequence:
# Test 1: Basic connectivity
./zerohand run --url https://httpbin.org/get --rps 5 --duration 3
# Test 2: Increase load
./zerohand run --url https://httpbin.org/get --rps 20 --duration 10
# Test 3: Test error handling
./zerohand run --url https://httpbin.org/status/500 --rps 10 --duration 5
Future Enhancements
- Distributed load generation across multiple nodes
- Real-time metrics visualization with Web UI
- WebSocket and Server-Sent Events support
- Multi-step scenario testing
- Advanced authentication support
- Result history and comparison tools
Troubleshooting
Connection Refused Errors
Check if the target URL is correct and the server is running.
DNS Resolution Errors
Verify the domain name and DNS settings.
High Timeout Count
Consider increasing the --timeout value or checking network connectivity.
Progress Not Updating
Progress updates every second. For very short tests (<3 seconds), you might not see many updates.