@loadstrike/loadstrike-sdk 1.0.10101 → 1.0.10801

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/cjs/sinks.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OtelCollectorReportingSink = exports.SplunkReportingSink = exports.DatadogReportingSink = exports.TimescaleDbReportingSink = exports.GrafanaLokiReportingSink = exports.InfluxDbReportingSink = exports.CompositeReportingSink = exports.ConsoleReportingSink = exports.MemoryReportingSink = exports.OtelCollectorReportingSinkOptions = exports.SplunkReportingSinkOptions = exports.DatadogReportingSinkOptions = exports.TimescaleDbReportingSinkOptions = exports.GrafanaLokiReportingSinkOptions = exports.InfluxDbReportingSinkOptions = void 0;
3
+ exports.__loadstrikeTestExports = exports.OtelCollectorReportingSink = exports.SplunkReportingSink = exports.DatadogReportingSink = exports.TimescaleDbReportingSink = exports.GrafanaLokiReportingSink = exports.InfluxDbReportingSink = exports.CompositeReportingSink = exports.ConsoleReportingSink = exports.MemoryReportingSink = exports.OtelCollectorReportingSinkOptions = exports.SplunkReportingSinkOptions = exports.DatadogReportingSinkOptions = exports.TimescaleDbReportingSinkOptions = exports.GrafanaLokiReportingSinkOptions = exports.InfluxDbReportingSinkOptions = void 0;
4
4
  const runtime_js_1 = require("./runtime.js");
5
5
  const pg_1 = require("pg");
6
6
  const DEFAULT_INFLUX_CONFIGURATION_SECTION_PATH = "LoadStrike:ReportingSinks:InfluxDb";
