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.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +2 -1
- package/package.json +2 -2
- package/skills/perf/SKILL.md +228 -72
- package/skills/perf/evals/evals.json +149 -0
- package/skills/perf/references/tools/gatling.md +286 -286
- package/skills/perf/references/tools/jmeter.md +251 -251
- package/skills/perf/references/tools/k6.md +269 -269
- package/skills/perf/references/tools/locust.md +133 -133
- package/skills/perf/references/topics/correlation.md +406 -0
- package/skills/perf/references/topics/database-testing.md +8 -8
- package/skills/perf/references/topics/modern-architectures.md +15 -15
- package/skills/perf/references/topics/observability.md +3 -3
- package/skills/perf/references/topics/production-testing.md +13 -13
- package/skills/perf/references/topics/protocol-testing.md +15 -15
- package/skills/perf/references/topics/results-analysis.md +13 -13
- package/skills/perf/references/topics/script-generation.md +9 -9
- package/skills/perf/references/topics/test-data.md +6 -6
- package/skills/perf/references/topics/test-execution.md +5 -5
- package/skills/perf/references/topics/workload-design.md +3 -3
|
@@ -1,133 +1,133 @@
|
|
|
1
|
-
# Locust Reference
|
|
2
|
-
|
|
3
|
-
> Targets: Locust 2.20+, Python 3.9+
|
|
4
|
-
|
|
5
|
-
Locust is a Python-based, open-source load testing tool. Tests are plain Python code
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Core Concepts
|
|
10
|
-
|
|
11
|
-
| Concept | Description |
|
|
12
|
-
|---|---|
|
|
13
|
-
| **User class** | Defines behavior of a simulated user |
|
|
14
|
-
| **TaskSet** | Group of tasks; can be nested |
|
|
15
|
-
| **task decorator** | Marks a method as a task with optional weight |
|
|
16
|
-
| **wait_time** | Think time between tasks |
|
|
17
|
-
| **HttpUser** | Preconfigured User with HTTP client |
|
|
18
|
-
| **FastHttpUser** | High-performance HTTP client (gevent-based) |
|
|
19
|
-
| **events** | Hooks for setup, teardown, request success/failure |
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Basic Script
|
|
24
|
-
|
|
25
|
-
```python
|
|
26
|
-
from locust import HttpUser, task, between
|
|
27
|
-
import json, random
|
|
28
|
-
|
|
29
|
-
class ShopUser(HttpUser):
|
|
30
|
-
wait_time = between(1, 4) # Think time: 1–4 seconds (uniform random)
|
|
31
|
-
host = "https://api.example.com"
|
|
32
|
-
|
|
33
|
-
def on_start(self):
|
|
34
|
-
"""Runs once per VU at startup"""
|
|
35
|
-
res = self.client.post("/auth/login", json={
|
|
36
|
-
"username": f"user{random.randint(1, 1000)}@test.com",
|
|
37
|
-
"password": "testpass123"
|
|
38
|
-
})
|
|
39
|
-
self.token = res.json()["access_token"]
|
|
40
|
-
self.client.headers.update({"Authorization": f"Bearer {self.token}"})
|
|
41
|
-
|
|
42
|
-
@task(3) # Weight: called 3x more than weight-1 tasks
|
|
43
|
-
def browse_products(self):
|
|
44
|
-
self.client.get("/products", name="GET /products")
|
|
45
|
-
|
|
46
|
-
@task(1)
|
|
47
|
-
def add_to_cart(self):
|
|
48
|
-
product_id = random.randint(1, 100)
|
|
49
|
-
with self.client.post(
|
|
50
|
-
f"/cart/items",
|
|
51
|
-
json={"productId": product_id, "qty": 1},
|
|
52
|
-
catch_response=True, # Manually handle response
|
|
53
|
-
name="POST /cart/items"
|
|
54
|
-
) as response:
|
|
55
|
-
if response.status_code == 200:
|
|
56
|
-
response.success()
|
|
57
|
-
else:
|
|
58
|
-
response.failure(f"Expected 200, got {response.status_code}")
|
|
59
|
-
|
|
60
|
-
def on_stop(self):
|
|
61
|
-
self.client.post("/auth/logout")
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Running Locust
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
# Web UI mode
|
|
70
|
-
locust -f locustfile.py --host https://api.example.com
|
|
71
|
-
|
|
72
|
-
# Headless (CLI) mode
|
|
73
|
-
locust -f locustfile.py \
|
|
74
|
-
--headless \
|
|
75
|
-
--users 100 \
|
|
76
|
-
--spawn-rate 10 \
|
|
77
|
-
--run-time 5m \
|
|
78
|
-
--host https://api.example.com \
|
|
79
|
-
--html report.html \
|
|
80
|
-
--csv results
|
|
81
|
-
|
|
82
|
-
# Distributed mode
|
|
83
|
-
# On master:
|
|
84
|
-
locust -f locustfile.py --master --users 1000 --spawn-rate 50
|
|
85
|
-
# On each worker:
|
|
86
|
-
locust -f locustfile.py --worker --master-host=<master-ip>
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## Custom Wait Times
|
|
92
|
-
|
|
93
|
-
```python
|
|
94
|
-
from locust import constant, constant_pacing, between, constant_throughput
|
|
95
|
-
|
|
96
|
-
wait_time = between(1, 5) # Uniform random 1–5s
|
|
97
|
-
wait_time = constant(2) # Fixed 2s
|
|
98
|
-
wait_time = constant_pacing(10) # Paces to 1 iteration per 10s (handles slow responses)
|
|
99
|
-
wait_time = constant_throughput(0.1) # Target 0.1 RPS per VU (10s average)
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## Custom Events and Hooks
|
|
105
|
-
|
|
106
|
-
```python
|
|
107
|
-
from locust import events
|
|
108
|
-
|
|
109
|
-
@events.test_start.add_listener
|
|
110
|
-
def on_test_start(environment, **kwargs):
|
|
111
|
-
print("Test starting
|
|
112
|
-
|
|
113
|
-
@events.request.add_listener
|
|
114
|
-
def on_request(request_type, name, response_time, response_length, exception, **kwargs):
|
|
115
|
-
if exception:
|
|
116
|
-
print(f"FAILED: {name}
|
|
117
|
-
|
|
118
|
-
@events.test_stop.add_listener
|
|
119
|
-
def on_test_stop(environment, **kwargs):
|
|
120
|
-
print("Test finished
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## Locust-Specific Tips
|
|
126
|
-
|
|
127
|
-
- Always use `name=` parameter to group parameterized URLs (e.g., `/products/123` → `name="GET /products/{id}"`).
|
|
128
|
-
- Use `catch_response=True` for custom validation
|
|
129
|
-
- Use `FastHttpUser` instead of `HttpUser` for CPU-bound or high-throughput scenarios.
|
|
130
|
-
- Use distributed mode above 500–1000 VUs
|
|
131
|
-
|
|
132
|
-
> For anti-patterns, assertions, think time, and parameterization principles, see **Key Principles** in `SKILL.md`.
|
|
133
|
-
> For CI/CD integration and distributed execution details, see `../topics/test-execution.md`.
|
|
1
|
+
# Locust Reference
|
|
2
|
+
|
|
3
|
+
> Targets: Locust 2.20+, Python 3.9+
|
|
4
|
+
|
|
5
|
+
Locust is a Python-based, open-source load testing tool. Tests are plain Python code - no DSL, no XML. It supports distributed testing and has a built-in web UI.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Core Concepts
|
|
10
|
+
|
|
11
|
+
| Concept | Description |
|
|
12
|
+
|---|---|
|
|
13
|
+
| **User class** | Defines behavior of a simulated user |
|
|
14
|
+
| **TaskSet** | Group of tasks; can be nested |
|
|
15
|
+
| **task decorator** | Marks a method as a task with optional weight |
|
|
16
|
+
| **wait_time** | Think time between tasks |
|
|
17
|
+
| **HttpUser** | Preconfigured User with HTTP client |
|
|
18
|
+
| **FastHttpUser** | High-performance HTTP client (gevent-based) |
|
|
19
|
+
| **events** | Hooks for setup, teardown, request success/failure |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Basic Script
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from locust import HttpUser, task, between
|
|
27
|
+
import json, random
|
|
28
|
+
|
|
29
|
+
class ShopUser(HttpUser):
|
|
30
|
+
wait_time = between(1, 4) # Think time: 1–4 seconds (uniform random)
|
|
31
|
+
host = "https://api.example.com"
|
|
32
|
+
|
|
33
|
+
def on_start(self):
|
|
34
|
+
"""Runs once per VU at startup"""
|
|
35
|
+
res = self.client.post("/auth/login", json={
|
|
36
|
+
"username": f"user{random.randint(1, 1000)}@test.com",
|
|
37
|
+
"password": "testpass123"
|
|
38
|
+
})
|
|
39
|
+
self.token = res.json()["access_token"]
|
|
40
|
+
self.client.headers.update({"Authorization": f"Bearer {self.token}"})
|
|
41
|
+
|
|
42
|
+
@task(3) # Weight: called 3x more than weight-1 tasks
|
|
43
|
+
def browse_products(self):
|
|
44
|
+
self.client.get("/products", name="GET /products")
|
|
45
|
+
|
|
46
|
+
@task(1)
|
|
47
|
+
def add_to_cart(self):
|
|
48
|
+
product_id = random.randint(1, 100)
|
|
49
|
+
with self.client.post(
|
|
50
|
+
f"/cart/items",
|
|
51
|
+
json={"productId": product_id, "qty": 1},
|
|
52
|
+
catch_response=True, # Manually handle response
|
|
53
|
+
name="POST /cart/items"
|
|
54
|
+
) as response:
|
|
55
|
+
if response.status_code == 200:
|
|
56
|
+
response.success()
|
|
57
|
+
else:
|
|
58
|
+
response.failure(f"Expected 200, got {response.status_code}")
|
|
59
|
+
|
|
60
|
+
def on_stop(self):
|
|
61
|
+
self.client.post("/auth/logout")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Running Locust
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Web UI mode
|
|
70
|
+
locust -f locustfile.py --host https://api.example.com
|
|
71
|
+
|
|
72
|
+
# Headless (CLI) mode
|
|
73
|
+
locust -f locustfile.py \
|
|
74
|
+
--headless \
|
|
75
|
+
--users 100 \
|
|
76
|
+
--spawn-rate 10 \
|
|
77
|
+
--run-time 5m \
|
|
78
|
+
--host https://api.example.com \
|
|
79
|
+
--html report.html \
|
|
80
|
+
--csv results
|
|
81
|
+
|
|
82
|
+
# Distributed mode
|
|
83
|
+
# On master:
|
|
84
|
+
locust -f locustfile.py --master --users 1000 --spawn-rate 50
|
|
85
|
+
# On each worker:
|
|
86
|
+
locust -f locustfile.py --worker --master-host=<master-ip>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Custom Wait Times
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from locust import constant, constant_pacing, between, constant_throughput
|
|
95
|
+
|
|
96
|
+
wait_time = between(1, 5) # Uniform random 1–5s
|
|
97
|
+
wait_time = constant(2) # Fixed 2s
|
|
98
|
+
wait_time = constant_pacing(10) # Paces to 1 iteration per 10s (handles slow responses)
|
|
99
|
+
wait_time = constant_throughput(0.1) # Target 0.1 RPS per VU (10s average)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Custom Events and Hooks
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from locust import events
|
|
108
|
+
|
|
109
|
+
@events.test_start.add_listener
|
|
110
|
+
def on_test_start(environment, **kwargs):
|
|
111
|
+
print("Test starting - seeding test data")
|
|
112
|
+
|
|
113
|
+
@events.request.add_listener
|
|
114
|
+
def on_request(request_type, name, response_time, response_length, exception, **kwargs):
|
|
115
|
+
if exception:
|
|
116
|
+
print(f"FAILED: {name} - {exception}")
|
|
117
|
+
|
|
118
|
+
@events.test_stop.add_listener
|
|
119
|
+
def on_test_stop(environment, **kwargs):
|
|
120
|
+
print("Test finished - cleaning up data")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Locust-Specific Tips
|
|
126
|
+
|
|
127
|
+
- Always use `name=` parameter to group parameterized URLs (e.g., `/products/123` → `name="GET /products/{id}"`).
|
|
128
|
+
- Use `catch_response=True` for custom validation - HTTP 200 with error body passes silently otherwise.
|
|
129
|
+
- Use `FastHttpUser` instead of `HttpUser` for CPU-bound or high-throughput scenarios.
|
|
130
|
+
- Use distributed mode above 500–1000 VUs - a single worker process saturates one CPU core.
|
|
131
|
+
|
|
132
|
+
> For anti-patterns, assertions, think time, and parameterization principles, see **Key Principles** in `SKILL.md`.
|
|
133
|
+
> For CI/CD integration and distributed execution details, see `../topics/test-execution.md`.
|