perf-skills 2.0.0 → 4.0.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/.claude-plugin/marketplace.json +14 -6
- package/.claude-plugin/plugin.json +2 -2
- package/README.md +216 -187
- package/package.json +7 -2
- package/skills/perf/SKILL.md +60 -33
- package/skills/perf/evals/evals.json +80 -0
- package/skills/perf/evals/trigger-eval.json +38 -0
- package/skills/perf/references/tools/artillery.md +331 -0
- package/skills/perf/references/tools/loadrunner.md +24 -0
- package/skills/perf/references/tools/neoload.md +54 -0
- package/skills/perf/references/topics/correlation.md +4 -0
- package/skills/perf/references/topics/database-testing.md +2 -0
- package/skills/perf/references/topics/llm-inference.md +179 -0
- package/skills/perf/references/topics/modern-architectures.md +2 -0
- package/skills/perf/references/topics/observability.md +2 -0
- package/skills/perf/references/topics/production-testing.md +2 -0
- package/skills/perf/references/topics/protocol-testing.md +65 -0
- package/skills/perf/references/topics/results-analysis.md +2 -0
- package/skills/perf/references/topics/script-generation.md +10 -17
- package/skills/perf/references/topics/slo-capacity.md +136 -0
- package/skills/perf/references/topics/test-data.md +2 -0
- package/skills/perf/references/topics/test-execution.md +32 -5
package/skills/perf/SKILL.md
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: perf
|
|
3
3
|
description: Performance testing expert covering the full lifecycle for
|
|
4
|
-
JMeter, k6, Gatling, Locust, NeoLoad,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
JMeter, k6, Gatling, Locust, NeoLoad, LoadRunner, and Artillery, plus
|
|
5
|
+
LLM inference (vLLM, TRT-LLM, SGLang, OpenAI-compatible endpoints).
|
|
6
|
+
Use this skill whenever writing or reviewing load test scripts,
|
|
7
|
+
setting thresholds, choosing executors, configuring CI/CD pipelines,
|
|
8
|
+
diagnosing latency issues, designing workloads, analyzing results,
|
|
9
|
+
or recommending tools - even if the tool is not named explicitly.
|
|
10
|
+
Always consult before suggesting thresholds, executor types, or
|
|
11
|
+
output configuration. Prefer this skill over general knowledge for
|
|
12
|
+
any performance testing decision, debugging session, tool comparison,
|
|
13
|
+
LLM/TGPT streaming-performance question, or SLO/capacity-planning
|
|
14
|
+
decision.
|
|
12
15
|
---
|
|
13
16
|
|
|
14
17
|
# Performance Testing Skill
|
|
@@ -46,6 +49,7 @@ Multiple files may apply.
|
|
|
46
49
|
| k6 scripting, extensions, cloud | `references/tools/k6.md` |
|
|
47
50
|
| Gatling simulations, Scala/Java DSL | `references/tools/gatling.md` |
|
|
48
51
|
| Locust Python tests, distributed | `references/tools/locust.md` |
|
|
52
|
+
| Artillery YAML/JS/TS scripts, cloud | `references/tools/artillery.md` |
|
|
49
53
|
| NeoLoad projects, GUI, APIs | `references/tools/neoload.md` |
|
|
50
54
|
| LoadRunner scripts, protocols, VuGen | `references/tools/loadrunner.md` |
|
|
51
55
|
| OctoPerf cloud test management | `references/tools/octoperf.md` |
|
|
@@ -60,6 +64,8 @@ Multiple files may apply.
|
|
|
60
64
|
| gRPC, GraphQL, WebSocket, messaging protocols | `references/topics/protocol-testing.md` |
|
|
61
65
|
| Database load testing (JDBC, connection pools) | `references/topics/database-testing.md` |
|
|
62
66
|
| Microservices, K8s, serverless performance | `references/topics/modern-architectures.md` |
|
|
67
|
+
| LLM inference: TTFT, TPOT/ITL, TPS, goodput | `references/topics/llm-inference.md` |
|
|
68
|
+
| SLOs, error budgets, capacity & headroom | `references/topics/slo-capacity.md` |
|
|
63
69
|
|
|
64
70
|
### Protocol Routing Table
|
|
65
71
|
|
|
@@ -76,6 +82,8 @@ right tool and reference:
|
|
|
76
82
|
| Kafka / Message Queues | k6 (xk6-kafka), JMeter | `references/topics/protocol-testing.md` |
|
|
77
83
|
| SOAP / WSDL | LoadRunner, JMeter | Tool file |
|
|
78
84
|
| SAP / Citrix | LoadRunner, NeoLoad | Tool file |
|
|
85
|
+
| LLM inference (streaming) | vLLM bench, GenAI-Perf, GuideLLM, llmperf | `references/topics/llm-inference.md` |
|
|
86
|
+
| SLO/capacity (error budgets, headroom) | any | `references/topics/slo-capacity.md` |
|
|
79
87
|
|
|
80
88
|
---
|
|
81
89
|
|
|
@@ -83,16 +91,16 @@ right tool and reference:
|
|
|
83
91
|
|
|
84
92
|
Use this to recommend the right tool when the user hasn't decided yet.
|
|
85
93
|
|
|
86
|
-
| Criteria | JMeter | k6 | Gatling | Locust | NeoLoad | LoadRunner | OctoPerf |
|
|
94
|
+
| Criteria | JMeter | k6 | Gatling | Locust | Artillery | NeoLoad | LoadRunner | OctoPerf |
|
|
87
95
|
|----------------------|---------------------|-----------------------|----------------------|----------------|------------------|-------------------------|-----------------------|
|
|
88
|
-
| **Language** | GUI/XML + Groovy | JavaScript/TypeScript | Scala/Java | Python | GUI + NeoLoad DSL| VuGen C-like
|
|
89
|
-
| **Open source** | ✅ | ✅ | ✅ | ✅ |
|
|
90
|
-
| **Protocol support** | HTTP, JDBC, JMS, MQTT, FTP, gRPC | HTTP, gRPC, WS | HTTP, JMS, gRPC | HTTP, gRPC | HTTP, gRPC, WS,
|
|
91
|
-
| **Developer-friendly** | Medium | High | High | High |
|
|
92
|
-
| **Enterprise support** | Community + BlazeMeter | Grafana Cloud | Gatling Enterprise | Limited |
|
|
93
|
-
| **CI/CD integration** | Good (Maven/Gradle) | Excellent | Excellent | Good | Good | Moderate | Good |
|
|
94
|
-
| **Cloud execution** | BlazeMeter, OctoPerf | Grafana Cloud | Gatling Enterprise | Self-managed | NeoLoad Cloud | AWS/on-prem | OctoPerf Cloud |
|
|
95
|
-
| **Best for** | Legacy systems, JDBC, protocols | Modern APIs, TypeScript devs | High-throughput HTTP | Python teams, flexible | SAP/Citrix enterprise | Mainframe, legacy enterprise | JMeter teams needing cloud UI |
|
|
96
|
+
| **Language** | GUI/XML + Groovy | JavaScript/TypeScript | Scala/Java | Python | YAML / JS / TS | GUI + NeoLoad DSL | VuGen C-like | Web UI (JMeter-based) |
|
|
97
|
+
| **Open source** | ✅ | ✅ | ✅ | ✅ | ✅ (core) | ❌ | ❌ | ❌ (SaaS) |
|
|
98
|
+
| **Protocol support** | HTTP, JDBC, JMS, MQTT, FTP, gRPC | HTTP, gRPC, WS | HTTP, JMS, gRPC | HTTP, gRPC | HTTP, gRPC, WS, Socket.IO | HTTP, SAP, Citrix, Flex | HTTP, SAP, Citrix, many | HTTP (JMeter-backed) |
|
|
99
|
+
| **Developer-friendly** | Medium | High | High | High | Medium | Low | Low | Medium |
|
|
100
|
+
| **Enterprise support** | Community + BlazeMeter | Grafana Cloud | Gatling Enterprise | Limited | Artillery Cloud | ✅ | ✅ | ✅ |
|
|
101
|
+
| **CI/CD integration** | Good (Maven/Gradle) | Excellent | Excellent | Good | Good | Moderate | Good | Good |
|
|
102
|
+
| **Cloud execution** | BlazeMeter, OctoPerf | Grafana Cloud | Gatling Enterprise | Self-managed | Artillery Cloud (Lambda/Fargate) | NeoLoad Cloud | AWS/on-prem | OctoPerf Cloud |
|
|
103
|
+
| **Best for** | Legacy systems, JDBC, protocols | Modern APIs, TypeScript devs | High-throughput HTTP | Python teams, flexible | Node teams, YAML tests, cloud scale | SAP/Citrix enterprise | Mainframe, legacy enterprise | JMeter teams needing cloud UI |
|
|
96
104
|
|
|
97
105
|
### Quick decision rules
|
|
98
106
|
|
|
@@ -107,6 +115,7 @@ Use this to recommend the right tool when the user hasn't decided yet.
|
|
|
107
115
|
Correlation Recorder) or LoadRunner
|
|
108
116
|
- **gRPC or GraphQL APIs** → k6 or Gatling
|
|
109
117
|
- **Message queues (Kafka, RabbitMQ)** → k6 (xk6-kafka) or JMeter
|
|
118
|
+
- **Node shop / prefer YAML over code** → Artillery (YAML, JS, TS; easy Lambda/Fargate cloud scale)
|
|
110
119
|
|
|
111
120
|
---
|
|
112
121
|
|
|
@@ -181,28 +190,46 @@ ask about them.
|
|
|
181
190
|
that skews both throughput and latency measurements. Always run
|
|
182
191
|
workers on separate machines or containers for distributed tests.
|
|
183
192
|
|
|
184
|
-
|
|
193
|
+
### Artillery
|
|
194
|
+
|
|
195
|
+
- **No `ensure` block** - without `ensure`, Artillery reports metrics
|
|
196
|
+
but always exits 0, so CI never fails on latency or error spikes.
|
|
197
|
+
Always add `ensure.thresholds` (or `conditions`) for SLA gates.
|
|
198
|
+
- **`arrivalRate` mistaken for concurrency** - it is new users per
|
|
199
|
+
second (open model). On a slow backend, pending VUs pile up unbounded.
|
|
200
|
+
Set `maxVusers` to cap real concurrency, or use `arrivalCount`.
|
|
201
|
+
- **Strict captures aborting VUs** - captures are strict by default;
|
|
202
|
+
a missed extractor stops the whole VU. Only set `strict: false`
|
|
203
|
+
when a downstream 404 is acceptable.
|
|
204
|
+
- **`payload.order: sequence` in distributed runs** - sequential CSV
|
|
205
|
+
consumption breaks under Lambda/Fargate workers (each has its own
|
|
206
|
+
copy). Use the default `random` ordering for distributed tests.
|
|
207
|
+
- **Zero `think` time** - 1 VU/sec with no think time fires the
|
|
208
|
+
maximum RPS for the journey; add `think` to model real pacing.
|
|
209
|
+
- **Forgetting `http.response_time` is TTFB** - latency metrics are
|
|
210
|
+
time-to-first-byte by default. Enable `config.http.extendedMetrics`
|
|
211
|
+
for full download timing (`http.total.*`) when that matters.
|
|
185
212
|
|
|
186
|
-
|
|
213
|
+
---
|
|
187
214
|
|
|
188
215
|
Use this when users are migrating between tools or asking how a
|
|
189
216
|
concept from one tool maps to another. Claude should always provide
|
|
190
217
|
the specific mapping rather than a generic explanation.
|
|
191
218
|
|
|
192
|
-
| Concept | JMeter | k6 | Gatling | Locust | LoadRunner |
|
|
193
|
-
|
|
194
|
-
| Virtual user | Thread | VU | User | User | Vuser |
|
|
195
|
-
| Test plan | .jmx file | .js / .ts script | Simulation class | .py file | VuGen script (.usr) |
|
|
196
|
-
| User entrypoint | Thread Group | `default()` function | `scenario()` | task methods | `Action()` |
|
|
197
|
-
| Concurrency ctrl | Thread Group settings | executor | `inject()` | `spawn_rate` | Vuser Group |
|
|
198
|
-
| Think time | Constant/Uniform Timer | `sleep()` | `pause()` | `time.sleep()` | `lr_think_time()` |
|
|
199
|
-
| Inline assertion | Response Assertion | `check()` | `.check()` | `catch_response` | `lr_eval_string()` |
|
|
200
|
-
| SLA enforcement | Duration Assertion | `thresholds` | Assertions (Enterprise) | custom + exit code | SLA definition |
|
|
201
|
-
| Correlation | Regex / CSS Extractor | `res.json()` / regex | `.check()` + `saveAs()` | `response.text` + regex | `web_reg_save_param`|
|
|
202
|
-
| Data feed | CSV Data Set Config | `SharedArray` | `feeder` | CSV reader | `lr_paramarr()` |
|
|
203
|
-
| Grouping | Transaction Controller | `group()` | `group()` | task sets | Transaction |
|
|
204
|
-
| Distributed | Controller + Agents | k6 cloud / k6 operator | Gatling Enterprise | master + workers | Load Generator |
|
|
205
|
-
| Results output | .jtl (CSV/XML) | JSON / InfluxDB / cloud | simulation.log | CSV / Locust web UI | .lrr file |
|
|
219
|
+
| Concept | JMeter | k6 | Gatling | Locust | Artillery | LoadRunner |
|
|
220
|
+
|------------------|-------------------------|-------------------------|--------------------------|--------------------------|--------------------------|---------------------|
|
|
221
|
+
| Virtual user | Thread | VU | User | User | VU (arrival per sec) | Vuser |
|
|
222
|
+
| Test plan | .jmx file | .js / .ts script | Simulation class | .py file | .yml / .js / .ts script | VuGen script (.usr) |
|
|
223
|
+
| User entrypoint | Thread Group | `default()` function | `scenario()` | task methods | `flow` in scenario | `Action()` |
|
|
224
|
+
| Concurrency ctrl | Thread Group settings | executor | `inject()` | `spawn_rate` | `maxVusers` / `arrivalRate` | Vuser Group |
|
|
225
|
+
| Think time | Constant/Uniform Timer | `sleep()` | `pause()` | `time.sleep()` | `think` | `lr_think_time()` |
|
|
226
|
+
| Inline assertion | Response Assertion | `check()` | `.check()` | `catch_response` | `afterResponse` hooks | `lr_eval_string()` |
|
|
227
|
+
| SLA enforcement | Duration Assertion | `thresholds` | Assertions (Enterprise) | custom + exit code | `ensure` plugin | SLA definition |
|
|
228
|
+
| Correlation | Regex / CSS Extractor | `res.json()` / regex | `.check()` + `saveAs()` | `response.text` + regex | `capture` (json/xpath/regexp/header) | `web_reg_save_param`|
|
|
229
|
+
| Data feed | CSV Data Set Config | `SharedArray` | `feeder` | CSV reader | `payload` / `variables` | `lr_paramarr()` |
|
|
230
|
+
| Grouping | Transaction Controller | `group()` | `group()` | task sets | `name` on scenario | Transaction |
|
|
231
|
+
| Distributed | Controller + Agents | k6 cloud / k6 operator | Gatling Enterprise | master + workers | Lambda / Fargate workers | Load Generator |
|
|
232
|
+
| Results output | .jtl (CSV/XML) | JSON / InfluxDB / cloud | simulation.log | CSV / Locust web UI | JSON / HTML report | .lrr file |
|
|
206
233
|
|
|
207
234
|
---
|
|
208
235
|
|
|
@@ -144,6 +144,86 @@
|
|
|
144
144
|
"text": "Notes that values are baselines and should be adjusted to actual SLA requirements"
|
|
145
145
|
}
|
|
146
146
|
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": 8,
|
|
150
|
+
"prompt": "My Artillery test reports great metrics but my CI pipeline always passes even when p95 latency is 5 seconds. How do I make the test fail in CI?",
|
|
151
|
+
"expected_output": "Identifies missing ensure block as the cause. Without ensure, Artillery always exits 0. Provides an ensure.thresholds example with p95 and error rate conditions.",
|
|
152
|
+
"files": [],
|
|
153
|
+
"assertions": [
|
|
154
|
+
{
|
|
155
|
+
"id": "ensure-block-cause",
|
|
156
|
+
"text": "Identifies that without an ensure block, Artillery always exits 0 regardless of metrics"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"id": "ensure-example",
|
|
160
|
+
"text": "Provides a concrete ensure.thresholds or ensure.conditions YAML example"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"id": "exit-code",
|
|
164
|
+
"text": "Explains that ensure causes a non-zero exit code when thresholds are breached, enabling CI gating"
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"id": 9,
|
|
170
|
+
"prompt": "I set arrivalRate to 100 in Artillery expecting 100 concurrent users, but my backend is getting overwhelmed with way more than 100 simultaneous requests. What's happening?",
|
|
171
|
+
"expected_output": "Explains that arrivalRate is new users per second (open model), not concurrency. On a slow backend, VUs pile up unbounded. Recommends maxVusers to cap concurrency or arrivalCount for a fixed total.",
|
|
172
|
+
"files": [],
|
|
173
|
+
"assertions": [
|
|
174
|
+
{
|
|
175
|
+
"id": "open-model-explanation",
|
|
176
|
+
"text": "Explains that arrivalRate means new users per second (open model), not concurrent users"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"id": "pileup-risk",
|
|
180
|
+
"text": "Explains that on a slow backend, pending VUs accumulate unboundedly"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"id": "maxvusers-fix",
|
|
184
|
+
"text": "Recommends maxVusers to cap real concurrency, or arrivalCount for a fixed total number of users"
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"id": 10,
|
|
190
|
+
"prompt": "We're benchmarking our vLLM endpoint for a chat application. What metrics should we measure and what tools should we use?",
|
|
191
|
+
"expected_output": "Recommends TTFT, TPOT/ITL, tokens per second, and goodput as key metrics. Suggests vLLM bench, GenAI-Perf, GuideLLM, or llmperf as benchmarking tools. Distinguishes streaming vs non-streaming measurement.",
|
|
192
|
+
"files": [],
|
|
193
|
+
"assertions": [
|
|
194
|
+
{
|
|
195
|
+
"id": "ttft-tpot-metrics",
|
|
196
|
+
"text": "Names TTFT (time to first token) and TPOT or ITL (inter-token latency) as key streaming metrics"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"id": "benchmarking-tools",
|
|
200
|
+
"text": "Recommends at least one specific LLM benchmarking tool such as vLLM bench, GenAI-Perf, GuideLLM, or llmperf"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"id": "goodput-or-throughput",
|
|
204
|
+
"text": "Mentions goodput or tokens per second as a throughput metric distinct from raw request latency"
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"id": 11,
|
|
210
|
+
"prompt": "How do I set up SLO-based CI gating for my k6 load tests? I want the build to fail if we burn more than 2% of our error budget.",
|
|
211
|
+
"expected_output": "Explains error budget concept (100% - SLO target). Shows how to translate an error budget into k6 thresholds. Recommends tracking burn rate over the test window.",
|
|
212
|
+
"files": [],
|
|
213
|
+
"assertions": [
|
|
214
|
+
{
|
|
215
|
+
"id": "error-budget-concept",
|
|
216
|
+
"text": "Explains error budget as 100% minus the SLO target (e.g., 99.9% SLO = 0.1% budget)"
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"id": "k6-threshold-mapping",
|
|
220
|
+
"text": "Shows how to express the error budget as concrete k6 thresholds"
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"id": "burn-rate",
|
|
224
|
+
"text": "Mentions burn rate or multi-window alerting as a way to avoid false positives from short test runs"
|
|
225
|
+
}
|
|
226
|
+
]
|
|
147
227
|
}
|
|
148
228
|
]
|
|
149
229
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "perf",
|
|
3
|
+
"description": "Queries that SHOULD trigger the perf skill",
|
|
4
|
+
"trigger": [
|
|
5
|
+
"Help me write a k6 load test for our REST API",
|
|
6
|
+
"My JMeter test crashes with OutOfMemoryError in CI",
|
|
7
|
+
"What tool should I use for load testing a gRPC service?",
|
|
8
|
+
"How do I correlate JSESSIONID in JMeter?",
|
|
9
|
+
"Set up a distributed Locust run in GitLab CI",
|
|
10
|
+
"Our p95 latency spikes during database writes",
|
|
11
|
+
"What TTFT can our vLLM endpoint sustain at 200 concurrent users?",
|
|
12
|
+
"How many replicas do we need for our SLO?",
|
|
13
|
+
"Write an Artillery test with ensure thresholds for our checkout API",
|
|
14
|
+
"Compare k6 vs Gatling for high-throughput HTTP testing",
|
|
15
|
+
"My Locust test shows zero failures but the server logs have 500 errors",
|
|
16
|
+
"How do I parameterize test data in Gatling?",
|
|
17
|
+
"Set up k6 thresholds for CI gating in GitHub Actions",
|
|
18
|
+
"What is a good p95 target for a payment endpoint?",
|
|
19
|
+
"Help me design a soak test to find memory leaks",
|
|
20
|
+
"How do I benchmark tokens per second on our LLM inference server?",
|
|
21
|
+
"My Artillery arrivalRate is overwhelming the backend",
|
|
22
|
+
"Explain Little's Law and how it applies to load testing",
|
|
23
|
+
"How do I test WebSocket performance?",
|
|
24
|
+
"Set up error budget alerts for our 99.9% SLO"
|
|
25
|
+
],
|
|
26
|
+
"no_trigger": [
|
|
27
|
+
"Help me write a unit test for my Python function",
|
|
28
|
+
"What is the difference between SQL and NoSQL databases?",
|
|
29
|
+
"How do I set up a React component?",
|
|
30
|
+
"Explain how Docker containers work",
|
|
31
|
+
"Write a REST API endpoint in Express.js",
|
|
32
|
+
"How do I configure ESLint for my project?",
|
|
33
|
+
"What is the best way to learn machine learning?",
|
|
34
|
+
"Help me debug a CSS layout issue",
|
|
35
|
+
"How do I set up a Kubernetes cluster?",
|
|
36
|
+
"Write a GitHub Actions workflow for deploying my app"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# Artillery Reference
|
|
2
|
+
|
|
3
|
+
> Targets: Artillery v2.x (YAML, JS, and TS test definitions; `http`, `playwright`, `socketio`, `ws` engines)
|
|
4
|
+
|
|
5
|
+
Artillery is a developer-centric, open-source load testing tool that runs on Node.js. Tests can be written in YAML, JavaScript, or TypeScript, and it scales from a single laptop to distributed AWS Lambda / Fargate runs (Artillery Cloud). It is the closest JS/TS-native alternative to k6 and is a strong fit for teams already in the Node ecosystem.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Core Concepts
|
|
10
|
+
|
|
11
|
+
| Concept | Description |
|
|
12
|
+
|---|---|
|
|
13
|
+
| **Virtual User (VU)** | A single simulated user executing a `flow` |
|
|
14
|
+
| **Arrival (open model)** | New VUs generated per second - the default load model |
|
|
15
|
+
| **Phase** | A timed load segment (`arrivalRate`, `rampTo`, `arrivalCount`, `pause`) |
|
|
16
|
+
| **Scenario** | Named user journey; a `flow` of requests/actions |
|
|
17
|
+
| **Flow** | Ordered list of actions (request, `think`, `capture`, `loop`, `function`) |
|
|
18
|
+
| **Capture** | Extract a dynamic value from a response for later reuse (correlation) |
|
|
19
|
+
| **Processor** | Custom JS/TS module supplying hooks and metric logic |
|
|
20
|
+
| **`ensure`** | SLO/assertion plugin - FAILS the run (non-zero exit) if breached |
|
|
21
|
+
| **Environment** | Named config profile switched with `-e` |
|
|
22
|
+
|
|
23
|
+
> Artillery uses an **open (arrival-rate) load model by default**. `arrivalRate` is *new users per second*, NOT concurrent users. Use `maxVusers` to cap real concurrency. For closed/concurrency modeling, see `../topics/workload-design.md`.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Script Structure (YAML)
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
config:
|
|
31
|
+
target: 'https://staging.example.com'
|
|
32
|
+
phases:
|
|
33
|
+
- duration: '2m'
|
|
34
|
+
arrivalRate: 10
|
|
35
|
+
rampTo: 50
|
|
36
|
+
name: ramp-up
|
|
37
|
+
- duration: '5m'
|
|
38
|
+
arrivalRate: 50
|
|
39
|
+
maxVusers: 200
|
|
40
|
+
name: sustain
|
|
41
|
+
ensure:
|
|
42
|
+
thresholds:
|
|
43
|
+
- 'http.response_time.p95': 500
|
|
44
|
+
- 'http.response_time.p99': 1000
|
|
45
|
+
conditions:
|
|
46
|
+
- expression: 'http.codes.5xx < http.codes.2xx * 0.01' # <1% 5xx
|
|
47
|
+
processor: './helpers.js'
|
|
48
|
+
|
|
49
|
+
scenarios:
|
|
50
|
+
- name: 'Browse + Checkout'
|
|
51
|
+
weight: 1
|
|
52
|
+
flow:
|
|
53
|
+
- post:
|
|
54
|
+
url: '/auth'
|
|
55
|
+
json:
|
|
56
|
+
username: '{{ username }}'
|
|
57
|
+
password: '{{ password }}'
|
|
58
|
+
capture:
|
|
59
|
+
- json: '$.id_token'
|
|
60
|
+
as: token
|
|
61
|
+
- think: 2
|
|
62
|
+
- get:
|
|
63
|
+
url: '/products'
|
|
64
|
+
headers:
|
|
65
|
+
authorization: 'Bearer {{ token }}'
|
|
66
|
+
- post:
|
|
67
|
+
url: '/checkout'
|
|
68
|
+
json:
|
|
69
|
+
itemId: '{{ $uuid }}'
|
|
70
|
+
capture:
|
|
71
|
+
- json: '$.orderId'
|
|
72
|
+
as: orderId
|
|
73
|
+
- get:
|
|
74
|
+
url: '/orders/{{ orderId }}'
|
|
75
|
+
headers:
|
|
76
|
+
authorization: 'Bearer {{ token }}'
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Script Structure (JS / TS)
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
export const config = {
|
|
85
|
+
target: 'https://staging.example.com',
|
|
86
|
+
phases: [
|
|
87
|
+
{ duration: '2m', arrivalRate: 10, rampTo: 50, name: 'ramp-up' },
|
|
88
|
+
{ duration: '5m', arrivalRate: 50, maxVusers: 200, name: 'sustain' },
|
|
89
|
+
],
|
|
90
|
+
ensure: {
|
|
91
|
+
thresholds: [
|
|
92
|
+
'http.response_time.p95: 500',
|
|
93
|
+
'http.response_time.p99: 1000',
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
processor: './helpers.js',
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const scenarios = [
|
|
100
|
+
{
|
|
101
|
+
name: 'Browse + Checkout',
|
|
102
|
+
flow: [
|
|
103
|
+
{
|
|
104
|
+
post: {
|
|
105
|
+
url: '/auth',
|
|
106
|
+
json: { username: '{{ username }}', password: '{{ password }}' },
|
|
107
|
+
capture: [{ json: '$.id_token', as: 'token' }],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
{ think: 2 },
|
|
111
|
+
{
|
|
112
|
+
get: {
|
|
113
|
+
url: '/products',
|
|
114
|
+
headers: { authorization: 'Bearer {{ token }}' },
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
];
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Load Phases
|
|
125
|
+
|
|
126
|
+
`config.phases` is an array executed sequentially. Four phase kinds:
|
|
127
|
+
|
|
128
|
+
| Phase kind | Key options | Use case |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| **Constant arrival** | `arrivalRate` | Steady RPS-style load (open model) |
|
|
131
|
+
| **Ramp** | `arrivalRate` + `rampTo` (both over `duration`) | Warm-up / ramp-up |
|
|
132
|
+
| **Fixed count** | `arrivalCount` | Exact N total users spread over `duration` |
|
|
133
|
+
| **Pause** | `pause` | Idle gap (soak cool-down, between spikes) |
|
|
134
|
+
|
|
135
|
+
```yaml
|
|
136
|
+
phases:
|
|
137
|
+
- duration: '30m'
|
|
138
|
+
arrivalRate: 1
|
|
139
|
+
rampTo: 100
|
|
140
|
+
name: ramp-up
|
|
141
|
+
- duration: '3h'
|
|
142
|
+
arrivalRate: 100
|
|
143
|
+
name: sustain # soak/endurance
|
|
144
|
+
- duration: '1m'
|
|
145
|
+
arrivalRate: 500
|
|
146
|
+
name: spike # spike test
|
|
147
|
+
- pause: 60
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- `duration` / `pause` accept human-readable units (`'5m'`, `'3h'`) as well as seconds.
|
|
151
|
+
- `maxVusers` caps in-flight VUs for any phase - essential to bound concurrency on slow servers (open-model load otherwise queues unbounded pending VUs).
|
|
152
|
+
- `name` makes phases identifiable in CLI output and Artillery Cloud.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Correlation (Capture / Dynamic Values)
|
|
157
|
+
|
|
158
|
+
Use `capture` on a request to extract a value for later steps. Requires `as` and one extractor:
|
|
159
|
+
|
|
160
|
+
| Extractor | Syntax | Example |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| JSONPath | `json: '$.path'` | `json: '$.id_token'` |
|
|
163
|
+
| XPath | `xpath: '//node/text()'` | SOAP / XML bodies |
|
|
164
|
+
| Regex | `regexp: 'pattern'`, optional `group`, `flags` | `regexp: 'sid=([^&]+)'` |
|
|
165
|
+
| Header | `header: 'X-Custom'` | `header: 'Set-Cookie'` |
|
|
166
|
+
| Selector | `selector: 'a.product'`, `attr`, `index` | HTML scraping |
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
- get:
|
|
170
|
+
url: '/login'
|
|
171
|
+
capture:
|
|
172
|
+
- json: '$.csrf'
|
|
173
|
+
as: csrf
|
|
174
|
+
- header: 'set-cookie'
|
|
175
|
+
as: cookie
|
|
176
|
+
- post:
|
|
177
|
+
url: '/submit'
|
|
178
|
+
headers:
|
|
179
|
+
x-csrf-token: '{{ csrf }}'
|
|
180
|
+
cookie:
|
|
181
|
+
session: '{{ cookie }}'
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- **Captures are strict by default**: a failed capture stops that VU. Set `strict: false` only when a later request can safely 404.
|
|
185
|
+
- For multi-step journeys, capture once near the top and reuse via `{{ var }}` in every later request.
|
|
186
|
+
- Capture multiple values from one response with an array of capture specs.
|
|
187
|
+
|
|
188
|
+
> For framework-specific extraction rules (ASP.NET ViewState, JSF, JWT, SAP `sap-contextid`), see `../topics/correlation.md`.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Parameterization
|
|
193
|
+
|
|
194
|
+
### CSV payload (`config.payload`)
|
|
195
|
+
```yaml
|
|
196
|
+
config:
|
|
197
|
+
payload:
|
|
198
|
+
path: 'users.csv'
|
|
199
|
+
fields: ['username', 'password']
|
|
200
|
+
skipHeader: true
|
|
201
|
+
order: sequence # 'random' (default) | 'sequence'
|
|
202
|
+
scenarios:
|
|
203
|
+
- flow:
|
|
204
|
+
- post:
|
|
205
|
+
url: '/auth'
|
|
206
|
+
json:
|
|
207
|
+
username: '{{ username }}'
|
|
208
|
+
password: '{{ password }}'
|
|
209
|
+
```
|
|
210
|
+
- `order: sequence` is deterministic but **breaks under distributed runs** (each worker has its own copy). Use `random` (default) for distributed tests.
|
|
211
|
+
- `loadAll: true` + `name` exposes the whole dataset to each VU for `loop`.
|
|
212
|
+
- `cast: false` keeps values as strings; `delimiter` overrides the comma.
|
|
213
|
+
|
|
214
|
+
### Inline variables (`config.variables`)
|
|
215
|
+
```yaml
|
|
216
|
+
config:
|
|
217
|
+
variables:
|
|
218
|
+
postcode: ['SE1', 'EC1', 'E8']
|
|
219
|
+
id: ['8731', '9965', '2806']
|
|
220
|
+
```
|
|
221
|
+
One value is picked at random per VU. Cannot template `config` values.
|
|
222
|
+
|
|
223
|
+
### Environment variables (`$env`)
|
|
224
|
+
```yaml
|
|
225
|
+
headers:
|
|
226
|
+
x-api-key: '{{ $env.API_KEY }}'
|
|
227
|
+
```
|
|
228
|
+
Run with `API_KEY=xxx artillery run script.yml` or `--env-file .env`. Keeps secrets out of source.
|
|
229
|
+
|
|
230
|
+
### Environments (`-e`)
|
|
231
|
+
Reuse one script across dev/staging/prod by defining `config.environments` with per-env `target` and `phases`:
|
|
232
|
+
```bash
|
|
233
|
+
artillery run -e production script.yml
|
|
234
|
+
```
|
|
235
|
+
Access the active name via `{{ $environment }}` (e.g. to pick a CSV: `path: '{{ $environment }}-logins.csv'`).
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## SLO Checks with `ensure` (Assertions)
|
|
240
|
+
|
|
241
|
+
`ensure` is Artillery's SLA gate - **without it, the run reports metrics but always exits 0**, so CI never fails on latency. Always add it for CI.
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
config:
|
|
245
|
+
plugins:
|
|
246
|
+
ensure:
|
|
247
|
+
thresholds: # value must be LESS than this
|
|
248
|
+
- 'http.response_time.p95': 500
|
|
249
|
+
- 'http.response_time.p99': 1000
|
|
250
|
+
conditions: # advanced boolean/numeric expressions
|
|
251
|
+
- expression: 'http.response_time.p95 < 500 and http.request_rate > 1000'
|
|
252
|
+
- expression: 'http.codes.5xx <= http.codes.2xx * 0.01'
|
|
253
|
+
strict: false # optional check; failure won't fail the run
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- `thresholds` check a metric's aggregate is **below** the integer.
|
|
257
|
+
- `conditions` combine metrics with `+ - * / % ^`, comparisons, `and`/`or`/`not`, and `ceil/floor/round`.
|
|
258
|
+
- `strict: true` (default) fails the run on breach; `strict: false` reports only.
|
|
259
|
+
- Using a non-existent metric name makes that check fail.
|
|
260
|
+
|
|
261
|
+
### Key metrics for `ensure`
|
|
262
|
+
| Metric | Meaning |
|
|
263
|
+
|---|---|
|
|
264
|
+
| `http.response_time.p95` / `.p99` | Latency percentile (ms) |
|
|
265
|
+
| `http.request_rate` | Requests/sec |
|
|
266
|
+
| `http.codes.2xx` / `.4xx` / `.5xx` | Status-code counters |
|
|
267
|
+
| `http.downloaded_bytes` | Total payload bytes |
|
|
268
|
+
| `vusers.completed` / `vusers.failed` | VU outcomes |
|
|
269
|
+
|
|
270
|
+
> `http.response_time.*` is **TTFB** by default. Enable `config.http.extendedMetrics: true` for full `http.total.*` (download-complete) timing. For SLA baseline tables, see SKILL.md "Threshold Starting Points" and `../topics/results-analysis.md`.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Custom Logic (Processor Hooks)
|
|
275
|
+
|
|
276
|
+
Load JS/TS via `config.processor`:
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
// helpers.js
|
|
280
|
+
module.exports = {
|
|
281
|
+
setApiKey(context, events, done) {
|
|
282
|
+
context.vars.apiKey = process.env.API_KEY;
|
|
283
|
+
return done();
|
|
284
|
+
},
|
|
285
|
+
assertOrder(context, events, done) {
|
|
286
|
+
const status = context.vars.orderStatus;
|
|
287
|
+
if (status !== 'confirmed') {
|
|
288
|
+
events.emit('counter', 'order_failures', 1);
|
|
289
|
+
}
|
|
290
|
+
return done();
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Hook points:
|
|
296
|
+
- **`beforeRequest` / `afterResponse`** - set on a request; customize/inspect URL, headers, body.
|
|
297
|
+
- **`beforeScenario` / `afterScenario`** - set on a scenario.
|
|
298
|
+
- **`function`** step - run arbitrary code mid-flow.
|
|
299
|
+
|
|
300
|
+
Async hooks are supported (v2.0.7+). Use `events.emit('counter'|'histogram'|'rate', name, value)` for custom metrics.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Output and Observability
|
|
305
|
+
|
|
306
|
+
| Output | How |
|
|
307
|
+
|---|---|
|
|
308
|
+
| Terminal summary | Default (`artillery run script.yml`) |
|
|
309
|
+
| JSON report | `artillery run -o json=report.json script.yml` |
|
|
310
|
+
| Artillery Cloud | `artillery run --record script.yml` (dashboards, historical trends) |
|
|
311
|
+
| CSV | `artillery run -o csv=results.csv script.yml` |
|
|
312
|
+
| Distributed | AWS Lambda / Fargate workers via `artillery run-fargate` |
|
|
313
|
+
|
|
314
|
+
Enable `config.http.distributedTracing: true` to attach a W3C `traceparent` header to every request - correlates load with backend spans in your APM.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Artillery-Specific Tips
|
|
319
|
+
|
|
320
|
+
- **`arrivalRate` is new-users-per-second, not concurrency.** A slow backend makes pending VUs pile up. Always set `maxVusers` to bound real concurrency, or switch to `arrivalCount`/closed-model thinking via `workload-design.md`.
|
|
321
|
+
- **Always add `ensure` for CI.** A test with no `ensure` exits 0 regardless of latency or error spikes - it generates traffic but enforces nothing.
|
|
322
|
+
- **Captures are strict by default.** A missed extractor aborts the whole VU. Only set `strict: false` when a downstream 404 is acceptable.
|
|
323
|
+
- **Add `think` between steps.** Zero think time maximizes RPS unrealistically; use `think` (seconds or `ms` units) to model real pacing.
|
|
324
|
+
- **Default `payload.order` is `random`** - deterministic `sequence` ordering does not work correctly in distributed runs.
|
|
325
|
+
- **`http.response_time` is TTFB.** Turn on `extendedMetrics` if you need full download time (`http.total.*`).
|
|
326
|
+
- **Secrets via `$env` / `--env-file`**, never inline. Use `config.environments` + `-e` to promote the same script dev → staging → prod.
|
|
327
|
+
- **Avoid heavy `log` actions under load** - they add overhead; prefer `ensure`/custom counters for visibility.
|
|
328
|
+
- **Browser load?** Use the `playwright` engine (`engines: { playwright: {} }`) to drive real pages; note it is far heavier per VU than HTTP.
|
|
329
|
+
|
|
330
|
+
> For CI/CD integration (GitHub Actions, GitLab CI, distributed execution), see `../topics/test-execution.md`.
|
|
331
|
+
> For anti-patterns, assertions, think time, and parameterization principles, see **Key Principles** in `SKILL.md`.
|
|
@@ -112,5 +112,29 @@ web_add_header("Authorization", "Bearer {AuthToken}");
|
|
|
112
112
|
- Use **Correlation graphs** to overlay server metrics (CPU, memory) from SiteScope/Diagnostics.
|
|
113
113
|
- Export to Excel or integrate with LoadRunner Cloud for trend analysis across runs.
|
|
114
114
|
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## LoadRunner-Specific Tips
|
|
118
|
+
|
|
119
|
+
- **Register correlations before the request** - `web_reg_save_param_regexp` must appear
|
|
120
|
+
*before* the `web_url`/`web_submit_form` that returns the dynamic value. Placing it after
|
|
121
|
+
silently captures nothing.
|
|
122
|
+
- **Use `lr_eval_string()` for debugging** - log parameter values during replay
|
|
123
|
+
(`lr_log_message("Token={AuthToken}")`) to verify correlation is working before scaling VUs.
|
|
124
|
+
- **Avoid `lr_think_time(0)` in Action** - zero think time generates maximum RPS per VU,
|
|
125
|
+
which never reflects real user behavior. Use `lr_think_time(3)` or `lr_user_think_time()`
|
|
126
|
+
with a runtime distribution.
|
|
127
|
+
- **Parameterize with data tables, not hardcoded values** - use `lr_paramarr_idx()` or
|
|
128
|
+
Parameter List in VuGen to feed unique credentials per VU. Hardcoded users cause
|
|
129
|
+
session collisions and cache-hot results.
|
|
130
|
+
- **Set JVM heap for Load Generators** - default LG memory is often too low for 500+ VUs.
|
|
131
|
+
Increase via `mdrv -heap_size` or the LG configuration panel.
|
|
132
|
+
- **Use Goal-Oriented scenarios for capacity tests** - instead of guessing VU counts,
|
|
133
|
+
let Controller auto-adjust to hit a target RPS or response time. This finds the
|
|
134
|
+
saturation point without manual iteration.
|
|
135
|
+
- **Disable extended logging in CI** - `lr_set_debug_message` and extended logs add
|
|
136
|
+
20-40% overhead. Use standard logging or disable entirely for large runs.
|
|
137
|
+
|
|
115
138
|
> For anti-patterns, assertions, think time, and parameterization principles, see **Key Principles** in `SKILL.md`.
|
|
116
139
|
> For CI/CD integration details, see `../topics/test-execution.md`.
|
|
140
|
+
> For correlation strategies across tools, see `../topics/correlation.md`.
|