Skip to content

Commit 0fe6b6a

Browse files
committed
add a simple stress testing suite for client
Useful to compare different http client libraries
1 parent ecb65e6 commit 0fe6b6a

File tree

14 files changed

+969
-0
lines changed

14 files changed

+969
-0
lines changed

test/specs/stresstest.yaml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
openapi: 3.0.3
2+
info:
3+
title: Stress Test Echo Service
4+
description: Simple echo service for stress testing the OpenAPI client
5+
version: 1.0.0
6+
servers:
7+
- url: http://127.0.0.1:8082
8+
description: Local test server
9+
paths:
10+
/echo:
11+
get:
12+
summary: Echo GET endpoint
13+
description: Returns a simple JSON response with server timestamp
14+
responses:
15+
'200':
16+
description: Successful response
17+
content:
18+
application/json:
19+
schema:
20+
type: object
21+
properties:
22+
timestamp:
23+
type: string
24+
format: date-time
25+
description: Server timestamp when request was received
26+
message:
27+
type: string
28+
description: Echo message
29+
post:
30+
summary: Echo POST endpoint
31+
description: Echoes back the request body with metadata
32+
requestBody:
33+
required: true
34+
content:
35+
application/json:
36+
schema:
37+
type: object
38+
properties:
39+
data:
40+
type: string
41+
description: Data to echo back
42+
responses:
43+
'200':
44+
description: Successful response
45+
content:
46+
application/json:
47+
schema:
48+
type: object
49+
properties:
50+
timestamp:
51+
type: string
52+
format: date-time
53+
description: Server timestamp when request was received
54+
data:
55+
type: string
56+
description: Echoed data from request

