blaze-performance-tester 3.1.7 → 3.1.8

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 CHANGED
@@ -224,6 +224,9 @@ async function runIntelligentAgenticStressTest(config) {
224
224
  let lastRawRequests = [];
225
225
  let total1xx = 0, total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
226
226
  let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: [], lcp: [], fid: [], cls: [] };
227
+ let totalEconnreset = 0;
228
+ let totalEconnrefused = 0;
229
+ const globalCodeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
227
230
  let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
228
231
  let baseStep = config.stepSize;
229
232
  let isStable = true;
@@ -241,6 +244,11 @@ async function runIntelligentAgenticStressTest(config) {
241
244
  total3xx += metrics.c3xx;
242
245
  total4xx += metrics.c4xx;
243
246
  total5xx += metrics.c5xx;
247
+ totalEconnreset += metrics.econnresetCount;
248
+ totalEconnrefused += metrics.econnrefusedCount;
249
+ Object.keys(globalCodeCounts).forEach((code) => {
250
+ globalCodeCounts[code] += metrics.codeCounts[code] || 0;
251
+ });
244
252
  globalMetricsAccumulator.dns.push(metrics.avgDnsMs);
245
253
  globalMetricsAccumulator.tcp.push(metrics.avgTcpMs);
246
254
  globalMetricsAccumulator.tls.push(metrics.avgTlsMs);
@@ -261,7 +269,10 @@ async function runIntelligentAgenticStressTest(config) {
261
269
  failedRequests: metrics.c4xx + metrics.c5xx,
262
270
  lcp: metrics.lcpMs,
263
271
  fid: metrics.fidMs,
264
- cls: metrics.clsScore
272
+ cls: metrics.clsScore,
273
+ econnresetRate: metrics.econnresetRate,
274
+ econnrefusedCount: metrics.econnrefusedCount,
275
+ codeRates: metrics.codeRates
265
276
  };
266
277
  printMatrixDashboard(metrics, currentThreads);
267
278
  history.push(currentState);
@@ -305,6 +316,11 @@ async function runIntelligentAgenticStressTest(config) {
305
316
  }
306
317
  const totalTestSeconds = history.length * config.durationSec;
307
318
  const vuRampUpVelocity = history.length > 1 && totalTestSeconds > 0 ? (history[history.length - 1].threads - history[0].threads) / totalTestSeconds : config.threads / config.durationSec;
319
+ const totalGlobalRequests = total1xx + total2xx + total3xx + total4xx + total5xx;
320
+ const aggregatedCodeRates = {};
321
+ Object.keys(globalCodeCounts).forEach((code) => {
322
+ aggregatedCodeRates[code] = totalGlobalRequests === 0 ? 0 : globalCodeCounts[code] / totalGlobalRequests * 100;
323
+ });
308
324
  const finalSummaryCards = {
309
325
  apdex: history[history.length - 1]?.apdex || 0,
310
326
  throughput: history[history.length - 1]?.throughput || 0,
@@ -318,7 +334,10 @@ async function runIntelligentAgenticStressTest(config) {
318
334
  vuRampUpVelocity,
319
335
  lcp: mathUtils.mean(globalMetricsAccumulator.lcp),
320
336
  fid: mathUtils.mean(globalMetricsAccumulator.fid),
321
- cls: mathUtils.mean(globalMetricsAccumulator.cls)
337
+ cls: mathUtils.mean(globalMetricsAccumulator.cls),
338
+ econnresetRate: totalGlobalRequests === 0 ? 0 : totalEconnreset / totalGlobalRequests * 100,
339
+ econnrefusedCount: totalEconnrefused,
340
+ codeRates: aggregatedCodeRates
322
341
  };
323
342
  generateFinalAgentReport(history);
324
343
  exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx }, finalSummaryCards, lastRawRequests);
@@ -338,7 +357,10 @@ async function runStandardStressTest(config) {
338
357
  failedRequests: metrics.c4xx + metrics.c5xx,
339
358
  lcp: metrics.lcpMs,
340
359
  fid: metrics.fidMs,
341
- cls: metrics.clsScore
360
+ cls: metrics.clsScore,
361
+ econnresetRate: metrics.econnresetRate,
362
+ econnrefusedCount: metrics.econnrefusedCount,
363
+ codeRates: metrics.codeRates
342
364
  }];
343
365
  let semanticReport = null;
