blaze-performance-tester 3.0.36 → 3.0.38
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 +57 -10
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -209,7 +209,7 @@ async function runBlazeCoreEngine(config) {
|
|
|
209
209
|
const steadyStateRequests = rawRequests.slice(warmUpCutoff);
|
|
210
210
|
const metrics = processMetricsTelemetry(steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests, config.durationSec);
|
|
211
211
|
const rawErrors = rawRequests.filter((r) => r.errorMessage).map((r) => r.errorMessage);
|
|
212
|
-
resolve2({ metrics, rawErrors });
|
|
212
|
+
resolve2({ metrics, rawErrors, rawRequests: steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests });
|
|
213
213
|
}, 1e3);
|
|
214
214
|
});
|
|
215
215
|
}
|
|
@@ -217,6 +217,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
217
217
|
console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
|
|
218
218
|
const history = [];
|
|
219
219
|
let aggregateErrorLogs = [];
|
|
220
|
+
let lastRawRequests = [];
|
|
220
221
|
let total1xx = 0, total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
|
|
221
222
|
let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: [] };
|
|
222
223
|
let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
|
|
@@ -226,10 +227,11 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
226
227
|
let saturationKneePoint = null;
|
|
227
228
|
while (currentThreads <= config.maxThreads && isStable) {
|
|
228
229
|
console.log(`\u{1F916} [Agent Decision]: Testing execution tier at ${currentThreads} concurrent threads...`);
|
|
229
|
-
const { metrics, rawErrors } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
|
|
230
|
+
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
|
|
230
231
|
if (config.clusterLogs) {
|
|
231
232
|
aggregateErrorLogs = aggregateErrorLogs.concat(rawErrors);
|
|
232
233
|
}
|
|
234
|
+
lastRawRequests = rawRequests;
|
|
233
235
|
total1xx += metrics.c1xx;
|
|
234
236
|
total2xx += metrics.c2xx;
|
|
235
237
|
total3xx += metrics.c3xx;
|
|
@@ -291,6 +293,8 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
291
293
|
const analyzer = new LogAnalyzer();
|
|
292
294
|
semanticReport = analyzer.process(aggregateErrorLogs);
|
|
293
295
|
}
|
|
296
|
+
const totalTestSeconds = history.length * config.durationSec;
|
|
297
|
+
const vuRampUpVelocity = history.length > 1 && totalTestSeconds > 0 ? (history[history.length - 1].threads - history[0].threads) / totalTestSeconds : config.threads / config.durationSec;
|
|
294
298
|
const finalSummaryCards = {
|
|
295
299
|
apdex: history[history.length - 1]?.apdex || 0,
|
|
296
300
|
throughput: history[history.length - 1]?.throughput || 0,
|
|
@@ -300,14 +304,15 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
300
304
|
tcp: mathUtils.mean(globalMetricsAccumulator.tcp),
|
|
301
305
|
tls: mathUtils.mean(globalMetricsAccumulator.tls),
|
|
302
306
|
stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies)),
|
|
303
|
-
saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50
|
|
307
|
+
saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50,
|
|
308
|
+
vuRampUpVelocity
|
|
304
309
|
};
|
|
305
310
|
generateFinalAgentReport(history);
|
|
306
|
-
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx }, finalSummaryCards);
|
|
311
|
+
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx }, finalSummaryCards, lastRawRequests);
|
|
307
312
|
}
|
|
308
313
|
async function runStandardStressTest(config) {
|
|
309
314
|
console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
|
|
310
|
-
const { metrics, rawErrors } = await runBlazeCoreEngine(config);
|
|
315
|
+
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine(config);
|
|
311
316
|
printMatrixDashboard(metrics, config.threads);
|
|
312
317
|
const history = [{
|
|
313
318
|
threads: config.threads,
|
|
@@ -335,7 +340,8 @@ async function runStandardStressTest(config) {
|
|
|
335
340
|
tcp: metrics.avgTcpMs,
|
|
336
341
|
tls: metrics.avgTlsMs,
|
|
337
342
|
stdDev: metrics.stdDevMs,
|
|
338
|
-
saturationKneePoint: config.threads
|
|
343
|
+
saturationKneePoint: config.threads,
|
|
344
|
+
vuRampUpVelocity: config.threads / config.durationSec
|
|
339
345
|
};
|
|
340
346
|
const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
|
|
341
347
|
const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
|
|
@@ -345,7 +351,7 @@ async function runStandardStressTest(config) {
|
|
|
345
351
|
total3xx: metrics.c3xx,
|
|
346
352
|
total4xx: metrics.c4xx,
|
|
347
353
|
total5xx: metrics.c5xx
|
|
348
|
-
}, finalSummaryCards);
|
|
354
|
+
}, finalSummaryCards, rawRequests);
|
|
349
355
|
}
|
|
350
356
|
function getFallbackClusterLogs() {
|
|
351
357
|
const logs = [];
|
|
@@ -454,7 +460,7 @@ function generateFinalAgentReport(history) {
|
|
|
454
460
|
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
455
461
|
console.log("=======================================================\n");
|
|
456
462
|
}
|
|
457
|
-
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards) {
|
|
463
|
+
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = []) {
|
|
458
464
|
const labels = history.map((h, i) => `${i + 1}s`);
|
|
459
465
|
const successRequestsData = history.map((h) => h.successRequests);
|
|
460
466
|
const failedWorkloadsData = history.map((h) => h.failedRequests);
|
|
@@ -466,6 +472,11 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
466
472
|
const estimatedMonthlyCost = (cards.throughput * 0.045 * 24 * 30).toFixed(2);
|
|
467
473
|
const recommendedCpuCores = Math.max(2, Math.ceil(cards.saturationKneePoint / 75));
|
|
468
474
|
const recommendedRamGb = recommendedCpuCores * 2;
|
|
475
|
+
const firstTimestamp = rawRequests[0]?.timestampMs || Date.now();
|
|
476
|
+
const scatterPoints = rawRequests.slice(0, 180).map((r) => ({
|
|
477
|
+
x: Number(((r.timestampMs - firstTimestamp) / 1e3).toFixed(2)),
|
|
478
|
+
y: Number(((r.dnsTimeMs || 0) + (r.tcpTimeMs || 0) + (r.tlsTimeMs || 0) + r.durationMs * 0.3).toFixed(1))
|
|
479
|
+
}));
|
|
469
480
|
let logClustersHtml = "";
|
|
470
481
|
if (semanticReport) {
|
|
471
482
|
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
@@ -573,7 +584,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
573
584
|
h1 { color: #38bdf8; margin: 0; font-size: 2rem; }
|
|
574
585
|
.meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
|
|
575
586
|
|
|
576
|
-
.cards-wrapper { display: grid; grid-template-columns: repeat(
|
|
587
|
+
.cards-wrapper { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
|
|
577
588
|
.metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
|
|
578
589
|
.card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
|
|
579
590
|
.card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }
|
|
@@ -581,6 +592,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
581
592
|
.card-value.green { color: #10b981; }
|
|
582
593
|
.card-value.orange { color: #f97316; }
|
|
583
594
|
.card-value.purple { color: #a855f7; }
|
|
595
|
+
.card-value.cyan { color: #38bdf8; }
|
|
584
596
|
.card-subtext { font-size: 0.8rem; color: #10b981; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
|
|
585
597
|
|
|
586
598
|
.top-layout-grid { display: grid; grid-template-columns: 1fr 400px; gap: 1.5rem; margin-bottom: 2rem; }
|
|
@@ -603,7 +615,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
603
615
|
.badge-5xx { background: rgba(220, 38, 38, 0.2); color: #f87171; }
|
|
604
616
|
.matrix-value { font-size: 1rem; font-weight: bold; color: #ffffff; }
|
|
605
617
|
|
|
606
|
-
.charts-grid { display: grid; grid-template-columns: repeat(
|
|
618
|
+
.charts-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; margin-bottom: 2rem; }
|
|
607
619
|
.graph-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }
|
|
608
620
|
.graph-title { font-size: 1.1rem; font-weight: 700; color: #ffffff; margin-bottom: 1.2rem; display: flex; align-items: center; gap: 0.5rem; }
|
|
609
621
|
|
|
@@ -639,6 +651,10 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
639
651
|
<div class="card-title">Avg Time To First Byte</div>
|
|
640
652
|
<div class="card-value">${cards.ttfb.toFixed(1)}<span class="unit">ms</span></div>
|
|
641
653
|
</div>
|
|
654
|
+
<div class="metric-card">
|
|
655
|
+
<div class="card-title">VU Ramp-up Velocity</div>
|
|
656
|
+
<div class="card-value cyan">${cards.vuRampUpVelocity.toFixed(1)}<span class="unit">VUs/s</span></div>
|
|
657
|
+
</div>
|
|
642
658
|
<div class="metric-card">
|
|
643
659
|
<div class="card-title">DNS Lookup</div>
|
|
644
660
|
<div class="card-value">${cards.dns.toFixed(2)}<span class="unit">ms</span></div>
|
|
@@ -710,6 +726,13 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
710
726
|
<canvas id="statusDonutChart"></canvas>
|
|
711
727
|
</div>
|
|
712
728
|
</div>
|
|
729
|
+
|
|
730
|
+
<div class="graph-card">
|
|
731
|
+
<div class="graph-title">\u{1F4C8} Time-to-First-Byte Scatter Plot</div>
|
|
732
|
+
<div style="height: 280px; position: relative;">
|
|
733
|
+
<canvas id="ttfbScatterChart"></canvas>
|
|
734
|
+
</div>
|
|
735
|
+
</div>
|
|
713
736
|
</div>
|
|
714
737
|
|
|
715
738
|
<div class="card">
|
|
@@ -861,6 +884,30 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
861
884
|
cutout: '65%'
|
|
862
885
|
}
|
|
863
886
|
});
|
|
887
|
+
|
|
888
|
+
new Chart(document.getElementById('ttfbScatterChart'), {
|
|
889
|
+
type: 'scatter',
|
|
890
|
+
data: {
|
|
891
|
+
datasets: [{
|
|
892
|
+
label: 'Request Processing Delay',
|
|
893
|
+
data: ${JSON.stringify(scatterPoints)},
|
|
894
|
+
backgroundColor: '#a855f7',
|
|
895
|
+
pointRadius: 4,
|
|
896
|
+
pointHoverRadius: 6
|
|
897
|
+
}]
|
|
898
|
+
},
|
|
899
|
+
options: {
|
|
900
|
+
responsive: true,
|
|
901
|
+
maintainAspectRatio: false,
|
|
902
|
+
plugins: {
|
|
903
|
+
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
|
|
904
|
+
},
|
|
905
|
+
scales: {
|
|
906
|
+
x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' }, title: { display: true, text: 'Time offset (s)', color: '#64748b' } },
|
|
907
|
+
y: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' }, title: { display: true, text: 'TTFB / Delay (ms)', color: '#64748b' } }
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
});
|
|
864
911
|
</script></body></html>`;
|
|
865
912
|
try {
|
|
866
913
|
fs.writeFileSync(config.outputHtml, htmlContent, "utf-8");
|
|
Binary file
|