perf-skills 1.0.3 → 2.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.
@@ -1,269 +1,269 @@
1
- # k6 Reference
2
-
3
- > Targets: k6 v0.50+, xk6 extensions ecosystem
4
-
5
- k6 is a developer-centric, open-source load testing tool built by Grafana Labs. Tests are written in JavaScript/TypeScript and executed with a Go runtime — making it fast, scriptable, and CI/CD-friendly.
6
-
7
- ---
8
-
9
- ## Core Concepts
10
-
11
- | Concept | Description |
12
- |---|---|
13
- | **Virtual User (VU)** | A single simulated user executing the script |
14
- | **Iteration** | One full execution of the default function |
15
- | **Scenario** | Named execution profile with its own executor and config |
16
- | **Executor** | Controls how VUs and iterations are scheduled |
17
- | **Metric** | Built-in or custom measurement (counters, gauges, rates, trends) |
18
- | **Check** | Inline assertion — does NOT fail the test; records pass/fail rate |
19
- | **Threshold** | SLA definition — FAILS the test if breached |
20
- | **Group** | Logical grouping of requests for metric aggregation |
21
-
22
- ---
23
-
24
- ## Script Structure
25
-
26
- ```javascript
27
- import http from 'k6/http';
28
- import { check, sleep, group } from 'k6';
29
- import { Counter, Trend } from 'k6/metrics';
30
-
31
- // Custom metrics
32
- const loginErrors = new Counter('login_errors');
33
- const checkoutDuration = new Trend('checkout_duration_ms');
34
-
35
- // Test configuration
36
- export const options = {
37
- scenarios: {
38
- ramp_up: {
39
- executor: 'ramping-vus',
40
- startVUs: 0,
41
- stages: [
42
- { duration: '2m', target: 50 },
43
- { duration: '5m', target: 50 },
44
- { duration: '2m', target: 0 },
45
- ],
46
- },
47
- },
48
- thresholds: {
49
- http_req_duration: ['p(95)<500', 'p(99)<1000'],
50
- http_req_failed: ['rate<0.01'],
51
- login_errors: ['count<5'],
52
- },
53
- };
54
-
55
- // Setup (runs once before VUs start)
56
- export function setup() {
57
- const res = http.post('https://api.example.com/auth/token', {
58
- client_id: 'perf-test',
59
- client_secret: __ENV.API_SECRET,
60
- });
61
- return { token: res.json('access_token') };
62
- }
63
-
64
- // Default VU function
65
- export default function (data) {
66
- group('Login Flow', () => {
67
- const res = http.post('https://api.example.com/login', JSON.stringify({
68
- username: `user_${__VU}@example.com`,
69
- password: 'testpass',
70
- }), {
71
- headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${data.token}` },
72
- });
73
-
74
- const ok = check(res, {
75
- 'login status 200': (r) => r.status === 200,
76
- 'has userId': (r) => r.json('userId') !== undefined,
77
- });
78
- if (!ok) loginErrors.add(1);
79
- });
80
-
81
- sleep(Math.random() * 3 + 1); // Think time: 1–4 seconds
82
- }
83
-
84
- // Teardown (runs once after all VUs finish)
85
- export function teardown(data) {
86
- // Cleanup, invalidate tokens, etc.
87
- }
88
- ```
89
-
90
- ---
91
-
92
- ## Executors
93
-
94
- | Executor | Use Case | Key Options |
95
- |---|---|---|
96
- | `ramping-vus` | Ramp up/down | `stages: [{duration, target}]` |
97
- | `constant-vus` | Fixed concurrency | `vus`, `duration` |
98
- | `per-vu-iterations` | Each VU runs N times | `vus`, `iterations` |
99
- | `shared-iterations` | Total N iterations split across VUs | `vus`, `iterations` |
100
- | `constant-arrival-rate` | Fixed RPS (open model) | `rate`, `duration`, `preAllocatedVUs` |
101
- | `ramping-arrival-rate` | Ramping RPS (open model) | `stages`, `preAllocatedVUs` |
102
- | `externally-controlled` | Controlled via k6 REST API in real-time | — |
103
-
104
- > For closed vs open model guidance and when to use each, see `../topics/workload-design.md`.
105
-
106
- ---
107
-
108
- ## Checks vs Thresholds
109
-
110
- ```javascript
111
- // Check: logs pass/fail but does NOT fail the test
112
- check(res, { 'status 200': (r) => r.status === 200 });
113
-
114
- // Threshold: FAILS the test run (non-zero exit code) if breached
115
- // Put these in options.thresholds
116
- thresholds: {
117
- http_req_duration: ['p(95)<500'], // p95 must be under 500ms
118
- checks: ['rate>0.99'], // At least 99% of checks must pass
119
- }
120
- ```
121
-
122
- Use thresholds for SLA enforcement in CI/CD pipelines.
123
-
124
- ---
125
-
126
- ## Parameterization
127
-
128
- ### Environment variables
129
- ```bash
130
- k6 run -e USERNAME=testuser -e PASSWORD=secret script.js
131
- ```
132
- ```javascript
133
- const username = __ENV.USERNAME;
134
- ```
135
-
136
- ### SharedArray (CSV / JSON data files)
137
- ```javascript
138
- import { SharedArray } from 'k6/data';
139
- import papaparse from 'https://jslib.k6.io/papaparse/5.1.1/index.js';
140
-
141
- const users = new SharedArray('users', function () {
142
- return papaparse.parse(open('./data/users.csv'), { header: true }).data;
143
- });
144
-
145
- export default function () {
146
- const user = users[__VU % users.length]; // Round-robin by VU
147
- // use user.username, user.password
148
- }
149
- ```
150
-
151
- **SharedArray loads data once and shares it across all VUs** — critical for memory efficiency at high concurrency.
152
-
153
- ---
154
-
155
- ## Correlation (Session Handling)
156
-
157
- ```javascript
158
- // Extract value from JSON response
159
- const token = res.json('data.access_token');
160
-
161
- // Extract from HTML (regex)
162
- const csrfToken = res.html().find('input[name="_token"]').attr('value');
163
-
164
- // Extract from headers
165
- const sessionId = res.headers['Set-Cookie'].match(/JSESSIONID=([^;]+)/)[1];
166
-
167
- // Use in next request
168
- http.get('https://api.example.com/profile', {
169
- headers: { 'Authorization': `Bearer ${token}` },
170
- });
171
- ```
172
-
173
- ---
174
-
175
- ## Custom Metrics
176
-
177
- ```javascript
178
- import { Counter, Gauge, Rate, Trend } from 'k6/metrics';
179
-
180
- const checkoutErrors = new Counter('checkout_errors'); // cumulative count
181
- const activeUsers = new Gauge('active_users'); // current value
182
- const successRate = new Rate('success_rate'); // ratio
183
- const transactionTime = new Trend('transaction_time_ms'); // distribution (p50/p95/p99)
184
-
185
- // Usage inside default()
186
- transactionTime.add(res.timings.duration);
187
- successRate.add(res.status === 200);
188
- ```
189
-
190
- ---
191
-
192
- ## Modules & Extensions
193
-
194
- ### Built-in k6 modules
195
- - `k6/http` — HTTP/1.1 and HTTP/2
196
- - `k6/ws` — WebSocket
197
- - `k6/grpc` — gRPC
198
- - `k6/browser` — Browser-based testing (Chromium)
199
- - `k6/experimental/redis` — Redis client
200
- - `k6/crypto` — Hashing and HMAC
201
- - `k6/encoding` — Base64
202
-
203
- ### Popular xk6 extensions (require custom build)
204
- - `xk6-kafka` — Kafka load testing
205
- - `xk6-sql` — SQL database testing
206
- - `xk6-output-prometheus-remote` — Push metrics to Prometheus
207
-
208
- Build custom k6: `xk6 build --with github.com/grafana/xk6-kafka`
209
-
210
- ---
211
-
212
- ## Running k6
213
-
214
- ```bash
215
- # Local run
216
- k6 run script.js
217
-
218
- # With options override
219
- k6 run --vus 50 --duration 5m script.js
220
-
221
- # With env vars
222
- k6 run -e BASE_URL=https://staging.example.com script.js
223
-
224
- # Output to multiple sinks
225
- k6 run --out json=results.json --out influxdb=http://localhost:8086/k6 script.js
226
-
227
- # Cloud run (Grafana Cloud k6)
228
- k6 cloud script.js
229
- ```
230
-
231
- ---
232
-
233
- ## Output and Observability
234
-
235
- | Output | Command |
236
- |---|---|
237
- | Terminal summary | Default |
238
- | JSON | `--out json=results.json` |
239
- | InfluxDB (Grafana stack) | `--out influxdb=http://influx:8086/k6` |
240
- | Prometheus | `--out experimental-prometheus-rw` |
241
- | Grafana Cloud | `k6 cloud` or `--out cloud` |
242
- | CSV | `--out csv=results.csv` |
243
-
244
- ### InfluxDB + Grafana Dashboard
245
- The canonical observability stack: k6 → InfluxDB → Grafana with the official k6 Grafana dashboard (ID: 2587).
246
-
247
- ---
248
-
249
- ## TypeScript Support
250
-
251
- ```bash
252
- # Use k6 template with TypeScript
253
- npx create-k6-app@latest --template typescript my-test
254
- ```
255
-
256
- Benefits: Type safety, IDE autocomplete, better refactoring for large test suites.
257
-
258
- ---
259
-
260
- ## k6-Specific Tips
261
-
262
- - **Always use `SharedArray`** for data files — loading data inside `default()` causes massive per-iteration overhead.
263
- - **Use `for` loops only for sequential steps**, not concurrency — use VUs and executors for parallel load.
264
- - **Remove `console.log` from hot paths** — dramatically reduces throughput during load runs.
265
- - **Use `__ENV.BASE_URL`** for environment portability — never hardcode base URLs.
266
- - **Prefer thresholds over checks alone** — without thresholds, the test always "passes" in CI/CD.
267
-
268
- > For CI/CD integration (GitHub Actions, GitLab CI, Jenkins), see `../topics/test-execution.md`.
269
- > For anti-patterns, assertions, think time, and parameterization principles, see **Key Principles** in `SKILL.md`.
1
+ # k6 Reference
2
+
3
+ > Targets: k6 v0.50+, xk6 extensions ecosystem
4
+
5
+ k6 is a developer-centric, open-source load testing tool built by Grafana Labs. Tests are written in JavaScript/TypeScript and executed with a Go runtime - making it fast, scriptable, and CI/CD-friendly.
6
+
7
+ ---
8
+
9
+ ## Core Concepts
10
+
11
+ | Concept | Description |
12
+ |---|---|
13
+ | **Virtual User (VU)** | A single simulated user executing the script |
14
+ | **Iteration** | One full execution of the default function |
15
+ | **Scenario** | Named execution profile with its own executor and config |
16
+ | **Executor** | Controls how VUs and iterations are scheduled |
17
+ | **Metric** | Built-in or custom measurement (counters, gauges, rates, trends) |
18
+ | **Check** | Inline assertion - does NOT fail the test; records pass/fail rate |
19
+ | **Threshold** | SLA definition - FAILS the test if breached |
20
+ | **Group** | Logical grouping of requests for metric aggregation |
21
+
22
+ ---
23
+
24
+ ## Script Structure
25
+
26
+ ```javascript
27
+ import http from 'k6/http';
28
+ import { check, sleep, group } from 'k6';
29
+ import { Counter, Trend } from 'k6/metrics';
30
+
31
+ // Custom metrics
32
+ const loginErrors = new Counter('login_errors');
33
+ const checkoutDuration = new Trend('checkout_duration_ms');
34
+
35
+ // Test configuration
36
+ export const options = {
37
+ scenarios: {
38
+ ramp_up: {
39
+ executor: 'ramping-vus',
40
+ startVUs: 0,
41
+ stages: [
42
+ { duration: '2m', target: 50 },
43
+ { duration: '5m', target: 50 },
44
+ { duration: '2m', target: 0 },
45
+ ],
46
+ },
47
+ },
48
+ thresholds: {
49
+ http_req_duration: ['p(95)<500', 'p(99)<1000'],
50
+ http_req_failed: ['rate<0.01'],
51
+ login_errors: ['count<5'],
52
+ },
53
+ };
54
+
55
+ // Setup (runs once before VUs start)
56
+ export function setup() {
57
+ const res = http.post('https://api.example.com/auth/token', {
58
+ client_id: 'perf-test',
59
+ client_secret: __ENV.API_SECRET,
60
+ });
61
+ return { token: res.json('access_token') };
62
+ }
63
+
64
+ // Default VU function
65
+ export default function (data) {
66
+ group('Login Flow', () => {
67
+ const res = http.post('https://api.example.com/login', JSON.stringify({
68
+ username: `user_${__VU}@example.com`,
69
+ password: 'testpass',
70
+ }), {
71
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${data.token}` },
72
+ });
73
+
74
+ const ok = check(res, {
75
+ 'login status 200': (r) => r.status === 200,
76
+ 'has userId': (r) => r.json('userId') !== undefined,
77
+ });
78
+ if (!ok) loginErrors.add(1);
79
+ });
80
+
81
+ sleep(Math.random() * 3 + 1); // Think time: 1–4 seconds
82
+ }
83
+
84
+ // Teardown (runs once after all VUs finish)
85
+ export function teardown(data) {
86
+ // Cleanup, invalidate tokens, etc.
87
+ }
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Executors
93
+
94
+ | Executor | Use Case | Key Options |
95
+ |---|---|---|
96
+ | `ramping-vus` | Ramp up/down | `stages: [{duration, target}]` |
97
+ | `constant-vus` | Fixed concurrency | `vus`, `duration` |
98
+ | `per-vu-iterations` | Each VU runs N times | `vus`, `iterations` |
99
+ | `shared-iterations` | Total N iterations split across VUs | `vus`, `iterations` |
100
+ | `constant-arrival-rate` | Fixed RPS (open model) | `rate`, `duration`, `preAllocatedVUs` |
101
+ | `ramping-arrival-rate` | Ramping RPS (open model) | `stages`, `preAllocatedVUs` |
102
+ | `externally-controlled` | Controlled via k6 REST API in real-time | - |
103
+
104
+ > For closed vs open model guidance and when to use each, see `../topics/workload-design.md`.
105
+
106
+ ---
107
+
108
+ ## Checks vs Thresholds
109
+
110
+ ```javascript
111
+ // Check: logs pass/fail but does NOT fail the test
112
+ check(res, { 'status 200': (r) => r.status === 200 });
113
+
114
+ // Threshold: FAILS the test run (non-zero exit code) if breached
115
+ // Put these in options.thresholds
116
+ thresholds: {
117
+ http_req_duration: ['p(95)<500'], // p95 must be under 500ms
118
+ checks: ['rate>0.99'], // At least 99% of checks must pass
119
+ }
120
+ ```
121
+
122
+ Use thresholds for SLA enforcement in CI/CD pipelines.
123
+
124
+ ---
125
+
126
+ ## Parameterization
127
+
128
+ ### Environment variables
129
+ ```bash
130
+ k6 run -e USERNAME=testuser -e PASSWORD=secret script.js
131
+ ```
132
+ ```javascript
133
+ const username = __ENV.USERNAME;
134
+ ```
135
+
136
+ ### SharedArray (CSV / JSON data files)
137
+ ```javascript
138
+ import { SharedArray } from 'k6/data';
139
+ import papaparse from 'https://jslib.k6.io/papaparse/5.1.1/index.js';
140
+
141
+ const users = new SharedArray('users', function () {
142
+ return papaparse.parse(open('./data/users.csv'), { header: true }).data;
143
+ });
144
+
145
+ export default function () {
146
+ const user = users[__VU % users.length]; // Round-robin by VU
147
+ // use user.username, user.password
148
+ }
149
+ ```
150
+
151
+ **SharedArray loads data once and shares it across all VUs** - critical for memory efficiency at high concurrency.
152
+
153
+ ---
154
+
155
+ ## Correlation (Session Handling)
156
+
157
+ ```javascript
158
+ // Extract value from JSON response
159
+ const token = res.json('data.access_token');
160
+
161
+ // Extract from HTML (regex)
162
+ const csrfToken = res.html().find('input[name="_token"]').attr('value');
163
+
164
+ // Extract from headers
165
+ const sessionId = res.headers['Set-Cookie'].match(/JSESSIONID=([^;]+)/)[1];
166
+
167
+ // Use in next request
168
+ http.get('https://api.example.com/profile', {
169
+ headers: { 'Authorization': `Bearer ${token}` },
170
+ });
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Custom Metrics
176
+
177
+ ```javascript
178
+ import { Counter, Gauge, Rate, Trend } from 'k6/metrics';
179
+
180
+ const checkoutErrors = new Counter('checkout_errors'); // cumulative count
181
+ const activeUsers = new Gauge('active_users'); // current value
182
+ const successRate = new Rate('success_rate'); // ratio
183
+ const transactionTime = new Trend('transaction_time_ms'); // distribution (p50/p95/p99)
184
+
185
+ // Usage inside default()
186
+ transactionTime.add(res.timings.duration);
187
+ successRate.add(res.status === 200);
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Modules & Extensions
193
+
194
+ ### Built-in k6 modules
195
+ - `k6/http` - HTTP/1.1 and HTTP/2
196
+ - `k6/ws` - WebSocket
197
+ - `k6/grpc` - gRPC
198
+ - `k6/browser` - Browser-based testing (Chromium)
199
+ - `k6/experimental/redis` - Redis client
200
+ - `k6/crypto` - Hashing and HMAC
201
+ - `k6/encoding` - Base64
202
+
203
+ ### Popular xk6 extensions (require custom build)
204
+ - `xk6-kafka` - Kafka load testing
205
+ - `xk6-sql` - SQL database testing
206
+ - `xk6-output-prometheus-remote` - Push metrics to Prometheus
207
+
208
+ Build custom k6: `xk6 build --with github.com/grafana/xk6-kafka`
209
+
210
+ ---
211
+
212
+ ## Running k6
213
+
214
+ ```bash
215
+ # Local run
216
+ k6 run script.js
217
+
218
+ # With options override
219
+ k6 run --vus 50 --duration 5m script.js
220
+
221
+ # With env vars
222
+ k6 run -e BASE_URL=https://staging.example.com script.js
223
+
224
+ # Output to multiple sinks
225
+ k6 run --out json=results.json --out influxdb=http://localhost:8086/k6 script.js
226
+
227
+ # Cloud run (Grafana Cloud k6)
228
+ k6 cloud script.js
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Output and Observability
234
+
235
+ | Output | Command |
236
+ |---|---|
237
+ | Terminal summary | Default |
238
+ | JSON | `--out json=results.json` |
239
+ | InfluxDB (Grafana stack) | `--out influxdb=http://influx:8086/k6` |
240
+ | Prometheus | `--out experimental-prometheus-rw` |
241
+ | Grafana Cloud | `k6 cloud` or `--out cloud` |
242
+ | CSV | `--out csv=results.csv` |
243
+
244
+ ### InfluxDB + Grafana Dashboard
245
+ The canonical observability stack: k6 → InfluxDB → Grafana with the official k6 Grafana dashboard (ID: 2587).
246
+
247
+ ---
248
+
249
+ ## TypeScript Support
250
+
251
+ ```bash
252
+ # Use k6 template with TypeScript
253
+ npx create-k6-app@latest --template typescript my-test
254
+ ```
255
+
256
+ Benefits: Type safety, IDE autocomplete, better refactoring for large test suites.
257
+
258
+ ---
259
+
260
+ ## k6-Specific Tips
261
+
262
+ - **Always use `SharedArray`** for data files - loading data inside `default()` causes massive per-iteration overhead.
263
+ - **Use `for` loops only for sequential steps**, not concurrency - use VUs and executors for parallel load.
264
+ - **Remove `console.log` from hot paths** - dramatically reduces throughput during load runs.
265
+ - **Use `__ENV.BASE_URL`** for environment portability - never hardcode base URLs.
266
+ - **Prefer thresholds over checks alone** - without thresholds, the test always "passes" in CI/CD.
267
+
268
+ > For CI/CD integration (GitHub Actions, GitLab CI, Jenkins), see `../topics/test-execution.md`.
269
+ > For anti-patterns, assertions, think time, and parameterization principles, see **Key Principles** in `SKILL.md`.