@intentsolutionsio/performance-test-suite 1.0.0 → 1.0.8

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/README.md CHANGED
@@ -64,6 +64,7 @@ export let options = {
64
64
  ```
65
65
 
66
66
  **Validates:**
67
+
67
68
  - Normal performance under expected load
68
69
  - Response times remain acceptable
69
70
  - Error rates stay low
@@ -87,6 +88,7 @@ export let options = {
87
88
  ```
88
89
 
89
90
  **Validates:**
91
+
90
92
  - Maximum capacity before failure
91
93
  - Graceful degradation under stress
92
94
  - Recovery after overload
@@ -109,6 +111,7 @@ export let options = {
109
111
  ```
110
112
 
111
113
  **Validates:**
114
+
112
115
  - Auto-scaling response
113
116
  - Rate limiting effectiveness
114
117
  - System stability during surge
@@ -130,6 +133,7 @@ export let options = {
130
133
  ```
131
134
 
132
135
  **Validates:**
136
+
133
137
  - Memory leaks over time
134
138
  - Resource exhaustion
135
139
  - Connection pool issues
@@ -165,24 +169,28 @@ export let options = {
165
169
  The agent identifies common performance issues:
166
170
 
167
171
  ### High CPU Usage
172
+
168
173
  - Inefficient algorithms
169
174
  - Missing caching
170
175
  - Excessive computations
171
176
  - Unoptimized loops
172
177
 
173
178
  ### High Memory Usage
179
+
174
180
  - Memory leaks
175
181
  - Large object retention
176
182
  - Inefficient data structures
177
183
  - Missing garbage collection
178
184
 
179
185
  ### Slow Database
186
+
180
187
  - N+1 query problems
181
188
  - Missing indexes
182
189
  - Inefficient queries
183
190
  - Connection pool exhaustion
184
191
 
185
192
  ### Network Saturation
193
+
186
194
  - Large response payloads
187
195
  - Missing compression
188
196
  - Too many requests
@@ -1,8 +1,35 @@
1
1
  ---
2
2
  name: performance-tester
3
- description: >
4
- Specialized agent for load testing, performance benchmarking, and
5
- bottleneck...
3
+ description: Specialized agent for load testing, performance benchmarking, and bottleneck...
4
+ tools:
5
+ - Read
6
+ - Write
7
+ - Edit
8
+ - Bash
9
+ - Glob
10
+ - Grep
11
+ - WebFetch
12
+ - WebSearch
13
+ - Task
14
+ - TodoWrite
15
+ model: sonnet
16
+ color: red
17
+ version: 1.0.0
18
+ author: Jeremy Longshore <jeremy@intentsolutions.io>
19
+ tags:
20
+ - testing
21
+ - performance
22
+ - tester
23
+ disallowedTools: []
24
+ skills: []
25
+ background: false
26
+ # ── upgrade levers — uncomment + set when tuning this agent ──
27
+ # effort: high # reasoning depth: low/medium/high/xhigh/max (omit = inherit session)
28
+ # maxTurns: 50 # cap the agentic loop (omit = engine default)
29
+ # memory: project # persistent scope: user/project/local (omit = ephemeral)
30
+ # isolation: worktree # run in an isolated git worktree
31
+ # initialPrompt: "…" # seed the agent's first turn
32
+ # hooks / mcpServers / permissionMode → set at the PLUGIN level, not on a plugin agent
6
33
  ---
7
34
  # Performance Test Suite Agent
8
35
 
@@ -11,6 +38,7 @@ You are a performance testing specialist that designs and executes load tests, a
11
38
  ## Your Capabilities
12
39
 
13
40
  ### 1. Load Testing
41
+
14
42
  - **Gradual ramp-up** - Incrementally increase load
15
43
  - **Sustained load** - Constant traffic over time
16
44
  - **Peak load** - Maximum capacity testing
@@ -18,24 +46,28 @@ You are a performance testing specialist that designs and executes load tests, a
18
46
  - **Think time** - Realistic user behavior patterns
19
47
 
20
48
  ### 2. Stress Testing
49
+
21
50
  - **Breaking point identification** - Find maximum capacity
22
51
  - **Graceful degradation** - Verify failure handling
23
52
  - **Recovery testing** - System recovery after overload
24
53
  - **Resource saturation** - CPU, memory, disk, network limits
25
54
 
26
55
  ### 3. Spike Testing
56
+
27
57
  - **Sudden traffic surges** - Rapid load increases
28
58
  - **Flash sale scenarios** - High-traffic events
29
59
  - **Auto-scaling validation** - Infrastructure response
30
60
  - **Rate limiting** - Throttling effectiveness
31
61
 
32
62
  ### 4. Endurance Testing (Soak Testing)
63
+
33
64
  - **Memory leaks** - Long-running stability
34
65
  - **Resource exhaustion** - Gradual degradation
35
66
  - **Connection pool issues** - Resource management
36
67
  - **Database connection leaks** - Connection handling
37
68
 
38
69
  ### 5. Metrics Analysis
70
+
39
71
  - **Response times** - P50, P95, P99 percentiles
40
72
  - **Throughput** - Requests per second
41
73
  - **Error rates** - Success vs failure ratio
@@ -45,6 +77,7 @@ You are a performance testing specialist that designs and executes load tests, a
45
77
  ## When to Activate
46
78
 
47
79
  Activate when the user needs to:
80
+
48
81
  - Perform load or stress testing
49
82
  - Benchmark application performance
50
83
  - Identify performance bottlenecks
@@ -220,6 +253,7 @@ class WebsiteUser(HttpUser):
220
253
  ## Metrics to Report
221
254
 
222
255
  ### Response Time Metrics
256
+
223
257
  - **Average** - Mean response time
224
258
  - **Median (P50)** - 50th percentile
225
259
  - **P95** - 95% of requests faster than this
@@ -227,16 +261,19 @@ class WebsiteUser(HttpUser):
227
261
  - **Max** - Slowest request
228
262
 
229
263
  ### Throughput Metrics
264
+
230
265
  - **Requests/second** - Total throughput
231
266
  - **Data transferred** - Bandwidth usage
232
267
  - **Concurrent users** - Active connections
233
268
 
234
269
  ### Error Metrics
270
+
235
271
  - **Error rate** - Percentage of failed requests
236
272
  - **Error types** - Breakdown by HTTP status
237
273
  - **First error** - When errors started appearing
238
274
 
239
275
  ### Resource Metrics
276
+
240
277
  - **CPU usage** - Average and peak
241
278
  - **Memory usage** - Average and peak
242
279
  - **Network I/O** - Bandwidth utilization
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentsolutionsio/performance-test-suite",
3
- "version": "1.0.0",
3
+ "version": "1.0.8",
4
4
  "description": "Load testing and performance benchmarking with metrics analysis and bottleneck identification",
5
5
  "keywords": [
6
6
  "testing",
@@ -1,16 +1,22 @@
1
1
  ---
2
2
  name: running-performance-tests
3
- description: |
4
- Execute load testing, stress testing, and performance benchmarking.
3
+ description: 'Execute load testing, stress testing, and performance benchmarking.
4
+
5
5
  Use when performing specialized testing.
6
- Trigger with phrases like "run load tests", "test performance", or "benchmark the system".
7
6
 
7
+ Trigger with phrases like "run load tests", "test performance", or "benchmark the
8
+ system".
9
+
10
+ '
8
11
  allowed-tools: Read, Write, Edit, Grep, Glob, Bash(test:perf-*)
9
12
  version: 1.0.0
10
13
  author: Jeremy Longshore <jeremy@intentsolutions.io>
11
14
  license: MIT
12
- compatible-with: claude-code, codex, openclaw
13
- tags: [testing, performance, performance-tests]
15
+ tags:
16
+ - testing
17
+ - performance
18
+ - performance-tests
19
+ compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
14
20
  ---
15
21
  # Performance Test Suite
16
22
 
@@ -79,6 +85,7 @@ Execute load testing, stress testing, and performance benchmarking to identify b
79
85
  ## Examples
80
86
 
81
87
  **k6 load test script:**
88
+
82
89
  ```javascript
83
90
  import http from 'k6/http';
84
91
  import { check, sleep } from 'k6';
@@ -107,6 +114,7 @@ export default function () {
107
114
  ```
108
115
 
109
116
  **Artillery test configuration:**
117
+
110
118
  ```yaml
111
119
  config:
112
120
  target: "https://api.test.com"
@@ -137,4 +145,4 @@ scenarios:
137
145
  - Locust (Python): https://docs.locust.io/
138
146
  - Apache JMeter: https://jmeter.apache.org/
139
147
  - autocannon (Node.js): https://github.com/mcollina/autocannon
140
- - Performance testing best practices: https://grafana.com/blog/2024/01/30/load-testing-best-practices/
148
+ - Performance testing best practices:
@@ -1,4 +1,3 @@
1
1
  # References
2
2
 
3
3
  Bundled resources for performance-test-suite skill
4
-
@@ -6,6 +6,6 @@ Bundled resources for performance-test-suite skill
6
6
  - [x] run_test.sh: Script to execute the performance test using k6 or other tools.
7
7
  - [x] analyze_results.py: Script to analyze the test results and generate a report.
8
8
 
9
-
10
9
  ## Auto-Generated
10
+
11
11
  Scripts generated on 2025-12-10 03:48:17
@@ -5,31 +5,25 @@ Script to analyze the test results and generate a report.
5
5
  Generated: 2025-12-10 03:48:17
6
6
  """
7
7
 
8
- import os
9
8
  import json
10
9
  import argparse
11
10
  from pathlib import Path
12
- from typing import Dict, List
11
+ from typing import Dict
13
12
  from datetime import datetime
14
13
 
14
+
15
15
  class Analyzer:
16
16
  def __init__(self, target_path: str):
17
17
  self.target_path = Path(target_path)
18
- self.stats = {
19
- 'total_files': 0,
20
- 'total_size': 0,
21
- 'file_types': {},
22
- 'issues': [],
23
- 'recommendations': []
24
- }
18
+ self.stats = {"total_files": 0, "total_size": 0, "file_types": {}, "issues": [], "recommendations": []}
25
19
 
26
20
  def analyze_directory(self) -> Dict:
27
21
  """Analyze directory structure and contents."""
28
22
  if not self.target_path.exists():
29
- self.stats['issues'].append(f"Path does not exist: {self.target_path}")
23
+ self.stats["issues"].append(f"Path does not exist: {self.target_path}")
30
24
  return self.stats
31
25
 
32
- for file_path in self.target_path.rglob('*'):
26
+ for file_path in self.target_path.rglob("*"):
33
27
  if file_path.is_file():
34
28
  self.analyze_file(file_path)
35
29
 
@@ -37,38 +31,38 @@ class Analyzer:
37
31
 
38
32
  def analyze_file(self, file_path: Path):
39
33
  """Analyze individual file."""
40
- self.stats['total_files'] += 1
41
- self.stats['total_size'] += file_path.stat().st_size
34
+ self.stats["total_files"] += 1
35
+ self.stats["total_size"] += file_path.stat().st_size
42
36
 
43
37
  # Track file types
44
38
  ext = file_path.suffix.lower()
45
39
  if ext:
46
- self.stats['file_types'][ext] = self.stats['file_types'].get(ext, 0) + 1
40
+ self.stats["file_types"][ext] = self.stats["file_types"].get(ext, 0) + 1
47
41
 
48
42
  # Check for potential issues
49
43
  if file_path.stat().st_size > 100 * 1024 * 1024: # 100MB
50
- self.stats['issues'].append(f"Large file: {file_path} ({file_path.stat().st_size // 1024 // 1024}MB)")
44
+ self.stats["issues"].append(f"Large file: {file_path} ({file_path.stat().st_size // 1024 // 1024}MB)")
51
45
 
52
46
  if file_path.stat().st_size == 0:
53
- self.stats['issues'].append(f"Empty file: {file_path}")
47
+ self.stats["issues"].append(f"Empty file: {file_path}")
54
48
 
55
49
  def generate_recommendations(self):
56
50
  """Generate recommendations based on analysis."""
57
- if self.stats['total_files'] == 0:
58
- self.stats['recommendations'].append("No files found - check target path")
51
+ if self.stats["total_files"] == 0:
52
+ self.stats["recommendations"].append("No files found - check target path")
59
53
 
60
- if len(self.stats['file_types']) > 20:
61
- self.stats['recommendations'].append("Many file types detected - consider organizing")
54
+ if len(self.stats["file_types"]) > 20:
55
+ self.stats["recommendations"].append("Many file types detected - consider organizing")
62
56
 
63
- if self.stats['total_size'] > 1024 * 1024 * 1024: # 1GB
64
- self.stats['recommendations'].append("Large total size - consider archiving old data")
57
+ if self.stats["total_size"] > 1024 * 1024 * 1024: # 1GB
58
+ self.stats["recommendations"].append("Large total size - consider archiving old data")
65
59
 
66
60
  def generate_report(self) -> str:
67
61
  """Generate analysis report."""
68
62
  report = []
69
- report.append("\n" + "="*60)
70
- report.append(f"ANALYSIS REPORT - performance-test-suite")
71
- report.append("="*60)
63
+ report.append("\n" + "=" * 60)
64
+ report.append("ANALYSIS REPORT - performance-test-suite")
65
+ report.append("=" * 60)
72
66
  report.append(f"Target: {self.target_path}")
73
67
  report.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
74
68
  report.append("")
@@ -80,34 +74,35 @@ class Analyzer:
80
74
  report.append(f" File Types: {len(self.stats['file_types'])}")
81
75
 
82
76
  # Top file types
83
- if self.stats['file_types']:
77
+ if self.stats["file_types"]:
84
78
  report.append("\n📁 TOP FILE TYPES")
85
- sorted_types = sorted(self.stats['file_types'].items(), key=lambda x: x[1], reverse=True)[:5]
79
+ sorted_types = sorted(self.stats["file_types"].items(), key=lambda x: x[1], reverse=True)[:5]
86
80
  for ext, count in sorted_types:
87
81
  report.append(f" {ext or 'no extension'}: {count} files")
88
82
 
89
83
  # Issues
90
- if self.stats['issues']:
84
+ if self.stats["issues"]:
91
85
  report.append(f"\n⚠️ ISSUES ({len(self.stats['issues'])})")
92
- for issue in self.stats['issues'][:10]:
86
+ for issue in self.stats["issues"][:10]:
93
87
  report.append(f" - {issue}")
94
- if len(self.stats['issues']) > 10:
88
+ if len(self.stats["issues"]) > 10:
95
89
  report.append(f" ... and {len(self.stats['issues']) - 10} more")
96
90
 
97
91
  # Recommendations
98
- if self.stats['recommendations']:
92
+ if self.stats["recommendations"]:
99
93
  report.append("\n💡 RECOMMENDATIONS")
100
- for rec in self.stats['recommendations']:
94
+ for rec in self.stats["recommendations"]:
101
95
  report.append(f" - {rec}")
102
96
 
103
97
  report.append("")
104
98
  return "\n".join(report)
105
99
 
100
+
106
101
  def main():
107
102
  parser = argparse.ArgumentParser(description="Script to analyze the test results and generate a report.")
108
- parser.add_argument('target', help='Target directory to analyze')
109
- parser.add_argument('--output', '-o', help='Output report file')
110
- parser.add_argument('--json', action='store_true', help='Output as JSON')
103
+ parser.add_argument("target", help="Target directory to analyze")
104
+ parser.add_argument("--output", "-o", help="Output report file")
105
+ parser.add_argument("--json", action="store_true", help="Output as JSON")
111
106
 
112
107
  args = parser.parse_args()
113
108
 
@@ -127,8 +122,10 @@ def main():
127
122
  else:
128
123
  print(output)
129
124
 
130
- return 0 if len(stats['issues']) == 0 else 1
125
+ return 0 if len(stats["issues"]) == 0 else 1
126
+
131
127
 
132
128
  if __name__ == "__main__":
133
129
  import sys
130
+
134
131
  sys.exit(main())
@@ -5,23 +5,17 @@ Script to initialize a performance test based on user input.
5
5
  Generated: 2025-12-10 03:48:17
6
6
  """
7
7
 
8
- import os
9
8
  import json
10
9
  import argparse
11
10
  from pathlib import Path
12
11
 
12
+
13
13
  def create_project_structure(project_name: str, output_dir: str = "."):
14
14
  """Create project structure for performance-test-suite."""
15
15
  base_path = Path(output_dir) / project_name
16
16
 
17
17
  # Create directories
18
- directories = [
19
- base_path,
20
- base_path / "config",
21
- base_path / "data",
22
- base_path / "output",
23
- base_path / "logs"
24
- ]
18
+ directories = [base_path, base_path / "config", base_path / "data", base_path / "output", base_path / "logs"]
25
19
 
26
20
  for dir_path in directories:
27
21
  dir_path.mkdir(parents=True, exist_ok=True)
@@ -33,16 +27,12 @@ def create_project_structure(project_name: str, output_dir: str = "."):
33
27
  "version": "1.0.0",
34
28
  "skill": "performance-test-suite",
35
29
  "category": "testing",
36
- "created": time.strftime('%Y-%m-%d %H:%M:%S'),
37
- "settings": {
38
- "debug": False,
39
- "verbose": True,
40
- "max_workers": 4
41
- }
30
+ "created": time.strftime("%Y-%m-%d %H:%M:%S"),
31
+ "settings": {"debug": False, "verbose": True, "max_workers": 4},
42
32
  }
43
33
 
44
34
  config_file = base_path / "config" / "settings.json"
45
- with open(config_file, 'w') as f:
35
+ with open(config_file, "w") as f:
46
36
  json.dump(config, f, indent=2)
47
37
  print(f"✓ Created configuration: {config_file}")
48
38
 
@@ -67,11 +57,12 @@ See skill documentation for usage instructions.
67
57
 
68
58
  return base_path
69
59
 
60
+
70
61
  def main():
71
62
  parser = argparse.ArgumentParser(description="Script to initialize a performance test based on user input.")
72
- parser.add_argument('--project', '-p', required=True, help='Project name')
73
- parser.add_argument('--output', '-o', default='.', help='Output directory')
74
- parser.add_argument('--config', '-c', help='Configuration file')
63
+ parser.add_argument("--project", "-p", required=True, help="Project name")
64
+ parser.add_argument("--output", "-o", default=".", help="Output directory")
65
+ parser.add_argument("--config", "-c", help="Configuration file")
75
66
 
76
67
  args = parser.parse_args()
77
68
 
@@ -82,13 +73,15 @@ def main():
82
73
  # Load additional configuration
83
74
  if Path(args.config).exists():
84
75
  with open(args.config) as f:
85
- extra_config = json.load(f)
76
+ json.load(f)
86
77
  print(f"✓ Loaded configuration from {args.config}")
87
78
 
88
79
  print(f"\n✅ Project initialized successfully at {project_path}")
89
80
  return 0
90
81
 
82
+
91
83
  if __name__ == "__main__":
92
84
  import sys
93
85
  import time
86
+
94
87
  sys.exit(main())
@@ -5,12 +5,11 @@ Script to execute the performance test using k6 or other tools.
5
5
  Generated: 2025-12-10 03:48:17
6
6
  """
7
7
 
8
- import os
9
8
  import sys
10
9
  import json
11
10
  import argparse
12
11
  from pathlib import Path
13
- from datetime import datetime
12
+
14
13
 
15
14
  def process_file(file_path: Path) -> bool:
16
15
  """Process individual file."""
@@ -24,7 +23,7 @@ def process_file(file_path: Path) -> bool:
24
23
  # This is a template that can be customized
25
24
 
26
25
  try:
27
- if file_path.suffix == '.json':
26
+ if file_path.suffix == ".json":
28
27
  with open(file_path) as f:
29
28
  data = json.load(f)
30
29
  print(f" ✓ Valid JSON with {len(data)} keys")
@@ -37,12 +36,13 @@ def process_file(file_path: Path) -> bool:
37
36
  print(f" ✗ Error: {e}")
38
37
  return False
39
38
 
39
+
40
40
  def process_directory(dir_path: Path) -> int:
41
41
  """Process all files in directory."""
42
42
  processed = 0
43
43
  failed = 0
44
44
 
45
- for file_path in dir_path.rglob('*'):
45
+ for file_path in dir_path.rglob("*"):
46
46
  if file_path.is_file():
47
47
  if process_file(file_path):
48
48
  processed += 1
@@ -51,28 +51,27 @@ def process_directory(dir_path: Path) -> int:
51
51
 
52
52
  return processed, failed
53
53
 
54
+
54
55
  def main():
55
- parser = argparse.ArgumentParser(
56
- description="Script to execute the performance test using k6 or other tools."
57
- )
58
- parser.add_argument('input', help='Input file or directory')
59
- parser.add_argument('--output', '-o', help='Output directory')
60
- parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output')
61
- parser.add_argument('--config', '-c', help='Configuration file')
56
+ parser = argparse.ArgumentParser(description="Script to execute the performance test using k6 or other tools.")
57
+ parser.add_argument("input", help="Input file or directory")
58
+ parser.add_argument("--output", "-o", help="Output directory")
59
+ parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
60
+ parser.add_argument("--config", "-c", help="Configuration file")
62
61
 
63
62
  args = parser.parse_args()
64
63
 
65
64
  input_path = Path(args.input)
66
65
 
67
- print(f"🚀 performance-test-suite - run_test.sh")
68
- print(f" Category: testing")
69
- print(f" Plugin: performance-test-suite")
66
+ print("🚀 performance-test-suite - run_test.sh")
67
+ print(" Category: testing")
68
+ print(" Plugin: performance-test-suite")
70
69
  print(f" Input: {input_path}")
71
70
 
72
71
  if args.config:
73
72
  if Path(args.config).exists():
74
73
  with open(args.config) as f:
75
- config = json.load(f)
74
+ json.load(f)
76
75
  print(f" Config: {args.config}")
77
76
 
78
77
  # Process input
@@ -81,7 +80,7 @@ def main():
81
80
  result = 0 if success else 1
82
81
  elif input_path.is_dir():
83
82
  processed, failed = process_directory(input_path)
84
- print(f"\n📊 SUMMARY")
83
+ print("\n📊 SUMMARY")
85
84
  print(f" ✅ Processed: {processed}")
86
85
  print(f" ❌ Failed: {failed}")
87
86
  result = 0 if failed == 0 else 1
@@ -96,5 +95,6 @@ def main():
96
95
 
97
96
  return result
98
97
 
98
+
99
99
  if __name__ == "__main__":
100
100
  sys.exit(main())