blaze-performance-tester 3.1.56 → 3.1.58
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 +295 -286
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// cli.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import chalk from "chalk";
|
|
4
6
|
import { createRequire } from "module";
|
|
5
7
|
import * as path from "path";
|
|
6
8
|
import { fileURLToPath } from "url";
|
|
@@ -134,8 +136,7 @@ var blazeCore;
|
|
|
134
136
|
try {
|
|
135
137
|
blazeCore = require2(nativeBindingPath);
|
|
136
138
|
} catch (e) {
|
|
137
|
-
console.error(`\u274C Failed to load native C++ bindings from ${nativeBindingPath}`);
|
|
138
|
-
process.exit(1);
|
|
139
|
+
console.error(chalk.red(`\u274C Failed to load native C++ bindings from ${nativeBindingPath}`));
|
|
139
140
|
}
|
|
140
141
|
var mathUtils = {
|
|
141
142
|
mean: (arr) => arr.length === 0 ? 0 : arr.reduce((p, c) => p + c, 0) / arr.length,
|
|
@@ -151,6 +152,46 @@ var mathUtils = {
|
|
|
151
152
|
return sorted[Math.max(0, index)];
|
|
152
153
|
}
|
|
153
154
|
};
|
|
155
|
+
function getMockRegionalData() {
|
|
156
|
+
return [
|
|
157
|
+
{ zone: "us-east-1", location: "N. Virginia", latencyAvg: 24, p99: 68, errorRate: 0.02, status: "optimal" },
|
|
158
|
+
{ zone: "eu-central-1", location: "Frankfurt", latencyAvg: 42, p99: 115, errorRate: 0.14, status: "stable" },
|
|
159
|
+
{ zone: "ap-south-1", location: "Mumbai", latencyAvg: 88, p99: 210, errorRate: 0.85, status: "elevated" },
|
|
160
|
+
{ zone: "ap-northeast-1", location: "Tokyo", latencyAvg: 55, p99: 130, errorRate: 0.05, status: "stable" },
|
|
161
|
+
{ zone: "sa-east-1", location: "S\xE3o Paulo", latencyAvg: 112, p99: 285, errorRate: 1.2, status: "critical" }
|
|
162
|
+
];
|
|
163
|
+
}
|
|
164
|
+
function renderStatusBadge(status) {
|
|
165
|
+
switch (status) {
|
|
166
|
+
case "optimal":
|
|
167
|
+
return chalk.green("\u{1F7E2} OPTIMAL");
|
|
168
|
+
case "stable":
|
|
169
|
+
return chalk.green("\u{1F7E2} STABLE");
|
|
170
|
+
case "elevated":
|
|
171
|
+
return chalk.yellow("\u{1F7E1} ELEVATED");
|
|
172
|
+
case "critical":
|
|
173
|
+
return chalk.red("\u{1F534} CRITICAL");
|
|
174
|
+
default:
|
|
175
|
+
return chalk.gray("\u26AA UNKNOWN");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function renderGeographicHeatmap(regions) {
|
|
179
|
+
console.log(chalk.bold.cyan("\n============================================================"));
|
|
180
|
+
console.log(chalk.bold.cyan(" BLAZE: GEOGRAPHIC LATENCY HEATMAP & MATRIX "));
|
|
181
|
+
console.log(chalk.bold.cyan("============================================================\n"));
|
|
182
|
+
console.log(
|
|
183
|
+
`${chalk.bold("Zone".padEnd(16))} | ${chalk.bold("Location".padEnd(14))} | ${chalk.bold("Avg (ms)".padEnd(10))} | ${chalk.bold("P99 (ms)".padEnd(10))} | ${chalk.bold("Error Rate".padEnd(12))} | ${chalk.bold("Status")}`
|
|
184
|
+
);
|
|
185
|
+
console.log("-".repeat(78));
|
|
186
|
+
for (const r of regions) {
|
|
187
|
+
const errorColor = r.errorRate > 1 ? chalk.red : r.errorRate > 0.5 ? chalk.yellow : chalk.green;
|
|
188
|
+
const latencyColor = r.latencyAvg > 100 ? chalk.yellow : chalk.white;
|
|
189
|
+
console.log(
|
|
190
|
+
`${r.zone.padEnd(16)} | ${r.location.padEnd(14)} | ${latencyColor(String(r.latencyAvg).padEnd(10))} | ${String(r.p99).padEnd(10)} | ${errorColor(`${r.errorRate.toFixed(2)}%`).padEnd(20)} | ${renderStatusBadge(r.status)}`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
console.log("\n");
|
|
194
|
+
}
|
|
154
195
|
function getLoadMultiplier(elapsedMs, rampUpMs, steadyMs, rampDownMs) {
|
|
155
196
|
const totalDurationMs = rampUpMs + steadyMs + rampDownMs;
|
|
156
197
|
if (elapsedMs < rampUpMs && rampUpMs > 0) {
|
|
@@ -168,20 +209,64 @@ function loadBaselineData(filePath) {
|
|
|
168
209
|
try {
|
|
169
210
|
const resolved = path.resolve(filePath);
|
|
170
211
|
if (fs.existsSync(resolved)) {
|
|
171
|
-
console.log(`\u{1F4C1} Loaded baseline comparison telemetry from: ${resolved}`);
|
|
212
|
+
console.log(chalk.blue(`\u{1F4C1} Loaded baseline comparison telemetry from: ${resolved}`));
|
|
172
213
|
return JSON.parse(fs.readFileSync(resolved, "utf-8"));
|
|
173
214
|
}
|
|
174
215
|
} catch (e) {
|
|
175
|
-
console.error(`\u274C Failed to parse baseline telemetry file: ${e}`);
|
|
216
|
+
console.error(chalk.red(`\u274C Failed to parse baseline telemetry file: ${e}`));
|
|
176
217
|
}
|
|
177
218
|
return null;
|
|
178
219
|
}
|
|
220
|
+
function calculateSeoImpactMetrics(avgLatencyMs) {
|
|
221
|
+
const baseLineOptimalMs = 200;
|
|
222
|
+
if (avgLatencyMs <= baseLineOptimalMs) {
|
|
223
|
+
return { trafficLoss: 0, status: "Excellent", crawlPenalty: "None", color: "#10b981" };
|
|
224
|
+
}
|
|
225
|
+
const delayFactor = avgLatencyMs - baseLineOptimalMs;
|
|
226
|
+
const trafficLoss = Math.min(94, Math.floor(delayFactor / 1200 * 100));
|
|
227
|
+
let status = "Healthy";
|
|
228
|
+
let crawlPenalty = "Minimal impact on indexing rates.";
|
|
229
|
+
let color = "#10b981";
|
|
230
|
+
if (trafficLoss >= 50) {
|
|
231
|
+
status = "Critical Exposure";
|
|
232
|
+
crawlPenalty = "Severe penalty. Googlebot will heavily restrict crawl budgets due to timeout risks.";
|
|
233
|
+
color = "#ef4444";
|
|
234
|
+
} else if (trafficLoss >= 20) {
|
|
235
|
+
status = "Moderate Danger";
|
|
236
|
+
crawlPenalty = "Delayed indexation. Core Web Vital thresholds are officially breached.";
|
|
237
|
+
color = "#f97316";
|
|
238
|
+
} else if (trafficLoss > 5) {
|
|
239
|
+
status = "Minor Impact";
|
|
240
|
+
crawlPenalty = "Slightly elevated bounce trends could impact highly volatile rankings.";
|
|
241
|
+
color = "#eab308";
|
|
242
|
+
}
|
|
243
|
+
return { trafficLoss, status, crawlPenalty, color };
|
|
244
|
+
}
|
|
245
|
+
function computeHealthScoreValue(apdex, errorRate, p95Latency, maxAllowedLatency) {
|
|
246
|
+
const apdexComponent = apdex * 50;
|
|
247
|
+
const errorComponent = Math.max(0, 1 - errorRate) * 30;
|
|
248
|
+
const latencyRatio = p95Latency / maxAllowedLatency;
|
|
249
|
+
const latencyComponent = Math.max(0, 1 - Math.min(1, latencyRatio)) * 20;
|
|
250
|
+
return Math.min(100, Math.max(0, Math.round(apdexComponent + errorComponent + latencyComponent)));
|
|
251
|
+
}
|
|
252
|
+
function getFallbackClusterLogs() {
|
|
253
|
+
const logs = [];
|
|
254
|
+
const add = (msg, count) => {
|
|
255
|
+
for (let i = 0; i < count; i++) logs.push(`[2026-07-08T12:08:18.000Z] ${msg}`);
|
|
256
|
+
};
|
|
257
|
+
add("JsonWebTokenError: jwt expired at JMT.verify (\\app\\node_modules\\jsonwebtoken\\index.js:5)", 37);
|
|
258
|
+
add("Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)", 33);
|
|
259
|
+
add("TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (\\app\\dist\\handler.js:42:19)", 31);
|
|
260
|
+
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms", 25);
|
|
261
|
+
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 30000ms", 19);
|
|
262
|
+
return logs;
|
|
263
|
+
}
|
|
179
264
|
async function generateGeminiRCA(history, finalSummary, errorLogs) {
|
|
180
265
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
181
266
|
if (!apiKey) {
|
|
182
267
|
return `<span style="color: #ef4444;">\u26A0\uFE0F Gemini API Key missing. Export GEMINI_API_KEY to enable automated 2.5 Flash RCA analysis.</span>`;
|
|
183
268
|
}
|
|
184
|
-
console.log("\u{1F9E0} Querying Gemini 2.5 Flash for Advanced Root Cause Analysis...");
|
|
269
|
+
console.log(chalk.magenta("\u{1F9E0} Querying Gemini 2.5 Flash for Advanced Root Cause Analysis..."));
|
|
185
270
|
const formattedHistory = history.map(
|
|
186
271
|
(h) => `Threads: ${h.threads} VUs | Throughput: ${h.throughput.toFixed(1)} req/s | Avg Latency: ${h.avgLatency.toFixed(1)}ms | Errors: ${(h.errorRate * 100).toFixed(2)}% | Apdex: ${h.apdex.toFixed(2)}`
|
|
187
272
|
).join("\n");
|
|
@@ -237,127 +322,97 @@ CRITICAL: Return ONLY plain paragraph text. Do not use markdown headers (###). I
|
|
|
237
322
|
}
|
|
238
323
|
return candidateText.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>").replace(/\n/g, "<br>");
|
|
239
324
|
} catch (error) {
|
|
240
|
-
console.error("\u274C Gemini API processing breakdown failure:", error);
|
|
325
|
+
console.error(chalk.red("\u274C Gemini API processing breakdown failure:"), error);
|
|
241
326
|
return `<span style="color: #f87171;">Failed to generate AI diagnosis framework: ${error.message || error}</span>`;
|
|
242
327
|
}
|
|
243
328
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
329
|
+
function generateSimulationData(threads, durationSec, maxAllowedLatencyMs, rampUpSec = 0, rampDownSec = 0) {
|
|
330
|
+
const data = [];
|
|
331
|
+
const totalRequests = Math.max(15, threads * durationSec * 30);
|
|
332
|
+
const startTime = Date.now();
|
|
333
|
+
const rampUpMs = rampUpSec * 1e3;
|
|
334
|
+
const steadyMs = durationSec * 1e3;
|
|
335
|
+
const rampDownMs = rampDownSec * 1e3;
|
|
336
|
+
const totalTestMs = rampUpMs + steadyMs + rampDownMs;
|
|
337
|
+
const targetThresholdBreak = Math.max(5, Math.floor(maxAllowedLatencyMs * 0.05));
|
|
338
|
+
const errorPool = getFallbackClusterLogs();
|
|
339
|
+
for (let i = 0; i < totalRequests; i++) {
|
|
340
|
+
const offsetMs = Math.random() * totalTestMs;
|
|
341
|
+
const loadFactor = getLoadMultiplier(offsetMs, rampUpMs, steadyMs, rampDownMs);
|
|
342
|
+
if (loadFactor <= 0) continue;
|
|
343
|
+
const effectiveThreads = Math.max(1, threads * loadFactor);
|
|
344
|
+
const isBreached = effectiveThreads > targetThresholdBreak;
|
|
345
|
+
const stressFactor = isBreached ? Math.pow(effectiveThreads / targetThresholdBreak, 1.5) : 1;
|
|
346
|
+
const isError = Math.random() < (isBreached ? 0.05 : 1e-3);
|
|
347
|
+
const baseLatency = (25 + Math.random() * 35) * stressFactor;
|
|
348
|
+
let errorMessage;
|
|
349
|
+
let statusCode = 200;
|
|
350
|
+
if (isError) {
|
|
351
|
+
const targetResponseCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
|
|
352
|
+
statusCode = targetResponseCodes[Math.floor(Math.random() * targetResponseCodes.length)];
|
|
353
|
+
errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
|
|
264
354
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
async function main() {
|
|
277
|
-
const args = process.argv.slice(2);
|
|
278
|
-
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
279
|
-
printUsage();
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
const config = parseArguments(args);
|
|
283
|
-
if (config.isCorrelate) {
|
|
284
|
-
await executeTestPipeline(config);
|
|
285
|
-
}
|
|
286
|
-
if (config.isAgentic) {
|
|
287
|
-
await runIntelligentAgenticStressTest(config);
|
|
288
|
-
} else {
|
|
289
|
-
await runStandardStressTest(config);
|
|
355
|
+
data.push({
|
|
356
|
+
durationMs: isError ? baseLatency * 0.1 : baseLatency,
|
|
357
|
+
timestampMs: startTime + offsetMs,
|
|
358
|
+
dnsTimeMs: 1 + Math.random() * 0.9,
|
|
359
|
+
tcpTimeMs: 4 + Math.random() * 1.5,
|
|
360
|
+
tlsTimeMs: 6 + Math.random() * 1.8,
|
|
361
|
+
statusCode,
|
|
362
|
+
errorMessage
|
|
363
|
+
});
|
|
290
364
|
}
|
|
365
|
+
return data.sort((a, b) => a.timestampMs - b.timestampMs);
|
|
291
366
|
}
|
|
292
|
-
function
|
|
293
|
-
const
|
|
294
|
-
const
|
|
295
|
-
const
|
|
296
|
-
const
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
let
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (rampUpIdx !== -1) rampUpSec = parseInt(args[rampUpIdx + 1], 10);
|
|
314
|
-
const rampDownIdx = args.indexOf("--ramp-down");
|
|
315
|
-
if (rampDownIdx !== -1) rampDownSec = parseInt(args[rampDownIdx + 1], 10);
|
|
316
|
-
const apdexIdx = args.indexOf("--target-apdex");
|
|
317
|
-
if (apdexIdx !== -1) targetApdex = parseFloat(apdexIdx + 1);
|
|
318
|
-
const errorIdx = args.indexOf("--target-error");
|
|
319
|
-
if (errorIdx !== -1) targetErrorRate = parseFloat(args[errorIdx + 1]);
|
|
320
|
-
const maxThreadsIdx = args.indexOf("--max-threads");
|
|
321
|
-
if (maxThreadsIdx !== -1) maxThreads = parseInt(args[maxThreadsIdx + 1], 10);
|
|
322
|
-
const outputIdx = args.indexOf("--output");
|
|
323
|
-
if (outputIdx !== -1) outputHtml = args[outputIdx + 1];
|
|
324
|
-
const baselineIdx = args.indexOf("--baseline");
|
|
325
|
-
if (baselineIdx !== -1) baselinePath = args[baselineIdx + 1];
|
|
326
|
-
const positionalNums = args.slice(1).filter((arg) => !arg.startsWith("-")).map(Number).filter((n) => !isNaN(n));
|
|
327
|
-
if (positionalNums.length > 0 && threadsIdx === -1 && !isAgentic) threads = positionalNums[0];
|
|
328
|
-
if (positionalNums.length > 1 && durationIdx === -1 && !isAgentic) durationSec = positionalNums[1];
|
|
329
|
-
if (positionalNums.length > 2 && errorIdx === -1 && !isAgentic) targetErrorRate = positionalNums[2] / 100;
|
|
330
|
-
if (isAgentic) {
|
|
331
|
-
const agenticIdx = args.indexOf("--agentic");
|
|
332
|
-
const trailingArgs = args.slice(agenticIdx + 1).filter((arg) => !arg.startsWith("--"));
|
|
333
|
-
if (trailingArgs[0]) maxThreads = parseInt(trailingArgs[0], 10);
|
|
334
|
-
if (trailingArgs[1]) {
|
|
335
|
-
let rawLatency = parseFloat(trailingArgs[1]);
|
|
336
|
-
if (rawLatency < 50) {
|
|
337
|
-
maxAllowedLatencyMs = rawLatency * 1e3;
|
|
338
|
-
} else {
|
|
339
|
-
maxAllowedLatencyMs = rawLatency;
|
|
340
|
-
}
|
|
367
|
+
function processMetricsTelemetry(requests, durationSec) {
|
|
368
|
+
const totalRequests = requests.length;
|
|
369
|
+
const durations = requests.map((r) => r.durationMs);
|
|
370
|
+
const avgLatencyMs = mathUtils.mean(durations);
|
|
371
|
+
const stdDevMs = mathUtils.stdDev(durations, avgLatencyMs);
|
|
372
|
+
const p95LatencyMs = mathUtils.percentile(durations, 95);
|
|
373
|
+
const avgDnsMs = mathUtils.mean(requests.map((r) => r.dnsTimeMs || 0));
|
|
374
|
+
const avgTcpMs = mathUtils.mean(requests.map((r) => r.tcpTimeMs || 0));
|
|
375
|
+
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
376
|
+
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
377
|
+
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
378
|
+
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
|
|
379
|
+
[400, 401, 403, 404, 429, 500, 502, 503, 504].forEach((c) => codeCounts[c] = 0);
|
|
380
|
+
requests.forEach((r) => {
|
|
381
|
+
if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
|
|
382
|
+
else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
|
|
383
|
+
else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
|
|
384
|
+
else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
|
|
385
|
+
else if (r.statusCode >= 500) c5xx++;
|
|
386
|
+
if (r.statusCode in codeCounts) {
|
|
387
|
+
codeCounts[r.statusCode]++;
|
|
341
388
|
}
|
|
342
|
-
|
|
343
|
-
|
|
389
|
+
});
|
|
390
|
+
const errorCount = c4xx + c5xx;
|
|
391
|
+
const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
|
|
392
|
+
const T = 50;
|
|
393
|
+
const satisfied = requests.filter((r) => r.durationMs <= T && r.statusCode < 400).length;
|
|
394
|
+
const tolerating = requests.filter((r) => r.durationMs > T && r.durationMs <= T * 4 && r.statusCode < 400).length;
|
|
395
|
+
const apdexScore = totalRequests === 0 ? 0 : (satisfied + tolerating / 2) / totalRequests;
|
|
396
|
+
const bandwidthMb = totalRequests * 1.2 / durationSec / 10;
|
|
344
397
|
return {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
398
|
+
totalRequests,
|
|
399
|
+
requestsPerSecond: totalRequests / durationSec,
|
|
400
|
+
avgLatencyMs,
|
|
401
|
+
stdDevMs,
|
|
402
|
+
p95LatencyMs,
|
|
403
|
+
errorRate,
|
|
404
|
+
apdexScore,
|
|
405
|
+
c1xx,
|
|
406
|
+
c2xx,
|
|
407
|
+
c3xx,
|
|
408
|
+
c4xx,
|
|
409
|
+
c5xx,
|
|
410
|
+
avgDnsMs,
|
|
411
|
+
avgTcpMs,
|
|
412
|
+
avgTlsMs,
|
|
413
|
+
avgTtfbMs,
|
|
414
|
+
bandwidthMb,
|
|
415
|
+
codeCounts
|
|
361
416
|
};
|
|
362
417
|
}
|
|
363
418
|
async function runBlazeCoreEngine(config) {
|
|
@@ -381,40 +436,62 @@ async function runBlazeCoreEngine(config) {
|
|
|
381
436
|
}, 1e3);
|
|
382
437
|
});
|
|
383
438
|
}
|
|
384
|
-
function
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
439
|
+
function printMatrixDashboard(m, threads) {
|
|
440
|
+
const pad = (val, size) => String(val).padEnd(size).substring(0, size);
|
|
441
|
+
console.log(`-----------------------------------------------------------------------------------------`);
|
|
442
|
+
console.log(`| Threads | Samples | Avg Latency | P95 Latency | Throughput | Error Rate | Apdex |`);
|
|
443
|
+
console.log(`-----------------------------------------------------------------------------------------`);
|
|
444
|
+
console.log(`| ${pad(threads, 7)} | ${pad(m.totalRequests, 9)} | ${pad(m.avgLatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.p95LatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.requestsPerSecond.toFixed(0) + "/s", 10)} | ${pad((m.errorRate * 100).toFixed(2) + "%", 10)} | ${pad(m.apdexScore.toFixed(2), 9)} |`);
|
|
445
|
+
console.log(`-----------------------------------------------------------------------------------------`);
|
|
446
|
+
}
|
|
447
|
+
function generateFinalAgentReport(history, score) {
|
|
448
|
+
if (history.length === 0) return;
|
|
449
|
+
const peakThroughput = Math.max(...history.map((h) => h.throughput));
|
|
450
|
+
const cleanRuns = history.filter((h) => h.apdex >= 0.85 && h.errorRate <= 0.01);
|
|
451
|
+
const maxSafeThreads = cleanRuns.length > 0 ? cleanRuns[cleanRuns.length - 1].threads : history[0].threads;
|
|
452
|
+
console.log(chalk.bold.green("\n======================================================="));
|
|
453
|
+
console.log(chalk.bold.cyan("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT"));
|
|
454
|
+
console.log(chalk.bold.green("======================================================="));
|
|
455
|
+
console.log(`\u{1F7E2} Unified Blaze Health Score : ${score}/100`);
|
|
456
|
+
console.log(`\u{1F3C6} Recommended Max Safe Concurrency : ${maxSafeThreads} allocation threads`);
|
|
457
|
+
console.log(`\u{1F4A5} Infrastructure Failure Boundary : ${history[history.length - 1].threads} concurrency allocation`);
|
|
458
|
+
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
459
|
+
console.log(chalk.bold.green("=======================================================\n"));
|
|
460
|
+
}
|
|
461
|
+
async function executeTestPipeline(config) {
|
|
462
|
+
if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
|
|
463
|
+
console.error(chalk.red("\u274C Error: runCorrelatedTransaction function is missing from the compiled binary bindings."));
|
|
464
|
+
return;
|
|
388
465
|
}
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
466
|
+
const transactionalScenario = [
|
|
467
|
+
{
|
|
468
|
+
name: "Fetch Target Anti-Forgery Nonce",
|
|
469
|
+
url: "https://httpbin.org/json",
|
|
470
|
+
method: "GET",
|
|
471
|
+
body: null
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
name: "Perform Contextual Post Action",
|
|
475
|
+
url: "https://httpbin.org/post?verification=${csrf_token}",
|
|
476
|
+
method: "POST",
|
|
477
|
+
body: JSON.stringify({
|
|
478
|
+
data: "performance_payload",
|
|
479
|
+
security_token: "${csrf_token}"
|
|
480
|
+
})
|
|
481
|
+
}
|
|
482
|
+
];
|
|
483
|
+
console.log(chalk.blue(`Launching automated script transaction analysis for: ${config.targetScript}`));
|
|
484
|
+
const sanitizedSteps = transactionalScenario.map((step) => ({
|
|
485
|
+
...step,
|
|
486
|
+
body: typeof step.body === "string" ? step.body : step.body ? JSON.stringify(step.body) : ""
|
|
487
|
+
}));
|
|
488
|
+
const success = await blazeCore.runCorrelatedTransaction(sanitizedSteps);
|
|
489
|
+
if (success) {
|
|
490
|
+
console.log(chalk.green("Pipeline run complete. Parameter tracking successfully mitigated breaking changes."));
|
|
406
491
|
}
|
|
407
|
-
return { trafficLoss, status, crawlPenalty, color };
|
|
408
|
-
}
|
|
409
|
-
function computeHealthScoreValue(apdex, errorRate, p95Latency, maxAllowedLatency) {
|
|
410
|
-
const apdexComponent = apdex * 50;
|
|
411
|
-
const errorComponent = Math.max(0, 1 - errorRate) * 30;
|
|
412
|
-
const latencyRatio = p95Latency / maxAllowedLatency;
|
|
413
|
-
const latencyComponent = Math.max(0, 1 - Math.min(1, latencyRatio)) * 20;
|
|
414
|
-
return Math.min(100, Math.max(0, Math.round(apdexComponent + errorComponent + latencyComponent)));
|
|
415
492
|
}
|
|
416
493
|
async function runIntelligentAgenticStressTest(config) {
|
|
417
|
-
console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
|
|
494
|
+
console.log(chalk.magenta("\u{1F680} Initializing Intelligent Autonomous Load Agent..."));
|
|
418
495
|
const history = [];
|
|
419
496
|
let aggregateErrorLogs = [];
|
|
420
497
|
let lastRawRequests = [];
|
|
@@ -428,7 +505,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
428
505
|
let verdictReason = "The system successfully scaled and remained stable within parameters up to maximum configured capacity allocations.";
|
|
429
506
|
let saturationKneePoint = null;
|
|
430
507
|
while (currentThreads <= config.maxThreads && isStable) {
|
|
431
|
-
console.log(`\u{1F916} [Agent Decision]: Testing execution tier at ${currentThreads} concurrent threads...`);
|
|
508
|
+
console.log(chalk.yellow(`\u{1F916} [Agent Decision]: Testing execution tier at ${currentThreads} concurrent threads...`));
|
|
432
509
|
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
|
|
433
510
|
if (config.clusterLogs) {
|
|
434
511
|
aggregateErrorLogs = aggregateErrorLogs.concat(rawErrors);
|
|
@@ -521,7 +598,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
521
598
|
if (config.isSeo) {
|
|
522
599
|
const finalLat = finalState.avgLatency || finalSummaryCards.ttfb;
|
|
523
600
|
const seo = calculateSeoImpactMetrics(finalLat);
|
|
524
|
-
console.log(`\u{1F50E} [SEO Impact Report]: Target latency under stress (${finalLat.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
|
|
601
|
+
console.log(chalk.bold.yellow(`\u{1F50E} [SEO Impact Report]: Target latency under stress (${finalLat.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`));
|
|
525
602
|
}
|
|
526
603
|
const breakdownRates = {};
|
|
527
604
|
Object.keys(globalCodeCounts).forEach((codeStr) => {
|
|
@@ -532,11 +609,11 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
532
609
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, geminiAnalysisHtml, baselineData);
|
|
533
610
|
}
|
|
534
611
|
async function runStandardStressTest(config) {
|
|
535
|
-
console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s | RampUp: ${config.rampUpSec}s | RampDown: ${config.rampDownSec}s]`);
|
|
612
|
+
console.log(chalk.blue(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s | RampUp: ${config.rampUpSec}s | RampDown: ${config.rampDownSec}s]`));
|
|
536
613
|
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine(config);
|
|
537
614
|
printMatrixDashboard(metrics, config.threads);
|
|
538
615
|
const healthScore = computeHealthScoreValue(metrics.apdexScore, metrics.errorRate, metrics.p95LatencyMs, config.maxAllowedLatencyMs);
|
|
539
|
-
console.log(`\u{1F49A} Unified Blaze Health Score: ${healthScore}/100`);
|
|
616
|
+
console.log(chalk.green(`\u{1F49A} Unified Blaze Health Score: ${healthScore}/100`));
|
|
540
617
|
const history = [{
|
|
541
618
|
threads: config.threads,
|
|
542
619
|
avgLatency: metrics.avgLatencyMs,
|
|
@@ -573,7 +650,7 @@ async function runStandardStressTest(config) {
|
|
|
573
650
|
const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, rawErrors.length > 0 ? rawErrors : getFallbackClusterLogs());
|
|
574
651
|
if (config.isSeo) {
|
|
575
652
|
const seo = calculateSeoImpactMetrics(metrics.avgLatencyMs);
|
|
576
|
-
console.log(`\u{1F50E} [SEO Impact Report]: Target latency (${metrics.avgLatencyMs.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
|
|
653
|
+
console.log(chalk.bold.yellow(`\u{1F50E} [SEO Impact Report]: Target latency (${metrics.avgLatencyMs.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`));
|
|
577
654
|
}
|
|
578
655
|
const breakdownRates = {};
|
|
579
656
|
Object.keys(metrics.codeCounts).forEach((codeStr) => {
|
|
@@ -590,129 +667,6 @@ async function runStandardStressTest(config) {
|
|
|
590
667
|
breakdownRates
|
|
591
668
|
}, finalSummaryCards, rawRequests, geminiAnalysisHtml, baselineData);
|
|
592
669
|
}
|
|
593
|
-
function getFallbackClusterLogs() {
|
|
594
|
-
const logs = [];
|
|
595
|
-
const add = (msg, count) => {
|
|
596
|
-
for (let i = 0; i < count; i++) logs.push(`[2026-07-08T12:08:18.000Z] ${msg}`);
|
|
597
|
-
};
|
|
598
|
-
add("JsonWebTokenError: jwt expired at JMT.verify (\\app\\node_modules\\jsonwebtoken\\index.js:5)", 37);
|
|
599
|
-
add("Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)", 33);
|
|
600
|
-
add("TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (\\app\\dist\\handler.js:42:19)", 31);
|
|
601
|
-
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms", 25);
|
|
602
|
-
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 30000ms", 19);
|
|
603
|
-
return logs;
|
|
604
|
-
}
|
|
605
|
-
function generateSimulationData(threads, durationSec, maxAllowedLatencyMs, rampUpSec = 0, rampDownSec = 0) {
|
|
606
|
-
const data = [];
|
|
607
|
-
const totalRequests = Math.max(15, threads * durationSec * 30);
|
|
608
|
-
const startTime = Date.now();
|
|
609
|
-
const rampUpMs = rampUpSec * 1e3;
|
|
610
|
-
const steadyMs = durationSec * 1e3;
|
|
611
|
-
const rampDownMs = rampDownSec * 1e3;
|
|
612
|
-
const totalTestMs = rampUpMs + steadyMs + rampDownMs;
|
|
613
|
-
const targetThresholdBreak = Math.max(5, Math.floor(maxAllowedLatencyMs * 0.05));
|
|
614
|
-
const errorPool = getFallbackClusterLogs();
|
|
615
|
-
for (let i = 0; i < totalRequests; i++) {
|
|
616
|
-
const offsetMs = Math.random() * totalTestMs;
|
|
617
|
-
const loadFactor = getLoadMultiplier(offsetMs, rampUpMs, steadyMs, rampDownMs);
|
|
618
|
-
if (loadFactor <= 0) continue;
|
|
619
|
-
const effectiveThreads = Math.max(1, threads * loadFactor);
|
|
620
|
-
const isBreached = effectiveThreads > targetThresholdBreak;
|
|
621
|
-
const stressFactor = isBreached ? Math.pow(effectiveThreads / targetThresholdBreak, 1.5) : 1;
|
|
622
|
-
const isError = Math.random() < (isBreached ? 0.05 : 1e-3);
|
|
623
|
-
const baseLatency = (25 + Math.random() * 35) * stressFactor;
|
|
624
|
-
let errorMessage;
|
|
625
|
-
let statusCode = 200;
|
|
626
|
-
if (isError) {
|
|
627
|
-
const targetResponseCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
|
|
628
|
-
statusCode = targetResponseCodes[Math.floor(Math.random() * targetResponseCodes.length)];
|
|
629
|
-
errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
|
|
630
|
-
}
|
|
631
|
-
data.push({
|
|
632
|
-
durationMs: isError ? baseLatency * 0.1 : baseLatency,
|
|
633
|
-
timestampMs: startTime + offsetMs,
|
|
634
|
-
dnsTimeMs: 1 + Math.random() * 0.9,
|
|
635
|
-
tcpTimeMs: 4 + Math.random() * 1.5,
|
|
636
|
-
tlsTimeMs: 6 + Math.random() * 1.8,
|
|
637
|
-
statusCode,
|
|
638
|
-
errorMessage
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
return data.sort((a, b) => a.timestampMs - b.timestampMs);
|
|
642
|
-
}
|
|
643
|
-
function processMetricsTelemetry(requests, durationSec) {
|
|
644
|
-
const totalRequests = requests.length;
|
|
645
|
-
const durations = requests.map((r) => r.durationMs);
|
|
646
|
-
const avgLatencyMs = mathUtils.mean(durations);
|
|
647
|
-
const stdDevMs = mathUtils.stdDev(durations, avgLatencyMs);
|
|
648
|
-
const p95LatencyMs = mathUtils.percentile(durations, 95);
|
|
649
|
-
const avgDnsMs = mathUtils.mean(requests.map((r) => r.dnsTimeMs || 0));
|
|
650
|
-
const avgTcpMs = mathUtils.mean(requests.map((r) => r.tcpTimeMs || 0));
|
|
651
|
-
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
652
|
-
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
653
|
-
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
654
|
-
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
|
|
655
|
-
[400, 401, 403, 404, 429, 500, 502, 503, 504].forEach((c) => codeCounts[c] = 0);
|
|
656
|
-
requests.forEach((r) => {
|
|
657
|
-
if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
|
|
658
|
-
else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
|
|
659
|
-
else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
|
|
660
|
-
else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
|
|
661
|
-
else if (r.statusCode >= 500) c5xx++;
|
|
662
|
-
if (r.statusCode in codeCounts) {
|
|
663
|
-
codeCounts[r.statusCode]++;
|
|
664
|
-
}
|
|
665
|
-
});
|
|
666
|
-
const errorCount = c4xx + c5xx;
|
|
667
|
-
const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
|
|
668
|
-
const T = 50;
|
|
669
|
-
const satisfied = requests.filter((r) => r.durationMs <= T && r.statusCode < 400).length;
|
|
670
|
-
const tolerating = requests.filter((r) => r.durationMs > T && r.durationMs <= T * 4 && r.statusCode < 400).length;
|
|
671
|
-
const apdexScore = totalRequests === 0 ? 0 : (satisfied + tolerating / 2) / totalRequests;
|
|
672
|
-
const bandwidthMb = totalRequests * 1.2 / durationSec / 10;
|
|
673
|
-
return {
|
|
674
|
-
totalRequests,
|
|
675
|
-
requestsPerSecond: totalRequests / durationSec,
|
|
676
|
-
avgLatencyMs,
|
|
677
|
-
stdDevMs,
|
|
678
|
-
p95LatencyMs,
|
|
679
|
-
errorRate,
|
|
680
|
-
apdexScore,
|
|
681
|
-
c1xx,
|
|
682
|
-
c2xx,
|
|
683
|
-
c3xx,
|
|
684
|
-
c4xx,
|
|
685
|
-
c5xx,
|
|
686
|
-
avgDnsMs,
|
|
687
|
-
avgTcpMs,
|
|
688
|
-
avgTlsMs,
|
|
689
|
-
avgTtfbMs,
|
|
690
|
-
bandwidthMb,
|
|
691
|
-
codeCounts
|
|
692
|
-
};
|
|
693
|
-
}
|
|
694
|
-
function printMatrixDashboard(m, threads) {
|
|
695
|
-
const pad = (val, size) => String(val).padEnd(size).substring(0, size);
|
|
696
|
-
console.log(`-----------------------------------------------------------------------------------------`);
|
|
697
|
-
console.log(`| Threads | Samples | Avg Latency | P95 Latency | Throughput | Error Rate | Apdex |`);
|
|
698
|
-
console.log(`-----------------------------------------------------------------------------------------`);
|
|
699
|
-
console.log(`| ${pad(threads, 7)} | ${pad(m.totalRequests, 9)} | ${pad(m.avgLatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.p95LatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.requestsPerSecond.toFixed(0) + "/s", 10)} | ${pad((m.errorRate * 100).toFixed(2) + "%", 10)} | ${pad(m.apdexScore.toFixed(2), 9)} |`);
|
|
700
|
-
console.log(`-----------------------------------------------------------------------------------------`);
|
|
701
|
-
}
|
|
702
|
-
function generateFinalAgentReport(history, score) {
|
|
703
|
-
if (history.length === 0) return;
|
|
704
|
-
const peakThroughput = Math.max(...history.map((h) => h.throughput));
|
|
705
|
-
const cleanRuns = history.filter((h) => h.apdex >= 0.85 && h.errorRate <= 0.01);
|
|
706
|
-
const maxSafeThreads = cleanRuns.length > 0 ? cleanRuns[cleanRuns.length - 1].threads : history[0].threads;
|
|
707
|
-
console.log("\n=======================================================");
|
|
708
|
-
console.log("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT");
|
|
709
|
-
console.log("=======================================================");
|
|
710
|
-
console.log(`\u{1F49A} Unified Blaze Health Score : ${score}/100`);
|
|
711
|
-
console.log(`\u{1F3C6} Recommended Max Safe Concurrency : ${maxSafeThreads} allocation threads`);
|
|
712
|
-
console.log(`\u{1F4A5} Infrastructure Failure Boundary : ${history[history.length - 1].threads} concurrency allocation`);
|
|
713
|
-
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
714
|
-
console.log("=======================================================\n");
|
|
715
|
-
}
|
|
716
670
|
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "", baselineData = null) {
|
|
717
671
|
const summaryArtifactPath = config.outputHtml.replace(/\.html$/, "-summary.json");
|
|
718
672
|
try {
|
|
@@ -1203,7 +1157,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1203
1157
|
const feedback = document.getElementById('nlpQueryFeedback');
|
|
1204
1158
|
|
|
1205
1159
|
let filterFn = (row, data) => true;
|
|
1206
|
-
const numMatch = q.match(/(d+(
|
|
1160
|
+
const numMatch = q.match(/(\\d+(?:\\.\\d+)?)/);
|
|
1207
1161
|
const targetNum = numMatch ? parseFloat(numMatch[1]) : null;
|
|
1208
1162
|
|
|
1209
1163
|
const isGreater = q.includes('>') || q.includes('greater') || q.includes('above') || q.includes('more');
|
|
@@ -1431,14 +1385,69 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1431
1385
|
</script></body></html>`;
|
|
1432
1386
|
try {
|
|
1433
1387
|
fs.writeFileSync(config.outputHtml, htmlContent, "utf-8");
|
|
1434
|
-
console.log(`\u{1F4CA} Standalone Dashboard exported successfully to: ${path.resolve(config.outputHtml)}`);
|
|
1388
|
+
console.log(chalk.bold.green(`\u{1F4CA} Standalone Dashboard exported successfully to: ${path.resolve(config.outputHtml)}`));
|
|
1435
1389
|
} catch (err) {
|
|
1436
|
-
console.error(`\u274C Failed to write HTML output dashboard: ${err}`);
|
|
1390
|
+
console.error(chalk.red(`\u274C Failed to write HTML output dashboard: ${err}`));
|
|
1437
1391
|
}
|
|
1438
1392
|
}
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1393
|
+
var program = new Command();
|
|
1394
|
+
program.name("blaze").description("Blaze CLI - High-performance distributed load and latency tester").version("1.0.0");
|
|
1395
|
+
program.command("run").description("Run a distributed load or local performance/stress test pipeline").argument("[script]", "Target script or directory path to evaluate", ".").option("-u, --url <url>", "Target simulation URL for distributed load routing", "https://api.example.com/health").option("-r, --regions <zones>", "Comma-separated list of target AWS/Cloud zones to simulate (e.g. us-east-1,eu-central-1,ap-south-1)").option("-t, --threads <threads>", "Number of parallel virtual users (VUs)", "10").option("-d, --duration <seconds>", "Test duration in seconds", "10").option("--ramp-up <seconds>", "Ramp-up duration in seconds", "0").option("--ramp-down <seconds>", "Ramp-down duration in seconds", "0").option("--target-apdex <score>", "Target Apdex satisfaction index (0.0 to 1.0)", "0.85").option("--target-error <rate>", "Target maximum allowed error rate (e.g. 0.01 for 1%)", "0.01").option("--max-threads <max>", "Maximum parallel threads for dynamic agentic scaling tests", "300").option("--max-allowed-latency <ms>", "SLA violation latency threshold (in milliseconds)", "800").option("-o, --output <filename>", "Destination path of the exported interactive HTML telemetry dashboard", "blaze-dashboard.html").option("--baseline <filepath>", "Reference JSON summary data to run automatic regression comparisons").option("--agentic", "Deploy the autonomous cognitive agent to auto-scale load until failure limits are hit", false).option("--correlate", "Enable transaction tracking pipelines (mitigates CSRF/nonce state mutations)", false).option("--seo", "Model SEO bounce rate, googlebot budget indexing penalties, and visibility impact", false).option("--no-cluster-logs", "Disable structural failure pattern clustering").action(async (script, options) => {
|
|
1396
|
+
const parsedThreads = parseInt(options.threads, 10);
|
|
1397
|
+
const parsedDuration = parseInt(options.duration, 10);
|
|
1398
|
+
const parsedRampUp = parseInt(options.rampUp, 10) || 0;
|
|
1399
|
+
const parsedRampDown = parseInt(options.rampDown, 10) || 0;
|
|
1400
|
+
const parsedApdex = parseFloat(options.targetApdex);
|
|
1401
|
+
const parsedError = parseFloat(options.targetError);
|
|
1402
|
+
const parsedMaxThreads = parseInt(options.maxThreads, 10);
|
|
1403
|
+
const parsedMaxLatencyRaw = parseFloat(options.maxAllowedLatency || "800");
|
|
1404
|
+
const parsedMaxLatency = parsedMaxLatencyRaw < 50 ? parsedMaxLatencyRaw * 1e3 : parsedMaxLatencyRaw;
|
|
1405
|
+
const config = {
|
|
1406
|
+
targetScript: path.resolve(script || "."),
|
|
1407
|
+
isAgentic: !!options.agentic,
|
|
1408
|
+
isCorrelate: !!options.correlate,
|
|
1409
|
+
isSeo: !!options.seo,
|
|
1410
|
+
clusterLogs: options.clusterLogs !== false,
|
|
1411
|
+
threads: parsedThreads,
|
|
1412
|
+
durationSec: parsedDuration,
|
|
1413
|
+
rampUpSec: parsedRampUp,
|
|
1414
|
+
rampDownSec: parsedRampDown,
|
|
1415
|
+
targetApdex: parsedApdex,
|
|
1416
|
+
targetErrorRate: parsedError,
|
|
1417
|
+
maxThreads: parsedMaxThreads,
|
|
1418
|
+
stepSize: 15,
|
|
1419
|
+
maxAllowedLatencyMs: parsedMaxLatency,
|
|
1420
|
+
outputHtml: options.output,
|
|
1421
|
+
baselinePath: options.baseline || null
|
|
1422
|
+
};
|
|
1423
|
+
if (options.regions) {
|
|
1424
|
+
console.log(chalk.blue(`
|
|
1425
|
+
Initializing Blaze load test simulation against ${chalk.bold(options.url)}...`));
|
|
1426
|
+
console.log(chalk.gray(`Target regions: ${options.regions}`));
|
|
1427
|
+
console.log(chalk.gray(`Duration: ${options.duration}s
|
|
1428
|
+
`));
|
|
1429
|
+
await new Promise((resolve2) => {
|
|
1430
|
+
setTimeout(() => {
|
|
1431
|
+
const allRegions = getMockRegionalData();
|
|
1432
|
+
const requestedZones = options.regions.split(",").map((z) => z.trim());
|
|
1433
|
+
const filteredRegions = allRegions.filter((r) => requestedZones.includes(r.zone));
|
|
1434
|
+
renderGeographicHeatmap(filteredRegions.length > 0 ? filteredRegions : allRegions);
|
|
1435
|
+
console.log(chalk.gray(`Executing localized system stress verification pipelines...
|
|
1436
|
+
`));
|
|
1437
|
+
resolve2(null);
|
|
1438
|
+
}, 1e3);
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
if (config.isCorrelate) {
|
|
1442
|
+
await executeTestPipeline(config);
|
|
1443
|
+
}
|
|
1444
|
+
if (config.isAgentic) {
|
|
1445
|
+
await runIntelligentAgenticStressTest(config);
|
|
1446
|
+
} else {
|
|
1447
|
+
await runStandardStressTest(config);
|
|
1448
|
+
}
|
|
1449
|
+
});
|
|
1450
|
+
program.command("heatmap").description("Display real-time geographic latency heatmap breakdown").action(() => {
|
|
1451
|
+
renderGeographicHeatmap(getMockRegionalData());
|
|
1452
|
+
});
|
|
1453
|
+
program.parse(process.argv);
|
|
Binary file
|