blaze-performance-tester 3.1.62 → 3.2.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/cli.js +110 -5
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -196,6 +196,93 @@ function loadBaselineData(filePath) {
|
|
|
196
196
|
}
|
|
197
197
|
return null;
|
|
198
198
|
}
|
|
199
|
+
async function generateScenarioTS(prompt) {
|
|
200
|
+
const apiKey = process.env.GEMINI_API_KEY;
|
|
201
|
+
if (!apiKey) {
|
|
202
|
+
throw new Error("\u274C Environment variable GEMINI_API_KEY is missing. AI scenario generation aborted.");
|
|
203
|
+
}
|
|
204
|
+
console.log("\u{1F9E0} Translating natural language requirements into TypeScript via Gemini 2.5 Flash...");
|
|
205
|
+
const systemInstruction = `
|
|
206
|
+
You are an expert Performance & Systems Reliability Engineer specializing in QuickJS-compatible virtual user load testing scripts for the Blaze framework.
|
|
207
|
+
Your task is to convert a natural language description into a clean, valid TypeScript simulation script.
|
|
208
|
+
|
|
209
|
+
The script must adhere to this exact structural import pattern:
|
|
210
|
+
\`\`\`typescript
|
|
211
|
+
import { VirtualUser } from '../src/core/vu';
|
|
212
|
+
|
|
213
|
+
export async function runScenario(vu: VirtualUser) {
|
|
214
|
+
// Setup headers
|
|
215
|
+
// Execute multi-step operations (e.g., fetching a login, parsing tokens, making subsequent requests)
|
|
216
|
+
// Manage dynamic value extraction (e.g., const token = response.json().token) and pass variables forward
|
|
217
|
+
// Include standard loops (e.g., for-loops) or timeouts as requested
|
|
218
|
+
}
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
Rules:
|
|
222
|
+
1. Return ONLY executable, valid TypeScript script.
|
|
223
|
+
2. Cleanly extract dynamic payload fields or tokens and assign them to downstream headers.
|
|
224
|
+
3. Keep logic performance-optimized and sandbox-compatible.
|
|
225
|
+
4. Do NOT wrap code blocks in backticks like \`\`\`typescript. Start directly with the TypeScript imports and export block. Do not include markdown or text commentary.
|
|
226
|
+
`;
|
|
227
|
+
try {
|
|
228
|
+
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${apiKey}`, {
|
|
229
|
+
method: "POST",
|
|
230
|
+
headers: { "Content-Type": "application/json" },
|
|
231
|
+
body: JSON.stringify({
|
|
232
|
+
contents: [{ parts: [{ text: `Generate a Virtual User script for this scenario: ${prompt}` }] }],
|
|
233
|
+
generationConfig: {
|
|
234
|
+
temperature: 0.1,
|
|
235
|
+
maxOutputTokens: 65536
|
|
236
|
+
},
|
|
237
|
+
systemInstruction: {
|
|
238
|
+
parts: [{ text: systemInstruction }]
|
|
239
|
+
}
|
|
240
|
+
})
|
|
241
|
+
});
|
|
242
|
+
const data = await response.json();
|
|
243
|
+
if (data?.error) {
|
|
244
|
+
throw new Error(`Google API Error ${data.error.code}: ${data.error.message}`);
|
|
245
|
+
}
|
|
246
|
+
const candidateText = data?.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
247
|
+
if (!candidateText) {
|
|
248
|
+
throw new Error(`Malformed API layout or empty response body.`);
|
|
249
|
+
}
|
|
250
|
+
return candidateText.replace(/```typescript/g, "").replace(/```javascript/g, "").replace(/```/g, "").trim();
|
|
251
|
+
} catch (error) {
|
|
252
|
+
throw new Error(`Failed to generate script via Gemini: ${error.message || error}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
async function handleScenarioGeneration(config) {
|
|
256
|
+
const targetDir = path.resolve(__dirname, "./tests");
|
|
257
|
+
const tsFilePath = path.join(targetDir, "generated_scenario.ts");
|
|
258
|
+
const jsFilePath = path.join(targetDir, "generated_scenario.js");
|
|
259
|
+
try {
|
|
260
|
+
if (!fs.existsSync(targetDir)) {
|
|
261
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
262
|
+
}
|
|
263
|
+
const tsCode = await generateScenarioTS(config.scenarioPrompt);
|
|
264
|
+
fs.writeFileSync(tsFilePath, tsCode, "utf-8");
|
|
265
|
+
console.log(`\u{1F4BE} Successfully generated scenario script saved to: ${tsFilePath}`);
|
|
266
|
+
console.log("\u2699\uFE0F Transpiling generated scenario to JavaScript for native QuickJS sandbox validation...");
|
|
267
|
+
let compiledSuccessfully = false;
|
|
268
|
+
try {
|
|
269
|
+
const { execSync } = require2("child_process");
|
|
270
|
+
execSync(`npx tsc "${tsFilePath}" --target es2020 --module commonjs --allowJs --skipLibCheck`, { stdio: "ignore" });
|
|
271
|
+
compiledSuccessfully = true;
|
|
272
|
+
} catch (e) {
|
|
273
|
+
console.warn("\u26A0\uFE0F TypeScript compiler (tsc) was not found or timed out. Falling back to clean JS copy conversion...");
|
|
274
|
+
}
|
|
275
|
+
if (!compiledSuccessfully) {
|
|
276
|
+
const cleanJs = tsCode.replace(/: VirtualUser/g, "").replace(/import {[^}]+} from .*/g, "").replace(/export async/g, "async");
|
|
277
|
+
fs.writeFileSync(jsFilePath, cleanJs, "utf-8");
|
|
278
|
+
}
|
|
279
|
+
console.log(`\u2705 Sandbox compilation resolved. Active test file: ${jsFilePath}`);
|
|
280
|
+
config.targetScript = jsFilePath;
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.error(`\u274C Scenario generation flow aborted: ${error.message || error}`);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
199
286
|
async function generateGeminiRCA(history, finalSummary, errorLogs) {
|
|
200
287
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
201
288
|
if (!apiKey) {
|
|
@@ -232,7 +319,7 @@ Paragraph 3 - ARCHITECTURAL SIZING RECOMMENDATIONS: Give concrete, infrastructur
|
|
|
232
319
|
CRITICAL: Return ONLY plain paragraph text. Do not use markdown headers (###). If you use bold text, use standard HTML <strong> tags. Wrap lines cleanly.
|
|
233
320
|
`;
|
|
234
321
|
try {
|
|
235
|
-
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${apiKey}`, {
|
|
322
|
+
const response = await fetch(`[https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=$](https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=$){apiKey}`, {
|
|
236
323
|
method: "POST",
|
|
237
324
|
headers: { "Content-Type": "application/json" },
|
|
238
325
|
body: JSON.stringify({
|
|
@@ -269,13 +356,13 @@ async function executeTestPipeline(config) {
|
|
|
269
356
|
const transactionalScenario = [
|
|
270
357
|
{
|
|
271
358
|
name: "Fetch Target Anti-Forgery Nonce",
|
|
272
|
-
url: "https://httpbin.org/json",
|
|
359
|
+
url: "[https://httpbin.org/json](https://httpbin.org/json)",
|
|
273
360
|
method: "GET",
|
|
274
361
|
body: null
|
|
275
362
|
},
|
|
276
363
|
{
|
|
277
364
|
name: "Perform Contextual Post Action",
|
|
278
|
-
url: "https://httpbin.org/post?verification=${csrf_token}",
|
|
365
|
+
url: "[https://httpbin.org/post?verification=$](https://httpbin.org/post?verification=$){csrf_token}",
|
|
279
366
|
method: "POST",
|
|
280
367
|
body: JSON.stringify({
|
|
281
368
|
data: "performance_payload",
|
|
@@ -300,6 +387,9 @@ async function main() {
|
|
|
300
387
|
return;
|
|
301
388
|
}
|
|
302
389
|
const config = parseArguments(args);
|
|
390
|
+
if (config.scenarioPrompt) {
|
|
391
|
+
await handleScenarioGeneration(config);
|
|
392
|
+
}
|
|
303
393
|
if (config.isCorrelate) {
|
|
304
394
|
await executeTestPipeline(config);
|
|
305
395
|
}
|
|
@@ -310,6 +400,12 @@ async function main() {
|
|
|
310
400
|
}
|
|
311
401
|
}
|
|
312
402
|
function parseArguments(args) {
|
|
403
|
+
const scenarioIdx = args.indexOf("--generate-scenario");
|
|
404
|
+
let scenarioPrompt = null;
|
|
405
|
+
if (scenarioIdx !== -1) {
|
|
406
|
+
scenarioPrompt = args[scenarioIdx + 1];
|
|
407
|
+
args.splice(scenarioIdx, 2);
|
|
408
|
+
}
|
|
313
409
|
const targetScript = path.resolve(args[0] || ".");
|
|
314
410
|
const isAgentic = args.includes("--agentic");
|
|
315
411
|
const isCorrelate = args.includes("--correlate");
|
|
@@ -363,6 +459,7 @@ function parseArguments(args) {
|
|
|
363
459
|
}
|
|
364
460
|
return {
|
|
365
461
|
targetScript,
|
|
462
|
+
scenarioPrompt,
|
|
366
463
|
isAgentic,
|
|
367
464
|
isCorrelate,
|
|
368
465
|
isSeo,
|
|
@@ -966,7 +1063,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
966
1063
|
const htmlContent = `<!DOCTYPE html><html lang="en"><head>
|
|
967
1064
|
<meta charset="UTF-8">
|
|
968
1065
|
<title>Blaze Core Performance Report</title>
|
|
969
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
1066
|
+
<script src="[https://cdn.jsdelivr.net/npm/chart.js](https://cdn.jsdelivr.net/npm/chart.js)"></script>
|
|
970
1067
|
<style>
|
|
971
1068
|
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0b111e; color: #f8fafc; margin: 0; padding: 2rem; }
|
|
972
1069
|
.container { max-width: 1300px; margin: 0 auto; }
|
|
@@ -1459,6 +1556,14 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1459
1556
|
function printUsage() {
|
|
1460
1557
|
console.log(`Blaze Core Performance Test CLI Engine
|
|
1461
1558
|
Options:
|
|
1462
|
-
--
|
|
1559
|
+
--generate-scenario <prompt> Generates a virtual user script from a natural language prompt
|
|
1560
|
+
--threads <count> Number of concurrent threads (default: 10)
|
|
1561
|
+
--duration <seconds> Duration of stress testing in seconds (default: 10)
|
|
1562
|
+
--ramp-up <seconds> Ramp-up speed
|
|
1563
|
+
--ramp-down <seconds> Ramp-down speed
|
|
1564
|
+
--agentic Enable Intelligent Autonomous Agentic Stress Test
|
|
1565
|
+
--correlate Launch dynamic transaction parameter mapping pipeline
|
|
1566
|
+
--baseline <json_file> Input baseline JSON benchmark reference
|
|
1567
|
+
--output <html_file> Target path for exported standalone dashboard`);
|
|
1463
1568
|
}
|
|
1464
1569
|
main().catch(console.error);
|
|
Binary file
|