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,22 +1,22 @@
1
1
  # Protocol-Specific Performance Testing
2
2
 
3
- Covers gRPC, GraphQL, WebSocket/SSE, and message queue (Kafka, RabbitMQ, SQS) load testing — protocols with unique challenges beyond standard HTTP/REST.
3
+ Covers gRPC, GraphQL, WebSocket/SSE, and message queue (Kafka, RabbitMQ, SQS) load testing - protocols with unique challenges beyond standard HTTP/REST.
4
4
 
5
5
  ---
6
6
 
7
7
  ## gRPC Performance Testing
8
8
 
9
- gRPC uses HTTP/2, Protocol Buffers, and persistent connections — fundamentally different from REST at the wire level.
9
+ gRPC uses HTTP/2, Protocol Buffers, and persistent connections - fundamentally different from REST at the wire level.
10
10
 
11
11
  ### Key Challenges
12
12
 
13
13
  | Challenge | Why It Matters |
14
14
  |---|---|
15
15
  | **Protobuf compilation** | Tests require compiled `.proto` definitions; can't just send raw JSON |
16
- | **Connection multiplexing** | HTTP/2 multiplexes streams over a single connection — fewer connections needed but different bottleneck profile |
16
+ | **Connection multiplexing** | HTTP/2 multiplexes streams over a single connection - fewer connections needed but different bottleneck profile |
17
17
  | **Streaming** | Unary, server-streaming, client-streaming, and bidirectional-streaming each need different test strategies |
18
18
  | **Metadata vs headers** | gRPC metadata is the equivalent of HTTP headers; auth tokens go here |
19
- | **Error codes** | gRPC uses its own status codes (OK, UNAVAILABLE, DEADLINE_EXCEEDED) — not HTTP status codes |
19
+ | **Error codes** | gRPC uses its own status codes (OK, UNAVAILABLE, DEADLINE_EXCEEDED) - not HTTP status codes |
20
20
 
21
21
  ### Tool Support
22
22
 