344
366
  if (config.clusterLogs) {
@@ -360,7 +382,10 @@ async function runStandardStressTest(config) {
360
382
  vuRampUpVelocity: config.threads / config.durationSec,
361
383
  lcp: metrics.lcpMs,
362
384
  fid: metrics.fidMs,
363
- cls: metrics.clsScore
385
+ cls: metrics.clsScore,
386
+ econnresetRate: metrics.econnresetRate,
387
+ econnrefusedCount: metrics.econnrefusedCount,
388
+ codeRates: metrics.codeRates
364
389
  };
365
390
  const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
366
391
  const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
@@ -392,14 +417,26 @@ function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
392
417
  const isBreached = threads > targetThresholdBreak;
393
418
  const stressFactor = isBreached ? Math.pow(threads / targetThresholdBreak, 1.5) : 1;
394
419
  const errorPool = getFallbackClusterLogs();
420
+ const targetFailureCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
395
421
  for (let i = 0; i < totalRequests; i++) {
396
- const isError = Math.random() < (isBreached ? 0.05 : 1e-3);
422
+ const isError = Math.random() < (isBreached ? 0.08 : 5e-3);
397
423
  const baseLatency = (25 + Math.random() * 35) * stressFactor;
398
424
  let errorMessage;
399
425
  let statusCode = 200;
400
426
  if (isError) {
401
- statusCode = Math.random() > 0.3 ? 500 : 404;
402
- errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
427
+ const coin = Math.random();
428
+ if (coin < 0.25) {
429
+ statusCode = 502;
430
+ errorMessage = "Error: ECONNRESET socket hang up abruptly by remote host";
431
+ } else if (coin < 0.5) {
432
+ statusCode = 503;
433
+ errorMessage = "Error: ECONNREFUSED 127.0.0.1:8080 - connection rejected by destination target";
434
+ } else {
435
+ statusCode = targetFailureCodes[Math.floor(Math.random() * targetFailureCodes.length)];
436
+ errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
437
+ }
438
+ } else {
439
+ if (Math.random() < 0.03) statusCode = 302;
403
440
  }
404
441
  data.push({
405
442
  durationMs: isError ? baseLatency * 0.1 : baseLatency,
@@ -424,13 +461,29 @@ function processMetricsTelemetry(requests, durationSec, apdexT) {
424
461
  const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
425
462
  const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
426
463
  let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
464
+ let econnresetCount = 0;
465
+ let econnrefusedCount = 0;
466
+ const targetCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
467
+ const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
427
468
  requests.forEach((r) => {
428
469
  if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
429
470
  else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
430
471
  else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
431
472
  else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
432
473
  else if (r.statusCode >= 500) c5xx++;
474
+ if (r.statusCode in codeCounts) {
475
+ codeCounts[r.statusCode]++;
476
+ }
477
+ if (r.errorMessage) {
478
+ if (r.errorMessage.includes("ECONNRESET")) econnresetCount++;
479
+ if (r.errorMessage.includes("ECONNREFUSED")) econnrefusedCount++;
480
+ }
481
+ });
482
+ const codeRates = {};
483
+ targetCodes.forEach((code) => {
484
+ codeRates[code] = totalRequests === 0 ? 0 : codeCounts[code] / totalRequests * 100;
433
485
  });
486
+ const econnresetRate = totalRequests === 0 ? 0 : econnresetCount / totalRequests * 100;
434
487
  const errorCount = c4xx + c5xx;
435
488
  const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
436
489
  const satisfied = requests.filter((r) => r.durationMs <= apdexT && r.statusCode < 400).length;
@@ -460,7 +513,12 @@ function processMetricsTelemetry(requests, durationSec, apdexT) {
460
513
  bandwidthMb,
461
514
  lcpMs,
462
515
  fidMs,
463
- clsScore
516
+ clsScore,
517
+ econnresetCount,
518
+ econnresetRate,
519
+ econnrefusedCount,
520
+ codeCounts,
521
+ codeRates
464
522
  };
465
523
  }
466
524
  function printMatrixDashboard(m, threads) {
@@ -470,7 +528,7 @@ function printMatrixDashboard(m, threads) {
470
528
  console.log(`-----------------------------------------------------------------------------------------`);
471
529
  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)} |`);
472
530
  console.log(`-----------------------------------------------------------------------------------------`);
473
- console.log(`| Simulated Web Vitals Equivalent -> LCP: ${m.lcpMs.toFixed(0)}ms | FID: ${m.fidMs.toFixed(1)}ms | CLS: ${m.clsScore.toFixed(3)} |`);
531
+ console.log(`| Network State -> RESET Rate: ${m.econnresetRate.toFixed(2)}% | REFUSED Count: ${m.econnrefusedCount} | Web Vitals -> LCP: ${m.lcpMs.toFixed(0)}ms |`);
474
532
  console.log(`-----------------------------------------------------------------------------------------`);
475
533
  }
476
534
  function generateFinalAgentReport(history) {
@@ -493,7 +551,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
493
551
  const activeThreadsData = history.map((h) => h.threads);
494
552
  const ttfTrendData = history.map((h) => h.avgLatency * 1.1);
495
553
  const waveListItems = history.map((h) => {
496
- return `<div class="wave-item">Wave (${h.threads} VUs): P95 ${h.p95Latency.toFixed(1)}ms, Errors ${(h.errorRate * 100).toFixed(1)}%, LCP ${h.lcp.toFixed(0)}ms</div>`;
554
+ return `<div class="wave-item">Wave (${h.threads} VUs): P95 ${h.p95Latency.toFixed(1)}ms, ECONNRESET Rate: ${h.econnresetRate.toFixed(1)}%, REFUSED: ${h.econnrefusedCount}</div>`;
497
555
  }).join("");
498
556
  const estimatedMonthlyCost = (cards.throughput * 0.045 * 24 * 30).toFixed(2);
499
557
  const recommendedCpuCores = Math.max(2, Math.ceil(cards.saturationKneePoint / 75));
@@ -509,6 +567,56 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
509
567
  const lcpStat = getLcpStatus(cards.lcp);
510
568
  const fidStat = getFidStatus(cards.fid);
511
569
  const clsStat = getClsStatus(cards.cls);
570
+ const connectionDiagnosticsPanelHtml = `
571
+ <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
572
+ <h3 style="color: #38bdf8; font-size: 1.2rem; border-bottom: none; margin-bottom: 0.25rem;">
573
+ \u{1F50C} Network Connection & Detailed HTTP Status Diagnostics
574
+ </h3>
575
+ <div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
576
+ Real-time breakdown tracking transport anomalies and precise layer-7 distribution indicators.
577
+ </div>
578
+
579
+ <div style="display: grid; grid-template-columns: 1fr 2fr; gap: 2rem; flex-wrap: wrap;">
580
+ <div style="display: flex; flex-direction: column; gap: 1rem;">
581
+ <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
582
+ <div style="font-size: 0.75rem; color: #64748b; text-transform: uppercase; font-weight: bold;">ECONNRESET Rate</div>
583
+ <div style="font-size: 1.8rem; font-weight: bold; color: ${cards.econnresetRate > 1 ? "#ef4444" : "#10b981"};">
584
+ ${cards.econnresetRate.toFixed(2)}<span style="font-size: 1rem; color: #94a3b8;"> %</span>
585
+ </div>
586
+ <div style="font-size: 0.8rem; color: #64748b; margin-top: 0.25rem;">Abrupt remote host termination frequency</div>
587
+ </div>
588
+
589
+ <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
590
+ <div style="font-size: 0.75rem; color: #64748b; text-transform: uppercase; font-weight: bold;">ECONNREFUSED Count</div>
591
+ <div style="font-size: 1.8rem; font-weight: bold; color: ${cards.econnrefusedCount > 0 ? "#f59e0b" : "#10b981"};">
592
+ ${cards.econnrefusedCount}<span style="font-size: 1rem; color: #94a3b8;"> drops</span>
593
+ </div>
594
+ <div style="font-size: 0.8rem; color: #64748b; margin-top: 0.25rem;">Total complete backend port link rejections</div>
595
+ </div>
596
+ </div>
597
+
598
+ <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
599
+ <div style="font-size: 0.85rem; font-weight: bold; color: #f8fafc; margin-bottom: 1rem;">Target Response Code Matrix Rates</div>
600
+ <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem;">
601
+ ${Object.keys(cards.codeRates).map((code) => {
602
+ const percentage = cards.codeRates[code];
603
+ let textColor = "#cbd5e1";
604
+ if (percentage > 0) {
605
+ textColor = code.startsWith("5") ? "#f87171" : "#fde047";
606
+ }
607
+ return `
608
+ <div style="background: #131c2e; padding: 0.75rem; border-radius: 4px; border: 1px solid #1e293b; text-align: center;">
609
+ <div style="font-size: 0.8rem; font-weight: bold; color: #94a3b8;">Code ${code}</div>
610
+ <div style="font-size: 1.1rem; font-weight: bold; margin-top: 0.25rem; color: ${textColor};">
611
+ ${percentage.toFixed(2)}%
612
+ </div>
613
+ </div>
614
+ `;
615
+ }).join("")}
616
+ </div>
617
+ </div>
618
+ </div>
619
+ </div>`;
512
620
  let logClustersHtml = "";
513
621
  if (semanticReport) {
514
622
  const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
@@ -519,7 +627,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
519
627
  \u{1F9E0} Interactive Remediation Playbooks & Log Classification
520
628
  </h3>
521
629
  <div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
522
- Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns. Expand a playbook to inspect automated remediation strategies and diagnostics confidence ratings.
630
+ Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns.
523
631
  </div>
524
632
 
525
633
  <div style="display: flex; flex-direction: column; gap: 1rem;">
@@ -542,11 +650,11 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
542
650
  let explanation = "High concurrency is causing socket/connection starvation. Increase connection limits or enable pooling keep-alives.";
543
651
  if (c.category === "Authentication_Error") {
544
652
  fixTitle = "Auth Token / JWT Strategy";
545
- fixCode = "// Implement token caching and silent rotation\napp.use(authMiddleware({ cacheTtl: 300, allowGracePeriod: 60 }));";
653
+ fixCode = "// Implement token caching and silent rotation\\napp.use(authMiddleware({ cacheTtl: 300, allowGracePeriod: 60 }));";
546
654
  explanation = "Frequent token verification failures under load. Extend signature verification cache or decouple auth validation check.";
547
655
  } else if (c.category === "Product_Error") {
548
656
  fixTitle = "Application Null-Safety / Guard Fix";
549
- fixCode = "const configId = payload?.config_id ?? defaultConfigurationId;\nif (!configId) throw new ValidationError('Missing config_id');";
657
+ fixCode = "const configId = payload?.config_id ?? defaultConfigurationId;\\nif (!configId) throw new ValidationError('Missing config_id');";
550
658
  explanation = "Runtime reference error for undefined payload field under race condition spikes. Add optional chaining and input contracts.";
551
659
  }
552
660
  const snippetId = `snippet-${idx}`;
@@ -804,8 +912,8 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
804
912
  <th>Throughput</th>
805
913
  <th>Avg Latency</th>
806
914
  <th>P95 Latency</th>
807
- <th>Simulated LCP</th>
808
- <th>Error Rate</th>
915
+ <th>ECONNRESET Rate</th>
916
+ <th>ECONNREFUSED</th>
809
917
  <th>Status</th>
810
918
  </tr>
811
919
  </thead>
@@ -817,14 +925,15 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
817
925
  <td>${h.throughput.toFixed(0)} req/sec</td>
818
926
  <td>${h.avgLatency.toFixed(1)} ms</td>
819
927
  <td>${h.p95Latency.toFixed(1)} ms</td>
820
- <td>${h.lcp.toFixed(0)} ms</td>
821
- <td>${(h.errorRate * 100).toFixed(2)}%</td>
928
+ <td>${h.econnresetRate.toFixed(2)}%</td>
929
+ <td>${h.econnrefusedCount} nodes</td>
822
930
  <td><span class="badge ${isPassed ? "badge-success" : "badge-fail"}">${isPassed ? "SLO PASS" : "SLO BREACH"}</span></td>
823
931
  </tr>`;
824
932
  }).join("")}
825
933
  </tbody>
826
934
  </table>
827
935
  </div>
936
+ ${connectionDiagnosticsPanelHtml}
828
937
  ${liveAdjusterHtml}
829
938
  ${rightSizingHtml}
830
939
  ${logClustersHtml}
@@ -844,7 +953,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
844
953
  const baseThroughput = ${cards.throughput};
845
954
  const baseLatency = ${cards.ttfb};
846
955
 
847
- // Live Concurrency Adjuster interactive client logic
848
956
  const slider = document.getElementById('concurrencySlider');
849
957
  const sliderVal = document.getElementById('sliderValue');
850
958
  const simThroughput = document.getElementById('simThroughput');
@@ -929,8 +1037,8 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
929
1037
  },
