blaze-performance-tester 3.1.30 → 3.1.31

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
@@ -133,6 +133,41 @@ ${errorSummary}`
133
133
  return `<span style="color: #ef4444;">Failed to resolve external cloud model: ${error.message}</span>`;
134
134
  }
135
135
  }
136
+ async function fetchIncidentNarrative(history, semanticReport, apiKey) {
137
+ const timelineSummary = history.map((h) => `Wave Tier [${h.threads} VUs] -> Throughput: ${h.throughput.toFixed(0)} req/s, Avg Latency: ${h.avgLatency.toFixed(1)}ms, Error Rate: ${(h.errorRate * 100).toFixed(2)}%`).join("\n");
138
+ const logSummary = semanticReport && semanticReport.clusters ? semanticReport.clusters.map((c) => `[Error Count: ${c.count}] Pattern Blueprint: ${c.template}`).join("\n") : "No major software errors logged.";
139
+ try {
140
+ const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${apiKey}`, {
141
+ method: "POST",
142
+ headers: { "Content-Type": "application/json" },
143
+ body: JSON.stringify({
144
+ systemInstruction: {
145
+ parts: [{
146
+ text: "You are an expert technical writer and lead SRE. Write a fluid, highly professional, plain-English narrative story explaining the timeline of how the system degraded during this load test. Synthesize the raw timeline curves and matching log errors together. Return clean, elegant paragraphs (<p> text </p>) using standard HTML inline formatting elements like <strong> where needed. Do not wrap the response in markdown block quotes (like ```html)."
147
+ }]
148
+ },
149
+ contents: [{
150
+ role: "user",
151
+ parts: [{
152
+ text: `Analyze this historical load pipeline timeline and corresponding logs. Write a clear narrative detailing the failure journey as concurrency grew:
153
+
154
+ === Chronological Testing Waves ===
155
+ ${timelineSummary}
156
+
157
+ === Captured Structural Error Blueprints ===
158
+ ${logSummary}`
159
+ }]
160
+ }],
161
+ generationConfig: { temperature: 0.4 }
162
+ })
163
+ });
164
+ if (!response.ok) return `<em>Narrative generator unavailable: ${response.statusText}</em>`;
165
+ const data = await response.json();
166
+ return data.candidates?.[0]?.content?.parts?.[0]?.text || "<em>Failed to construct incident storyline parameters.</em>";
167
+ } catch (e) {
168
+ return `<em>Failed to compile conversational telemetry narrative: ${e.message}</em>`;
169
+ }
170
+ }
136
171
  async function executeTestPipeline(config) {
137
172
  if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
138
173
  console.error("\u274C Error: runCorrelatedTransaction function is missing from the compiled binary bindings.");
@@ -141,13 +176,13 @@ async function executeTestPipeline(config) {
141
176
  const transactionalScenario = [
142
177
  {
143
178
  name: "Fetch Target Anti-Forgery Nonce",
144
- url: "https://httpbin.org/json",
179
+ url: "[https://httpbin.org/json](https://httpbin.org/json)",
145
180
  method: "GET",
146
181
  body: null
147
182
  },
148
183
  {
149
184
  name: "Perform Contextual Post Action",
150
- url: "https://httpbin.org/post?verification=${csrf_token}",
185
+ url: "[https://httpbin.org/post?verification=](https://httpbin.org/post?verification=)${csrf_token}",
151
186
  method: "POST",
152
187
  body: JSON.stringify({
153
188
  data: "performance_payload",
@@ -378,6 +413,7 @@ async function runIntelligentAgenticStressTest(config) {
378
413
  }
379
414
  let semanticReport = null;
380
415
  let rcaInsights = "";
416
+ let incidentNarrative = "";
381
417
  if (config.clusterLogs) {
382
418
  if (aggregateErrorLogs.length === 0) {
383
419
  aggregateErrorLogs = getFallbackClusterLogs();
@@ -387,6 +423,8 @@ async function runIntelligentAgenticStressTest(config) {
387
423
  if (config.aiKey) {
388
424
  console.log("\u{1F9E0} Fetching autonomous root-cause analysis from model...");
389
425
  rcaInsights = await fetchRcaInsights(semanticReport, config.aiKey);
426
+ console.log("\u{1F4D6} Generating plain-English incident narrative...");
427
+ incidentNarrative = await fetchIncidentNarrative(history, semanticReport, config.aiKey);
390
428
  }
391
429
  }
392
430
  const finalState = history[history.length - 1] || { apdex: 0, errorRate: 0, p95Latency: 0, throughput: 0 };
@@ -413,7 +451,7 @@ async function runIntelligentAgenticStressTest(config) {
413
451
  Object.keys(globalCodeCounts).forEach((code) => {
414
452
  breakdownRates[code] = totalRequestsAccumulator === 0 ? 0 : globalCodeCounts[code] / totalRequestsAccumulator * 100;
415
453
  });
416
- exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, rcaInsights);
454
+ exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, rcaInsights, incidentNarrative);
417
455
  }
418
456
  async function runStandardStressTest(config) {
419
457
  console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
@@ -433,6 +471,7 @@ async function runStandardStressTest(config) {
433
471
  }];
434
472
  let semanticReport = null;
435
473
  let rcaInsights = "";
474
+ let incidentNarrative = "";
436
475
  if (config.clusterLogs) {
437
476
  let errsToProcess = rawErrors;
438
477
  if (errsToProcess.length === 0) errsToProcess = getFallbackClusterLogs();
@@ -441,6 +480,8 @@ async function runStandardStressTest(config) {
441
480
  if (config.aiKey) {
442
481
  console.log("\u{1F9E0} Fetching autonomous root-cause analysis from model...");
443
482
  rcaInsights = await fetchRcaInsights(semanticReport, config.aiKey);
483
+ console.log("\u{1F4D6} Generating plain-English incident narrative...");
484
+ incidentNarrative = await fetchIncidentNarrative(history, semanticReport, config.aiKey);
444
485
  }
445
486
  }
446
487
  const finalSummaryCards = {
@@ -472,7 +513,7 @@ async function runStandardStressTest(config) {
472
513
  total4xx: metrics.c4xx,
473
514
  total5xx: metrics.c5xx,
474
515
  breakdownRates
475
- }, finalSummaryCards, rawRequests, rcaInsights);
516
+ }, finalSummaryCards, rawRequests, rcaInsights, incidentNarrative);
476
517
  }
477
518
  function getFallbackClusterLogs() {
478
519
  const logs = [];
@@ -527,7 +568,7 @@ function processMetricsTelemetry(requests, durationSec) {
527
568
  const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
528
569
  const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
529
570
  let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
530
- const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
571
+ const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 502, 503: 0, 504: 0 };
531
572
  requests.forEach((r) => {
532
573
  if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
533
574
  else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
@@ -588,7 +629,7 @@ function generateFinalAgentReport(history, score) {
588
629
  console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
589
630
  console.log("=======================================================\n");
590
631
  }
591
- function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], rcaInsights = "") {
632
+ function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], rcaInsights = "", incidentNarrative = "") {
592
633
  const labels = history.map((h, i) => `${i + 1}s`);
593
634
  const successRequestsData = history.map((h) => h.successRequests);
594
635
  const failedWorkloadsData = history.map((h) => h.failedRequests);
@@ -768,7 +809,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
768
809
  const htmlContent = `<!DOCTYPE html><html lang="en"><head>
769
810
  <meta charset="UTF-8">
770
811
  <title>Blaze Core Performance Report</title>
771
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
812
+ <script src="[https://cdn.jsdelivr.net/npm/chart.js](https://cdn.jsdelivr.net/npm/chart.js)"></script>
772
813
  <style>
773
814
  body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0b111e; color: #f8fafc; margin: 0; padding: 2rem; }
774
815
  .container { max-width: 1300px; margin: 0 auto; }
@@ -869,6 +910,14 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
869
910
  <div class="verdict-box">
870
911
  <div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
871
912
  <div class="verdict-text">${verdictReason}</div>
913
+
914
+ <!-- GENERATIVE INCIDENT NARRATIVE INJECTION PANEL -->
915
+ ${incidentNarrative ? `
916
+ <div style="margin-top: 1rem; margin-bottom: 1rem; padding: 1rem; background: rgba(56, 189, 248, 0.06); border-left: 4px solid #38bdf8; border-radius: 4px; font-size: 0.95rem; line-height: 1.6; color: #cbd5e1;">
917
+ <strong style="color: #38bdf8; display: flex; align-items: center; gap: 0.4rem; margin-bottom: 0.5rem; text-transform: uppercase; font-size: 0.8rem; letter-spacing: 0.05em;">\u{1F4D6} Generative Incident Narrative:</strong>
918
+ ${incidentNarrative}
919
+ </div>` : ""}
920
+
872
921
  <div class="verdict-waves">${waveListItems}</div>
873
922
  </div>
874
923
 
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blaze-performance-tester",
3
- "version": "3.1.30",
3
+ "version": "3.1.31",
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",