@@ -244,13 +244,8 @@ class MemoryReportingSink {
244
244
  SaveRealtimeMetrics(metrics) {
245
245
  this.saveRealtimeMetrics(metrics);
246
246
  }
247
- saveFinalStats(result) {
248
- this.finalResults.push(cloneNodeStats(result));
249
- }
250
- SaveFinalStats(result) {
251
- this.saveFinalStats(result);
252
- }
253
247
  saveRunResult(result) {
248
+ this.finalResults.push(cloneRunResult(result));
254
249
  this.runResults.push(deepCloneRecord(result));
255
250
  }
256
251
  SaveRunResult(result) {
@@ -293,13 +288,9 @@ class ConsoleReportingSink {
293
288
  SaveRealtimeMetrics(metrics) {
294
289
  this.saveRealtimeMetrics(metrics);
295
290
  }
296
- saveFinalStats(result) {
291
+ saveRunResult(result) {
297
292
  this.writeLine(`final requests=${result.allRequestCount} ok=${result.allOkCount} fail=${result.allFailCount} failedThresholds=${result.failedThresholds}`);
298
293
  }
299
- SaveFinalStats(result) {
300
- this.saveFinalStats(result);
301
- }
302
- saveRunResult(_result) { }
303
294
  SaveRunResult(result) {
304
295
  this.saveRunResult(result);
305
296
  }
@@ -369,17 +360,6 @@ class CompositeReportingSink {
369
360
  async SaveRealtimeMetrics(metrics) {
370
361
  await this.saveRealtimeMetrics(metrics);
371
362
  }
372
- async saveFinalStats(result) {
373
- for (const sink of this.sinks) {
374
- const saveFinalStats = sink.saveFinalStats ?? sink.SaveFinalStats;
375
- if (saveFinalStats) {
376
- await saveFinalStats.call(sink, result);
377
- }
378
- }
379
- }
380
- async SaveFinalStats(result) {
381
- await this.saveFinalStats(result);
382
- }
383
363
  async saveRunResult(result) {
384
364
  for (const sink of this.sinks) {
385
365
  const saveRunResult = sink.saveRunResult ?? sink.SaveRunResult;
@@ -466,12 +446,6 @@ class InfluxDbReportingSink {
466
446
  async SaveRealtimeMetrics(metrics) {
467
447
  await this.saveRealtimeMetrics(metrics);
468
448
  }
469
- async saveFinalStats(result) {
470
- await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
471
- }
472
- async SaveFinalStats(result) {
473
- await this.saveFinalStats(result);
474
- }
475
449
  async saveRunResult(result) {
476
450
  await this.persistEvents(createRunResultEvents(this.getSession(), result));
477
451
  }
@@ -582,12 +556,6 @@ class GrafanaLokiReportingSink {
582
556
  async SaveRealtimeMetrics(metrics) {
583
557
  await this.saveRealtimeMetrics(metrics);
584
558
  }
585
- async saveFinalStats(result) {
586
- await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
587
- }
588
- async SaveFinalStats(result) {
589
- await this.saveFinalStats(result);
590
- }
591
559
  async saveRunResult(result) {
592
560
  await this.persistEvents(createRunResultEvents(this.getSession(), result));
593
561
  }
@@ -734,12 +702,6 @@ class TimescaleDbReportingSink {
734
702
  async SaveRealtimeMetrics(metrics) {
735
703
  await this.saveRealtimeMetrics(metrics);
736
704
  }
737
- async saveFinalStats(result) {
738
- await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
739
- }
740
- async SaveFinalStats(result) {
741
- await this.saveFinalStats(result);
742
- }
743
705
  async saveRunResult(result) {
744
706
  await this.persistEvents(createRunResultEvents(this.getSession(), result));
745
707
  }
@@ -1016,12 +978,6 @@ class DatadogReportingSink {
1016
978
  async SaveRealtimeMetrics(metrics) {
1017
979
  await this.saveRealtimeMetrics(metrics);
1018
980
  }
1019
- async saveFinalStats(result) {
1020
- await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
1021
- }
1022
- async SaveFinalStats(result) {
1023
- await this.saveFinalStats(result);
1024
- }
1025
981
  async saveRunResult(result) {
1026
982
  await this.persistEvents(createRunResultEvents(this.getSession(), result));
1027
983
  }
@@ -1145,12 +1101,6 @@ class SplunkReportingSink {
1145
1101
  async SaveRealtimeMetrics(metrics) {
1146
1102
  await this.saveRealtimeMetrics(metrics);
1147
1103
  }
1148
- async saveFinalStats(result) {
1149
- await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
1150
- }
1151
- async SaveFinalStats(result) {
1152
- await this.saveFinalStats(result);
1153
- }
1154
1104
  async saveRunResult(result) {
1155
1105
  await this.persistEvents(createRunResultEvents(this.getSession(), result));
1156
1106
  }
@@ -1254,12 +1204,6 @@ class OtelCollectorReportingSink {
1254
1204
  async SaveRealtimeMetrics(metrics) {
1255
1205
  await this.saveRealtimeMetrics(metrics);
1256
1206
  }
1257
- async saveFinalStats(result) {
1258
- await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
1259
- }
1260
- async SaveFinalStats(result) {
1261
- await this.saveFinalStats(result);
1262
- }
1263
1207
  async saveRunResult(result) {
1264
1208
  await this.persistEvents(createRunResultEvents(this.getSession(), result));
1265
1209
  }
@@ -1374,6 +1318,7 @@ function createFinalStatsEvents(session, stats) {
1374
1318
  function createRunResultEvents(session, result) {
1375
1319
  const occurredUtc = new Date();
1376
1320
  const events = [
1321
+ ...createFinalStatsEvents(session, runResultToNodeStats(result)),
1377
1322
  createReportingEvent(session, occurredUtc, "run.result.final", null, null, {
1378
1323
  phase: "final",
1379
1324
  entity: "run-result"
@@ -1468,7 +1413,8 @@ function createStepEvents(session, occurredUtc, phase, scenario) {
1468
1413
  return events;
1469
1414
  }
1470
1415
  function createStatusCodeEvents(session, occurredUtc, phase, scenarioName, stepName, resultKind, statusCodes) {
1471
- return statusCodes.map((statusCode) => createReportingEvent(session, occurredUtc, `status-code.${phase}`, scenarioName, stepName, {
1416
+ const normalizedStatusCodes = Array.isArray(statusCodes) ? statusCodes : [];
1417
+ return normalizedStatusCodes.map((statusCode) => createReportingEvent(session, occurredUtc, `status-code.${phase}`, scenarioName, stepName, {
1472
1418
  phase,
1473
1419
  entity: stepName ? "step-status-code" : "scenario-status-code",
1474
1420
  result_kind: resultKind,
@@ -1601,30 +1547,63 @@ function createReportingEvent(session, occurredUtc, eventType, scenarioName, ste
1601
1547
  };
1602
1548
  }
1603
1549
  function addMeasurementFields(fields, prefix, measurement) {
1604
- fields[`${prefix}_request_count`] = measurement.request.count;
1605
- fields[`${prefix}_request_percent`] = measurement.request.percent;
1606
- fields[`${prefix}_request_rps`] = measurement.request.rps;
1607
- fields[`${prefix}_latency_min_ms`] = measurement.latency.minMs;
1608
- fields[`${prefix}_latency_mean_ms`] = measurement.latency.meanMs;
1609
- fields[`${prefix}_latency_max_ms`] = measurement.latency.maxMs;
1610
- fields[`${prefix}_latency_p50_ms`] = measurement.latency.percent50;
1611
- fields[`${prefix}_latency_p75_ms`] = measurement.latency.percent75;
1612
- fields[`${prefix}_latency_p95_ms`] = measurement.latency.percent95;
1613
- fields[`${prefix}_latency_p99_ms`] = measurement.latency.percent99;
1614
- fields[`${prefix}_latency_std_dev`] = measurement.latency.stdDev;
1615
- fields[`${prefix}_latency_le_800_count`] = measurement.latency.latencyCount.lessOrEq800;
1616
- fields[`${prefix}_latency_gt_800_lt_1200_count`] = measurement.latency.latencyCount.more800Less1200;
1617
- fields[`${prefix}_latency_ge_1200_count`] = measurement.latency.latencyCount.moreOrEq1200;
1618
- fields[`${prefix}_bytes_all`] = measurement.dataTransfer.allBytes;
1619
- fields[`${prefix}_bytes_min`] = measurement.dataTransfer.minBytes;
1620
- fields[`${prefix}_bytes_mean`] = measurement.dataTransfer.meanBytes;
1621
- fields[`${prefix}_bytes_max`] = measurement.dataTransfer.maxBytes;
1622
- fields[`${prefix}_bytes_p50`] = measurement.dataTransfer.percent50;
1623
- fields[`${prefix}_bytes_p75`] = measurement.dataTransfer.percent75;
1624
- fields[`${prefix}_bytes_p95`] = measurement.dataTransfer.percent95;
1625
- fields[`${prefix}_bytes_p99`] = measurement.dataTransfer.percent99;
1626
- fields[`${prefix}_bytes_std_dev`] = measurement.dataTransfer.stdDev;
1627
- fields[`${prefix}_status_code_count`] = measurement.statusCodes.length;
1550
+ const request = measurement?.request ?? { count: 0, percent: 0, rps: 0 };
1551
+ const latency = measurement?.latency ?? {
1552
+ minMs: 0,
1553
+ meanMs: 0,
1554
+ maxMs: 0,
1555
+ percent50: 0,
1556
+ percent75: 0,
1557
+ percent95: 0,
1558
+ percent99: 0,
1559
+ stdDev: 0,
1560
+ latencyCount: {
1561
+ lessOrEq800: 0,
1562
+ more800Less1200: 0,
1563
+ moreOrEq1200: 0
1564
+ }
1565
+ };
1566
+ const latencyCount = latency.latencyCount ?? {
1567
+ lessOrEq800: 0,
1568
+ more800Less1200: 0,
1569
+ moreOrEq1200: 0
1570
+ };
1571
+ const dataTransfer = measurement?.dataTransfer ?? {
1572
+ allBytes: 0,
1573
+ minBytes: 0,
1574
+ meanBytes: 0,
1575
+ maxBytes: 0,
1576
+ percent50: 0,
1577
+ percent75: 0,
1578
+ percent95: 0,
1579
+ percent99: 0,
1580
+ stdDev: 0
1581
+ };
1582
+ const statusCodes = Array.isArray(measurement?.statusCodes) ? measurement.statusCodes : [];
1583
+ fields[`${prefix}_request_count`] = request.count ?? 0;
1584
+ fields[`${prefix}_request_percent`] = request.percent ?? 0;
1585
+ fields[`${prefix}_request_rps`] = request.rps ?? 0;
1586
+ fields[`${prefix}_latency_min_ms`] = latency.minMs ?? 0;
1587
+ fields[`${prefix}_latency_mean_ms`] = latency.meanMs ?? 0;
1588
+ fields[`${prefix}_latency_max_ms`] = latency.maxMs ?? 0;
1589
+ fields[`${prefix}_latency_p50_ms`] = latency.percent50 ?? 0;
1590
+ fields[`${prefix}_latency_p75_ms`] = latency.percent75 ?? 0;
1591
+ fields[`${prefix}_latency_p95_ms`] = latency.percent95 ?? 0;
1592
+ fields[`${prefix}_latency_p99_ms`] = latency.percent99 ?? 0;
1593
+ fields[`${prefix}_latency_std_dev`] = latency.stdDev ?? 0;
1594
+ fields[`${prefix}_latency_le_800_count`] = latencyCount.lessOrEq800 ?? 0;
1595
+ fields[`${prefix}_latency_gt_800_lt_1200_count`] = latencyCount.more800Less1200 ?? 0;
1596
+ fields[`${prefix}_latency_ge_1200_count`] = latencyCount.moreOrEq1200 ?? 0;
1597
+ fields[`${prefix}_bytes_all`] = dataTransfer.allBytes ?? 0;
1598
+ fields[`${prefix}_bytes_min`] = dataTransfer.minBytes ?? 0;
1599
+ fields[`${prefix}_bytes_mean`] = dataTransfer.meanBytes ?? 0;
1600
+ fields[`${prefix}_bytes_max`] = dataTransfer.maxBytes ?? 0;
1601
+ fields[`${prefix}_bytes_p50`] = dataTransfer.percent50 ?? 0;
1602
+ fields[`${prefix}_bytes_p75`] = dataTransfer.percent75 ?? 0;
1603
+ fields[`${prefix}_bytes_p95`] = dataTransfer.percent95 ?? 0;
1604
+ fields[`${prefix}_bytes_p99`] = dataTransfer.percent99 ?? 0;
1605
+ fields[`${prefix}_bytes_std_dev`] = dataTransfer.stdDev ?? 0;
1606
+ fields[`${prefix}_status_code_count`] = statusCodes.length;
1628
1607
  }
1629
1608
  function buildInfluxWriteUri(options) {
1630
1609
  const query = new URLSearchParams({
@@ -2596,28 +2575,28 @@ function cloneSessionStartInfo(session) {
2596
2575
  };
2597
2576
  }
2598
2577
  function cloneNodeInfo(nodeInfo) {
2599
- return { ...nodeInfo };
2578
+ return { ...(nodeInfo ?? {}) };
2600
2579
  }
2601
2580
  function cloneTestInfo(testInfo) {
2602
- return { ...testInfo };
2581
+ return { ...(testInfo ?? {}) };
2603
2582
  }
2604
2583
  function cloneMetricStats(metrics) {
2605
2584
  return {
2606
- counters: metrics.counters.map((value) => ({ ...value })),
2607
- gauges: metrics.gauges.map((value) => ({ ...value })),
2608
- durationMs: metrics.durationMs
2585
+ counters: (metrics?.counters ?? []).map((value) => ({ ...value })),
2586
+ gauges: (metrics?.gauges ?? []).map((value) => ({ ...value })),
2587
+ durationMs: metrics?.durationMs ?? 0
2609
2588
  };
2610
2589
  }
2611
2590
  function cloneScenarioStats(value) {
2612
2591
  return {
2613
2592
  ...value,
2614
- ok: deepCloneRecord(value.ok),
2615
- fail: deepCloneRecord(value.fail),
2616
- loadSimulationStats: { ...value.loadSimulationStats },
2617
- stepStats: value.stepStats.map((step) => ({
2593
+ ok: deepCloneRecord(value?.ok ?? {}),
2594
+ fail: deepCloneRecord(value?.fail ?? {}),
2595
+ loadSimulationStats: { ...(value?.loadSimulationStats ?? {}) },
2596
+ stepStats: (value?.stepStats ?? []).map((step) => ({
2618
2597
  ...step,
2619
- ok: deepCloneRecord(step.ok),
2620
- fail: deepCloneRecord(step.fail)
2598
+ ok: deepCloneRecord(step?.ok ?? {}),
2599
+ fail: deepCloneRecord(step?.fail ?? {})
2621
2600
  }))
2622
2601
  };
2623
2602
  }
@@ -2626,20 +2605,91 @@ function cloneNodeStats(result) {
2626
2605
  ...result,
2627
2606
  nodeInfo: cloneNodeInfo(result.nodeInfo),
2628
2607
  testInfo: cloneTestInfo(result.testInfo),
2629
- thresholds: result.thresholds.map((value) => ({ ...value })),
2630
- thresholdResults: result.thresholdResults.map((value) => ({ ...value })),
2608
+ thresholds: (result.thresholds ?? []).map((value) => ({ ...value })),
2609
+ thresholdResults: (result.thresholdResults ?? []).map((value) => ({ ...value })),
2631
2610
  metrics: cloneMetricStats(result.metrics),
2632
- metricValues: result.metricValues.map((value) => ({ ...value })),
2633
- scenarioStats: result.scenarioStats.map((value) => cloneScenarioStats(value)),
2634
- stepStats: result.stepStats.map((step) => ({
2611
+ metricValues: Array.isArray(result.metricValues) ? result.metricValues.map((value) => ({ ...value })) : [],
2612
+ scenarioStats: (result.scenarioStats ?? []).map((value) => cloneScenarioStats(value)),
2613
+ stepStats: (result.stepStats ?? []).map((step) => ({
2614
+ ...step,
2615
+ ok: deepCloneRecord(step?.ok ?? {}),
2616
+ fail: deepCloneRecord(step?.fail ?? {})
2617
+ })),
2618
+ pluginsData: (result.pluginsData ?? []).map((plugin) => new runtime_js_1.LoadStrikePluginData(plugin.pluginName, (plugin.tables ?? []).map((table) => new runtime_js_1.LoadStrikePluginDataTable(table.tableName, [...(table.headers ?? [])], (table.rows ?? []).map((row) => deepCloneRecord(row)))), [...(plugin.hints ?? [])])),
2619
+ disabledSinks: [...(result.disabledSinks ?? [])],
2620
+ sinkErrors: (result.sinkErrors ?? []).map((value) => ({ ...value })),
2621
+ reportFiles: [...(result.reportFiles ?? [])],
2622
+ logFiles: [...(result.logFiles ?? [])]
2623
+ };
2624
+ }
2625
+ function cloneRunResult(result) {
2626
+ return {
2627
+ ...result,
2628
+ nodeInfo: cloneNodeInfo(result.nodeInfo),
2629
+ testInfo: cloneTestInfo(result.testInfo),
2630
+ thresholds: (result.thresholds ?? []).map((value) => ({ ...value })),
2631
+ thresholdResults: (result.thresholdResults ?? []).map((value) => ({ ...value })),
2632
+ metricStats: cloneMetricStats(result.metricStats),
2633
+ metrics: Array.isArray(result.metrics) ? result.metrics.map((value) => ({ ...value })) : [],
2634
+ scenarioStats: (result.scenarioStats ?? []).map((value) => cloneScenarioStats(value)),
2635
+ stepStats: (result.stepStats ?? []).map((step) => ({
2635
2636
  ...step,
2636
- ok: deepCloneRecord(step.ok),
2637
- fail: deepCloneRecord(step.fail)
2637
+ ok: deepCloneRecord(step?.ok ?? {}),
2638
+ fail: deepCloneRecord(step?.fail ?? {})
2638
2639
  })),
2639
- pluginsData: result.pluginsData.map((plugin) => new runtime_js_1.LoadStrikePluginData(plugin.pluginName, plugin.tables.map((table) => new runtime_js_1.LoadStrikePluginDataTable(table.tableName, [...table.headers], table.rows.map((row) => deepCloneRecord(row)))), [...plugin.hints])),
2640
- disabledSinks: [...result.disabledSinks],
2641
- sinkErrors: result.sinkErrors.map((value) => ({ ...value })),
2642
- reportFiles: [...result.reportFiles]
2640
+ scenarioDurationsMs: { ...(result.scenarioDurationsMs ?? {}) },
2641
+ pluginsData: (result.pluginsData ?? []).map((plugin) => new runtime_js_1.LoadStrikePluginData(plugin.pluginName, (plugin.tables ?? []).map((table) => new runtime_js_1.LoadStrikePluginDataTable(table.tableName, [...(table.headers ?? [])], (table.rows ?? []).map((row) => deepCloneRecord(row)))), [...(plugin.hints ?? [])])),
2642
+ disabledSinks: [...(result.disabledSinks ?? [])],
2643
+ sinkErrors: (result.sinkErrors ?? []).map((value) => ({ ...value })),
2644
+ reportFiles: [...(result.reportFiles ?? [])],
2645
+ logFiles: [...(result.logFiles ?? [])],
2646
+ correlationRows: (result.correlationRows ?? []).map((row) => deepCloneRecord(row)),
2647
+ failedCorrelationRows: (result.failedCorrelationRows ?? []).map((row) => deepCloneRecord(row))
2648
+ };
2649
+ }
2650
+ function runResultToNodeStats(result) {
2651
+ return {
2652
+ startedUtc: result.startedUtc,
2653
+ completedUtc: result.completedUtc,
2654
+ allBytes: result.allBytes ?? 0,
2655
+ allRequestCount: result.allRequestCount ?? 0,
2656
+ allOkCount: result.allOkCount ?? 0,
2657
+ allFailCount: result.allFailCount ?? 0,
2658
+ failedThresholds: result.failedThresholds ?? 0,
2659
+ durationMs: result.durationMs ?? 0,
2660
+ nodeInfo: cloneNodeInfo(result.nodeInfo),
2661
+ testInfo: cloneTestInfo(result.testInfo),
2662
+ thresholds: (result.thresholds ?? []).map((value) => ({ ...value })),
2663
+ thresholdResults: (result.thresholdResults ?? []).map((value) => ({ ...value })),
2664
+ metrics: cloneMetricStats(result.metricStats),
2665
+ metricValues: Array.isArray(result.metrics) ? result.metrics.map((value) => ({ ...value })) : [],
2666
+ scenarioStats: (result.scenarioStats ?? []).map((value) => cloneScenarioStats(value)),
2667
+ stepStats: (result.stepStats ?? []).map((step) => ({
2668
+ ...step,
2669
+ ok: deepCloneRecord(step?.ok ?? {}),
2670
+ fail: deepCloneRecord(step?.fail ?? {})
2671
+ })),
2672
+ pluginsData: (result.pluginsData ?? []).map((plugin) => new runtime_js_1.LoadStrikePluginData(plugin.pluginName, (plugin.tables ?? []).map((table) => new runtime_js_1.LoadStrikePluginDataTable(table.tableName, [...(table.headers ?? [])], (table.rows ?? []).map((row) => deepCloneRecord(row)))), [...(plugin.hints ?? [])])),
2673
+ disabledSinks: [...(result.disabledSinks ?? [])],
2674
+ sinkErrors: (result.sinkErrors ?? []).map((value) => ({ ...value })),
2675
+ reportFiles: [...(result.reportFiles ?? [])],
2676
+ logFiles: [...(result.logFiles ?? [])],
2677
+ findScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
2678
+ getScenarioStats: (scenarioName) => {
2679
+ const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
2680
+ if (!scenario) {
2681
+ throw new Error(`Scenario stats not found: ${scenarioName}`);
2682
+ }
2683
+ return scenario;
2684
+ },
2685
+ FindScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
2686
+ GetScenarioStats: (scenarioName) => {
2687
+ const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
2688
+ if (!scenario) {
2689
+ throw new Error(`Scenario stats not found: ${scenarioName}`);
2690
+ }
2691
+ return scenario;
2692
+ }
2643
2693
  };
2644
2694
  }
2645
2695
  function deepCloneRecord(value) {
@@ -2673,3 +2723,47 @@ async function postWithTimeout(fetchImpl, url, init, timeoutMs, sinkName) {
2673
2723
  clearTimeout(timer);
2674
2724
  }
2675
2725
  }
2726
+ exports.__loadstrikeTestExports = {
2727
+ GrafanaLokiReportingSink,
2728
+ InfluxDbReportingSink,
2729
+ OtelCollectorReportingSink,
2730
+ SplunkReportingSink,
2731
+ TimescaleDbReportingSink,
2732
+ cleanNullableText,
2733
+ cloneBaseContext,
2734
+ cloneMetricStats,
2735
+ cloneNodeStats,
2736
+ cloneScenarioStats,
2737
+ cloneSessionStartInfo,
2738
+ createFinalStatsEvents,
2739
+ createRealtimeStatsEvents,
2740
+ createRunResultEvents,
2741
+ createReportingEvent,
2742
+ mergeDatadogOptions,
2743
+ mergeInfluxOptions,
2744
+ mergeGrafanaLokiOptions,
2745
+ mergeOtelCollectorOptions,
2746
+ mergeSplunkOptions,
2747
+ mergeTimescaleDbOptions,
2748
+ normalizeConfigKey,
2749
+ normalizePath,
2750
+ normalizePluginFieldName,
2751
+ normalizePluginFieldValue,
2752
+ normalizeStringMap,
2753
+ optionNumber,
2754
+ optionString,
2755
+ pickBooleanValue,
2756
+ pickRecordValue,
2757
+ postWithTimeout,
2758
+ quoteIdentifier,
2759
+ replaceLiteral,
2760
+ resolveConfigSection,
2761
+ resolveTimeoutMs,
2762
+ sanitizeGrafanaLabelKey,
2763
+ sanitizeGrafanaLabelValue,
2764
+ sinkSessionMetadataFromContext,
2765
+ toOtelAnyValue,
2766
+ trimTrailingSlashes,
2767
+ tryReadText,
2768
+ validateIdentifier
2769
+ };
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.EndpointAdapterFactory = exports.KafkaSaslOptions = exports.HttpAuthOptions = exports.HttpOAuth2ClientCredentialsOptions = exports.PushDiffusionEndpointDefinition = exports.DelegateStreamEndpointDefinition = exports.AzureEventHubsEndpointDefinition = exports.RedisStreamsEndpointDefinition = exports.NatsEndpointDefinition = exports.RabbitMqEndpointDefinition = exports.KafkaEndpointDefinition = exports.HttpEndpointDefinition = exports.TrafficEndpointDefinition = void 0;
36
+ exports.__loadstrikeTestExports = exports.EndpointAdapterFactory = exports.KafkaSaslOptions = exports.HttpAuthOptions = exports.HttpOAuth2ClientCredentialsOptions = exports.PushDiffusionEndpointDefinition = exports.DelegateStreamEndpointDefinition = exports.AzureEventHubsEndpointDefinition = exports.RedisStreamsEndpointDefinition = exports.NatsEndpointDefinition = exports.RabbitMqEndpointDefinition = exports.KafkaEndpointDefinition = exports.HttpEndpointDefinition = exports.TrafficEndpointDefinition = void 0;
37
37
  const node_crypto_1 = require("node:crypto");
38
38
  const correlation_js_1 = require("./correlation.js");
39
39
  class TrafficEndpointDefinitionModel {
@@ -247,6 +247,9 @@ class AzureEventHubsEndpointDefinitionModel extends TrafficEndpointDefinitionMod
247
247
  super.Validate();
248
248
  requireNonEmptyString(this.ConnectionString, "ConnectionString must be provided for Azure Event Hubs endpoint.");
249
249
  requireNonEmptyString(this.EventHubName, "EventHubName must be provided for Azure Event Hubs endpoint.");
250
+ if (this.PartitionCount != null && this.PartitionCount < 0) {
251
+ throw new RangeError("PartitionCount must be zero or greater when configured.");
252
+ }
250
253
  }
251
254
  }
252
255
  class DelegateStreamEndpointDefinitionModel extends TrafficEndpointDefinitionModel {
@@ -650,6 +653,12 @@ function initializeAzureEventHubsEndpointDefinitionModel(target, initial) {
650
653
  if (hasAnyEndpointField(raw, ["PartitionId", "partitionId"])) {
651
654
  target.PartitionId = pickOptionalEndpointString(raw, "PartitionId", "partitionId");
652
655
  }
656
+ if (hasAnyEndpointField(raw, ["PartitionKey", "partitionKey"])) {
657
+ target.PartitionKey = pickOptionalEndpointString(raw, "PartitionKey", "partitionKey");
658
+ }
659
+ if (hasAnyEndpointField(raw, ["PartitionCount", "partitionCount"])) {
660
+ target.PartitionCount = pickOptionalEndpointNumber(raw, "PartitionCount", "partitionCount");
661
+ }
653
662
  }
654
663
  function initializeDelegateStreamEndpointDefinitionModel(target, initial) {
655
664
  const raw = asRecordOrEmpty(initial);
@@ -740,10 +749,9 @@ function validateHttpAuthOptionsModel(target) {
740
749
  }
741
750
  return;
742
751
  case "oauth2clientcredentials":
743
- if (!target.OAuth2ClientCredentials) {
744
- throw new Error("OAuth2ClientCredentials must be provided for OAuth2 client-credentials auth.");
745
- }
746
- toHttpOAuth2ClientCredentialsOptionsModel(target.OAuth2ClientCredentials).Validate();
752
+ requireNonEmptyString(target.TokenUrl ?? target.OAuth2ClientCredentials?.TokenEndpoint, "TokenEndpoint must be provided for OAuth2 client credentials flow.");
753
+ requireNonEmptyString(target.ClientId ?? target.OAuth2ClientCredentials?.ClientId, "ClientId must be provided for OAuth2 client credentials flow.");
754
+ requireNonEmptyString(target.ClientSecret ?? target.OAuth2ClientCredentials?.ClientSecret, "ClientSecret must be provided for OAuth2 client credentials flow.");
747
755
  return;
748
756
  default:
749
757
  throw new RangeError("Unsupported HTTP auth type.");
@@ -933,8 +941,7 @@ const protocolBus = new class InMemoryProtocolBus {
933
941
  produceEventHub(endpoint, payload) {
934
942
  const options = endpoint.azureEventHubs ?? {};
935
943
  const hubName = optionString(options, "EventHubName", "eventHubName") || endpoint.name;
936
- const partitionId = optionString(options, "PartitionId", "partitionId")
937
- || partitionFromKey(optionString(options, "PartitionKey", "partitionKey"), optionNumber(options, "PartitionCount", "partitionCount") || 4);
944
+ const partitionId = resolveEventHubProducePartitionId(options) || "";
938
945
  const rows = this.eventHubs.get(hubName) ?? [];
939
946
  rows.push({
940
947
  partitionId,
@@ -1160,10 +1167,10 @@ class HttpEndpointAdapter extends CallbackAdapter {
1160
1167
  body.set("grant_type", "client_credentials");
1161
1168
  body.set("client_id", clientId);
1162
1169
  body.set("client_secret", clientSecret);
1163
- const scopes = Array.isArray(oauthOptions?.scopes)
1164
- ? oauthOptions.scopes.map((x) => String(x).trim()).filter((x) => x.length > 0)
1165
- : Array.isArray(auth?.scopes)
1166
- ? auth.scopes.map((x) => String(x).trim()).filter((x) => x.length > 0)
1170
+ const scopes = Array.isArray(auth?.scopes)
1171
+ ? auth.scopes.map((x) => String(x).trim()).filter((x) => x.length > 0)
1172
+ : Array.isArray(oauthOptions?.scopes)
1173
+ ? oauthOptions.scopes.map((x) => String(x).trim()).filter((x) => x.length > 0)
1167
1174
  : [];
1168
1175
  const scopeText = typeof auth?.scope === "string" && auth.scope.trim()
1169
1176
  ? auth.scope.trim()
@@ -1175,8 +1182,8 @@ class HttpEndpointAdapter extends CallbackAdapter {
1175
1182
  body.set("audience", auth.audience.trim());
1176
1183
  }
1177
1184
  for (const [key, value] of Object.entries({
1178
- ...(auth?.additionalFormFields ?? {}),
1179
- ...(oauthOptions?.additionalFormFields ?? {})
1185
+ ...(oauthOptions?.additionalFormFields ?? {}),
1186
+ ...(auth?.additionalFormFields ?? {})
1180
1187
  })) {
1181
1188
  if (key.trim() && typeof value === "string") {
1182
1189
  body.set(key.trim(), value);
@@ -1602,13 +1609,15 @@ class AzureEventHubsEndpointAdapter extends CallbackAdapter {
1602
1609
  const options = this.endpoint.azureEventHubs ?? {};
1603
1610
  const resolved = prepareProducedPayload(this.endpoint, payload);
1604
1611
  const wire = toWirePayload(resolved, this.endpoint);
1605
- const batch = await producer.createBatch();
1612
+ const partitionId = resolveEventHubProducePartitionId(options);
1613
+ const batch = partitionId
1614
+ ? await producer.createBatch({ partitionId })
1615
+ : await producer.createBatch();
1606
1616
  const eventData = {
1607
1617
  body: Buffer.from(wire.body),
1608
1618
  contentType: wire.contentType,
1609
1619
  properties: { ...wire.headers }
1610
1620
  };
1611
- const partitionId = optionString(options, "PartitionId", "partitionId");
1612
1621
  if (partitionId) {
1613
1622
  eventData.partitionId = partitionId;
1614
1623
  }
@@ -1835,6 +1844,10 @@ const AZURE_EVENT_HUBS_ENDPOINT_FLAT_KEYS = [
1835
1844
  "consumerGroup",
1836
1845
  "PartitionId",
1837
1846
  "partitionId",
1847
+ "PartitionKey",
1848
+ "partitionKey",
1849
+ "PartitionCount",
1850
+ "partitionCount",
1838
1851
  "StartFromEarliest",
1839
1852
  "startFromEarliest"
1840
1853
  ];
@@ -1947,7 +1960,11 @@ function resolveEndpointKind(raw) {
1947
1960
  "EventHubName",
1948
1961
  "eventHubName",
1949
1962
  "PartitionId",
1950
- "partitionId"
1963
+ "partitionId",
1964
+ "PartitionKey",
1965
+ "partitionKey",
1966
+ "PartitionCount",
1967
+ "partitionCount"
1951
1968
  ])) {
1952
1969
  return "AzureEventHubs";
1953
1970
  }
@@ -2448,6 +2465,10 @@ function validateAzureEventHubsEndpoint(endpoint, mode, hasModeDelegate) {
2448
2465
  }
2449
2466
  requireNonEmptyString(optionString(options, "ConnectionString", "connectionString"), "ConnectionString must be provided for Azure Event Hubs endpoint.");
2450
2467
  requireNonEmptyString(optionString(options, "EventHubName", "eventHubName"), "EventHubName must be provided for Azure Event Hubs endpoint.");
2468
+ const partitionCount = optionNumber(options, "PartitionCount", "partitionCount");
2469
+ if (partitionCount < 0) {
2470
+ throw new RangeError("PartitionCount must be zero or greater when configured.");
2471
+ }
2451
2472
  }
2452
2473
  function validatePushDiffusionEndpoint(endpoint, mode) {
2453
2474
  const options = endpoint.pushDiffusion;
@@ -2847,6 +2868,17 @@ function partitionFromKey(value, partitionCount) {
2847
2868
  const normalized = Math.abs(hash) % count;
2848
2869
  return String(normalized);
2849
2870
  }
2871
+ function resolveEventHubProducePartitionId(options) {
2872
+ const explicitPartitionId = optionString(options, "PartitionId", "partitionId");
2873
+ if (explicitPartitionId) {
2874
+ return explicitPartitionId;
2875
+ }
2876
+ const partitionKey = optionString(options, "PartitionKey", "partitionKey");
2877
+ if (!partitionKey) {
2878
+ return undefined;
2879
+ }
2880
+ return partitionFromKey(partitionKey, optionNumber(options, "PartitionCount", "partitionCount") || 4);
2881
+ }
2850
2882
  function attachPayloadHelpers(payload) {
2851
2883
  const target = {
2852
2884
  ...payload,
@@ -3029,10 +3061,10 @@ function deserializeBrokerPayloadBody(body, contentType, messagePayloadType) {
3029
3061
  function extractTrackingValue(payload, selector) {
3030
3062
  const normalized = selector.trim().toLowerCase();
3031
3063
  if (normalized.startsWith("header:")) {
3032
- const headerName = selector.slice("header:".length).trim().toLowerCase();
3064
+ const headerName = selector.slice("header:".length).trim();
3033
3065
  for (const [key, value] of Object.entries(payload.headers ?? {})) {
3034
3066
  const resolved = String(value ?? "").trim();
3035
- if (key.toLowerCase() === headerName && resolved) {
3067
+ if (key === headerName && resolved) {
3036
3068
  return resolved;
3037
3069
  }
3038
3070
  }
@@ -3693,3 +3725,57 @@ function payloadBodyAsUtf8(body) {
3693
3725
  return String(body);
3694
3726
  }
3695
3727
  }
3728
+ exports.__loadstrikeTestExports = {
3729
+ AzureEventHubsEndpointAdapter,
3730
+ AzureEventHubsEndpointDefinition: exports.AzureEventHubsEndpointDefinition,
3731
+ AzureEventHubsEndpointDefinitionModel,
3732
+ CallbackAdapter,
3733
+ DelegateStreamEndpointDefinition: exports.DelegateStreamEndpointDefinition,
3734
+ DelegateStreamEndpointDefinitionModel,
3735
+ HttpEndpointAdapter,
3736
+ NatsEndpointDefinition: exports.NatsEndpointDefinition,
3737
+ NatsEndpointDefinitionModel,
3738
+ PushDiffusionEndpointDefinition: exports.PushDiffusionEndpointDefinition,
3739
+ PushDiffusionEndpointDefinitionModel,
3740
+ RabbitMqEndpointDefinition: exports.RabbitMqEndpointDefinition,
3741
+ RabbitMqEndpointDefinitionModel,
3742
+ RedisStreamsEndpointAdapter,
3743
+ RedisStreamsEndpointDefinition: exports.RedisStreamsEndpointDefinition,
3744
+ RedisStreamsEndpointDefinitionModel,
3745
+ bufferToUint8Array,
3746
+ applyHttpAuthHeaders,
3747
+ buildHttpRequestBody,
3748
+ buildConfluentKafkaClientOptions,
3749
+ buildKafkaClientOptions,
3750
+ canonicalizeHttpResponseSource,
3751
+ createDelegateRequestEndpointView,
3752
+ createNatsHeaders,
3753
+ createRedisStreamPayload,
3754
+ deserializeBrokerPayloadBody,
3755
+ extractTrackingValue,
3756
+ fromKafkaHeaders,
3757
+ headerValue,
3758
+ attachDotNetTrackingPayloadAliases,
3759
+ attachPayloadHelpers,
3760
+ attachStructuredProducedMessageRequestAliases,
3761
+ inferLegacyHttpResponseSource,
3762
+ injectTrackingValue,
3763
+ mapConfluentKafkaSaslMechanism,
3764
+ mapConfluentKafkaSecurityProtocol,
3765
+ mapKafkaSaslMechanism,
3766
+ parseBodyObject,
3767
+ partitionFromKey,
3768
+ payloadBodyAsUtf8,
3769
+ prepareProducedPayload,
3770
+ protocolBus: protocolBus,
3771
+ readFirstRedisStreamEntry,
3772
+ resolveConnectionMetadata,
3773
+ resolveKafkaOAuthBearerToken,
3774
+ serializePayloadBody,
3775
+ setJsonBodyValue,
3776
+ shouldUseConfluentKafkaClient,
3777
+ toHeaderRecord,
3778
+ toKafkaHeadersWithContentType,
3779
+ validateHttpEndpoint,
3780
+ validateTrackingSelectorPath
3781
+ };
@@ -401,3 +401,20 @@ function booleanOrDefault(value, fallback) {
401
401
  async function sleep(ms) {
402
402
  await new Promise((resolve) => setTimeout(resolve, ms));
403
403
  }
404
+ export const __loadstrikeTestExports = {
405
+ DistributedClusterAgent,
406
+ DistributedClusterCoordinator,
407
+ LocalClusterCoordinator,
408
+ arrayOrUndefined,
409
+ booleanOrDefault,
410
+ buildWeightedCycle,
411
+ convertRunResult,
412
+ numberOrDefault,
413
+ parseRunCommand,
414
+ parseRunResult,
415
+ planAgentScenarioAssignments,
416
+ recordOrUndefined,
417
+ sanitizeToken,
418
+ sleep,
419
+ stringOrDefault
420
+ };