blaze-performance-tester 3.1.55 → 3.1.57
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 +82 -8
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -163,6 +163,19 @@ function getLoadMultiplier(elapsedMs, rampUpMs, steadyMs, rampDownMs) {
|
|
|
163
163
|
}
|
|
164
164
|
return elapsedMs >= totalDurationMs ? 0 : 1;
|
|
165
165
|
}
|
|
166
|
+
function loadBaselineData(filePath) {
|
|
167
|
+
if (!filePath) return null;
|
|
168
|
+
try {
|
|
169
|
+
const resolved = path.resolve(filePath);
|
|
170
|
+
if (fs.existsSync(resolved)) {
|
|
171
|
+
console.log(`\u{1F4C1} Loaded baseline comparison telemetry from: ${resolved}`);
|
|
172
|
+
return JSON.parse(fs.readFileSync(resolved, "utf-8"));
|
|
173
|
+
}
|
|
174
|
+
} catch (e) {
|
|
175
|
+
console.error(`\u274C Failed to parse baseline telemetry file: ${e}`);
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
166
179
|
async function generateGeminiRCA(history, finalSummary, errorLogs) {
|
|
167
180
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
168
181
|
if (!apiKey) {
|
|
@@ -291,6 +304,7 @@ function parseArguments(args) {
|
|
|
291
304
|
let maxThreads = 300;
|
|
292
305
|
let maxAllowedLatencyMs = 800;
|
|
293
306
|
let outputHtml = "blaze-dashboard.html";
|
|
307
|
+
let baselinePath = null;
|
|
294
308
|
const threadsIdx = args.indexOf("--threads");
|
|
295
309
|
if (threadsIdx !== -1) threads = parseInt(args[threadsIdx + 1], 10);
|
|
296
310
|
const durationIdx = args.indexOf("--duration");
|
|
@@ -300,13 +314,15 @@ function parseArguments(args) {
|
|
|
300
314
|
const rampDownIdx = args.indexOf("--ramp-down");
|
|
301
315
|
if (rampDownIdx !== -1) rampDownSec = parseInt(args[rampDownIdx + 1], 10);
|
|
302
316
|
const apdexIdx = args.indexOf("--target-apdex");
|
|
303
|
-
if (apdexIdx !== -1) targetApdex = parseFloat(
|
|
317
|
+
if (apdexIdx !== -1) targetApdex = parseFloat(apdexIdx + 1);
|
|
304
318
|
const errorIdx = args.indexOf("--target-error");
|
|
305
319
|
if (errorIdx !== -1) targetErrorRate = parseFloat(args[errorIdx + 1]);
|
|
306
320
|
const maxThreadsIdx = args.indexOf("--max-threads");
|
|
307
321
|
if (maxThreadsIdx !== -1) maxThreads = parseInt(args[maxThreadsIdx + 1], 10);
|
|
308
322
|
const outputIdx = args.indexOf("--output");
|
|
309
323
|
if (outputIdx !== -1) outputHtml = args[outputIdx + 1];
|
|
324
|
+
const baselineIdx = args.indexOf("--baseline");
|
|
325
|
+
if (baselineIdx !== -1) baselinePath = args[baselineIdx + 1];
|
|
310
326
|
const positionalNums = args.slice(1).filter((arg) => !arg.startsWith("-")).map(Number).filter((n) => !isNaN(n));
|
|
311
327
|
if (positionalNums.length > 0 && threadsIdx === -1 && !isAgentic) threads = positionalNums[0];
|
|
312
328
|
if (positionalNums.length > 1 && durationIdx === -1 && !isAgentic) durationSec = positionalNums[1];
|
|
@@ -340,7 +356,8 @@ function parseArguments(args) {
|
|
|
340
356
|
maxThreads,
|
|
341
357
|
stepSize: 15,
|
|
342
358
|
maxAllowedLatencyMs,
|
|
343
|
-
outputHtml
|
|
359
|
+
outputHtml,
|
|
360
|
+
baselinePath
|
|
344
361
|
};
|
|
345
362
|
}
|
|
346
363
|
async function runBlazeCoreEngine(config) {
|
|
@@ -495,7 +512,9 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
495
512
|
tls: mathUtils.mean(globalMetricsAccumulator.tls),
|
|
496
513
|
stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies)),
|
|
497
514
|
saturationKneePoint: saturationKneePoint || finalState.threads || 50,
|
|
498
|
-
healthScore
|
|
515
|
+
healthScore,
|
|
516
|
+
errorRate: finalState.errorRate,
|
|
517
|
+
p95Latency: finalState.p95Latency
|
|
499
518
|
};
|
|
500
519
|
generateFinalAgentReport(history, healthScore);
|
|
501
520
|
const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, aggregateErrorLogs);
|
|
@@ -509,7 +528,8 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
509
528
|
const code = Number(codeStr);
|
|
510
529
|
breakdownRates[code] = totalRequestsAccumulator === 0 ? 0 : globalCodeCounts[code] / totalRequestsAccumulator * 100;
|
|
511
530
|
});
|
|
512
|
-
|
|
531
|
+
const baselineData = loadBaselineData(config.baselinePath);
|
|
532
|
+
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, geminiAnalysisHtml, baselineData);
|
|
513
533
|
}
|
|
514
534
|
async function runStandardStressTest(config) {
|
|
515
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]`);
|
|
@@ -544,7 +564,9 @@ async function runStandardStressTest(config) {
|
|
|
544
564
|
tls: metrics.avgTlsMs,
|
|
545
565
|
stdDev: metrics.stdDevMs,
|
|
546
566
|
saturationKneePoint: config.threads,
|
|
547
|
-
healthScore
|
|
567
|
+
healthScore,
|
|
568
|
+
errorRate: metrics.errorRate,
|
|
569
|
+
p95Latency: metrics.p95LatencyMs
|
|
548
570
|
};
|
|
549
571
|
const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
|
|
550
572
|
const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
|
|
@@ -558,6 +580,7 @@ async function runStandardStressTest(config) {
|
|
|
558
580
|
const code = Number(codeStr);
|
|
559
581
|
breakdownRates[code] = metrics.totalRequests === 0 ? 0 : metrics.codeCounts[code] / metrics.totalRequests * 100;
|
|
560
582
|
});
|
|
583
|
+
const baselineData = loadBaselineData(config.baselinePath);
|
|
561
584
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, {
|
|
562
585
|
total1xx: metrics.c1xx,
|
|
563
586
|
total2xx: metrics.c2xx,
|
|
@@ -565,7 +588,7 @@ async function runStandardStressTest(config) {
|
|
|
565
588
|
total4xx: metrics.c4xx,
|
|
566
589
|
total5xx: metrics.c5xx,
|
|
567
590
|
breakdownRates
|
|
568
|
-
}, finalSummaryCards, rawRequests, geminiAnalysisHtml);
|
|
591
|
+
}, finalSummaryCards, rawRequests, geminiAnalysisHtml, baselineData);
|
|
569
592
|
}
|
|
570
593
|
function getFallbackClusterLogs() {
|
|
571
594
|
const logs = [];
|
|
@@ -690,7 +713,12 @@ function generateFinalAgentReport(history, score) {
|
|
|
690
713
|
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
691
714
|
console.log("=======================================================\n");
|
|
692
715
|
}
|
|
693
|
-
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "") {
|
|
716
|
+
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "", baselineData = null) {
|
|
717
|
+
const summaryArtifactPath = config.outputHtml.replace(/\.html$/, "-summary.json");
|
|
718
|
+
try {
|
|
719
|
+
fs.writeFileSync(summaryArtifactPath, JSON.stringify(cards, null, 2), "utf-8");
|
|
720
|
+
} catch (e) {
|
|
721
|
+
}
|
|
694
722
|
const labels = history.map((h, i) => `${i + 1}s`);
|
|
695
723
|
const successRequestsData = history.map((h) => h.successRequests);
|
|
696
724
|
const failedWorkloadsData = history.map((h) => h.failedRequests);
|
|
@@ -707,6 +735,50 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
707
735
|
x: Number(((r.timestampMs - firstTimestamp) / 1e3).toFixed(2)),
|
|
708
736
|
y: Number(((r.dnsTimeMs || 0) + (r.tcpTimeMs || 0) + (r.tlsTimeMs || 0) + r.durationMs * 0.3).toFixed(1))
|
|
709
737
|
}));
|
|
738
|
+
let baselineComparisonHtml = "";
|
|
739
|
+
if (baselineData) {
|
|
740
|
+
const diffApdex = cards.apdex - baselineData.apdex;
|
|
741
|
+
const diffThroughput = (cards.throughput - baselineData.throughput) / (baselineData.throughput || 1) * 100;
|
|
742
|
+
const diffTtfb = (cards.ttfb - baselineData.ttfb) / (baselineData.ttfb || 1) * 100;
|
|
743
|
+
const diffHealth = cards.healthScore - baselineData.healthScore;
|
|
744
|
+
const formatDelta = (val, isInverse = false) => {
|
|
745
|
+
const good = isInverse ? val <= 0 : val >= 0;
|
|
746
|
+
const color = good ? "#10b981" : "#ef4444";
|
|
747
|
+
const sign = val > 0 ? "+" : "";
|
|
748
|
+
return `<span style="color: ${color}; font-weight: bold;">${sign}${val.toFixed(1)}%</span>`;
|
|
749
|
+
};
|
|
750
|
+
baselineComparisonHtml = `
|
|
751
|
+
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #7c3aed;">
|
|
752
|
+
<h3 style="color: #a78bfa; display: flex; align-items: center; gap: 0.6rem; font-size: 1.2rem; border-bottom: 1px solid #1e293b; padding-bottom: 0.5rem;">
|
|
753
|
+
\u{1F4CA} Baseline Regression Comparison (Delta Engine)
|
|
754
|
+
</h3>
|
|
755
|
+
<p style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
|
|
756
|
+
Comparing current execution metrics directly against reference payload from baseline source.
|
|
757
|
+
</p>
|
|
758
|
+
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem;">
|
|
759
|
+
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
760
|
+
<div class="card-title">Apdex Shift</div>
|
|
761
|
+
<div style="font-size: 1.4rem; font-weight: bold; color: #ffffff;">${cards.apdex.toFixed(2)}</div>
|
|
762
|
+
<div style="font-size: 0.8rem; margin-top: 0.2rem;">Delta: <span style="color: ${diffApdex >= 0 ? "#10b981" : "#ef4444"}; font-weight: bold;">${diffApdex >= 0 ? "+" : ""}${diffApdex.toFixed(2)}</span></div>
|
|
763
|
+
</div>
|
|
764
|
+
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
765
|
+
<div class="card-title">Throughput Delta</div>
|
|
766
|
+
<div style="font-size: 1.4rem; font-weight: bold; color: #ffffff;">${cards.throughput.toFixed(0)}/s</div>
|
|
767
|
+
<div style="font-size: 0.8rem; margin-top: 0.2rem;">Delta: ${formatDelta(diffThroughput, false)}</div>
|
|
768
|
+
</div>
|
|
769
|
+
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
770
|
+
<div class="card-title">TTFB Latency Shift</div>
|
|
771
|
+
<div style="font-size: 1.4rem; font-weight: bold; color: #ffffff;">${cards.ttfb.toFixed(1)}ms</div>
|
|
772
|
+
<div style="font-size: 0.8rem; margin-top: 0.2rem;">Delta: ${formatDelta(diffTtfb, true)}</div>
|
|
773
|
+
</div>
|
|
774
|
+
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
775
|
+
<div class="card-title">Health Score Diff</div>
|
|
776
|
+
<div style="font-size: 1.4rem; font-weight: bold; color: #ffffff;">${cards.healthScore}/100</div>
|
|
777
|
+
<div style="font-size: 0.8rem; margin-top: 0.2rem;">Delta: <span style="color: ${diffHealth >= 0 ? "#10b981" : "#ef4444"}; font-weight: bold;">${diffHealth >= 0 ? "+" : ""}${diffHealth} pts</span></div>
|
|
778
|
+
</div>
|
|
779
|
+
</div>
|
|
780
|
+
</div>`;
|
|
781
|
+
}
|
|
710
782
|
let logClustersHtml = "";
|
|
711
783
|
if (semanticReport) {
|
|
712
784
|
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
@@ -969,6 +1041,8 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
969
1041
|
</div>
|
|
970
1042
|
</div>
|
|
971
1043
|
|
|
1044
|
+
${baselineComparisonHtml}
|
|
1045
|
+
|
|
972
1046
|
<div class="top-layout-grid">
|
|
973
1047
|
<div class="verdict-box">
|
|
974
1048
|
<div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
|
|
@@ -1365,6 +1439,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1365
1439
|
function printUsage() {
|
|
1366
1440
|
console.log(`Blaze Core Performance Test CLI Engine
|
|
1367
1441
|
Options:
|
|
1368
|
-
--threads <count> | --duration <seconds> | --
|
|
1442
|
+
--threads <count> | --duration <seconds> | --baseline <json_file> | --output <html_file>`);
|
|
1369
1443
|
}
|
|
1370
1444
|
main().catch(console.error);
|
|
Binary file
|