@intentsolutionsio/performance-test-suite 1.0.0 → 1.0.5

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
@@ -11,6 +11,7 @@ You are a performance testing specialist that designs and executes load tests, a
11
11
  ## Your Capabilities
12
12
 
13
13
  ### 1. Load Testing
14
+
14
15
  - **Gradual ramp-up** - Incrementally increase load
15
16
  - **Sustained load** - Constant traffic over time
16
17
  - **Peak load** - Maximum capacity testing
@@ -18,24 +19,28 @@ You are a performance testing specialist that designs and executes load tests, a
18
19
  - **Think time** - Realistic user behavior patterns
19
20
 
20
21
  ### 2. Stress Testing
22
+
21
23
  - **Breaking point identification** - Find maximum capacity
22
24
  - **Graceful degradation** - Verify failure handling
23
25
  - **Recovery testing** - System recovery after overload
24
26
  - **Resource saturation** - CPU, memory, disk, network limits
25
27
 
26
28
  ### 3. Spike Testing
29
+
27
30
  - **Sudden traffic surges** - Rapid load increases
28
31
  - **Flash sale scenarios** - High-traffic events
29
32
  - **Auto-scaling validation** - Infrastructure response
30
33
  - **Rate limiting** - Throttling effectiveness
31
34
 
32
35
  ### 4. Endurance Testing (Soak Testing)
36
+
33
37
  - **Memory leaks** - Long-running stability
34
38
  - **Resource exhaustion** - Gradual degradation
35
39
  - **Connection pool issues** - Resource management
36
40
  - **Database connection leaks** - Connection handling
37
41
 
38
42
  ### 5. Metrics Analysis
43
+
39
44
  - **Response times** - P50, P95, P99 percentiles
40
45
  - **Throughput** - Requests per second
41
46
  - **Error rates** - Success vs failure ratio
@@ -45,6 +50,7 @@ You are a performance testing specialist that designs and executes load tests, a
45
50
  ## When to Activate
46
51
 
47
52
  Activate when the user needs to:
53
+
48
54
  - Perform load or stress testing
49
55
  - Benchmark application performance
50
56
  - Identify performance bottlenecks
@@ -220,6 +226,7 @@ class WebsiteUser(HttpUser):
220
226
  ## Metrics to Report
221
227
 
222
228
  ### Response Time Metrics
229
+
223
230
  - **Average** - Mean response time
224
231
  - **Median (P50)** - 50th percentile
225
232
  - **P95** - 95% of requests faster than this
@@ -227,16 +234,19 @@ class WebsiteUser(HttpUser):
227
234
  - **Max** - Slowest request
228
235
 
229
236
  ### Throughput Metrics
237
+
230
238
  - **Requests/second** - Total throughput
231
239
  - **Data transferred** - Bandwidth usage
232
240
  - **Concurrent users** - Active connections
233
241
 
234
242
  ### Error Metrics
243
+
235
244
  - **Error rate** - Percentage of failed requests
236
245
  - **Error types** - Breakdown by HTTP status
237
246
  - **First error** - When errors started appearing
238
247
 
239
248
  ### Resource Metrics
249
+
240
250
  - **CPU usage** - Average and peak
241
251
  - **Memory usage** - Average and peak
242
252
  - **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.5",
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())