thunderbench 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +818 -0
- package/bin/darwin-arm64/wrk +0 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/core/config-validation.d.ts +7 -0
- package/dist/core/config-validation.d.ts.map +1 -0
- package/dist/core/json-report-generator.d.ts +174 -0
- package/dist/core/json-report-generator.d.ts.map +1 -0
- package/dist/core/markdown-report-generator.d.ts +16 -0
- package/dist/core/markdown-report-generator.d.ts.map +1 -0
- package/dist/core/report-storage.d.ts +10 -0
- package/dist/core/report-storage.d.ts.map +1 -0
- package/dist/core/stats-calculation.d.ts +16 -0
- package/dist/core/stats-calculation.d.ts.map +1 -0
- package/dist/core/weight-distribution.d.ts +9 -0
- package/dist/core/weight-distribution.d.ts.map +1 -0
- package/dist/core/wrk-test-engine.d.ts +181 -0
- package/dist/core/wrk-test-engine.d.ts.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10494 -0
- package/dist/types/index.d.ts +88 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/wrk-binary.d.ts +41 -0
- package/dist/utils/wrk-binary.d.ts.map +1 -0
- package/docs/cli-usage.md +245 -0
- package/docs/requirements.md +222 -0
- package/examples/complex-config.ts +244 -0
- package/examples/complex-wrk-demo.ts +121 -0
- package/examples/programmatic-usage-cjs.js +156 -0
- package/examples/programmatic-usage.js +205 -0
- package/examples/simple-wrk-config.js +33 -0
- package/package.json +68 -0
- package/scripts/setup-wrk.js +98 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { BenchmarkConfig } from "../src/types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 复杂的性能测试配置示例
|
|
5
|
+
* 展示了多种测试场景和配置选项
|
|
6
|
+
*/
|
|
7
|
+
const complexConfig: BenchmarkConfig = {
|
|
8
|
+
name: "复杂性能测试配置",
|
|
9
|
+
description: "展示多种测试场景和配置选项",
|
|
10
|
+
groups: [
|
|
11
|
+
// 用户认证相关API测试 - 并发模式
|
|
12
|
+
{
|
|
13
|
+
name: "user-authentication",
|
|
14
|
+
http: {
|
|
15
|
+
baseUrl: "https://jsonplaceholder.typicode.com",
|
|
16
|
+
timeout: 5000,
|
|
17
|
+
headers: {
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
"User-Agent": "JS-Benchmark/1.0",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
threads: 4, // 4个线程
|
|
23
|
+
connections: 20, // 20个连接
|
|
24
|
+
duration: 30, // 30秒
|
|
25
|
+
timeout: 5, // 5秒超时
|
|
26
|
+
latency: true, // 启用延迟统计
|
|
27
|
+
executionMode: "parallel",
|
|
28
|
+
tests: [
|
|
29
|
+
{
|
|
30
|
+
name: "user-login",
|
|
31
|
+
weight: 40,
|
|
32
|
+
request: {
|
|
33
|
+
method: "POST",
|
|
34
|
+
url: "/users",
|
|
35
|
+
body: {
|
|
36
|
+
username: "testuser",
|
|
37
|
+
password: "testpass123",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "get-user-profile",
|
|
43
|
+
weight: 35,
|
|
44
|
+
request: {
|
|
45
|
+
method: "GET",
|
|
46
|
+
url: "/users/1",
|
|
47
|
+
headers: {
|
|
48
|
+
Authorization: "Bearer fake-token",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "update-user-profile",
|
|
54
|
+
weight: 25,
|
|
55
|
+
request: {
|
|
56
|
+
method: "PUT",
|
|
57
|
+
url: "/users/1",
|
|
58
|
+
body: {
|
|
59
|
+
name: "Updated Name",
|
|
60
|
+
email: "updated@example.com",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// 内容管理API测试 - 串行模式,模拟按顺序执行的业务流程
|
|
68
|
+
{
|
|
69
|
+
name: "content-management",
|
|
70
|
+
http: {
|
|
71
|
+
baseUrl: "https://jsonplaceholder.typicode.com",
|
|
72
|
+
timeout: 3000,
|
|
73
|
+
headers: {
|
|
74
|
+
"Content-Type": "application/json",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
threads: 2, // 2个线程
|
|
78
|
+
connections: 10, // 10个连接
|
|
79
|
+
duration: 20, // 运行20秒
|
|
80
|
+
timeout: 3, // 3秒超时
|
|
81
|
+
latency: true, // 启用延迟统计
|
|
82
|
+
executionMode: "sequential",
|
|
83
|
+
delay: 2, // 每批之间延迟2秒
|
|
84
|
+
tests: [
|
|
85
|
+
{
|
|
86
|
+
name: "list-posts",
|
|
87
|
+
weight: 50,
|
|
88
|
+
request: {
|
|
89
|
+
method: "GET",
|
|
90
|
+
url: "/posts",
|
|
91
|
+
query: {
|
|
92
|
+
_page: 1,
|
|
93
|
+
_limit: 10,
|
|
94
|
+
_sort: "id",
|
|
95
|
+
_order: "desc",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "create-post",
|
|
101
|
+
weight: 25,
|
|
102
|
+
request: {
|
|
103
|
+
method: "POST",
|
|
104
|
+
url: "/posts",
|
|
105
|
+
body: {
|
|
106
|
+
title: "Performance Test Post",
|
|
107
|
+
body: "This post was created during performance testing",
|
|
108
|
+
userId: 1,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "get-post-details",
|
|
114
|
+
weight: 15,
|
|
115
|
+
request: {
|
|
116
|
+
method: "GET",
|
|
117
|
+
url: "/posts/1",
|
|
118
|
+
query: {
|
|
119
|
+
_embed: "comments",
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: "delete-post",
|
|
125
|
+
weight: 10,
|
|
126
|
+
request: {
|
|
127
|
+
method: "DELETE",
|
|
128
|
+
url: "/posts/1",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
// API网关压力测试 - 高并发模式
|
|
135
|
+
{
|
|
136
|
+
name: "api-gateway-stress",
|
|
137
|
+
http: {
|
|
138
|
+
baseUrl: "https://jsonplaceholder.typicode.com",
|
|
139
|
+
timeout: 2000,
|
|
140
|
+
headers: {
|
|
141
|
+
Accept: "application/json",
|
|
142
|
+
"Cache-Control": "no-cache",
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
threads: 8, // 8个线程
|
|
146
|
+
connections: 50, // 50个连接
|
|
147
|
+
duration: 30, // 30秒
|
|
148
|
+
timeout: 2, // 2秒超时
|
|
149
|
+
latency: true, // 启用延迟统计
|
|
150
|
+
executionMode: "parallel",
|
|
151
|
+
tests: [
|
|
152
|
+
{
|
|
153
|
+
name: "health-check",
|
|
154
|
+
weight: 30,
|
|
155
|
+
request: {
|
|
156
|
+
method: "GET",
|
|
157
|
+
url: "/posts/1", // 简单的健康检查
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "data-query",
|
|
162
|
+
weight: 50,
|
|
163
|
+
request: {
|
|
164
|
+
method: "GET",
|
|
165
|
+
url: "/posts",
|
|
166
|
+
query: {
|
|
167
|
+
_limit: 20,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "data-creation",
|
|
173
|
+
weight: 20,
|
|
174
|
+
request: {
|
|
175
|
+
method: "POST",
|
|
176
|
+
url: "/posts",
|
|
177
|
+
body: {
|
|
178
|
+
title: "Stress Test",
|
|
179
|
+
body: "Testing high concurrency",
|
|
180
|
+
userId: 1,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
// 移动端API测试 - 模拟移动设备的间歇性请求
|
|
188
|
+
{
|
|
189
|
+
name: "mobile-api",
|
|
190
|
+
http: {
|
|
191
|
+
baseUrl: "https://jsonplaceholder.typicode.com",
|
|
192
|
+
timeout: 8000, // 移动端网络可能较慢
|
|
193
|
+
headers: {
|
|
194
|
+
"Content-Type": "application/json",
|
|
195
|
+
"User-Agent": "MobileApp/1.0",
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
threads: 2, // 2个线程
|
|
199
|
+
connections: 10, // 10个连接
|
|
200
|
+
duration: 30, // 较长时间测试
|
|
201
|
+
timeout: 8, // 8秒超时
|
|
202
|
+
latency: true, // 启用延迟统计
|
|
203
|
+
executionMode: "sequential",
|
|
204
|
+
delay: 1, // 1秒延迟模拟用户操作间隔
|
|
205
|
+
tests: [
|
|
206
|
+
{
|
|
207
|
+
name: "app-initialization",
|
|
208
|
+
weight: 20,
|
|
209
|
+
request: {
|
|
210
|
+
method: "GET",
|
|
211
|
+
url: "/users/1",
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "content-sync",
|
|
216
|
+
weight: 60,
|
|
217
|
+
request: {
|
|
218
|
+
method: "GET",
|
|
219
|
+
url: "/posts",
|
|
220
|
+
query: {
|
|
221
|
+
userId: 1,
|
|
222
|
+
_limit: 5,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: "offline-sync",
|
|
228
|
+
weight: 20,
|
|
229
|
+
request: {
|
|
230
|
+
method: "POST",
|
|
231
|
+
url: "/posts",
|
|
232
|
+
body: {
|
|
233
|
+
title: "Offline Post",
|
|
234
|
+
body: "Posted while offline, now syncing",
|
|
235
|
+
userId: 1,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export default complexConfig;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { BenchmarkConfig } from "../src/types";
|
|
2
|
+
|
|
3
|
+
const config: BenchmarkConfig = {
|
|
4
|
+
name: "复杂 wrk 测试演示",
|
|
5
|
+
description: "展示 wrk 的各种参数配置和权重分配",
|
|
6
|
+
groups: [
|
|
7
|
+
{
|
|
8
|
+
name: "高并发测试组",
|
|
9
|
+
http: {
|
|
10
|
+
baseUrl: "http://localhost:3000",
|
|
11
|
+
headers: {
|
|
12
|
+
"User-Agent": "wrk-benchmark/1.0",
|
|
13
|
+
"Accept": "application/json",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
threads: 8, // 8个线程
|
|
17
|
+
connections: 200, // 200个连接
|
|
18
|
+
duration: 30, // 30秒
|
|
19
|
+
timeout: 10, // 10秒超时
|
|
20
|
+
latency: true, // 启用详细延迟统计
|
|
21
|
+
executionMode: "parallel",
|
|
22
|
+
tests: [
|
|
23
|
+
{
|
|
24
|
+
name: "用户注册",
|
|
25
|
+
request: {
|
|
26
|
+
method: "POST",
|
|
27
|
+
url: "/api/users/register",
|
|
28
|
+
headers: {
|
|
29
|
+
"Content-Type": "application/json",
|
|
30
|
+
},
|
|
31
|
+
body: {
|
|
32
|
+
username: "testuser",
|
|
33
|
+
email: "test@example.com",
|
|
34
|
+
password: "password123",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
weight: 40, // 40% 的负载
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "用户登录",
|
|
41
|
+
request: {
|
|
42
|
+
method: "POST",
|
|
43
|
+
url: "/api/users/login",
|
|
44
|
+
headers: {
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
},
|
|
47
|
+
body: {
|
|
48
|
+
email: "test@example.com",
|
|
49
|
+
password: "password123",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
weight: 60, // 60% 的负载
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "串行测试组",
|
|
58
|
+
http: {
|
|
59
|
+
baseUrl: "http://localhost:3000",
|
|
60
|
+
headers: {
|
|
61
|
+
"Authorization": "Bearer test-token",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
threads: 4, // 4个线程
|
|
65
|
+
connections: 100, // 100个连接
|
|
66
|
+
duration: 20, // 20秒
|
|
67
|
+
timeout: 5, // 5秒超时
|
|
68
|
+
latency: true, // 启用详细延迟统计
|
|
69
|
+
executionMode: "sequential",
|
|
70
|
+
delay: 5, // 组间延迟5秒
|
|
71
|
+
tests: [
|
|
72
|
+
{
|
|
73
|
+
name: "获取用户信息",
|
|
74
|
+
request: {
|
|
75
|
+
method: "GET",
|
|
76
|
+
url: "/api/users/profile",
|
|
77
|
+
},
|
|
78
|
+
weight: 50, // 50% 的负载
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "更新用户信息",
|
|
82
|
+
request: {
|
|
83
|
+
method: "PUT",
|
|
84
|
+
url: "/api/users/profile",
|
|
85
|
+
headers: {
|
|
86
|
+
"Content-Type": "application/json",
|
|
87
|
+
},
|
|
88
|
+
body: {
|
|
89
|
+
name: "Updated Name",
|
|
90
|
+
bio: "Updated bio",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
weight: 50, // 50% 的负载
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "轻量级测试组",
|
|
99
|
+
http: {
|
|
100
|
+
baseUrl: "http://localhost:3000",
|
|
101
|
+
},
|
|
102
|
+
threads: 2, // 2个线程
|
|
103
|
+
connections: 50, // 50个连接
|
|
104
|
+
duration: 15, // 15秒
|
|
105
|
+
latency: false, // 不启用详细延迟统计
|
|
106
|
+
executionMode: "parallel",
|
|
107
|
+
tests: [
|
|
108
|
+
{
|
|
109
|
+
name: "健康检查",
|
|
110
|
+
request: {
|
|
111
|
+
method: "GET",
|
|
112
|
+
url: "/health",
|
|
113
|
+
},
|
|
114
|
+
weight: 100, // 100% 的负载
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export default config;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// ThunderBench 编程使用示例 (CommonJS 版本)
|
|
2
|
+
const { ThunderBench, runBenchmark, validateConfig } = require('thunderbench');
|
|
3
|
+
|
|
4
|
+
// 方式1:使用 ThunderBench 类
|
|
5
|
+
async function example1() {
|
|
6
|
+
const config = {
|
|
7
|
+
name: "编程API测试",
|
|
8
|
+
description: "通过编程方式运行性能测试",
|
|
9
|
+
groups: [
|
|
10
|
+
{
|
|
11
|
+
name: "基础测试组",
|
|
12
|
+
http: {
|
|
13
|
+
baseUrl: "http://localhost:3001",
|
|
14
|
+
headers: { "User-Agent": "thunderbench-programmatic/1.0" }
|
|
15
|
+
},
|
|
16
|
+
threads: 2,
|
|
17
|
+
connections: 50,
|
|
18
|
+
duration: 10,
|
|
19
|
+
timeout: 5,
|
|
20
|
+
latency: true,
|
|
21
|
+
executionMode: "parallel",
|
|
22
|
+
tests: [
|
|
23
|
+
{
|
|
24
|
+
name: "GET 请求测试",
|
|
25
|
+
request: { method: "GET", url: "/" },
|
|
26
|
+
weight: 100
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// 创建 ThunderBench 实例
|
|
34
|
+
const thunderbench = new ThunderBench(config, {
|
|
35
|
+
outputDir: "./programmatic-reports",
|
|
36
|
+
verbose: true
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
// 监听进度
|
|
41
|
+
thunderbench.getProgressStream().subscribe(progress => {
|
|
42
|
+
console.log(`进度: ${progress.groupName} - ${progress.percentage}%`);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// 监听统计
|
|
46
|
+
thunderbench.getStatsStream().subscribe(stats => {
|
|
47
|
+
console.log(`实时统计: ${stats.totalRequests} 请求, ${stats.requestsPerSecond.toFixed(1)} req/s`);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// 运行测试
|
|
51
|
+
const result = await thunderbench.runBenchmark();
|
|
52
|
+
console.log("测试完成:", result);
|
|
53
|
+
|
|
54
|
+
return result;
|
|
55
|
+
} finally {
|
|
56
|
+
// 清理资源
|
|
57
|
+
thunderbench.destroy();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 方式2:使用便捷函数
|
|
62
|
+
async function example2() {
|
|
63
|
+
const config = {
|
|
64
|
+
name: "便捷函数测试",
|
|
65
|
+
groups: [
|
|
66
|
+
{
|
|
67
|
+
name: "简单测试",
|
|
68
|
+
http: { baseUrl: "http://localhost:3001" },
|
|
69
|
+
threads: 1,
|
|
70
|
+
connections: 10,
|
|
71
|
+
duration: 5,
|
|
72
|
+
executionMode: "parallel",
|
|
73
|
+
tests: [
|
|
74
|
+
{
|
|
75
|
+
name: "快速测试",
|
|
76
|
+
request: { method: "GET", url: "/" },
|
|
77
|
+
weight: 100
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// 直接运行测试
|
|
85
|
+
const result = await runBenchmark(config, { verbose: true });
|
|
86
|
+
console.log("便捷函数测试完成:", result);
|
|
87
|
+
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 方式3:配置验证
|
|
92
|
+
function example3() {
|
|
93
|
+
const config = {
|
|
94
|
+
name: "配置验证测试",
|
|
95
|
+
groups: [
|
|
96
|
+
{
|
|
97
|
+
name: "测试组",
|
|
98
|
+
http: { baseUrl: "http://localhost:3001" },
|
|
99
|
+
threads: 2,
|
|
100
|
+
connections: 20,
|
|
101
|
+
duration: 10,
|
|
102
|
+
executionMode: "parallel",
|
|
103
|
+
tests: [
|
|
104
|
+
{
|
|
105
|
+
name: "验证测试",
|
|
106
|
+
request: { method: "GET", url: "/" },
|
|
107
|
+
weight: 100
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
// 验证配置
|
|
116
|
+
validateConfig(config);
|
|
117
|
+
console.log("✅ 配置验证通过");
|
|
118
|
+
return true;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error("❌ 配置验证失败:", error.message);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 主函数
|
|
126
|
+
async function main() {
|
|
127
|
+
console.log("🚀 ThunderBench 编程使用示例 (CommonJS)\n");
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
// 示例1:使用类
|
|
131
|
+
console.log("=== 示例1:使用 ThunderBench 类 ===");
|
|
132
|
+
await example1();
|
|
133
|
+
console.log();
|
|
134
|
+
|
|
135
|
+
// 示例2:使用便捷函数
|
|
136
|
+
console.log("=== 示例2:使用便捷函数 ===");
|
|
137
|
+
await example2();
|
|
138
|
+
console.log();
|
|
139
|
+
|
|
140
|
+
// 示例3:配置验证
|
|
141
|
+
console.log("=== 示例3:配置验证 ===");
|
|
142
|
+
example3();
|
|
143
|
+
console.log();
|
|
144
|
+
|
|
145
|
+
console.log("✅ 所有示例执行完成!");
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error("❌ 示例执行失败:", error);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 如果直接运行此文件
|
|
152
|
+
if (require.main === module) {
|
|
153
|
+
main();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = { example1, example2, example3 };
|