code-abyss 1.6.16 → 1.7.0
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/package.json +2 -2
- package/skills/SKILL.md +24 -16
- package/skills/domains/ai/SKILL.md +2 -2
- package/skills/domains/ai/prompt-and-eval.md +279 -0
- package/skills/domains/architecture/SKILL.md +2 -3
- package/skills/domains/architecture/security-arch.md +87 -0
- package/skills/domains/data-engineering/SKILL.md +188 -26
- package/skills/domains/development/SKILL.md +1 -4
- package/skills/domains/devops/SKILL.md +3 -5
- package/skills/domains/devops/performance.md +63 -0
- package/skills/domains/devops/testing.md +97 -0
- package/skills/domains/frontend-design/SKILL.md +12 -3
- package/skills/domains/frontend-design/claymorphism/SKILL.md +117 -0
- package/skills/domains/frontend-design/claymorphism/references/tokens.css +52 -0
- package/skills/domains/frontend-design/engineering.md +287 -0
- package/skills/domains/frontend-design/glassmorphism/SKILL.md +138 -0
- package/skills/domains/frontend-design/glassmorphism/references/tokens.css +32 -0
- package/skills/domains/frontend-design/liquid-glass/SKILL.md +135 -0
- package/skills/domains/frontend-design/liquid-glass/references/tokens.css +81 -0
- package/skills/domains/frontend-design/neubrutalism/SKILL.md +141 -0
- package/skills/domains/frontend-design/neubrutalism/references/tokens.css +44 -0
- package/skills/domains/infrastructure/SKILL.md +174 -34
- package/skills/domains/mobile/SKILL.md +211 -21
- package/skills/domains/orchestration/SKILL.md +1 -0
- package/skills/domains/security/SKILL.md +4 -6
- package/skills/domains/security/blue-team.md +57 -0
- package/skills/domains/security/red-team.md +54 -0
- package/skills/domains/security/threat-intel.md +50 -0
- package/skills/orchestration/multi-agent/SKILL.md +195 -46
- package/skills/run_skill.js +134 -0
- package/skills/tools/gen-docs/SKILL.md +6 -4
- package/skills/tools/gen-docs/scripts/doc_generator.js +349 -0
- package/skills/tools/verify-change/SKILL.md +8 -6
- package/skills/tools/verify-change/scripts/change_analyzer.js +270 -0
- package/skills/tools/verify-module/SKILL.md +6 -4
- package/skills/tools/verify-module/scripts/module_scanner.js +145 -0
- package/skills/tools/verify-quality/SKILL.md +5 -3
- package/skills/tools/verify-quality/scripts/quality_checker.js +276 -0
- package/skills/tools/verify-security/SKILL.md +7 -5
- package/skills/tools/verify-security/scripts/security_scanner.js +133 -0
- package/skills/__pycache__/run_skill.cpython-312.pyc +0 -0
- package/skills/domains/COVERAGE_PLAN.md +0 -232
- package/skills/domains/ai/model-evaluation.md +0 -790
- package/skills/domains/ai/prompt-engineering.md +0 -703
- package/skills/domains/architecture/compliance.md +0 -299
- package/skills/domains/architecture/data-security.md +0 -184
- package/skills/domains/data-engineering/data-pipeline.md +0 -762
- package/skills/domains/data-engineering/data-quality.md +0 -894
- package/skills/domains/data-engineering/stream-processing.md +0 -791
- package/skills/domains/development/dart.md +0 -963
- package/skills/domains/development/kotlin.md +0 -834
- package/skills/domains/development/php.md +0 -659
- package/skills/domains/development/swift.md +0 -755
- package/skills/domains/devops/e2e-testing.md +0 -914
- package/skills/domains/devops/performance-testing.md +0 -734
- package/skills/domains/devops/testing-strategy.md +0 -667
- package/skills/domains/frontend-design/build-tools.md +0 -743
- package/skills/domains/frontend-design/performance.md +0 -734
- package/skills/domains/frontend-design/testing.md +0 -699
- package/skills/domains/infrastructure/gitops.md +0 -735
- package/skills/domains/infrastructure/iac.md +0 -855
- package/skills/domains/infrastructure/kubernetes.md +0 -1018
- package/skills/domains/mobile/android-dev.md +0 -979
- package/skills/domains/mobile/cross-platform.md +0 -795
- package/skills/domains/mobile/ios-dev.md +0 -931
- package/skills/domains/security/secrets-management.md +0 -834
- package/skills/domains/security/supply-chain.md +0 -931
- package/skills/domains/security/threat-modeling.md +0 -828
- package/skills/run_skill.py +0 -153
- package/skills/tests/README.md +0 -225
- package/skills/tests/SUMMARY.md +0 -362
- package/skills/tests/__init__.py +0 -3
- package/skills/tests/__pycache__/test_change_analyzer.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_doc_generator.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_module_scanner.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_quality_checker.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_security_scanner.cpython-312.pyc +0 -0
- package/skills/tests/test_change_analyzer.py +0 -558
- package/skills/tests/test_doc_generator.py +0 -538
- package/skills/tests/test_module_scanner.py +0 -376
- package/skills/tests/test_quality_checker.py +0 -516
- package/skills/tests/test_security_scanner.py +0 -426
- package/skills/tools/gen-docs/scripts/__pycache__/doc_generator.cpython-312.pyc +0 -0
- package/skills/tools/gen-docs/scripts/doc_generator.py +0 -520
- package/skills/tools/verify-change/scripts/__pycache__/change_analyzer.cpython-312.pyc +0 -0
- package/skills/tools/verify-change/scripts/change_analyzer.py +0 -529
- package/skills/tools/verify-module/scripts/__pycache__/module_scanner.cpython-312.pyc +0 -0
- package/skills/tools/verify-module/scripts/module_scanner.py +0 -321
- package/skills/tools/verify-quality/scripts/__pycache__/quality_checker.cpython-312.pyc +0 -0
- package/skills/tools/verify-quality/scripts/quality_checker.py +0 -481
- package/skills/tools/verify-security/scripts/__pycache__/security_scanner.cpython-312.pyc +0 -0
- package/skills/tools/verify-security/scripts/security_scanner.py +0 -374
|
@@ -1,734 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: performance-testing
|
|
3
|
-
description: 性能测试。k6、JMeter、Gatling、负载测试、压力测试、浸泡测试、性能指标分析。当用户提到性能测试、k6、JMeter、负载测试、压力测试、基准测试时使用。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# ⚡ 性能测试 · Performance Testing
|
|
7
|
-
|
|
8
|
-
## 性能测试类型
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
负载测试 (Load Testing)
|
|
12
|
-
└─ 验证系统在预期负载下的表现
|
|
13
|
-
|
|
14
|
-
压力测试 (Stress Testing)
|
|
15
|
-
└─ 找到系统的极限和崩溃点
|
|
16
|
-
|
|
17
|
-
浸泡测试 (Soak Testing)
|
|
18
|
-
└─ 长时间运行检测内存泄漏
|
|
19
|
-
|
|
20
|
-
峰值测试 (Spike Testing)
|
|
21
|
-
└─ 突发流量下的系统表现
|
|
22
|
-
|
|
23
|
-
容量测试 (Capacity Testing)
|
|
24
|
-
└─ 确定系统最大容量
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### 测试场景对比
|
|
28
|
-
| 类型 | 用户数 | 持续时间 | 目标 |
|
|
29
|
-
|------|--------|----------|------|
|
|
30
|
-
| 负载测试 | 预期峰值 | 30分钟-2小时 | 验证性能指标 |
|
|
31
|
-
| 压力测试 | 超出峰值 | 1-3小时 | 找到崩溃点 |
|
|
32
|
-
| 浸泡测试 | 正常负载 | 8-72小时 | 检测内存泄漏 |
|
|
33
|
-
| 峰值测试 | 瞬间激增 | 短时间 | 测试弹性 |
|
|
34
|
-
|
|
35
|
-
## k6 基础
|
|
36
|
-
|
|
37
|
-
### 安装
|
|
38
|
-
```bash
|
|
39
|
-
# macOS
|
|
40
|
-
brew install k6
|
|
41
|
-
|
|
42
|
-
# Linux
|
|
43
|
-
sudo gpg -k
|
|
44
|
-
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
|
|
45
|
-
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
|
|
46
|
-
sudo apt-get update
|
|
47
|
-
sudo apt-get install k6
|
|
48
|
-
|
|
49
|
-
# Docker
|
|
50
|
-
docker run --rm -i grafana/k6 run - <script.js
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### 基础脚本
|
|
54
|
-
```javascript
|
|
55
|
-
import http from 'k6/http';
|
|
56
|
-
import { check, sleep } from 'k6';
|
|
57
|
-
|
|
58
|
-
export const options = {
|
|
59
|
-
vus: 10, // 虚拟用户数
|
|
60
|
-
duration: '30s', // 持续时间
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export default function () {
|
|
64
|
-
const res = http.get('https://api.example.com/users');
|
|
65
|
-
|
|
66
|
-
check(res, {
|
|
67
|
-
'status is 200': (r) => r.status === 200,
|
|
68
|
-
'response time < 500ms': (r) => r.timings.duration < 500,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
sleep(1);
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### 运行测试
|
|
76
|
-
```bash
|
|
77
|
-
# 基础运行
|
|
78
|
-
k6 run script.js
|
|
79
|
-
|
|
80
|
-
# 指定参数
|
|
81
|
-
k6 run --vus 100 --duration 5m script.js
|
|
82
|
-
|
|
83
|
-
# 输出结果
|
|
84
|
-
k6 run --out json=results.json script.js
|
|
85
|
-
k6 run --out influxdb=http://localhost:8086/k6 script.js
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## k6 高级场景
|
|
89
|
-
|
|
90
|
-
### 阶梯式负载
|
|
91
|
-
```javascript
|
|
92
|
-
export const options = {
|
|
93
|
-
stages: [
|
|
94
|
-
{ duration: '2m', target: 100 }, // 2分钟爬升到100用户
|
|
95
|
-
{ duration: '5m', target: 100 }, // 保持100用户5分钟
|
|
96
|
-
{ duration: '2m', target: 200 }, // 爬升到200用户
|
|
97
|
-
{ duration: '5m', target: 200 }, // 保持200用户
|
|
98
|
-
{ duration: '2m', target: 0 }, // 降到0
|
|
99
|
-
],
|
|
100
|
-
thresholds: {
|
|
101
|
-
http_req_duration: ['p(95)<500'], // 95%请求<500ms
|
|
102
|
-
http_req_failed: ['rate<0.01'], // 错误率<1%
|
|
103
|
-
},
|
|
104
|
-
};
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### 压力测试
|
|
108
|
-
```javascript
|
|
109
|
-
export const options = {
|
|
110
|
-
stages: [
|
|
111
|
-
{ duration: '5m', target: 100 },
|
|
112
|
-
{ duration: '10m', target: 100 },
|
|
113
|
-
{ duration: '5m', target: 200 },
|
|
114
|
-
{ duration: '10m', target: 200 },
|
|
115
|
-
{ duration: '5m', target: 300 },
|
|
116
|
-
{ duration: '10m', target: 300 },
|
|
117
|
-
{ duration: '5m', target: 400 },
|
|
118
|
-
{ duration: '10m', target: 400 },
|
|
119
|
-
{ duration: '5m', target: 0 },
|
|
120
|
-
],
|
|
121
|
-
};
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### 峰值测试
|
|
125
|
-
```javascript
|
|
126
|
-
export const options = {
|
|
127
|
-
stages: [
|
|
128
|
-
{ duration: '10s', target: 100 }, // 正常负载
|
|
129
|
-
{ duration: '1m', target: 100 },
|
|
130
|
-
{ duration: '10s', target: 1400 }, // 突然激增
|
|
131
|
-
{ duration: '3m', target: 1400 },
|
|
132
|
-
{ duration: '10s', target: 100 }, // 恢复正常
|
|
133
|
-
{ duration: '3m', target: 100 },
|
|
134
|
-
{ duration: '10s', target: 0 },
|
|
135
|
-
],
|
|
136
|
-
};
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### 浸泡测试
|
|
140
|
-
```javascript
|
|
141
|
-
export const options = {
|
|
142
|
-
stages: [
|
|
143
|
-
{ duration: '5m', target: 100 }, // 爬升
|
|
144
|
-
{ duration: '8h', target: 100 }, // 保持8小时
|
|
145
|
-
{ duration: '5m', target: 0 }, // 降低
|
|
146
|
-
],
|
|
147
|
-
};
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## k6 实战示例
|
|
151
|
-
|
|
152
|
-
### 登录流程测试
|
|
153
|
-
```javascript
|
|
154
|
-
import http from 'k6/http';
|
|
155
|
-
import { check, group, sleep } from 'k6';
|
|
156
|
-
|
|
157
|
-
export const options = {
|
|
158
|
-
vus: 50,
|
|
159
|
-
duration: '5m',
|
|
160
|
-
thresholds: {
|
|
161
|
-
'http_req_duration{name:login}': ['p(95)<1000'],
|
|
162
|
-
'http_req_duration{name:dashboard}': ['p(95)<500'],
|
|
163
|
-
},
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
export default function () {
|
|
167
|
-
group('用户登录流程', () => {
|
|
168
|
-
// 1. 访问登录页
|
|
169
|
-
let res = http.get('https://example.com/login');
|
|
170
|
-
check(res, { 'login page loaded': (r) => r.status === 200 });
|
|
171
|
-
|
|
172
|
-
// 2. 提交登录
|
|
173
|
-
res = http.post('https://example.com/api/login', {
|
|
174
|
-
username: 'testuser',
|
|
175
|
-
password: 'password123',
|
|
176
|
-
}, {
|
|
177
|
-
tags: { name: 'login' },
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
check(res, {
|
|
181
|
-
'login successful': (r) => r.status === 200,
|
|
182
|
-
'token received': (r) => r.json('token') !== undefined,
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
const token = res.json('token');
|
|
186
|
-
|
|
187
|
-
// 3. 访问受保护页面
|
|
188
|
-
res = http.get('https://example.com/dashboard', {
|
|
189
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
190
|
-
tags: { name: 'dashboard' },
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
check(res, { 'dashboard loaded': (r) => r.status === 200 });
|
|
194
|
-
|
|
195
|
-
sleep(1);
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### API 批量测试
|
|
201
|
-
```javascript
|
|
202
|
-
import http from 'k6/http';
|
|
203
|
-
import { check } from 'k6';
|
|
204
|
-
|
|
205
|
-
export default function () {
|
|
206
|
-
const requests = [
|
|
207
|
-
['GET', 'https://api.example.com/users'],
|
|
208
|
-
['GET', 'https://api.example.com/products'],
|
|
209
|
-
['GET', 'https://api.example.com/orders'],
|
|
210
|
-
];
|
|
211
|
-
|
|
212
|
-
const responses = http.batch(requests.map(([method, url]) => ({
|
|
213
|
-
method,
|
|
214
|
-
url,
|
|
215
|
-
})));
|
|
216
|
-
|
|
217
|
-
responses.forEach((res, i) => {
|
|
218
|
-
check(res, {
|
|
219
|
-
[`${requests[i][1]} status 200`]: (r) => r.status === 200,
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### 文件上传测试
|
|
226
|
-
```javascript
|
|
227
|
-
import http from 'k6/http';
|
|
228
|
-
import { check } from 'k6';
|
|
229
|
-
|
|
230
|
-
const binFile = open('./test-file.pdf', 'b');
|
|
231
|
-
|
|
232
|
-
export default function () {
|
|
233
|
-
const data = {
|
|
234
|
-
file: http.file(binFile, 'test-file.pdf'),
|
|
235
|
-
description: 'Test upload',
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
const res = http.post('https://api.example.com/upload', data);
|
|
239
|
-
|
|
240
|
-
check(res, {
|
|
241
|
-
'upload successful': (r) => r.status === 201,
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### WebSocket 测试
|
|
247
|
-
```javascript
|
|
248
|
-
import ws from 'k6/ws';
|
|
249
|
-
import { check } from 'k6';
|
|
250
|
-
|
|
251
|
-
export default function () {
|
|
252
|
-
const url = 'ws://example.com/ws';
|
|
253
|
-
|
|
254
|
-
const res = ws.connect(url, {}, function (socket) {
|
|
255
|
-
socket.on('open', () => {
|
|
256
|
-
console.log('connected');
|
|
257
|
-
socket.send(JSON.stringify({ type: 'subscribe', channel: 'updates' }));
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
socket.on('message', (data) => {
|
|
261
|
-
console.log('Message received:', data);
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
socket.on('close', () => console.log('disconnected'));
|
|
265
|
-
|
|
266
|
-
socket.setTimeout(() => {
|
|
267
|
-
socket.close();
|
|
268
|
-
}, 10000);
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
check(res, { 'status is 101': (r) => r && r.status === 101 });
|
|
272
|
-
}
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
## JMeter 基础
|
|
276
|
-
|
|
277
|
-
### 安装
|
|
278
|
-
```bash
|
|
279
|
-
# 下载
|
|
280
|
-
wget https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.6.2.tgz
|
|
281
|
-
tar -xzf apache-jmeter-5.6.2.tgz
|
|
282
|
-
|
|
283
|
-
# 运行 GUI
|
|
284
|
-
./apache-jmeter-5.6.2/bin/jmeter
|
|
285
|
-
|
|
286
|
-
# 命令行运行
|
|
287
|
-
./apache-jmeter-5.6.2/bin/jmeter -n -t test.jmx -l results.jtl
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### 测试计划结构
|
|
291
|
-
```
|
|
292
|
-
Test Plan
|
|
293
|
-
├── Thread Group (线程组)
|
|
294
|
-
│ ├── HTTP Request (HTTP请求)
|
|
295
|
-
│ ├── HTTP Header Manager (请求头)
|
|
296
|
-
│ ├── Assertions (断言)
|
|
297
|
-
│ └── Listeners (监听器)
|
|
298
|
-
├── CSV Data Set Config (CSV数据)
|
|
299
|
-
└── Summary Report (汇总报告)
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
### HTTP 请求配置
|
|
303
|
-
```xml
|
|
304
|
-
<!-- JMeter 测试计划示例 -->
|
|
305
|
-
<HTTPSamplerProxy>
|
|
306
|
-
<elementProp name="HTTPsampler.Arguments">
|
|
307
|
-
<collectionProp name="Arguments.arguments">
|
|
308
|
-
<elementProp name="username" elementType="HTTPArgument">
|
|
309
|
-
<stringProp name="Argument.value">testuser</stringProp>
|
|
310
|
-
</elementProp>
|
|
311
|
-
</collectionProp>
|
|
312
|
-
</elementProp>
|
|
313
|
-
<stringProp name="HTTPSampler.domain">api.example.com</stringProp>
|
|
314
|
-
<stringProp name="HTTPSampler.port">443</stringProp>
|
|
315
|
-
<stringProp name="HTTPSampler.protocol">https</stringProp>
|
|
316
|
-
<stringProp name="HTTPSampler.path">/api/login</stringProp>
|
|
317
|
-
<stringProp name="HTTPSampler.method">POST</stringProp>
|
|
318
|
-
</HTTPSamplerProxy>
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### 线程组配置
|
|
322
|
-
```
|
|
323
|
-
Number of Threads (users): 100
|
|
324
|
-
Ramp-up period (seconds): 60
|
|
325
|
-
Loop Count: 10
|
|
326
|
-
|
|
327
|
-
实际含义:
|
|
328
|
-
- 100个并发用户
|
|
329
|
-
- 60秒内逐步启动
|
|
330
|
-
- 每个用户执行10次
|
|
331
|
-
- 总请求数:100 * 10 = 1000
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### 断言配置
|
|
335
|
-
```xml
|
|
336
|
-
<ResponseAssertion>
|
|
337
|
-
<collectionProp name="Asserion.test_strings">
|
|
338
|
-
<stringProp name="49586">200</stringProp>
|
|
339
|
-
</collectionProp>
|
|
340
|
-
<stringProp name="Assertion.test_field">Assertion.response_code</stringProp>
|
|
341
|
-
<stringProp name="Assertion.assume_success">false</stringProp>
|
|
342
|
-
<intProp name="Assertion.test_type">8</intProp>
|
|
343
|
-
</ResponseAssertion>
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
## JMeter 高级功能
|
|
347
|
-
|
|
348
|
-
### CSV 参数化
|
|
349
|
-
```csv
|
|
350
|
-
# users.csv
|
|
351
|
-
username,password
|
|
352
|
-
user1,pass1
|
|
353
|
-
user2,pass2
|
|
354
|
-
user3,pass3
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
```xml
|
|
358
|
-
<CSVDataSet>
|
|
359
|
-
<stringProp name="filename">users.csv</stringProp>
|
|
360
|
-
<stringProp name="variableNames">username,password</stringProp>
|
|
361
|
-
<boolProp name="recycle">true</boolProp>
|
|
362
|
-
<boolProp name="stopThread">false</boolProp>
|
|
363
|
-
</CSVDataSet>
|
|
364
|
-
|
|
365
|
-
<!-- 使用变量 -->
|
|
366
|
-
<stringProp name="Argument.value">${username}</stringProp>
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
### 正则提取器
|
|
370
|
-
```xml
|
|
371
|
-
<RegexExtractor>
|
|
372
|
-
<stringProp name="RegexExtractor.refname">token</stringProp>
|
|
373
|
-
<stringProp name="RegexExtractor.regex">"token":"([^"]+)"</stringProp>
|
|
374
|
-
<stringProp name="RegexExtractor.template">$1$</stringProp>
|
|
375
|
-
<stringProp name="RegexExtractor.default">NOT_FOUND</stringProp>
|
|
376
|
-
<intProp name="RegexExtractor.match_number">1</intProp>
|
|
377
|
-
</RegexExtractor>
|
|
378
|
-
|
|
379
|
-
<!-- 后续请求使用 -->
|
|
380
|
-
<stringProp name="Header.value">Bearer ${token}</stringProp>
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
### BeanShell 脚本
|
|
384
|
-
```java
|
|
385
|
-
// 前置处理器
|
|
386
|
-
import java.util.Date;
|
|
387
|
-
import java.text.SimpleDateFormat;
|
|
388
|
-
|
|
389
|
-
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
390
|
-
String timestamp = sdf.format(new Date());
|
|
391
|
-
vars.put("timestamp", timestamp);
|
|
392
|
-
|
|
393
|
-
// 后置处理器
|
|
394
|
-
String response = prev.getResponseDataAsString();
|
|
395
|
-
log.info("Response: " + response);
|
|
396
|
-
|
|
397
|
-
if (prev.getResponseCode().equals("200")) {
|
|
398
|
-
vars.put("status", "success");
|
|
399
|
-
} else {
|
|
400
|
-
vars.put("status", "failed");
|
|
401
|
-
}
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
## 性能指标分析
|
|
405
|
-
|
|
406
|
-
### 关键指标
|
|
407
|
-
```
|
|
408
|
-
响应时间 (Response Time)
|
|
409
|
-
├── 平均响应时间 (Average)
|
|
410
|
-
├── 中位数 (Median/P50)
|
|
411
|
-
├── 90分位 (P90)
|
|
412
|
-
├── 95分位 (P95)
|
|
413
|
-
└── 99分位 (P99)
|
|
414
|
-
|
|
415
|
-
吞吐量 (Throughput)
|
|
416
|
-
├── 请求/秒 (RPS)
|
|
417
|
-
├── 事务/秒 (TPS)
|
|
418
|
-
└── 数据传输速率 (MB/s)
|
|
419
|
-
|
|
420
|
-
错误率 (Error Rate)
|
|
421
|
-
├── HTTP错误 (4xx/5xx)
|
|
422
|
-
├── 超时错误
|
|
423
|
-
└── 连接错误
|
|
424
|
-
|
|
425
|
-
并发用户数 (Concurrent Users)
|
|
426
|
-
└── 活跃用户数
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
### 指标阈值示例
|
|
430
|
-
```javascript
|
|
431
|
-
// k6 阈值配置
|
|
432
|
-
export const options = {
|
|
433
|
-
thresholds: {
|
|
434
|
-
// 响应时间
|
|
435
|
-
'http_req_duration': ['p(95)<500', 'p(99)<1000'],
|
|
436
|
-
|
|
437
|
-
// 错误率
|
|
438
|
-
'http_req_failed': ['rate<0.01'],
|
|
439
|
-
|
|
440
|
-
// 吞吐量
|
|
441
|
-
'http_reqs': ['rate>100'],
|
|
442
|
-
|
|
443
|
-
// 特定请求
|
|
444
|
-
'http_req_duration{name:login}': ['p(95)<1000'],
|
|
445
|
-
'http_req_duration{name:api}': ['p(95)<200'],
|
|
446
|
-
},
|
|
447
|
-
};
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
### 性能基准
|
|
451
|
-
| 场景 | P95响应时间 | 错误率 | 吞吐量 |
|
|
452
|
-
|------|-------------|--------|--------|
|
|
453
|
-
| API查询 | <200ms | <0.1% | >1000 RPS |
|
|
454
|
-
| API写入 | <500ms | <0.5% | >500 RPS |
|
|
455
|
-
| 页面加载 | <2s | <1% | >100 RPS |
|
|
456
|
-
| 文件上传 | <5s | <2% | >50 RPS |
|
|
457
|
-
|
|
458
|
-
## Gatling 示例
|
|
459
|
-
|
|
460
|
-
### 基础脚本
|
|
461
|
-
```scala
|
|
462
|
-
import io.gatling.core.Predef._
|
|
463
|
-
import io.gatling.http.Predef._
|
|
464
|
-
import scala.concurrent.duration._
|
|
465
|
-
|
|
466
|
-
class BasicSimulation extends Simulation {
|
|
467
|
-
|
|
468
|
-
val httpProtocol = http
|
|
469
|
-
.baseUrl("https://api.example.com")
|
|
470
|
-
.acceptHeader("application/json")
|
|
471
|
-
.userAgentHeader("Gatling")
|
|
472
|
-
|
|
473
|
-
val scn = scenario("Basic Load Test")
|
|
474
|
-
.exec(
|
|
475
|
-
http("Get Users")
|
|
476
|
-
.get("/users")
|
|
477
|
-
.check(status.is(200))
|
|
478
|
-
)
|
|
479
|
-
.pause(1)
|
|
480
|
-
|
|
481
|
-
setUp(
|
|
482
|
-
scn.inject(
|
|
483
|
-
rampUsers(100) during (60 seconds)
|
|
484
|
-
)
|
|
485
|
-
).protocols(httpProtocol)
|
|
486
|
-
}
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
### 复杂场景
|
|
490
|
-
```scala
|
|
491
|
-
class AdvancedSimulation extends Simulation {
|
|
492
|
-
|
|
493
|
-
val httpProtocol = http.baseUrl("https://api.example.com")
|
|
494
|
-
|
|
495
|
-
val login = exec(
|
|
496
|
-
http("Login")
|
|
497
|
-
.post("/api/login")
|
|
498
|
-
.body(StringBody("""{"username":"${username}","password":"${password}"}"""))
|
|
499
|
-
.check(jsonPath("$.token").saveAs("token"))
|
|
500
|
-
)
|
|
501
|
-
|
|
502
|
-
val browse = exec(
|
|
503
|
-
http("Get Dashboard")
|
|
504
|
-
.get("/dashboard")
|
|
505
|
-
.header("Authorization", "Bearer ${token}")
|
|
506
|
-
)
|
|
507
|
-
|
|
508
|
-
val scn = scenario("User Journey")
|
|
509
|
-
.feed(csv("users.csv").circular)
|
|
510
|
-
.exec(login)
|
|
511
|
-
.pause(2)
|
|
512
|
-
.exec(browse)
|
|
513
|
-
|
|
514
|
-
setUp(
|
|
515
|
-
scn.inject(
|
|
516
|
-
atOnceUsers(10),
|
|
517
|
-
rampUsers(50) during (30 seconds),
|
|
518
|
-
constantUsersPerSec(20) during (1 minute)
|
|
519
|
-
)
|
|
520
|
-
).protocols(httpProtocol)
|
|
521
|
-
}
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
## 性能监控集成
|
|
525
|
-
|
|
526
|
-
### Prometheus + Grafana
|
|
527
|
-
```yaml
|
|
528
|
-
# k6 输出到 Prometheus
|
|
529
|
-
export const options = {
|
|
530
|
-
ext: {
|
|
531
|
-
loadimpact: {
|
|
532
|
-
projectID: 123456,
|
|
533
|
-
name: "Performance Test"
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
# 或使用 xk6-output-prometheus-remote
|
|
539
|
-
K6_PROMETHEUS_REMOTE_URL=http://localhost:9090/api/v1/write k6 run script.js
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
### InfluxDB 集成
|
|
543
|
-
```bash
|
|
544
|
-
# 启动 InfluxDB
|
|
545
|
-
docker run -d -p 8086:8086 influxdb:1.8
|
|
546
|
-
|
|
547
|
-
# k6 输出到 InfluxDB
|
|
548
|
-
k6 run --out influxdb=http://localhost:8086/k6 script.js
|
|
549
|
-
```
|
|
550
|
-
|
|
551
|
-
### Grafana Dashboard
|
|
552
|
-
```json
|
|
553
|
-
{
|
|
554
|
-
"dashboard": {
|
|
555
|
-
"title": "k6 Performance Dashboard",
|
|
556
|
-
"panels": [
|
|
557
|
-
{
|
|
558
|
-
"title": "Response Time",
|
|
559
|
-
"targets": [
|
|
560
|
-
{
|
|
561
|
-
"measurement": "http_req_duration",
|
|
562
|
-
"select": [["value", "mean"]]
|
|
563
|
-
}
|
|
564
|
-
]
|
|
565
|
-
},
|
|
566
|
-
{
|
|
567
|
-
"title": "Throughput",
|
|
568
|
-
"targets": [
|
|
569
|
-
{
|
|
570
|
-
"measurement": "http_reqs",
|
|
571
|
-
"select": [["count", "sum"]]
|
|
572
|
-
}
|
|
573
|
-
]
|
|
574
|
-
}
|
|
575
|
-
]
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
## CI/CD 集成
|
|
581
|
-
|
|
582
|
-
### GitHub Actions
|
|
583
|
-
```yaml
|
|
584
|
-
name: Performance Test
|
|
585
|
-
|
|
586
|
-
on:
|
|
587
|
-
schedule:
|
|
588
|
-
- cron: '0 2 * * *' # 每天凌晨2点
|
|
589
|
-
workflow_dispatch:
|
|
590
|
-
|
|
591
|
-
jobs:
|
|
592
|
-
performance:
|
|
593
|
-
runs-on: ubuntu-latest
|
|
594
|
-
steps:
|
|
595
|
-
- uses: actions/checkout@v3
|
|
596
|
-
|
|
597
|
-
- name: Run k6 test
|
|
598
|
-
uses: grafana/k6-action@v0.3.0
|
|
599
|
-
with:
|
|
600
|
-
filename: tests/performance.js
|
|
601
|
-
flags: --out json=results.json
|
|
602
|
-
|
|
603
|
-
- name: Upload results
|
|
604
|
-
uses: actions/upload-artifact@v3
|
|
605
|
-
with:
|
|
606
|
-
name: k6-results
|
|
607
|
-
path: results.json
|
|
608
|
-
|
|
609
|
-
- name: Check thresholds
|
|
610
|
-
run: |
|
|
611
|
-
if grep -q '"thresholds".*"failed":true' results.json; then
|
|
612
|
-
echo "Performance thresholds failed"
|
|
613
|
-
exit 1
|
|
614
|
-
fi
|
|
615
|
-
```
|
|
616
|
-
|
|
617
|
-
### GitLab CI
|
|
618
|
-
```yaml
|
|
619
|
-
performance:
|
|
620
|
-
image: grafana/k6:latest
|
|
621
|
-
stage: test
|
|
622
|
-
script:
|
|
623
|
-
- k6 run --out json=results.json tests/performance.js
|
|
624
|
-
artifacts:
|
|
625
|
-
paths:
|
|
626
|
-
- results.json
|
|
627
|
-
reports:
|
|
628
|
-
performance: results.json
|
|
629
|
-
only:
|
|
630
|
-
- schedules
|
|
631
|
-
```
|
|
632
|
-
|
|
633
|
-
## 性能测试最佳实践
|
|
634
|
-
|
|
635
|
-
### 测试环境
|
|
636
|
-
```yaml
|
|
637
|
-
要求:
|
|
638
|
-
- 独立环境,避免干扰
|
|
639
|
-
- 配置与生产环境一致
|
|
640
|
-
- 稳定的网络环境
|
|
641
|
-
- 充足的资源(CPU/内存/带宽)
|
|
642
|
-
|
|
643
|
-
避免:
|
|
644
|
-
- 在生产环境测试
|
|
645
|
-
- 共享测试环境
|
|
646
|
-
- 资源不足的环境
|
|
647
|
-
```
|
|
648
|
-
|
|
649
|
-
### 测试数据
|
|
650
|
-
```javascript
|
|
651
|
-
// ✅ 使用真实数据分布
|
|
652
|
-
const users = [
|
|
653
|
-
{ type: 'light', weight: 70 }, // 70%轻度用户
|
|
654
|
-
{ type: 'medium', weight: 20 }, // 20%中度用户
|
|
655
|
-
{ type: 'heavy', weight: 10 }, // 10%重度用户
|
|
656
|
-
];
|
|
657
|
-
|
|
658
|
-
// ✅ 数据隔离
|
|
659
|
-
const userId = `user_${__VU}_${__ITER}`;
|
|
660
|
-
|
|
661
|
-
// ✅ 清理测试数据
|
|
662
|
-
export function teardown(data) {
|
|
663
|
-
// 清理逻辑
|
|
664
|
-
}
|
|
665
|
-
```
|
|
666
|
-
|
|
667
|
-
### 渐进式测试
|
|
668
|
-
```
|
|
669
|
-
1. 基准测试 (Baseline)
|
|
670
|
-
└─ 单用户,建立基准
|
|
671
|
-
|
|
672
|
-
2. 负载测试 (Load)
|
|
673
|
-
└─ 预期负载,验证性能
|
|
674
|
-
|
|
675
|
-
3. 压力测试 (Stress)
|
|
676
|
-
└─ 超出负载,找到极限
|
|
677
|
-
|
|
678
|
-
4. 浸泡测试 (Soak)
|
|
679
|
-
└─ 长时间运行,检测泄漏
|
|
680
|
-
```
|
|
681
|
-
|
|
682
|
-
### 结果分析
|
|
683
|
-
```javascript
|
|
684
|
-
// k6 自定义指标
|
|
685
|
-
import { Trend, Counter } from 'k6/metrics';
|
|
686
|
-
|
|
687
|
-
const loginDuration = new Trend('login_duration');
|
|
688
|
-
const loginErrors = new Counter('login_errors');
|
|
689
|
-
|
|
690
|
-
export default function () {
|
|
691
|
-
const start = Date.now();
|
|
692
|
-
const res = http.post('/login', payload);
|
|
693
|
-
loginDuration.add(Date.now() - start);
|
|
694
|
-
|
|
695
|
-
if (res.status !== 200) {
|
|
696
|
-
loginErrors.add(1);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
```
|
|
700
|
-
|
|
701
|
-
## 工具对比
|
|
702
|
-
|
|
703
|
-
| 工具 | 语言 | 学习曲线 | 性能 | 云支持 | 开源 |
|
|
704
|
-
|------|------|----------|------|--------|------|
|
|
705
|
-
| k6 | JavaScript | 低 | 高 | ✅ | ✅ |
|
|
706
|
-
| JMeter | Java/GUI | 中 | 中 | ⚠️ | ✅ |
|
|
707
|
-
| Gatling | Scala | 高 | 高 | ✅ | ✅ |
|
|
708
|
-
| Locust | Python | 低 | 中 | ⚠️ | ✅ |
|
|
709
|
-
| Artillery | JavaScript | 低 | 中 | ✅ | ✅ |
|
|
710
|
-
|
|
711
|
-
### 选择建议
|
|
712
|
-
```
|
|
713
|
-
k6:
|
|
714
|
-
✅ 现代化、易用、性能好
|
|
715
|
-
✅ 适合 DevOps 集成
|
|
716
|
-
✅ 云原生支持
|
|
717
|
-
|
|
718
|
-
JMeter:
|
|
719
|
-
✅ 功能全面、插件丰富
|
|
720
|
-
✅ GUI 适合初学者
|
|
721
|
-
⚠️ 资源消耗较大
|
|
722
|
-
|
|
723
|
-
Gatling:
|
|
724
|
-
✅ 高性能、DSL 优雅
|
|
725
|
-
⚠️ 学习曲线陡峭
|
|
726
|
-
✅ 适合大规模测试
|
|
727
|
-
|
|
728
|
-
Locust:
|
|
729
|
-
✅ Python 生态
|
|
730
|
-
✅ 分布式支持
|
|
731
|
-
⚠️ 性能不如 k6/Gatling
|
|
732
|
-
```
|
|
733
|
-
|
|
734
|
-
---
|