930
1038
  scales: {
931
1039
  x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
932
- y_threads: { position: 'left', grid: { color: '#1e293b' }, ticks: { color: '#38bdf8' }, title: { display: true, text: 'VUs / Threads', color: '#38bdf8' } },
933
- y_ttf: { position: 'right', grid: { drawOnChartArea: false }, ticks: { color: '#f43f5e' }, title: { display: true, text: 'TTF Index / Latency ms', color: '#f43f5e' } }
1040
+ yThreads: { position: 'left', grid: { color: '#1e293b' }, ticks: { color: '#38bdf8' }, title: { display: true, text: 'VUs / Threads', color: '#38bdf8' } },
1041
+ yTtf: { position: 'right', grid: { drawOnChartArea: false }, ticks: { color: '#f43f5e' }, title: { display: true, text: 'TTF Index / Latency ms', color: '#f43f5e' } }
934
1042
  }
935
1043
  }
936
1044
  });
@@ -988,8 +1096,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
988
1096
  }
989
1097
  }
990
1098
  function printUsage() {
991
- console.log(`Blaze Core Performance Test CLI Engine
992
- Options:
993
- --threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --apdex-t <ms>`);
1099
+ console.log(`Blaze Core Performance Test CLI Engine\\nOptions:\\n --threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --apdex-t <ms>`);
994
1100
  }
995
1101
  main().catch(console.error);
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blaze-performance-tester",
3
- "version": "3.1.7",
3
+ "version": "3.1.8",
4
4
  "description": "A high-performance, multi-threaded load testing engine built with Rust and QuickJS.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",