@@ -58,14 +58,14 @@ export default function () {
58
58
  - **Connection reuse**: Keep connections open across iterations; don't connect/close per request.
59
59
  - **Streaming throughput**: For server-streaming RPCs, measure messages-per-second, not just request latency.
60
60
  - **Deadline propagation**: Set gRPC deadlines in tests to match production timeouts.
61
- - **Load balancer awareness**: gRPC over HTTP/2 with persistent connections can cause uneven load across backends — test with client-side load balancing or L7 proxy.
62
- - **Protobuf payload size**: Binary encoding is smaller than JSON — adjust throughput expectations accordingly.
61
+ - **Load balancer awareness**: gRPC over HTTP/2 with persistent connections can cause uneven load across backends - test with client-side load balancing or L7 proxy.
62
+ - **Protobuf payload size**: Binary encoding is smaller than JSON - adjust throughput expectations accordingly.
63
63
 
64
64
  ---
65
65
 
66
66
  ## GraphQL Performance Testing
67
67
 
68
- GraphQL introduces query complexity as a variable — the same endpoint can serve trivially cheap or devastatingly expensive requests.
68
+ GraphQL introduces query complexity as a variable - the same endpoint can serve trivially cheap or devastatingly expensive requests.
69
69
 
70
70
  ### Key Challenges
71
71
 
@@ -79,7 +79,7 @@ GraphQL introduces query complexity as a variable — the same endpoint can serv
79
79
 
80
80
  ### Testing Strategy
81
81
 
82
- 1. **Catalog production queries**: Extract real queries from logs or APM traces — don't invent synthetic queries.
82
+ 1. **Catalog production queries**: Extract real queries from logs or APM traces - don't invent synthetic queries.
83
83
  2. **Categorize by cost**: Light (single field), medium (nested 2 levels), heavy (deep joins, lists).
84
84
  3. **Build a realistic query mix**: Weight tests by actual production query distribution.
85
85
  4. **Test with and without caching**: GraphQL caching (DataLoader, CDN) dramatically changes performance profiles.
@@ -136,7 +136,7 @@ Persistent connections have fundamentally different scaling characteristics from
136
136
 
137
137
  | Challenge | Why It Matters |
138
138
  |---|---|
139
- | **Connection count** | Each VU holds an open connection — tests memory/fd limits, not just CPU |
139
+ | **Connection count** | Each VU holds an open connection - tests memory/fd limits, not just CPU |
140
140
  | **Message throughput** | Measure messages/sec independently from connection count |
141
141
  | **Backpressure** | What happens when the server can't send fast enough? |
142
142
  | **Reconnection behavior** | Dropped connections should auto-reconnect; test the reconnect storm |
@@ -194,7 +194,7 @@ export default function () {
194
194
 
195
195
  ### WebSocket Testing Strategy
196
196
 
197
- 1. **Connection ramp**: Gradually open connections — don't blast 10k connections at once.
197
+ 1. **Connection ramp**: Gradually open connections - don't blast 10k connections at once.
198
198
  2. **Separate connection test from message test**: First, find max stable connections; then test message throughput at a stable connection count.
199
199
  3. **Measure server-side**: File descriptor count, memory per connection, event loop lag.
200
200
  4. **Test reconnection storms**: Kill server, observe client reconnection behavior and server recovery.
@@ -211,7 +211,7 @@ Testing Kafka, RabbitMQ, SQS, and similar systems requires measuring producer th
211
211
  |---|---|
212
212
  | **Producer throughput** | Messages/sec the system can ingest |
213
213
  | **Consumer lag** | How far behind consumers fall under load |
214
- | **End-to-end latency** | Time from produce to consume — the real user-facing metric |
214
+ | **End-to-end latency** | Time from produce to consume - the real user-facing metric |
215
215
  | **Partition scaling** | Kafka throughput scales with partitions; test with realistic partition counts |
216
216
  | **Message ordering** | Under load, verify ordering guarantees still hold |
217
217
  | **Dead letter queues** | Verify failed messages route correctly under pressure |
@@ -256,10 +256,10 @@ export function teardown() {
256
256
  ### Message Queue Testing Strategy
257
257
 
258
258
  1. **Test producers and consumers separately first**, then together.
259
- 2. **Measure consumer lag over time** — a growing lag under steady load indicates a bottleneck.
260
- 3. **Test with realistic message sizes** — a 100-byte message vs a 1MB payload have very different throughput ceilings.
261
- 4. **Verify idempotency** — under load with retries, duplicate messages should not corrupt state.
262
- 5. **Test partition rebalancing** — add/remove consumers during a test to verify rebalance behavior.
259
+ 2. **Measure consumer lag over time** - a growing lag under steady load indicates a bottleneck.
260
+ 3. **Test with realistic message sizes** - a 100-byte message vs a 1MB payload have very different throughput ceilings.
261
+ 4. **Verify idempotency** - under load with retries, duplicate messages should not corrupt state.
262
+ 5. **Test partition rebalancing** - add/remove consumers during a test to verify rebalance behavior.
263
263
 
264
264
  ---
265
265
 
@@ -1,6 +1,6 @@
1
1
  # Results Analysis
2
2
 
3
- Interpreting performance test results is a skill in itself. Raw numbers are meaningless without context — this reference covers how to read, analyze, and act on performance data.
3
+ Interpreting performance test results is a skill in itself. Raw numbers are meaningless without context - this reference covers how to read, analyze, and act on performance data.
4
4
 
5
5
  ---
6
6
 
@@ -9,12 +9,12 @@ Interpreting performance test results is a skill in itself. Raw numbers are mean
9
9
  | Metric | Description | Target |
10
10
  |---|---|---|
11
11
  | **Throughput** | Requests per second (RPS / TPS) | ≥ defined baseline |
12
- | **Response Time (p50)** | Median — half of requests faster than this | Per SLA |
13
- | **Response Time (p95)** | 95% of requests faster than this — main SLA metric | Per SLA |
14
- | **Response Time (p99)** | Tail latency — reveals worst-case behavior | Per SLA |
12
+ | **Response Time (p50)** | Median - half of requests faster than this | Per SLA |
13
+ | **Response Time (p95)** | 95% of requests faster than this - main SLA metric | Per SLA |
14
+ | **Response Time (p99)** | Tail latency - reveals worst-case behavior | Per SLA |
15
15
  | **Error Rate** | % of failed requests | < 1% (or as defined) |
16
16
  | **Active VUs / Concurrency** | Number of simulated users at any point | Matches load profile |
17
- | **Network I/O** | Bytes/sec in and out — detects bandwidth bottlenecks | Headroom vs NIC capacity |
17
+ | **Network I/O** | Bytes/sec in and out - detects bandwidth bottlenecks | Headroom vs NIC capacity |
18
18
 
19
19
  ---
20
20
 
@@ -47,9 +47,9 @@ Example: 100 requests
47
47
  | Column | Meaning |
48
48
  |---|---|
49
49
  | # Samples | Total requests sent |
50
- | Average | Mean response time (ms) — use sparingly |
50
+ | Average | Mean response time (ms) - use sparingly |
51
51
  | Min / Max | Absolute floor and ceiling |
52
- | Std. Dev. | Variance — high deviation = inconsistent behavior |
52
+ | Std. Dev. | Variance - high deviation = inconsistent behavior |
53
53
  | Error % | Percentage of failed requests |
54
54
  | Throughput | Requests/second |
55
55
  | KB/sec | Network throughput |
@@ -57,11 +57,11 @@ Example: 100 requests
57
57
 
58
58
  ### HTML Dashboard
59
59
  Generated with `-e -o results/dashboard` flag. Key graphs:
60
- - **Response Time Over Time** — spot degradation trends
61
- - **Transactions Per Second** — confirm throughput matches expectation
62
- - **Response Time Percentiles** — see distribution
63
- - **Active Threads Over Time** — correlate with response time
64
- - **Errors Over Time** — when and what errors spike
60
+ - **Response Time Over Time** - spot degradation trends
61
+ - **Transactions Per Second** - confirm throughput matches expectation
62
+ - **Response Time Percentiles** - see distribution
63
+ - **Active Threads Over Time** - correlate with response time
64
+ - **Errors Over Time** - when and what errors spike
65
65
 
66
66
  ### JTL Analysis (programmatic)
67
67
  ```python
@@ -191,7 +191,7 @@ Sudden jump at a load threshold = system has hit a constraint (thread limit, DB
191
191
 
192
192
  ## Comparing Runs (Trend Analysis)
193
193
 
194
- Always compare the current run against a baseline — never evaluate a run in isolation.
194
+ Always compare the current run against a baseline - never evaluate a run in isolation.
195
195
 
196
196
  | Metric | Run 1 (Baseline) | Run 2 | Delta | Status |
197
197
  |---|---|---|---|---|
@@ -1,6 +1,6 @@
1
1
  # Script Generation & Best Practices
2
2
 
3
- This reference covers how to write robust, realistic, and maintainable performance test scripts — regardless of tool. Apply these principles to JMeter, k6, Gatling, Locust, or any other tool.
3
+ This reference covers how to write robust, realistic, and maintainable performance test scripts - regardless of tool. Apply these principles to JMeter, k6, Gatling, Locust, or any other tool.
4
4
 
5
5
  ---
6
6
 
@@ -55,7 +55,7 @@ Correlation is extracting a dynamic value from a response and using it in a subs
55
55
  ### Correlation debugging approach
56
56
  1. Run the script with 1 VU.
57
57
  2. Look for HTTP 4xx errors (especially 403 Forbidden, 422 Unprocessable Entity).
58
- 3. Check the request body/headers — is a token missing or stale?
58
+ 3. Check the request body/headers - is a token missing or stale?
59
59
  4. Use the tool's debug output or proxy (Fiddler, Charles) to inspect live traffic.
60
60
  5. Identify where the value appears in a *previous* response.
61
61
  6. Add an extractor at that response, reference the variable in the failing request.
@@ -64,14 +64,14 @@ Correlation is extracting a dynamic value from a response and using it in a subs
64
64
 
65
65
  ## Assertions (Why They're Non-Negotiable)
66
66
 
67
- Without assertions, your test might generate 1000 RPS of 404 responses or empty bodies — and your metrics will look "fine."
67
+ Without assertions, your test might generate 1000 RPS of 404 responses or empty bodies - and your metrics will look "fine."
68
68
 
69
69
  ### What to assert
70
- - **Status code** — the obvious one; but also check for 200s that contain error bodies.
71
- - **Response body** — key field exists and has expected value.
72
- - **Response time** — flag individual responses over SLA as failures.
73
- - **Response size** — detect truncated or empty bodies.
74
- - **Content-Type header** — ensure you got JSON, not an HTML error page.
70
+ - **Status code** - the obvious one; but also check for 200s that contain error bodies.
71
+ - **Response body** - key field exists and has expected value.
72
+ - **Response time** - flag individual responses over SLA as failures.
73
+ - **Response size** - detect truncated or empty bodies.
74
+ - **Content-Type header** - ensure you got JSON, not an HTML error page.
75
75
 
76
76
  ### Assertion layering
77
77
 
@@ -141,7 +141,7 @@ Most tools handle cookies automatically. Verify the Cookie Manager is enabled.
141
141
  1. Authenticate in `setup()` or `on_start()`.
142
142
  2. Store the token in session variables.
143
143
  3. Add as Authorization header to subsequent requests.
144
- 4. Handle token expiry — check for 401 responses and re-authenticate.
144
+ 4. Handle token expiry - check for 401 responses and re-authenticate.
145
145
 
146
146
  ```javascript
147
147
  // k6: handle token refresh
@@ -6,10 +6,10 @@ Test data is a first-class concern in performance testing. Bad data causes false
6
6
 
7
7
  ## Why Test Data Matters
8
8
 
9
- - **Authentication tokens** expire — hardcoded tokens fail within minutes.
9
+ - **Authentication tokens** expire - hardcoded tokens fail within minutes.
10
10
  - **Unique constraints** (email, username, order number) cause failures at concurrency > 1.
11
11
  - **State-dependent flows** (checkout, approval) require data in the right state before the test.
12
- - **Cache effects** — if 1000 VUs all hit the same product ID, cache hit rates are unrealistically high; spread data across IDs.
12
+ - **Cache effects** - if 1000 VUs all hit the same product ID, cache hit rates are unrealistically high; spread data across IDs.
13
13
 
14
14
  ---
15
15
 
@@ -17,7 +17,7 @@ Test data is a first-class concern in performance testing. Bad data causes false
17
17
 
18
18
  | Test Type | Data Strategy |
19
19
  |---|---|
20
- | Smoke (1 VU) | Minimal — single known-good user/record |
20
+ | Smoke (1 VU) | Minimal - single known-good user/record |
21
21
  | Load (realistic VUs) | Pool of pre-created users/records matching production volume |
22
22
  | Stress (pushing limits) | Large pool; no uniqueness conflicts |
23
23
  | Soak (hours) | Rotating/recyclable data; handle state cleanup |
@@ -78,7 +78,7 @@ TO '/tmp/users.csv' CSV HEADER;
78
78
  Best for: data that must be in a specific state per VU (unique cart, session, transaction).
79
79
 
80
80
  ```javascript
81
- // k6 setup() — run before VUs start
81
+ // k6 setup() - run before VUs start
82
82
  export function setup() {
83
83
  const orders = [];
84
84
  for (let i = 0; i < 200; i++) {
@@ -103,7 +103,7 @@ def on_start(self):
103
103
 
104
104
  ### Strategy 4: Faker / Synthetic Data Generation
105
105
 
106
- Best for: registration flows, profile creation, form submission — where each VU needs unique PII-like data.
106
+ Best for: registration flows, profile creation, form submission - where each VU needs unique PII-like data.
107
107
 
108
108
  ```python
109
109
  # Python (Locust or data generation script)
@@ -169,7 +169,7 @@ Each VU/iteration picks the next row. Ensures even distribution.
169
169
  Better for cache-busting tests where you want realistic cache miss rates.
170
170
 
171
171
  ### Unique-Per-VU
172
- Each VU gets a dedicated row — critical for state-dependent flows (user owns specific order). Use VU index (`__VU` in k6, `${__threadNum}` in JMeter) to deterministically select a row.
172
+ Each VU gets a dedicated row - critical for state-dependent flows (user owns specific order). Use VU index (`__VU` in k6, `${__threadNum}` in JMeter) to deterministically select a row.
173
173
 
174
174
  ```javascript
175
175
  // k6: VU-indexed data
@@ -1,6 +1,6 @@
1
1
  # Test Execution
2
2
 
3
- Covers how to run performance tests reliably — locally, in CI/CD pipelines, distributed across injectors, and in the cloud.
3
+ Covers how to run performance tests reliably - locally, in CI/CD pipelines, distributed across injectors, and in the cloud.
4
4
 
5
5
  ---
6
6
 
@@ -19,7 +19,7 @@ Covers how to run performance tests reliably — locally, in CI/CD pipelines, di
19
19
 
20
20
  - Always use **non-GUI / headless mode** for actual load runs (GUI mode adds overhead).
21
21
  - Run scripts from the same network segment as the system under test when possible.
22
- - Monitor injector machine resources during the test — if CPU/memory of the injector saturates, results are invalid.
22
+ - Monitor injector machine resources during the test - if CPU/memory of the injector saturates, results are invalid.
23
23
  - Set JVM heap appropriately for JMeter: `JVM_ARGS="-Xms2g -Xmx4g" jmeter -n -t test.jmx`
24
24
 
25
25
  ---
@@ -47,7 +47,7 @@ remote_hosts=injector-1:1099,injector-2:1099,injector-3:1099
47
47
  jmeter -n -t test.jmx -r -l results.jtl -Jthreads=300 -Jduration=600
48
48
  ```
49
49
 
50
- **Ports to open:** 1099 (RMI control), 50000+ (dynamic data ports) — firewall rules critical.
50
+ **Ports to open:** 1099 (RMI control), 50000+ (dynamic data ports) - firewall rules critical.
51
51
 
52
52
  **Scaling:** Each injector can typically handle 300–500 VUs for HTTP at moderate response times. For 10k VUs, plan 20–30 injectors.
53
53
 
@@ -136,7 +136,7 @@ Code PR → Build → Unit/Integration Tests → [Performance Gate] →
136
136
  └─ PASS → Deploy / FAIL → Block
137
137
  ```
138
138
 
139
- ### GitHub Actions — k6
139
+ ### GitHub Actions - k6
140
140
 
141
141
  ```yaml
142
142
  name: Performance Gate
@@ -183,7 +183,7 @@ jobs:
183
183
  # For additional reporting, parse results.json here
184
184
  ```
185
185
 
186
- ### GitHub Actions — JMeter
186
+ ### GitHub Actions - JMeter
187
187
 
188
188
  ```yaml
189
189
  - name: Run JMeter Tests
@@ -1,6 +1,6 @@
1
1
  # Workload Design
2
2
 
3
- Workload design is the most impactful phase of performance testing. A poorly designed workload produces results that are irrelevant to production behavior — no matter how well-scripted the test is.
3
+ Workload design is the most impactful phase of performance testing. A poorly designed workload produces results that are irrelevant to production behavior - no matter how well-scripted the test is.
4
4
 
5
5
  ---
6
6
 
@@ -153,7 +153,7 @@ Every test must have explicit, measurable SLA targets before execution. Negotiat
153
153
  | Max response time | < 5,000ms |
154
154
 
155
155
  **Why percentiles matter more than averages:**
156
- Average response time hides outliers. p95 tells you what 95% of users experience — averages can look fine while 10% of users timeout.
156
+ Average response time hides outliers. p95 tells you what 95% of users experience - averages can look fine while 10% of users timeout.
157
157
 
158
158
  ---
159
159
 
@@ -185,7 +185,7 @@ Pacing is used when you want `N` iterations per hour per VU regardless of respon
185
185
 
186
186
  ## Ramp-Up Strategy
187
187
 
188
- Bad ramp-up causes a "thundering herd" — thousands of VUs hitting the server simultaneously, warming up connection pools, JVM, and caches all at once. This is unrealistic and produces misleading results.
188
+ Bad ramp-up causes a "thundering herd" - thousands of VUs hitting the server simultaneously, warming up connection pools, JVM, and caches all at once. This is unrealistic and produces misleading results.
189
189
 
190
190
  **Good ramp-up:**
191
191
  - Rule of thumb: Ramp to 100% over at least 5–10 minutes for large tests.