vaspera 2.10.0 → 2.10.1
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/dist/__tests__/scanners/ai-code/ai-detector.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.js +188 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.js +363 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.js +226 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/index.test.js +214 -0
- package/dist/__tests__/scanners/ai-code/index.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.js +67 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/index.test.js +84 -0
- package/dist/__tests__/scanners/deploy/index.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.js +88 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/types.test.js +126 -0
- package/dist/__tests__/scanners/deploy/types.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-feedback.test.js +1 -1
- package/dist/__tests__/scanners/fp-feedback.test.js.map +1 -1
- package/dist/__tests__/scanners/fp-tracker.test.js +1 -1
- package/dist/__tests__/scanners/fp-tracker.test.js.map +1 -1
- package/dist/__tests__/scanners/runtime/app-launcher.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.js +94 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.js +195 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/index.test.js +120 -0
- package/dist/__tests__/scanners/runtime/index.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/types.test.js +126 -0
- package/dist/__tests__/scanners/runtime/types.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.js +187 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/index.test.js +87 -0
- package/dist/__tests__/scanners/scale/index.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.js +122 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/types.test.js +129 -0
- package/dist/__tests__/scanners/scale/types.test.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +874 -0
- package/dist/index.js.map +1 -1
- package/dist/install-skills.d.ts +11 -0
- package/dist/install-skills.d.ts.map +1 -0
- package/dist/install-skills.js +81 -0
- package/dist/install-skills.js.map +1 -0
- package/dist/scanners/ai-code/ai-detector.d.ts +25 -0
- package/dist/scanners/ai-code/ai-detector.d.ts.map +1 -0
- package/dist/scanners/ai-code/ai-detector.js +192 -0
- package/dist/scanners/ai-code/ai-detector.js.map +1 -0
- package/dist/scanners/ai-code/confidence-scorer.d.ts +40 -0
- package/dist/scanners/ai-code/confidence-scorer.d.ts.map +1 -0
- package/dist/scanners/ai-code/confidence-scorer.js +148 -0
- package/dist/scanners/ai-code/confidence-scorer.js.map +1 -0
- package/dist/scanners/ai-code/hallucination-checker.d.ts +36 -0
- package/dist/scanners/ai-code/hallucination-checker.d.ts.map +1 -0
- package/dist/scanners/ai-code/hallucination-checker.js +298 -0
- package/dist/scanners/ai-code/hallucination-checker.js.map +1 -0
- package/dist/scanners/ai-code/index.d.ts +30 -0
- package/dist/scanners/ai-code/index.d.ts.map +1 -0
- package/dist/scanners/ai-code/index.js +224 -0
- package/dist/scanners/ai-code/index.js.map +1 -0
- package/dist/scanners/ai-code/types.d.ts +192 -0
- package/dist/scanners/ai-code/types.d.ts.map +1 -0
- package/dist/scanners/ai-code/types.js +37 -0
- package/dist/scanners/ai-code/types.js.map +1 -0
- package/dist/scanners/deploy/health-checker.d.ts +38 -0
- package/dist/scanners/deploy/health-checker.d.ts.map +1 -0
- package/dist/scanners/deploy/health-checker.js +272 -0
- package/dist/scanners/deploy/health-checker.js.map +1 -0
- package/dist/scanners/deploy/index.d.ts +44 -0
- package/dist/scanners/deploy/index.d.ts.map +1 -0
- package/dist/scanners/deploy/index.js +208 -0
- package/dist/scanners/deploy/index.js.map +1 -0
- package/dist/scanners/deploy/provider-detector.d.ts +25 -0
- package/dist/scanners/deploy/provider-detector.d.ts.map +1 -0
- package/dist/scanners/deploy/provider-detector.js +177 -0
- package/dist/scanners/deploy/provider-detector.js.map +1 -0
- package/dist/scanners/deploy/types.d.ts +406 -0
- package/dist/scanners/deploy/types.d.ts.map +1 -0
- package/dist/scanners/deploy/types.js +58 -0
- package/dist/scanners/deploy/types.js.map +1 -0
- package/dist/scanners/deploy/vercel-integration.d.ts +52 -0
- package/dist/scanners/deploy/vercel-integration.d.ts.map +1 -0
- package/dist/scanners/deploy/vercel-integration.js +280 -0
- package/dist/scanners/deploy/vercel-integration.js.map +1 -0
- package/dist/scanners/runtime/app-launcher.d.ts +33 -0
- package/dist/scanners/runtime/app-launcher.d.ts.map +1 -0
- package/dist/scanners/runtime/app-launcher.js +419 -0
- package/dist/scanners/runtime/app-launcher.js.map +1 -0
- package/dist/scanners/runtime/golden-path-runner.d.ts +48 -0
- package/dist/scanners/runtime/golden-path-runner.d.ts.map +1 -0
- package/dist/scanners/runtime/golden-path-runner.js +373 -0
- package/dist/scanners/runtime/golden-path-runner.js.map +1 -0
- package/dist/scanners/runtime/index.d.ts +41 -0
- package/dist/scanners/runtime/index.d.ts.map +1 -0
- package/dist/scanners/runtime/index.js +164 -0
- package/dist/scanners/runtime/index.js.map +1 -0
- package/dist/scanners/runtime/playwright-executor.d.ts +50 -0
- package/dist/scanners/runtime/playwright-executor.d.ts.map +1 -0
- package/dist/scanners/runtime/playwright-executor.js +387 -0
- package/dist/scanners/runtime/playwright-executor.js.map +1 -0
- package/dist/scanners/runtime/types.d.ts +215 -0
- package/dist/scanners/runtime/types.d.ts.map +1 -0
- package/dist/scanners/runtime/types.js +40 -0
- package/dist/scanners/runtime/types.js.map +1 -0
- package/dist/scanners/scale/bottleneck-detector.d.ts +17 -0
- package/dist/scanners/scale/bottleneck-detector.d.ts.map +1 -0
- package/dist/scanners/scale/bottleneck-detector.js +250 -0
- package/dist/scanners/scale/bottleneck-detector.js.map +1 -0
- package/dist/scanners/scale/capacity-estimator.d.ts +17 -0
- package/dist/scanners/scale/capacity-estimator.d.ts.map +1 -0
- package/dist/scanners/scale/capacity-estimator.js +197 -0
- package/dist/scanners/scale/capacity-estimator.js.map +1 -0
- package/dist/scanners/scale/index.d.ts +37 -0
- package/dist/scanners/scale/index.d.ts.map +1 -0
- package/dist/scanners/scale/index.js +101 -0
- package/dist/scanners/scale/index.js.map +1 -0
- package/dist/scanners/scale/load-profiler.d.ts +48 -0
- package/dist/scanners/scale/load-profiler.d.ts.map +1 -0
- package/dist/scanners/scale/load-profiler.js +377 -0
- package/dist/scanners/scale/load-profiler.js.map +1 -0
- package/dist/scanners/scale/types.d.ts +529 -0
- package/dist/scanners/scale/types.d.ts.map +1 -0
- package/dist/scanners/scale/types.js +57 -0
- package/dist/scanners/scale/types.js.map +1 -0
- package/dist/scanners/secrets.d.ts.map +1 -1
- package/dist/scanners/secrets.js +13 -2
- package/dist/scanners/secrets.js.map +1 -1
- package/package.json +4 -2
- package/skills/vaspera-add-tests/SKILL.md +102 -0
- package/skills/vaspera-ai-verify/SKILL.md +166 -0
- package/skills/vaspera-audit/SKILL.md +67 -0
- package/skills/vaspera-certify/SKILL.md +130 -0
- package/skills/vaspera-deploy/SKILL.md +152 -0
- package/skills/vaspera-fix-critical/SKILL.md +52 -0
- package/skills/vaspera-fix-high/SKILL.md +81 -0
- package/skills/vaspera-fix-medium/SKILL.md +56 -0
- package/skills/vaspera-fix-rls/SKILL.md +85 -0
- package/skills/vaspera-harden/SKILL.md +102 -0
- package/skills/vaspera-help/SKILL.md +61 -0
- package/skills/vaspera-load-test/SKILL.md +167 -0
- package/skills/vaspera-verify/SKILL.md +70 -0
- package/skills/vaspera-verify-e2e/SKILL.md +117 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { mkdir, writeFile, rm } from "fs/promises";
|
|
4
|
+
import { tmpdir } from "os";
|
|
5
|
+
import { detectBottlenecks, calculateBottleneckScore, } from "../../../scanners/scale/bottleneck-detector.js";
|
|
6
|
+
describe("bottleneck-detector", () => {
|
|
7
|
+
let testDir;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
testDir = join(tmpdir(), `bottleneck-test-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
10
|
+
await mkdir(testDir, { recursive: true });
|
|
11
|
+
});
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
await rm(testDir, { recursive: true, force: true });
|
|
14
|
+
});
|
|
15
|
+
describe("detectBottlenecks", () => {
|
|
16
|
+
it("detects N+1 query patterns", async () => {
|
|
17
|
+
const srcDir = join(testDir, "src");
|
|
18
|
+
await mkdir(srcDir, { recursive: true });
|
|
19
|
+
const code = `
|
|
20
|
+
const users = await prisma.user.findMany({
|
|
21
|
+
include: {
|
|
22
|
+
posts: true,
|
|
23
|
+
comments: true,
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
`;
|
|
27
|
+
await writeFile(join(srcDir, "users.ts"), code);
|
|
28
|
+
const bottlenecks = await detectBottlenecks(testDir);
|
|
29
|
+
const dbBottleneck = bottlenecks.find((b) => b.type === "database");
|
|
30
|
+
expect(dbBottleneck).toBeDefined();
|
|
31
|
+
expect(dbBottleneck?.description).toContain("N+1");
|
|
32
|
+
});
|
|
33
|
+
it("detects blocking operations", async () => {
|
|
34
|
+
const srcDir = join(testDir, "src");
|
|
35
|
+
await mkdir(srcDir, { recursive: true });
|
|
36
|
+
const code = `
|
|
37
|
+
const config = JSON.parse(fs.readFileSync('config.json', 'utf-8'));
|
|
38
|
+
const exists = fs.existsSync(path);
|
|
39
|
+
`;
|
|
40
|
+
await writeFile(join(srcDir, "config.ts"), code);
|
|
41
|
+
const bottlenecks = await detectBottlenecks(testDir);
|
|
42
|
+
const cpuBottleneck = bottlenecks.find((b) => b.type === "cpu");
|
|
43
|
+
expect(cpuBottleneck).toBeDefined();
|
|
44
|
+
expect(cpuBottleneck?.description).toContain("Blocking");
|
|
45
|
+
});
|
|
46
|
+
it("returns empty array for clean code", async () => {
|
|
47
|
+
const srcDir = join(testDir, "src");
|
|
48
|
+
await mkdir(srcDir, { recursive: true });
|
|
49
|
+
const code = `
|
|
50
|
+
export async function getData() {
|
|
51
|
+
const result = await fetch('/api/data');
|
|
52
|
+
return result.json();
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
await writeFile(join(srcDir, "api.ts"), code);
|
|
56
|
+
const bottlenecks = await detectBottlenecks(testDir);
|
|
57
|
+
expect(bottlenecks).toHaveLength(0);
|
|
58
|
+
});
|
|
59
|
+
it("analyzes load test results for high latency", async () => {
|
|
60
|
+
const loadTestResult = {
|
|
61
|
+
profile: "test",
|
|
62
|
+
tool: "k6",
|
|
63
|
+
startTime: new Date().toISOString(),
|
|
64
|
+
endTime: new Date().toISOString(),
|
|
65
|
+
duration: 60000,
|
|
66
|
+
scenarios: [],
|
|
67
|
+
summary: {
|
|
68
|
+
totalRequests: 1000,
|
|
69
|
+
failedRequests: 5,
|
|
70
|
+
errorRate: 0.005,
|
|
71
|
+
avgThroughput: 100,
|
|
72
|
+
peakThroughput: 150,
|
|
73
|
+
latency: {
|
|
74
|
+
min: 50,
|
|
75
|
+
max: 2000,
|
|
76
|
+
mean: 300,
|
|
77
|
+
median: 250,
|
|
78
|
+
p90: 450,
|
|
79
|
+
p95: 800, // High latency
|
|
80
|
+
p99: 1500,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
passed: false,
|
|
84
|
+
score: 60,
|
|
85
|
+
};
|
|
86
|
+
const bottlenecks = await detectBottlenecks(testDir, loadTestResult);
|
|
87
|
+
const latencyBottleneck = bottlenecks.find((b) => b.type === "endpoint" && b.description.includes("latency"));
|
|
88
|
+
expect(latencyBottleneck).toBeDefined();
|
|
89
|
+
expect(latencyBottleneck?.severity).toBe("high");
|
|
90
|
+
});
|
|
91
|
+
it("analyzes load test results for high error rate", async () => {
|
|
92
|
+
const loadTestResult = {
|
|
93
|
+
profile: "test",
|
|
94
|
+
tool: "k6",
|
|
95
|
+
startTime: new Date().toISOString(),
|
|
96
|
+
endTime: new Date().toISOString(),
|
|
97
|
+
duration: 60000,
|
|
98
|
+
scenarios: [],
|
|
99
|
+
summary: {
|
|
100
|
+
totalRequests: 1000,
|
|
101
|
+
failedRequests: 100, // 10% error rate
|
|
102
|
+
errorRate: 0.10,
|
|
103
|
+
avgThroughput: 100,
|
|
104
|
+
peakThroughput: 150,
|
|
105
|
+
latency: {
|
|
106
|
+
min: 50,
|
|
107
|
+
max: 500,
|
|
108
|
+
mean: 150,
|
|
109
|
+
median: 120,
|
|
110
|
+
p90: 200,
|
|
111
|
+
p95: 250,
|
|
112
|
+
p99: 400,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
passed: false,
|
|
116
|
+
score: 40,
|
|
117
|
+
};
|
|
118
|
+
const bottlenecks = await detectBottlenecks(testDir, loadTestResult);
|
|
119
|
+
const errorBottleneck = bottlenecks.find((b) => b.description.includes("error rate"));
|
|
120
|
+
expect(errorBottleneck).toBeDefined();
|
|
121
|
+
expect(errorBottleneck?.severity).toBe("critical");
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe("calculateBottleneckScore", () => {
|
|
125
|
+
it("returns 100 for no bottlenecks", () => {
|
|
126
|
+
const score = calculateBottleneckScore([]);
|
|
127
|
+
expect(score).toBe(100);
|
|
128
|
+
});
|
|
129
|
+
it("deducts points for critical bottlenecks", () => {
|
|
130
|
+
const bottlenecks = [
|
|
131
|
+
{
|
|
132
|
+
type: "endpoint",
|
|
133
|
+
location: "api",
|
|
134
|
+
severity: "critical",
|
|
135
|
+
description: "test",
|
|
136
|
+
metrics: { current: 0, threshold: 0, unit: "" },
|
|
137
|
+
recommendation: "",
|
|
138
|
+
},
|
|
139
|
+
];
|
|
140
|
+
const score = calculateBottleneckScore(bottlenecks);
|
|
141
|
+
expect(score).toBe(75); // -25 for critical
|
|
142
|
+
});
|
|
143
|
+
it("deducts points for multiple bottlenecks", () => {
|
|
144
|
+
const bottlenecks = [
|
|
145
|
+
{
|
|
146
|
+
type: "endpoint",
|
|
147
|
+
location: "api",
|
|
148
|
+
severity: "critical",
|
|
149
|
+
description: "test",
|
|
150
|
+
metrics: { current: 0, threshold: 0, unit: "" },
|
|
151
|
+
recommendation: "",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
type: "database",
|
|
155
|
+
location: "queries",
|
|
156
|
+
severity: "high",
|
|
157
|
+
description: "test",
|
|
158
|
+
metrics: { current: 0, threshold: 0, unit: "" },
|
|
159
|
+
recommendation: "",
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
type: "memory",
|
|
163
|
+
location: "leak",
|
|
164
|
+
severity: "medium",
|
|
165
|
+
description: "test",
|
|
166
|
+
metrics: { current: 0, threshold: 0, unit: "" },
|
|
167
|
+
recommendation: "",
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
const score = calculateBottleneckScore(bottlenecks);
|
|
171
|
+
expect(score).toBe(52); // 100 - 25 - 15 - 8
|
|
172
|
+
});
|
|
173
|
+
it("never goes below 0", () => {
|
|
174
|
+
const bottlenecks = Array(10).fill({
|
|
175
|
+
type: "endpoint",
|
|
176
|
+
location: "api",
|
|
177
|
+
severity: "critical",
|
|
178
|
+
description: "test",
|
|
179
|
+
metrics: { current: 0, threshold: 0, unit: "" },
|
|
180
|
+
recommendation: "",
|
|
181
|
+
});
|
|
182
|
+
const score = calculateBottleneckScore(bottlenecks);
|
|
183
|
+
expect(score).toBe(0);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
//# sourceMappingURL=bottleneck-detector.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bottleneck-detector.test.js","sourceRoot":"","sources":["../../../../src/__tests__/scanners/scale/bottleneck-detector.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/scanners/scale/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { runScaleAssessment, quickBottleneckScan, discoverProfiles, generateSampleProfile, detectBottlenecks, calculateBottleneckScore, estimateCapacity, calculateCapacityScore, detectLoadTool, isK6Available, } from "../../../scanners/scale/index.js";
|
|
3
|
+
describe("scale module exports", () => {
|
|
4
|
+
it("exports runScaleAssessment", () => {
|
|
5
|
+
expect(typeof runScaleAssessment).toBe("function");
|
|
6
|
+
});
|
|
7
|
+
it("exports quickBottleneckScan", () => {
|
|
8
|
+
expect(typeof quickBottleneckScan).toBe("function");
|
|
9
|
+
});
|
|
10
|
+
it("exports discoverProfiles", () => {
|
|
11
|
+
expect(typeof discoverProfiles).toBe("function");
|
|
12
|
+
});
|
|
13
|
+
it("exports generateSampleProfile", () => {
|
|
14
|
+
expect(typeof generateSampleProfile).toBe("function");
|
|
15
|
+
});
|
|
16
|
+
it("exports detectBottlenecks", () => {
|
|
17
|
+
expect(typeof detectBottlenecks).toBe("function");
|
|
18
|
+
});
|
|
19
|
+
it("exports calculateBottleneckScore", () => {
|
|
20
|
+
expect(typeof calculateBottleneckScore).toBe("function");
|
|
21
|
+
});
|
|
22
|
+
it("exports estimateCapacity", () => {
|
|
23
|
+
expect(typeof estimateCapacity).toBe("function");
|
|
24
|
+
});
|
|
25
|
+
it("exports calculateCapacityScore", () => {
|
|
26
|
+
expect(typeof calculateCapacityScore).toBe("function");
|
|
27
|
+
});
|
|
28
|
+
it("exports detectLoadTool", () => {
|
|
29
|
+
expect(typeof detectLoadTool).toBe("function");
|
|
30
|
+
});
|
|
31
|
+
it("exports isK6Available", () => {
|
|
32
|
+
expect(typeof isK6Available).toBe("function");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe("scale integration", () => {
|
|
36
|
+
describe("quickBottleneckScan", () => {
|
|
37
|
+
it("returns score and bottlenecks", async () => {
|
|
38
|
+
const result = await quickBottleneckScan(".");
|
|
39
|
+
expect(result).toHaveProperty("score");
|
|
40
|
+
expect(result).toHaveProperty("bottlenecks");
|
|
41
|
+
expect(typeof result.score).toBe("number");
|
|
42
|
+
expect(Array.isArray(result.bottlenecks)).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe("estimateCapacity", () => {
|
|
46
|
+
it("returns conservative estimates without load test", async () => {
|
|
47
|
+
const estimate = await estimateCapacity();
|
|
48
|
+
expect(estimate.maxConcurrentUsers).toBe(100);
|
|
49
|
+
expect(estimate.maxRequestsPerSecond).toBe(50);
|
|
50
|
+
expect(estimate.recommendations).toContain("Run load tests to get accurate capacity estimates");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe("calculateCapacityScore", () => {
|
|
54
|
+
it("returns 100 for 5x headroom", () => {
|
|
55
|
+
const estimate = {
|
|
56
|
+
maxConcurrentUsers: 500,
|
|
57
|
+
maxRequestsPerSecond: 1000,
|
|
58
|
+
estimatedBreakpoint: { vus: 500, confidence: 0.8 },
|
|
59
|
+
recommendations: [],
|
|
60
|
+
};
|
|
61
|
+
const score = calculateCapacityScore(estimate, 100);
|
|
62
|
+
expect(score).toBe(100);
|
|
63
|
+
});
|
|
64
|
+
it("returns lower score for tight capacity", () => {
|
|
65
|
+
const estimate = {
|
|
66
|
+
maxConcurrentUsers: 120,
|
|
67
|
+
maxRequestsPerSecond: 200,
|
|
68
|
+
estimatedBreakpoint: { vus: 120, confidence: 0.6 },
|
|
69
|
+
recommendations: [],
|
|
70
|
+
};
|
|
71
|
+
const score = calculateCapacityScore(estimate, 100);
|
|
72
|
+
expect(score).toBeLessThan(100);
|
|
73
|
+
expect(score).toBeGreaterThanOrEqual(50);
|
|
74
|
+
});
|
|
75
|
+
it("returns low score when below target", () => {
|
|
76
|
+
const estimate = {
|
|
77
|
+
maxConcurrentUsers: 50,
|
|
78
|
+
maxRequestsPerSecond: 100,
|
|
79
|
+
estimatedBreakpoint: { vus: 50, confidence: 0.5 },
|
|
80
|
+
recommendations: [],
|
|
81
|
+
};
|
|
82
|
+
const score = calculateCapacityScore(estimate, 100);
|
|
83
|
+
expect(score).toBeLessThan(50);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../../src/__tests__/scanners/scale/index.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-profiler.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/scanners/scale/load-profiler.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { mkdir, writeFile, rm, readFile } from "fs/promises";
|
|
4
|
+
import { tmpdir } from "os";
|
|
5
|
+
import { loadProfile, discoverProfiles, generateSampleProfile, generateK6Script, } from "../../../scanners/scale/load-profiler.js";
|
|
6
|
+
describe("load-profiler", () => {
|
|
7
|
+
let testDir;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
testDir = join(tmpdir(), `scale-test-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
10
|
+
await mkdir(testDir, { recursive: true });
|
|
11
|
+
});
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
await rm(testDir, { recursive: true, force: true });
|
|
14
|
+
});
|
|
15
|
+
describe("loadProfile", () => {
|
|
16
|
+
it("loads a valid YAML profile", async () => {
|
|
17
|
+
const profileContent = `
|
|
18
|
+
name: "test-profile"
|
|
19
|
+
description: "Test load profile"
|
|
20
|
+
tool: k6
|
|
21
|
+
scenarios:
|
|
22
|
+
- name: "Basic"
|
|
23
|
+
duration: "1m"
|
|
24
|
+
vus: 10
|
|
25
|
+
`;
|
|
26
|
+
const profilePath = join(testDir, "test.yaml");
|
|
27
|
+
await writeFile(profilePath, profileContent);
|
|
28
|
+
const profile = await loadProfile(profilePath);
|
|
29
|
+
expect(profile.name).toBe("test-profile");
|
|
30
|
+
expect(profile.tool).toBe("k6");
|
|
31
|
+
expect(profile.scenarios).toHaveLength(1);
|
|
32
|
+
});
|
|
33
|
+
it("throws on invalid YAML", async () => {
|
|
34
|
+
const profilePath = join(testDir, "invalid.yaml");
|
|
35
|
+
await writeFile(profilePath, "invalid: yaml: content:");
|
|
36
|
+
await expect(loadProfile(profilePath)).rejects.toThrow();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe("discoverProfiles", () => {
|
|
40
|
+
it("discovers all profiles in .vaspera/load/", async () => {
|
|
41
|
+
const profilesDir = join(testDir, ".vaspera/load");
|
|
42
|
+
await mkdir(profilesDir, { recursive: true });
|
|
43
|
+
const profile1 = `name: "profile1"\nscenarios:\n - name: "s1"\n duration: "1m"\n vus: 10`;
|
|
44
|
+
const profile2 = `name: "profile2"\nscenarios:\n - name: "s2"\n duration: "2m"\n vus: 20`;
|
|
45
|
+
await writeFile(join(profilesDir, "profile1.yaml"), profile1);
|
|
46
|
+
await writeFile(join(profilesDir, "profile2.yml"), profile2);
|
|
47
|
+
const profiles = await discoverProfiles(testDir);
|
|
48
|
+
expect(profiles).toHaveLength(2);
|
|
49
|
+
expect(profiles.map((p) => p.profile.name).sort()).toEqual(["profile1", "profile2"]);
|
|
50
|
+
});
|
|
51
|
+
it("returns empty array when no profiles directory", async () => {
|
|
52
|
+
const profiles = await discoverProfiles(testDir);
|
|
53
|
+
expect(profiles).toEqual([]);
|
|
54
|
+
});
|
|
55
|
+
it("skips invalid profile files", async () => {
|
|
56
|
+
const profilesDir = join(testDir, ".vaspera/load");
|
|
57
|
+
await mkdir(profilesDir, { recursive: true });
|
|
58
|
+
const valid = `name: "valid"\nscenarios:\n - name: "s"\n duration: "1m"\n vus: 1`;
|
|
59
|
+
const invalid = `name: 123\nscenarios: "not an array"`;
|
|
60
|
+
await writeFile(join(profilesDir, "valid.yaml"), valid);
|
|
61
|
+
await writeFile(join(profilesDir, "invalid.yaml"), invalid);
|
|
62
|
+
const profiles = await discoverProfiles(testDir);
|
|
63
|
+
expect(profiles).toHaveLength(1);
|
|
64
|
+
expect(profiles[0].profile.name).toBe("valid");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe("generateSampleProfile", () => {
|
|
68
|
+
it("creates a sample profile file", async () => {
|
|
69
|
+
const profilePath = await generateSampleProfile(testDir, "staging");
|
|
70
|
+
expect(profilePath).toBe(join(testDir, ".vaspera/load/staging.yaml"));
|
|
71
|
+
const content = await readFile(profilePath, "utf-8");
|
|
72
|
+
expect(content).toContain('name: "staging"');
|
|
73
|
+
expect(content).toContain("scenarios:");
|
|
74
|
+
expect(content).toContain("endpoints:");
|
|
75
|
+
});
|
|
76
|
+
it("uses default name when not specified", async () => {
|
|
77
|
+
const profilePath = await generateSampleProfile(testDir);
|
|
78
|
+
expect(profilePath).toContain("production.yaml");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe("generateK6Script", () => {
|
|
82
|
+
it("generates valid k6 script", () => {
|
|
83
|
+
const profile = {
|
|
84
|
+
name: "test",
|
|
85
|
+
tool: "k6",
|
|
86
|
+
thresholds: {
|
|
87
|
+
p95: 500,
|
|
88
|
+
p99: 1000,
|
|
89
|
+
errorRate: 0.01,
|
|
90
|
+
},
|
|
91
|
+
endpoints: [
|
|
92
|
+
{ path: "/", method: "GET", weight: 100 },
|
|
93
|
+
],
|
|
94
|
+
scenarios: [
|
|
95
|
+
{ name: "Ramp", type: "ramp", duration: "2m", vus: { start: 1, end: 50 } },
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
const script = generateK6Script(profile, "http://localhost:3000");
|
|
99
|
+
expect(script).toContain("import http from 'k6/http'");
|
|
100
|
+
expect(script).toContain("const BASE_URL = 'http://localhost:3000'");
|
|
101
|
+
expect(script).toContain("http_req_duration");
|
|
102
|
+
expect(script).toContain("p(95)<500");
|
|
103
|
+
expect(script).toContain("Ramp:");
|
|
104
|
+
});
|
|
105
|
+
it("includes endpoints with correct methods", () => {
|
|
106
|
+
const profile = {
|
|
107
|
+
name: "test",
|
|
108
|
+
tool: "k6",
|
|
109
|
+
endpoints: [
|
|
110
|
+
{ path: "/api/data", method: "POST", weight: 50, body: { key: "value" } },
|
|
111
|
+
],
|
|
112
|
+
scenarios: [
|
|
113
|
+
{ name: "Test", type: "ramp", duration: "1m", vus: 10 },
|
|
114
|
+
],
|
|
115
|
+
};
|
|
116
|
+
const script = generateK6Script(profile, "http://localhost:3000");
|
|
117
|
+
expect(script).toContain("http.post");
|
|
118
|
+
expect(script).toContain("/api/data");
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=load-profiler.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-profiler.test.js","sourceRoot":"","sources":["../../../../src/__tests__/scanners/scale/load-profiler.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/scanners/scale/types.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { LoadProfileSchema, EndpointSchema, ScenarioSchema, } from "../../../scanners/scale/types.js";
|
|
3
|
+
describe("scale types", () => {
|
|
4
|
+
describe("EndpointSchema", () => {
|
|
5
|
+
it("parses minimal endpoint", () => {
|
|
6
|
+
const endpoint = { path: "/api/health" };
|
|
7
|
+
const result = EndpointSchema.parse(endpoint);
|
|
8
|
+
expect(result.path).toBe("/api/health");
|
|
9
|
+
expect(result.method).toBe("GET");
|
|
10
|
+
expect(result.weight).toBe(100);
|
|
11
|
+
});
|
|
12
|
+
it("parses full endpoint with thresholds", () => {
|
|
13
|
+
const endpoint = {
|
|
14
|
+
path: "/api/checkout",
|
|
15
|
+
method: "POST",
|
|
16
|
+
weight: 30,
|
|
17
|
+
headers: { "X-Custom": "value" },
|
|
18
|
+
body: { items: [{ id: 1 }] },
|
|
19
|
+
thresholds: {
|
|
20
|
+
p95: 200,
|
|
21
|
+
p99: 500,
|
|
22
|
+
errorRate: 0.005,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
const result = EndpointSchema.parse(endpoint);
|
|
26
|
+
expect(result.method).toBe("POST");
|
|
27
|
+
expect(result.weight).toBe(30);
|
|
28
|
+
expect(result.thresholds?.p95).toBe(200);
|
|
29
|
+
});
|
|
30
|
+
it("validates method enum", () => {
|
|
31
|
+
const validMethods = ["GET", "POST", "PUT", "DELETE", "PATCH"];
|
|
32
|
+
for (const method of validMethods) {
|
|
33
|
+
expect(() => EndpointSchema.parse({ path: "/", method })).not.toThrow();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
it("rejects invalid method", () => {
|
|
37
|
+
expect(() => EndpointSchema.parse({ path: "/", method: "INVALID" })).toThrow();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("ScenarioSchema", () => {
|
|
41
|
+
it("parses fixed VUs scenario", () => {
|
|
42
|
+
const scenario = {
|
|
43
|
+
name: "Steady State",
|
|
44
|
+
duration: "5m",
|
|
45
|
+
vus: 50,
|
|
46
|
+
};
|
|
47
|
+
const result = ScenarioSchema.parse(scenario);
|
|
48
|
+
expect(result.name).toBe("Steady State");
|
|
49
|
+
expect(result.type).toBe("ramp");
|
|
50
|
+
expect(result.vus).toBe(50);
|
|
51
|
+
});
|
|
52
|
+
it("parses ramping VUs scenario", () => {
|
|
53
|
+
const scenario = {
|
|
54
|
+
name: "Ramp Up",
|
|
55
|
+
type: "ramp",
|
|
56
|
+
duration: "2m",
|
|
57
|
+
vus: { start: 1, end: 100 },
|
|
58
|
+
};
|
|
59
|
+
const result = ScenarioSchema.parse(scenario);
|
|
60
|
+
expect(result.vus).toEqual({ start: 1, end: 100 });
|
|
61
|
+
});
|
|
62
|
+
it("validates scenario types", () => {
|
|
63
|
+
const types = ["ramp", "spike", "soak", "stress", "breakpoint"];
|
|
64
|
+
for (const type of types) {
|
|
65
|
+
expect(() => ScenarioSchema.parse({ name: "test", type, duration: "1m", vus: 10 })).not.toThrow();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe("LoadProfileSchema", () => {
|
|
70
|
+
it("parses minimal profile", () => {
|
|
71
|
+
const profile = {
|
|
72
|
+
name: "test",
|
|
73
|
+
scenarios: [
|
|
74
|
+
{ name: "Basic", duration: "1m", vus: 10 },
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
const result = LoadProfileSchema.parse(profile);
|
|
78
|
+
expect(result.name).toBe("test");
|
|
79
|
+
expect(result.tool).toBe("k6");
|
|
80
|
+
expect(result.scenarios).toHaveLength(1);
|
|
81
|
+
});
|
|
82
|
+
it("parses full profile", () => {
|
|
83
|
+
const profile = {
|
|
84
|
+
name: "production",
|
|
85
|
+
description: "Production load test",
|
|
86
|
+
baseUrl: "http://localhost:3000",
|
|
87
|
+
tool: "k6",
|
|
88
|
+
thresholds: {
|
|
89
|
+
p95: 500,
|
|
90
|
+
p99: 1000,
|
|
91
|
+
errorRate: 0.01,
|
|
92
|
+
throughput: 100,
|
|
93
|
+
},
|
|
94
|
+
endpoints: [
|
|
95
|
+
{ path: "/", weight: 50 },
|
|
96
|
+
{ path: "/api/products", weight: 30 },
|
|
97
|
+
],
|
|
98
|
+
scenarios: [
|
|
99
|
+
{ name: "Ramp", type: "ramp", duration: "2m", vus: { start: 1, end: 50 } },
|
|
100
|
+
{ name: "Steady", duration: "5m", vus: 50 },
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
const result = LoadProfileSchema.parse(profile);
|
|
104
|
+
expect(result.tool).toBe("k6");
|
|
105
|
+
expect(result.thresholds?.p95).toBe(500);
|
|
106
|
+
expect(result.endpoints).toHaveLength(2);
|
|
107
|
+
expect(result.scenarios).toHaveLength(2);
|
|
108
|
+
});
|
|
109
|
+
it("validates tool enum", () => {
|
|
110
|
+
const tools = ["k6", "artillery", "autocannon", "wrk"];
|
|
111
|
+
for (const tool of tools) {
|
|
112
|
+
expect(() => LoadProfileSchema.parse({
|
|
113
|
+
name: "test",
|
|
114
|
+
tool,
|
|
115
|
+
scenarios: [{ name: "s", duration: "1m", vus: 1 }],
|
|
116
|
+
})).not.toThrow();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
it("requires name", () => {
|
|
120
|
+
expect(() => LoadProfileSchema.parse({
|
|
121
|
+
scenarios: [{ name: "s", duration: "1m", vus: 1 }],
|
|
122
|
+
})).toThrow();
|
|
123
|
+
});
|
|
124
|
+
it("requires scenarios", () => {
|
|
125
|
+
expect(() => LoadProfileSchema.parse({ name: "test" })).toThrow();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=types.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.test.js","sourceRoot":"","sources":["../../../../src/__tests__/scanners/scale/types.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiQpE;;GAEG;AACH,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM;;;;;EAIjC;AAED;;GAEG;AACH,iBAAS,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC;;;;;;EAK/D;AAED;;GAEG;AACH,iBAAS,aAAa,CAAC,OAAO,EAAE,MAAM;;;;;EAIrC;AA+CD,QAAA,MAAM,MAAM,WAGV,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiQpE;;GAEG;AACH,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM;;;;;EAIjC;AAED;;GAEG;AACH,iBAAS,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC;;;;;;EAK/D;AAED;;GAEG;AACH,iBAAS,aAAa,CAAC,OAAO,EAAE,MAAM;;;;;EAIrC;AA+CD,QAAA,MAAM,MAAM,WAGV,CAAC;AA+oMH,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC"}
|