test/stresstest/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Stress Test for OpenAPI.jl Client
2+
3+
Stress testing suite for the OpenAPI.jl HTTP client.
4+
5+
## Quick Start
6+
7+
Run the stress test with default settings:
8+
9+
```bash
10+
julia runtests.jl
11+
```
12+
13+
## Configuration
14+
15+
Configure via environment variables:
16+
17+
| Variable | Default | Description |
18+
|----------|---------|-------------|
19+
| `STRESS_DURATION` | 30 | Test duration in seconds |
20+
| `STRESS_CONCURRENCY` | 10 | Number of concurrent tasks |
21+
| `STRESS_PAYLOAD_SIZE` | 1024 | POST payload size in bytes |
22+
| `STRESS_HTTPLIB` | http | HTTP backend (`http` or `downloads`) |
23+
24+
## Examples
25+
26+
**Light test:**
27+
```bash
28+
STRESS_DURATION=5 STRESS_CONCURRENCY=5 julia runtests.jl
29+
```
30+
31+
**Test with Downloads.jl backend:**
32+
```bash
33+
STRESS_HTTPLIB=downloads STRESS_DURATION=30 STRESS_CONCURRENCY=100 julia runtests.jl
34+
```
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module StressTest
2+
3+
using JSON
4+
using Statistics
5+
using Printf
6+
7+
# Include submodules in correct dependency order
8+
include("metrics.jl") # Independent, must come first
9+
include("execution.jl") # Depends on metrics.jl
10+
11+
# Re-export all public functions and types
12+
export StressMetrics,
13+
record_success, record_error,
14+
report_metrics,
15+
calculate_percentile,
16+
get_total_requests, get_success_count,
17+
get_success_rate, get_error_rate, get_throughput,
18+
get_min_latency, get_max_latency,
19+
get_mean_latency, get_median_latency,
20+
StressTestConfig,
21+
run_get_stress_test, run_post_stress_test,
22+
generate_payload
23+
24+
end # module
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
"""
2+
Stress test execution functions for testing the OpenAPI client.
3+
"""
4+
5+
"""
6+
StressTestConfig
7+
8+
Configuration for stress tests.
9+
10+
# Fields
11+
- `duration::Int` - Test duration in seconds
12+
- `concurrency::Int` - Number of concurrent tasks
13+
- `payload_size::Int` - POST payload size in bytes
14+
- `httplib::Symbol` - HTTP backend to use (:http or :downloads)
15+
- `target_url::String` - Base URL of the echo server
16+
"""
17+
mutable struct StressTestConfig
18+
duration::Int
19+
concurrency::Int
20+
payload_size::Int
21+
httplib::Symbol
22+
target_url::String
23+
24+
function StressTestConfig(;
25+
duration=30,
26+
concurrency=100,
27+
payload_size=1024,
28+
httplib=:http,
29+
target_url="http://127.0.0.1:8082",
30+
)
31+
return new(duration, concurrency, payload_size, httplib, target_url)
32+
end
33+
end
34+
35+
function generate_payload(size::Int)
36+
data = "x" ^ max(1, size)
37+
return Main.StressTestClient.EchoPostRequest(; data = data)
38+
end
39+
40+
"""
41+
run_get_stress_test(api::DefaultApi, config::StressTestConfig, metrics::StressMetrics)
42+
43+
Run a GET stress test for the specified duration and concurrency.
44+
45+
# Arguments
46+
- `api::DefaultApi` - API instance to use
47+
- `config::StressTestConfig` - Test configuration
48+
- `metrics::StressMetrics` - Metrics container to record results
49+
"""
50+
function run_get_stress_test(api::Main.StressTestClient.DefaultApi, config::StressTestConfig, metrics::StressMetrics)
51+
@info("Starting GET stress test")
52+
53+
metrics.start_time = time()
54+
55+
@sync begin
56+
for task_idx in 1:config.concurrency
57+
@async begin
58+
task_start = time()
59+
local requests_made = 0
60+
61+
while time() - task_start < config.duration
62+
try
63+
t0 = time()
64+
result, resp = Main.StressTestClient.echo_get(api)
65+
duration = time() - t0
66+
67+
if resp.status == 200
68+
record_success(metrics, duration)
69+
else
70+
record_error(metrics, "HTTP-$(resp.status)")
71+
end
72+
73+
requests_made += 1
74+
catch ex
75+
error_type = string(typeof(ex))
76+
# Remove module prefix for cleaner output
77+
error_type = split(error_type, ".")[end]
78+
record_error(metrics, error_type)
79+
end
80+
end
81+
end
82+
end
83+
end
84+
85+
metrics.end_time = time()
86+
end
87+
88+
"""
89+
run_post_stress_test(api::DefaultApi, config::StressTestConfig, metrics::StressMetrics)
90+
91+
Run a POST stress test for the specified duration and concurrency.
92+
93+
# Arguments
94+
- `api::DefaultApi` - API instance to use
95+
- `config::StressTestConfig` - Test configuration
96+
- `metrics::StressMetrics` - Metrics container to record results
97+
"""
98+
function run_post_stress_test(api::Main.StressTestClient.DefaultApi, config::StressTestConfig, metrics::StressMetrics)
99+
@info("Starting POST stress test")
100+
payload = generate_payload(config.payload_size)
101+
metrics.start_time = time()
102+
103+
@sync begin
104+
for task_idx in 1:config.concurrency
105+
@async begin
106+
task_start = time()
107+
local requests_made = 0
108+
109+
while time() - task_start < config.duration
110+
try
111+
t0 = time()
112+
result, resp = Main.StressTestClient.echo_post(api, payload)
113+
duration = time() - t0
114+
115+
if resp.status == 200
116+
record_success(metrics, duration)
117+
else
118+
record_error(metrics, "HTTP-$(resp.status)")
119+
end
120+
121+
requests_made += 1
122+
catch ex
123+
error_type = string(typeof(ex))
124+
# Remove module prefix for cleaner output
125+
error_type = split(error_type, ".")[end]
126+
record_error(metrics, error_type)
127+
end
128+
end
129+
end
130+
end
131+
end
132+
133+
metrics.end_time = time()
134+
end

0 commit comments

Comments
 (0)