@loadstrike/loadstrike-sdk 1.0.10101 → 1.0.15201
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/README.md +8 -8
- package/dist/cjs/cluster.js +18 -1
- package/dist/cjs/correlation.js +69 -11
- package/dist/cjs/index.js +2 -14
- package/dist/cjs/local.js +107 -22
- package/dist/cjs/reporting.js +19 -5
- package/dist/cjs/runtime.js +526 -264
- package/dist/cjs/sinks.js +200 -106
- package/dist/cjs/transports.js +104 -18
- package/dist/esm/cluster.js +17 -0
- package/dist/esm/correlation.js +68 -10
- package/dist/esm/index.js +2 -4
- package/dist/esm/local.js +105 -20
- package/dist/esm/reporting.js +18 -2
- package/dist/esm/runtime.js +527 -264
- package/dist/esm/sinks.js +199 -105
- package/dist/esm/transports.js +103 -17
- package/dist/types/cluster.d.ts +30 -0
- package/dist/types/contracts.d.ts +15 -15
- package/dist/types/correlation.d.ts +41 -1
- package/dist/types/index.d.ts +4 -8
- package/dist/types/local.d.ts +146 -2
- package/dist/types/reporting.d.ts +33 -0
- package/dist/types/runtime.d.ts +464 -77
- package/dist/types/sinks.d.ts +212 -21
- package/dist/types/transports.d.ts +142 -0
- package/package.json +9 -20
package/dist/esm/sinks.js
CHANGED
|
@@ -235,13 +235,8 @@ export class MemoryReportingSink {
|
|
|
235
235
|
SaveRealtimeMetrics(metrics) {
|
|
236
236
|
this.saveRealtimeMetrics(metrics);
|
|
237
237
|
}
|
|
238
|
-
saveFinalStats(result) {
|
|
239
|
-
this.finalResults.push(cloneNodeStats(result));
|
|
240
|
-
}
|
|
241
|
-
SaveFinalStats(result) {
|
|
242
|
-
this.saveFinalStats(result);
|
|
243
|
-
}
|
|
244
238
|
saveRunResult(result) {
|
|
239
|
+
this.finalResults.push(cloneRunResult(result));
|
|
245
240
|
this.runResults.push(deepCloneRecord(result));
|
|
246
241
|
}
|
|
247
242
|
SaveRunResult(result) {
|
|
@@ -283,13 +278,9 @@ export class ConsoleReportingSink {
|
|
|
283
278
|
SaveRealtimeMetrics(metrics) {
|
|
284
279
|
this.saveRealtimeMetrics(metrics);
|
|
285
280
|
}
|
|
286
|
-
|
|
281
|
+
saveRunResult(result) {
|
|
287
282
|
this.writeLine(`final requests=${result.allRequestCount} ok=${result.allOkCount} fail=${result.allFailCount} failedThresholds=${result.failedThresholds}`);
|
|
288
283
|
}
|
|
289
|
-
SaveFinalStats(result) {
|
|
290
|
-
this.saveFinalStats(result);
|
|
291
|
-
}
|
|
292
|
-
saveRunResult(_result) { }
|
|
293
284
|
SaveRunResult(result) {
|
|
294
285
|
this.saveRunResult(result);
|
|
295
286
|
}
|
|
@@ -358,17 +349,6 @@ export class CompositeReportingSink {
|
|
|
358
349
|
async SaveRealtimeMetrics(metrics) {
|
|
359
350
|
await this.saveRealtimeMetrics(metrics);
|
|
360
351
|
}
|
|
361
|
-
async saveFinalStats(result) {
|
|
362
|
-
for (const sink of this.sinks) {
|
|
363
|
-
const saveFinalStats = sink.saveFinalStats ?? sink.SaveFinalStats;
|
|
364
|
-
if (saveFinalStats) {
|
|
365
|
-
await saveFinalStats.call(sink, result);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
async SaveFinalStats(result) {
|
|
370
|
-
await this.saveFinalStats(result);
|
|
371
|
-
}
|
|
372
352
|
async saveRunResult(result) {
|
|
373
353
|
for (const sink of this.sinks) {
|
|
374
354
|
const saveRunResult = sink.saveRunResult ?? sink.SaveRunResult;
|
|
@@ -454,12 +434,6 @@ export class InfluxDbReportingSink {
|
|
|
454
434
|
async SaveRealtimeMetrics(metrics) {
|
|
455
435
|
await this.saveRealtimeMetrics(metrics);
|
|
456
436
|
}
|
|
457
|
-
async saveFinalStats(result) {
|
|
458
|
-
await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
|
|
459
|
-
}
|
|
460
|
-
async SaveFinalStats(result) {
|
|
461
|
-
await this.saveFinalStats(result);
|
|
462
|
-
}
|
|
463
437
|
async saveRunResult(result) {
|
|
464
438
|
await this.persistEvents(createRunResultEvents(this.getSession(), result));
|
|
465
439
|
}
|
|
@@ -569,12 +543,6 @@ export class GrafanaLokiReportingSink {
|
|
|
569
543
|
async SaveRealtimeMetrics(metrics) {
|
|
570
544
|
await this.saveRealtimeMetrics(metrics);
|
|
571
545
|
}
|
|
572
|
-
async saveFinalStats(result) {
|
|
573
|
-
await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
|
|
574
|
-
}
|
|
575
|
-
async SaveFinalStats(result) {
|
|
576
|
-
await this.saveFinalStats(result);
|
|
577
|
-
}
|
|
578
546
|
async saveRunResult(result) {
|
|
579
547
|
await this.persistEvents(createRunResultEvents(this.getSession(), result));
|
|
580
548
|
}
|
|
@@ -720,12 +688,6 @@ export class TimescaleDbReportingSink {
|
|
|
720
688
|
async SaveRealtimeMetrics(metrics) {
|
|
721
689
|
await this.saveRealtimeMetrics(metrics);
|
|
722
690
|
}
|
|
723
|
-
async saveFinalStats(result) {
|
|
724
|
-
await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
|
|
725
|
-
}
|
|
726
|
-
async SaveFinalStats(result) {
|
|
727
|
-
await this.saveFinalStats(result);
|
|
728
|
-
}
|
|
729
691
|
async saveRunResult(result) {
|
|
730
692
|
await this.persistEvents(createRunResultEvents(this.getSession(), result));
|
|
731
693
|
}
|
|
@@ -1001,12 +963,6 @@ export class DatadogReportingSink {
|
|
|
1001
963
|
async SaveRealtimeMetrics(metrics) {
|
|
1002
964
|
await this.saveRealtimeMetrics(metrics);
|
|
1003
965
|
}
|
|
1004
|
-
async saveFinalStats(result) {
|
|
1005
|
-
await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
|
|
1006
|
-
}
|
|
1007
|
-
async SaveFinalStats(result) {
|
|
1008
|
-
await this.saveFinalStats(result);
|
|
1009
|
-
}
|
|
1010
966
|
async saveRunResult(result) {
|
|
1011
967
|
await this.persistEvents(createRunResultEvents(this.getSession(), result));
|
|
1012
968
|
}
|
|
@@ -1129,12 +1085,6 @@ export class SplunkReportingSink {
|
|
|
1129
1085
|
async SaveRealtimeMetrics(metrics) {
|
|
1130
1086
|
await this.saveRealtimeMetrics(metrics);
|
|
1131
1087
|
}
|
|
1132
|
-
async saveFinalStats(result) {
|
|
1133
|
-
await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
|
|
1134
|
-
}
|
|
1135
|
-
async SaveFinalStats(result) {
|
|
1136
|
-
await this.saveFinalStats(result);
|
|
1137
|
-
}
|
|
1138
1088
|
async saveRunResult(result) {
|
|
1139
1089
|
await this.persistEvents(createRunResultEvents(this.getSession(), result));
|
|
1140
1090
|
}
|
|
@@ -1237,12 +1187,6 @@ export class OtelCollectorReportingSink {
|
|
|
1237
1187
|
async SaveRealtimeMetrics(metrics) {
|
|
1238
1188
|
await this.saveRealtimeMetrics(metrics);
|
|
1239
1189
|
}
|
|
1240
|
-
async saveFinalStats(result) {
|
|
1241
|
-
await this.persistEvents(createFinalStatsEvents(this.getSession(), result));
|
|
1242
|
-
}
|
|
1243
|
-
async SaveFinalStats(result) {
|
|
1244
|
-
await this.saveFinalStats(result);
|
|
1245
|
-
}
|
|
1246
1190
|
async saveRunResult(result) {
|
|
1247
1191
|
await this.persistEvents(createRunResultEvents(this.getSession(), result));
|
|
1248
1192
|
}
|
|
@@ -1356,6 +1300,7 @@ function createFinalStatsEvents(session, stats) {
|
|
|
1356
1300
|
function createRunResultEvents(session, result) {
|
|
1357
1301
|
const occurredUtc = new Date();
|
|
1358
1302
|
const events = [
|
|
1303
|
+
...createFinalStatsEvents(session, runResultToNodeStats(result)),
|
|
1359
1304
|
createReportingEvent(session, occurredUtc, "run.result.final", null, null, {
|
|
1360
1305
|
phase: "final",
|
|
1361
1306
|
entity: "run-result"
|
|
@@ -1450,7 +1395,8 @@ function createStepEvents(session, occurredUtc, phase, scenario) {
|
|
|
1450
1395
|
return events;
|
|
1451
1396
|
}
|
|
1452
1397
|
function createStatusCodeEvents(session, occurredUtc, phase, scenarioName, stepName, resultKind, statusCodes) {
|
|
1453
|
-
|
|
1398
|
+
const normalizedStatusCodes = Array.isArray(statusCodes) ? statusCodes : [];
|
|
1399
|
+
return normalizedStatusCodes.map((statusCode) => createReportingEvent(session, occurredUtc, `status-code.${phase}`, scenarioName, stepName, {
|
|
1454
1400
|
phase,
|
|
1455
1401
|
entity: stepName ? "step-status-code" : "scenario-status-code",
|
|
1456
1402
|
result_kind: resultKind,
|
|
@@ -1583,30 +1529,63 @@ function createReportingEvent(session, occurredUtc, eventType, scenarioName, ste
|
|
|
1583
1529
|
};
|
|
1584
1530
|
}
|
|
1585
1531
|
function addMeasurementFields(fields, prefix, measurement) {
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1532
|
+
const request = measurement?.request ?? { count: 0, percent: 0, rps: 0 };
|
|
1533
|
+
const latency = measurement?.latency ?? {
|
|
1534
|
+
minMs: 0,
|
|
1535
|
+
meanMs: 0,
|
|
1536
|
+
maxMs: 0,
|
|
1537
|
+
percent50: 0,
|
|
1538
|
+
percent75: 0,
|
|
1539
|
+
percent95: 0,
|
|
1540
|
+
percent99: 0,
|
|
1541
|
+
stdDev: 0,
|
|
1542
|
+
latencyCount: {
|
|
1543
|
+
lessOrEq800: 0,
|
|
1544
|
+
more800Less1200: 0,
|
|
1545
|
+
moreOrEq1200: 0
|
|
1546
|
+
}
|
|
1547
|
+
};
|
|
1548
|
+
const latencyCount = latency.latencyCount ?? {
|
|
1549
|
+
lessOrEq800: 0,
|
|
1550
|
+
more800Less1200: 0,
|
|
1551
|
+
moreOrEq1200: 0
|
|
1552
|
+
};
|
|
1553
|
+
const dataTransfer = measurement?.dataTransfer ?? {
|
|
1554
|
+
allBytes: 0,
|
|
1555
|
+
minBytes: 0,
|
|
1556
|
+
meanBytes: 0,
|
|
1557
|
+
maxBytes: 0,
|
|
1558
|
+
percent50: 0,
|
|
1559
|
+
percent75: 0,
|
|
1560
|
+
percent95: 0,
|
|
1561
|
+
percent99: 0,
|
|
1562
|
+
stdDev: 0
|
|
1563
|
+
};
|
|
1564
|
+
const statusCodes = Array.isArray(measurement?.statusCodes) ? measurement.statusCodes : [];
|
|
1565
|
+
fields[`${prefix}_request_count`] = request.count ?? 0;
|
|
1566
|
+
fields[`${prefix}_request_percent`] = request.percent ?? 0;
|
|
1567
|
+
fields[`${prefix}_request_rps`] = request.rps ?? 0;
|
|
1568
|
+
fields[`${prefix}_latency_min_ms`] = latency.minMs ?? 0;
|
|
1569
|
+
fields[`${prefix}_latency_mean_ms`] = latency.meanMs ?? 0;
|
|
1570
|
+
fields[`${prefix}_latency_max_ms`] = latency.maxMs ?? 0;
|
|
1571
|
+
fields[`${prefix}_latency_p50_ms`] = latency.percent50 ?? 0;
|
|
1572
|
+
fields[`${prefix}_latency_p75_ms`] = latency.percent75 ?? 0;
|
|
1573
|
+
fields[`${prefix}_latency_p95_ms`] = latency.percent95 ?? 0;
|
|
1574
|
+
fields[`${prefix}_latency_p99_ms`] = latency.percent99 ?? 0;
|
|
1575
|
+
fields[`${prefix}_latency_std_dev`] = latency.stdDev ?? 0;
|
|
1576
|
+
fields[`${prefix}_latency_le_800_count`] = latencyCount.lessOrEq800 ?? 0;
|
|
1577
|
+
fields[`${prefix}_latency_gt_800_lt_1200_count`] = latencyCount.more800Less1200 ?? 0;
|
|
1578
|
+
fields[`${prefix}_latency_ge_1200_count`] = latencyCount.moreOrEq1200 ?? 0;
|
|
1579
|
+
fields[`${prefix}_bytes_all`] = dataTransfer.allBytes ?? 0;
|
|
1580
|
+
fields[`${prefix}_bytes_min`] = dataTransfer.minBytes ?? 0;
|
|
1581
|
+
fields[`${prefix}_bytes_mean`] = dataTransfer.meanBytes ?? 0;
|
|
1582
|
+
fields[`${prefix}_bytes_max`] = dataTransfer.maxBytes ?? 0;
|
|
1583
|
+
fields[`${prefix}_bytes_p50`] = dataTransfer.percent50 ?? 0;
|
|
1584
|
+
fields[`${prefix}_bytes_p75`] = dataTransfer.percent75 ?? 0;
|
|
1585
|
+
fields[`${prefix}_bytes_p95`] = dataTransfer.percent95 ?? 0;
|
|
1586
|
+
fields[`${prefix}_bytes_p99`] = dataTransfer.percent99 ?? 0;
|
|
1587
|
+
fields[`${prefix}_bytes_std_dev`] = dataTransfer.stdDev ?? 0;
|
|
1588
|
+
fields[`${prefix}_status_code_count`] = statusCodes.length;
|
|
1610
1589
|
}
|
|
1611
1590
|
function buildInfluxWriteUri(options) {
|
|
1612
1591
|
const query = new URLSearchParams({
|
|
@@ -2578,28 +2557,28 @@ function cloneSessionStartInfo(session) {
|
|
|
2578
2557
|
};
|
|
2579
2558
|
}
|
|
2580
2559
|
function cloneNodeInfo(nodeInfo) {
|
|
2581
|
-
return { ...nodeInfo };
|
|
2560
|
+
return { ...(nodeInfo ?? {}) };
|
|
2582
2561
|
}
|
|
2583
2562
|
function cloneTestInfo(testInfo) {
|
|
2584
|
-
return { ...testInfo };
|
|
2563
|
+
return { ...(testInfo ?? {}) };
|
|
2585
2564
|
}
|
|
2586
2565
|
function cloneMetricStats(metrics) {
|
|
2587
2566
|
return {
|
|
2588
|
-
counters: metrics
|
|
2589
|
-
gauges: metrics
|
|
2590
|
-
durationMs: metrics
|
|
2567
|
+
counters: (metrics?.counters ?? []).map((value) => ({ ...value })),
|
|
2568
|
+
gauges: (metrics?.gauges ?? []).map((value) => ({ ...value })),
|
|
2569
|
+
durationMs: metrics?.durationMs ?? 0
|
|
2591
2570
|
};
|
|
2592
2571
|
}
|
|
2593
2572
|
function cloneScenarioStats(value) {
|
|
2594
2573
|
return {
|
|
2595
2574
|
...value,
|
|
2596
|
-
ok: deepCloneRecord(value
|
|
2597
|
-
fail: deepCloneRecord(value
|
|
2598
|
-
loadSimulationStats: { ...value
|
|
2599
|
-
stepStats: value
|
|
2575
|
+
ok: deepCloneRecord(value?.ok ?? {}),
|
|
2576
|
+
fail: deepCloneRecord(value?.fail ?? {}),
|
|
2577
|
+
loadSimulationStats: { ...(value?.loadSimulationStats ?? {}) },
|
|
2578
|
+
stepStats: (value?.stepStats ?? []).map((step) => ({
|
|
2600
2579
|
...step,
|
|
2601
|
-
ok: deepCloneRecord(step
|
|
2602
|
-
fail: deepCloneRecord(step
|
|
2580
|
+
ok: deepCloneRecord(step?.ok ?? {}),
|
|
2581
|
+
fail: deepCloneRecord(step?.fail ?? {})
|
|
2603
2582
|
}))
|
|
2604
2583
|
};
|
|
2605
2584
|
}
|
|
@@ -2608,20 +2587,91 @@ function cloneNodeStats(result) {
|
|
|
2608
2587
|
...result,
|
|
2609
2588
|
nodeInfo: cloneNodeInfo(result.nodeInfo),
|
|
2610
2589
|
testInfo: cloneTestInfo(result.testInfo),
|
|
2611
|
-
thresholds: result.thresholds.map((value) => ({ ...value })),
|
|
2612
|
-
thresholdResults: result.thresholdResults.map((value) => ({ ...value })),
|
|
2590
|
+
thresholds: (result.thresholds ?? []).map((value) => ({ ...value })),
|
|
2591
|
+
thresholdResults: (result.thresholdResults ?? []).map((value) => ({ ...value })),
|
|
2613
2592
|
metrics: cloneMetricStats(result.metrics),
|
|
2614
|
-
metricValues: result.metricValues.map((value) => ({ ...value })),
|
|
2615
|
-
scenarioStats: result.scenarioStats.map((value) => cloneScenarioStats(value)),
|
|
2616
|
-
stepStats: result.stepStats.map((step) => ({
|
|
2593
|
+
metricValues: Array.isArray(result.metricValues) ? result.metricValues.map((value) => ({ ...value })) : [],
|
|
2594
|
+
scenarioStats: (result.scenarioStats ?? []).map((value) => cloneScenarioStats(value)),
|
|
2595
|
+
stepStats: (result.stepStats ?? []).map((step) => ({
|
|
2596
|
+
...step,
|
|
2597
|
+
ok: deepCloneRecord(step?.ok ?? {}),
|
|
2598
|
+
fail: deepCloneRecord(step?.fail ?? {})
|
|
2599
|
+
})),
|
|
2600
|
+
pluginsData: (result.pluginsData ?? []).map((plugin) => new LoadStrikePluginDataModel(plugin.pluginName, (plugin.tables ?? []).map((table) => new LoadStrikePluginDataTableModel(table.tableName, [...(table.headers ?? [])], (table.rows ?? []).map((row) => deepCloneRecord(row)))), [...(plugin.hints ?? [])])),
|
|
2601
|
+
disabledSinks: [...(result.disabledSinks ?? [])],
|
|
2602
|
+
sinkErrors: (result.sinkErrors ?? []).map((value) => ({ ...value })),
|
|
2603
|
+
reportFiles: [...(result.reportFiles ?? [])],
|
|
2604
|
+
logFiles: [...(result.logFiles ?? [])]
|
|
2605
|
+
};
|
|
2606
|
+
}
|
|
2607
|
+
function cloneRunResult(result) {
|
|
2608
|
+
return {
|
|
2609
|
+
...result,
|
|
2610
|
+
nodeInfo: cloneNodeInfo(result.nodeInfo),
|
|
2611
|
+
testInfo: cloneTestInfo(result.testInfo),
|
|
2612
|
+
thresholds: (result.thresholds ?? []).map((value) => ({ ...value })),
|
|
2613
|
+
thresholdResults: (result.thresholdResults ?? []).map((value) => ({ ...value })),
|
|
2614
|
+
metricStats: cloneMetricStats(result.metricStats),
|
|
2615
|
+
metrics: Array.isArray(result.metrics) ? result.metrics.map((value) => ({ ...value })) : [],
|
|
2616
|
+
scenarioStats: (result.scenarioStats ?? []).map((value) => cloneScenarioStats(value)),
|
|
2617
|
+
stepStats: (result.stepStats ?? []).map((step) => ({
|
|
2617
2618
|
...step,
|
|
2618
|
-
ok: deepCloneRecord(step
|
|
2619
|
-
fail: deepCloneRecord(step
|
|
2619
|
+
ok: deepCloneRecord(step?.ok ?? {}),
|
|
2620
|
+
fail: deepCloneRecord(step?.fail ?? {})
|
|
2620
2621
|
})),
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2622
|
+
scenarioDurationsMs: { ...(result.scenarioDurationsMs ?? {}) },
|
|
2623
|
+
pluginsData: (result.pluginsData ?? []).map((plugin) => new LoadStrikePluginDataModel(plugin.pluginName, (plugin.tables ?? []).map((table) => new LoadStrikePluginDataTableModel(table.tableName, [...(table.headers ?? [])], (table.rows ?? []).map((row) => deepCloneRecord(row)))), [...(plugin.hints ?? [])])),
|
|
2624
|
+
disabledSinks: [...(result.disabledSinks ?? [])],
|
|
2625
|
+
sinkErrors: (result.sinkErrors ?? []).map((value) => ({ ...value })),
|
|
2626
|
+
reportFiles: [...(result.reportFiles ?? [])],
|
|
2627
|
+
logFiles: [...(result.logFiles ?? [])],
|
|
2628
|
+
correlationRows: (result.correlationRows ?? []).map((row) => deepCloneRecord(row)),
|
|
2629
|
+
failedCorrelationRows: (result.failedCorrelationRows ?? []).map((row) => deepCloneRecord(row))
|
|
2630
|
+
};
|
|
2631
|
+
}
|
|
2632
|
+
function runResultToNodeStats(result) {
|
|
2633
|
+
return {
|
|
2634
|
+
startedUtc: result.startedUtc,
|
|
2635
|
+
completedUtc: result.completedUtc,
|
|
2636
|
+
allBytes: result.allBytes ?? 0,
|
|
2637
|
+
allRequestCount: result.allRequestCount ?? 0,
|
|
2638
|
+
allOkCount: result.allOkCount ?? 0,
|
|
2639
|
+
allFailCount: result.allFailCount ?? 0,
|
|
2640
|
+
failedThresholds: result.failedThresholds ?? 0,
|
|
2641
|
+
durationMs: result.durationMs ?? 0,
|
|
2642
|
+
nodeInfo: cloneNodeInfo(result.nodeInfo),
|
|
2643
|
+
testInfo: cloneTestInfo(result.testInfo),
|
|
2644
|
+
thresholds: (result.thresholds ?? []).map((value) => ({ ...value })),
|
|
2645
|
+
thresholdResults: (result.thresholdResults ?? []).map((value) => ({ ...value })),
|
|
2646
|
+
metrics: cloneMetricStats(result.metricStats),
|
|
2647
|
+
metricValues: Array.isArray(result.metrics) ? result.metrics.map((value) => ({ ...value })) : [],
|
|
2648
|
+
scenarioStats: (result.scenarioStats ?? []).map((value) => cloneScenarioStats(value)),
|
|
2649
|
+
stepStats: (result.stepStats ?? []).map((step) => ({
|
|
2650
|
+
...step,
|
|
2651
|
+
ok: deepCloneRecord(step?.ok ?? {}),
|
|
2652
|
+
fail: deepCloneRecord(step?.fail ?? {})
|
|
2653
|
+
})),
|
|
2654
|
+
pluginsData: (result.pluginsData ?? []).map((plugin) => new LoadStrikePluginDataModel(plugin.pluginName, (plugin.tables ?? []).map((table) => new LoadStrikePluginDataTableModel(table.tableName, [...(table.headers ?? [])], (table.rows ?? []).map((row) => deepCloneRecord(row)))), [...(plugin.hints ?? [])])),
|
|
2655
|
+
disabledSinks: [...(result.disabledSinks ?? [])],
|
|
2656
|
+
sinkErrors: (result.sinkErrors ?? []).map((value) => ({ ...value })),
|
|
2657
|
+
reportFiles: [...(result.reportFiles ?? [])],
|
|
2658
|
+
logFiles: [...(result.logFiles ?? [])],
|
|
2659
|
+
findScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
|
|
2660
|
+
getScenarioStats: (scenarioName) => {
|
|
2661
|
+
const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
|
|
2662
|
+
if (!scenario) {
|
|
2663
|
+
throw new Error(`Scenario stats not found: ${scenarioName}`);
|
|
2664
|
+
}
|
|
2665
|
+
return scenario;
|
|
2666
|
+
},
|
|
2667
|
+
FindScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
|
|
2668
|
+
GetScenarioStats: (scenarioName) => {
|
|
2669
|
+
const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
|
|
2670
|
+
if (!scenario) {
|
|
2671
|
+
throw new Error(`Scenario stats not found: ${scenarioName}`);
|
|
2672
|
+
}
|
|
2673
|
+
return scenario;
|
|
2674
|
+
}
|
|
2625
2675
|
};
|
|
2626
2676
|
}
|
|
2627
2677
|
function deepCloneRecord(value) {
|
|
@@ -2655,3 +2705,47 @@ async function postWithTimeout(fetchImpl, url, init, timeoutMs, sinkName) {
|
|
|
2655
2705
|
clearTimeout(timer);
|
|
2656
2706
|
}
|
|
2657
2707
|
}
|
|
2708
|
+
export const __loadstrikeTestExports = {
|
|
2709
|
+
GrafanaLokiReportingSink,
|
|
2710
|
+
InfluxDbReportingSink,
|
|
2711
|
+
OtelCollectorReportingSink,
|
|
2712
|
+
SplunkReportingSink,
|
|
2713
|
+
TimescaleDbReportingSink,
|
|
2714
|
+
cleanNullableText,
|
|
2715
|
+
cloneBaseContext,
|
|
2716
|
+
cloneMetricStats,
|
|
2717
|
+
cloneNodeStats,
|
|
2718
|
+
cloneScenarioStats,
|
|
2719
|
+
cloneSessionStartInfo,
|
|
2720
|
+
createFinalStatsEvents,
|
|
2721
|
+
createRealtimeStatsEvents,
|
|
2722
|
+
createRunResultEvents,
|
|
2723
|
+
createReportingEvent,
|
|
2724
|
+
mergeDatadogOptions,
|
|
2725
|
+
mergeInfluxOptions,
|
|
2726
|
+
mergeGrafanaLokiOptions,
|
|
2727
|
+
mergeOtelCollectorOptions,
|
|
2728
|
+
mergeSplunkOptions,
|
|
2729
|
+
mergeTimescaleDbOptions,
|
|
2730
|
+
normalizeConfigKey,
|
|
2731
|
+
normalizePath,
|
|
2732
|
+
normalizePluginFieldName,
|
|
2733
|
+
normalizePluginFieldValue,
|
|
2734
|
+
normalizeStringMap,
|
|
2735
|
+
optionNumber,
|
|
2736
|
+
optionString,
|
|
2737
|
+
pickBooleanValue,
|
|
2738
|
+
pickRecordValue,
|
|
2739
|
+
postWithTimeout,
|
|
2740
|
+
quoteIdentifier,
|
|
2741
|
+
replaceLiteral,
|
|
2742
|
+
resolveConfigSection,
|
|
2743
|
+
resolveTimeoutMs,
|
|
2744
|
+
sanitizeGrafanaLabelKey,
|
|
2745
|
+
sanitizeGrafanaLabelValue,
|
|
2746
|
+
sinkSessionMetadataFromContext,
|
|
2747
|
+
toOtelAnyValue,
|
|
2748
|
+
trimTrailingSlashes,
|
|
2749
|
+
tryReadText,
|
|
2750
|
+
validateIdentifier
|
|
2751
|
+
};
|
package/dist/esm/transports.js
CHANGED
|
@@ -211,6 +211,9 @@ class AzureEventHubsEndpointDefinitionModel extends TrafficEndpointDefinitionMod
|
|
|
211
211
|
super.Validate();
|
|
212
212
|
requireNonEmptyString(this.ConnectionString, "ConnectionString must be provided for Azure Event Hubs endpoint.");
|
|
213
213
|
requireNonEmptyString(this.EventHubName, "EventHubName must be provided for Azure Event Hubs endpoint.");
|
|
214
|
+
if (this.PartitionCount != null && this.PartitionCount < 0) {
|
|
215
|
+
throw new RangeError("PartitionCount must be zero or greater when configured.");
|
|
216
|
+
}
|
|
214
217
|
}
|
|
215
218
|
}
|
|
216
219
|
class DelegateStreamEndpointDefinitionModel extends TrafficEndpointDefinitionModel {
|
|
@@ -614,6 +617,12 @@ function initializeAzureEventHubsEndpointDefinitionModel(target, initial) {
|
|
|
614
617
|
if (hasAnyEndpointField(raw, ["PartitionId", "partitionId"])) {
|
|
615
618
|
target.PartitionId = pickOptionalEndpointString(raw, "PartitionId", "partitionId");
|
|
616
619
|
}
|
|
620
|
+
if (hasAnyEndpointField(raw, ["PartitionKey", "partitionKey"])) {
|
|
621
|
+
target.PartitionKey = pickOptionalEndpointString(raw, "PartitionKey", "partitionKey");
|
|
622
|
+
}
|
|
623
|
+
if (hasAnyEndpointField(raw, ["PartitionCount", "partitionCount"])) {
|
|
624
|
+
target.PartitionCount = pickOptionalEndpointNumber(raw, "PartitionCount", "partitionCount");
|
|
625
|
+
}
|
|
617
626
|
}
|
|
618
627
|
function initializeDelegateStreamEndpointDefinitionModel(target, initial) {
|
|
619
628
|
const raw = asRecordOrEmpty(initial);
|
|
@@ -704,10 +713,9 @@ function validateHttpAuthOptionsModel(target) {
|
|
|
704
713
|
}
|
|
705
714
|
return;
|
|
706
715
|
case "oauth2clientcredentials":
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
toHttpOAuth2ClientCredentialsOptionsModel(target.OAuth2ClientCredentials).Validate();
|
|
716
|
+
requireNonEmptyString(target.TokenUrl ?? target.OAuth2ClientCredentials?.TokenEndpoint, "TokenEndpoint must be provided for OAuth2 client credentials flow.");
|
|
717
|
+
requireNonEmptyString(target.ClientId ?? target.OAuth2ClientCredentials?.ClientId, "ClientId must be provided for OAuth2 client credentials flow.");
|
|
718
|
+
requireNonEmptyString(target.ClientSecret ?? target.OAuth2ClientCredentials?.ClientSecret, "ClientSecret must be provided for OAuth2 client credentials flow.");
|
|
711
719
|
return;
|
|
712
720
|
default:
|
|
713
721
|
throw new RangeError("Unsupported HTTP auth type.");
|
|
@@ -897,8 +905,7 @@ const protocolBus = new class InMemoryProtocolBus {
|
|
|
897
905
|
produceEventHub(endpoint, payload) {
|
|
898
906
|
const options = endpoint.azureEventHubs ?? {};
|
|
899
907
|
const hubName = optionString(options, "EventHubName", "eventHubName") || endpoint.name;
|
|
900
|
-
const partitionId =
|
|
901
|
-
|| partitionFromKey(optionString(options, "PartitionKey", "partitionKey"), optionNumber(options, "PartitionCount", "partitionCount") || 4);
|
|
908
|
+
const partitionId = resolveEventHubProducePartitionId(options) || "";
|
|
902
909
|
const rows = this.eventHubs.get(hubName) ?? [];
|
|
903
910
|
rows.push({
|
|
904
911
|
partitionId,
|
|
@@ -1124,10 +1131,10 @@ class HttpEndpointAdapter extends CallbackAdapter {
|
|
|
1124
1131
|
body.set("grant_type", "client_credentials");
|
|
1125
1132
|
body.set("client_id", clientId);
|
|
1126
1133
|
body.set("client_secret", clientSecret);
|
|
1127
|
-
const scopes = Array.isArray(
|
|
1128
|
-
?
|
|
1129
|
-
: Array.isArray(
|
|
1130
|
-
?
|
|
1134
|
+
const scopes = Array.isArray(auth?.scopes)
|
|
1135
|
+
? auth.scopes.map((x) => String(x).trim()).filter((x) => x.length > 0)
|
|
1136
|
+
: Array.isArray(oauthOptions?.scopes)
|
|
1137
|
+
? oauthOptions.scopes.map((x) => String(x).trim()).filter((x) => x.length > 0)
|
|
1131
1138
|
: [];
|
|
1132
1139
|
const scopeText = typeof auth?.scope === "string" && auth.scope.trim()
|
|
1133
1140
|
? auth.scope.trim()
|
|
@@ -1139,8 +1146,8 @@ class HttpEndpointAdapter extends CallbackAdapter {
|
|
|
1139
1146
|
body.set("audience", auth.audience.trim());
|
|
1140
1147
|
}
|
|
1141
1148
|
for (const [key, value] of Object.entries({
|
|
1142
|
-
...(
|
|
1143
|
-
...(
|
|
1149
|
+
...(oauthOptions?.additionalFormFields ?? {}),
|
|
1150
|
+
...(auth?.additionalFormFields ?? {})
|
|
1144
1151
|
})) {
|
|
1145
1152
|
if (key.trim() && typeof value === "string") {
|
|
1146
1153
|
body.set(key.trim(), value);
|
|
@@ -1566,13 +1573,15 @@ class AzureEventHubsEndpointAdapter extends CallbackAdapter {
|
|
|
1566
1573
|
const options = this.endpoint.azureEventHubs ?? {};
|
|
1567
1574
|
const resolved = prepareProducedPayload(this.endpoint, payload);
|
|
1568
1575
|
const wire = toWirePayload(resolved, this.endpoint);
|
|
1569
|
-
const
|
|
1576
|
+
const partitionId = resolveEventHubProducePartitionId(options);
|
|
1577
|
+
const batch = partitionId
|
|
1578
|
+
? await producer.createBatch({ partitionId })
|
|
1579
|
+
: await producer.createBatch();
|
|
1570
1580
|
const eventData = {
|
|
1571
1581
|
body: Buffer.from(wire.body),
|
|
1572
1582
|
contentType: wire.contentType,
|
|
1573
1583
|
properties: { ...wire.headers }
|
|
1574
1584
|
};
|
|
1575
|
-
const partitionId = optionString(options, "PartitionId", "partitionId");
|
|
1576
1585
|
if (partitionId) {
|
|
1577
1586
|
eventData.partitionId = partitionId;
|
|
1578
1587
|
}
|
|
@@ -1798,6 +1807,10 @@ const AZURE_EVENT_HUBS_ENDPOINT_FLAT_KEYS = [
|
|
|
1798
1807
|
"consumerGroup",
|
|
1799
1808
|
"PartitionId",
|
|
1800
1809
|
"partitionId",
|
|
1810
|
+
"PartitionKey",
|
|
1811
|
+
"partitionKey",
|
|
1812
|
+
"PartitionCount",
|
|
1813
|
+
"partitionCount",
|
|
1801
1814
|
"StartFromEarliest",
|
|
1802
1815
|
"startFromEarliest"
|
|
1803
1816
|
];
|
|
@@ -1910,7 +1923,11 @@ function resolveEndpointKind(raw) {
|
|
|
1910
1923
|
"EventHubName",
|
|
1911
1924
|
"eventHubName",
|
|
1912
1925
|
"PartitionId",
|
|
1913
|
-
"partitionId"
|
|
1926
|
+
"partitionId",
|
|
1927
|
+
"PartitionKey",
|
|
1928
|
+
"partitionKey",
|
|
1929
|
+
"PartitionCount",
|
|
1930
|
+
"partitionCount"
|
|
1914
1931
|
])) {
|
|
1915
1932
|
return "AzureEventHubs";
|
|
1916
1933
|
}
|
|
@@ -2411,6 +2428,10 @@ function validateAzureEventHubsEndpoint(endpoint, mode, hasModeDelegate) {
|
|
|
2411
2428
|
}
|
|
2412
2429
|
requireNonEmptyString(optionString(options, "ConnectionString", "connectionString"), "ConnectionString must be provided for Azure Event Hubs endpoint.");
|
|
2413
2430
|
requireNonEmptyString(optionString(options, "EventHubName", "eventHubName"), "EventHubName must be provided for Azure Event Hubs endpoint.");
|
|
2431
|
+
const partitionCount = optionNumber(options, "PartitionCount", "partitionCount");
|
|
2432
|
+
if (partitionCount < 0) {
|
|
2433
|
+
throw new RangeError("PartitionCount must be zero or greater when configured.");
|
|
2434
|
+
}
|
|
2414
2435
|
}
|
|
2415
2436
|
function validatePushDiffusionEndpoint(endpoint, mode) {
|
|
2416
2437
|
const options = endpoint.pushDiffusion;
|
|
@@ -2810,6 +2831,17 @@ function partitionFromKey(value, partitionCount) {
|
|
|
2810
2831
|
const normalized = Math.abs(hash) % count;
|
|
2811
2832
|
return String(normalized);
|
|
2812
2833
|
}
|
|
2834
|
+
function resolveEventHubProducePartitionId(options) {
|
|
2835
|
+
const explicitPartitionId = optionString(options, "PartitionId", "partitionId");
|
|
2836
|
+
if (explicitPartitionId) {
|
|
2837
|
+
return explicitPartitionId;
|
|
2838
|
+
}
|
|
2839
|
+
const partitionKey = optionString(options, "PartitionKey", "partitionKey");
|
|
2840
|
+
if (!partitionKey) {
|
|
2841
|
+
return undefined;
|
|
2842
|
+
}
|
|
2843
|
+
return partitionFromKey(partitionKey, optionNumber(options, "PartitionCount", "partitionCount") || 4);
|
|
2844
|
+
}
|
|
2813
2845
|
function attachPayloadHelpers(payload) {
|
|
2814
2846
|
const target = {
|
|
2815
2847
|
...payload,
|
|
@@ -2992,10 +3024,10 @@ function deserializeBrokerPayloadBody(body, contentType, messagePayloadType) {
|
|
|
2992
3024
|
function extractTrackingValue(payload, selector) {
|
|
2993
3025
|
const normalized = selector.trim().toLowerCase();
|
|
2994
3026
|
if (normalized.startsWith("header:")) {
|
|
2995
|
-
const headerName = selector.slice("header:".length).trim()
|
|
3027
|
+
const headerName = selector.slice("header:".length).trim();
|
|
2996
3028
|
for (const [key, value] of Object.entries(payload.headers ?? {})) {
|
|
2997
3029
|
const resolved = String(value ?? "").trim();
|
|
2998
|
-
if (key
|
|
3030
|
+
if (key === headerName && resolved) {
|
|
2999
3031
|
return resolved;
|
|
3000
3032
|
}
|
|
3001
3033
|
}
|
|
@@ -3656,3 +3688,57 @@ function payloadBodyAsUtf8(body) {
|
|
|
3656
3688
|
return String(body);
|
|
3657
3689
|
}
|
|
3658
3690
|
}
|
|
3691
|
+
export const __loadstrikeTestExports = {
|
|
3692
|
+
AzureEventHubsEndpointAdapter,
|
|
3693
|
+
AzureEventHubsEndpointDefinition,
|
|
3694
|
+
AzureEventHubsEndpointDefinitionModel,
|
|
3695
|
+
CallbackAdapter,
|
|
3696
|
+
DelegateStreamEndpointDefinition,
|
|
3697
|
+
DelegateStreamEndpointDefinitionModel,
|
|
3698
|
+
HttpEndpointAdapter,
|
|
3699
|
+
NatsEndpointDefinition,
|
|
3700
|
+
NatsEndpointDefinitionModel,
|
|
3701
|
+
PushDiffusionEndpointDefinition,
|
|
3702
|
+
PushDiffusionEndpointDefinitionModel,
|
|
3703
|
+
RabbitMqEndpointDefinition,
|
|
3704
|
+
RabbitMqEndpointDefinitionModel,
|
|
3705
|
+
RedisStreamsEndpointAdapter,
|
|
3706
|
+
RedisStreamsEndpointDefinition,
|
|
3707
|
+
RedisStreamsEndpointDefinitionModel,
|
|
3708
|
+
bufferToUint8Array,
|
|
3709
|
+
applyHttpAuthHeaders,
|
|
3710
|
+
buildHttpRequestBody,
|
|
3711
|
+
buildConfluentKafkaClientOptions,
|
|
3712
|
+
buildKafkaClientOptions,
|
|
3713
|
+
canonicalizeHttpResponseSource,
|
|
3714
|
+
createDelegateRequestEndpointView,
|
|
3715
|
+
createNatsHeaders,
|
|
3716
|
+
createRedisStreamPayload,
|
|
3717
|
+
deserializeBrokerPayloadBody,
|
|
3718
|
+
extractTrackingValue,
|
|
3719
|
+
fromKafkaHeaders,
|
|
3720
|
+
headerValue,
|
|
3721
|
+
attachDotNetTrackingPayloadAliases,
|
|
3722
|
+
attachPayloadHelpers,
|
|
3723
|
+
attachStructuredProducedMessageRequestAliases,
|
|
3724
|
+
inferLegacyHttpResponseSource,
|
|
3725
|
+
injectTrackingValue,
|
|
3726
|
+
mapConfluentKafkaSaslMechanism,
|
|
3727
|
+
mapConfluentKafkaSecurityProtocol,
|
|
3728
|
+
mapKafkaSaslMechanism,
|
|
3729
|
+
parseBodyObject,
|
|
3730
|
+
partitionFromKey,
|
|
3731
|
+
payloadBodyAsUtf8,
|
|
3732
|
+
prepareProducedPayload,
|
|
3733
|
+
protocolBus: protocolBus,
|
|
3734
|
+
readFirstRedisStreamEntry,
|
|
3735
|
+
resolveConnectionMetadata,
|
|
3736
|
+
resolveKafkaOAuthBearerToken,
|
|
3737
|
+
serializePayloadBody,
|
|
3738
|
+
setJsonBodyValue,
|
|
3739
|
+
shouldUseConfluentKafkaClient,
|
|
3740
|
+
toHeaderRecord,
|
|
3741
|
+
toKafkaHeadersWithContentType,
|
|
3742
|
+
validateHttpEndpoint,
|
|
3743
|
+
validateTrackingSelectorPath
|
|
3744
|
+
};
|
package/dist/types/cluster.d.ts
CHANGED
|
@@ -60,6 +60,7 @@ export interface ClusterNodeStatsPayload {
|
|
|
60
60
|
pluginsData?: unknown[];
|
|
61
61
|
nodeInfo?: Record<string, unknown>;
|
|
62
62
|
testInfo?: Record<string, unknown>;
|
|
63
|
+
logFiles?: string[];
|
|
63
64
|
}
|
|
64
65
|
export interface ClusterRunResultMessage {
|
|
65
66
|
commandId: string;
|
|
@@ -110,3 +111,32 @@ export declare class DistributedClusterAgent {
|
|
|
110
111
|
dispose(): Promise<void>;
|
|
111
112
|
pollAndExecuteOnce(execute: (dispatch: ClusterScenarioDispatch) => Promise<ClusterNodeResult> | ClusterNodeResult): Promise<boolean>;
|
|
112
113
|
}
|
|
114
|
+
declare function parseRunCommand(value: Record<string, unknown>): ClusterRunCommandMessage;
|
|
115
|
+
declare function parseRunResult(value: Record<string, unknown>): ClusterRunResultMessage;
|
|
116
|
+
declare function convertRunResult(result: ClusterRunResultMessage): ClusterNodeResult;
|
|
117
|
+
declare function sanitizeToken(value: string): string;
|
|
118
|
+
declare function buildWeightedCycle(weights: number[]): number[];
|
|
119
|
+
declare function stringOrDefault(value: unknown, fallback: string): string;
|
|
120
|
+
declare function numberOrDefault(value: unknown, fallback: number): number;
|
|
121
|
+
declare function recordOrUndefined(value: unknown): Record<string, unknown> | undefined;
|
|
122
|
+
declare function arrayOrUndefined(value: unknown): unknown[] | undefined;
|
|
123
|
+
declare function booleanOrDefault(value: unknown, fallback: boolean): boolean;
|
|
124
|
+
declare function sleep(ms: number): Promise<void>;
|
|
125
|
+
export declare const __loadstrikeTestExports: {
|
|
126
|
+
DistributedClusterAgent: typeof DistributedClusterAgent;
|
|
127
|
+
DistributedClusterCoordinator: typeof DistributedClusterCoordinator;
|
|
128
|
+
LocalClusterCoordinator: typeof LocalClusterCoordinator;
|
|
129
|
+
arrayOrUndefined: typeof arrayOrUndefined;
|
|
130
|
+
booleanOrDefault: typeof booleanOrDefault;
|
|
131
|
+
buildWeightedCycle: typeof buildWeightedCycle;
|
|
132
|
+
convertRunResult: typeof convertRunResult;
|
|
133
|
+
numberOrDefault: typeof numberOrDefault;
|
|
134
|
+
parseRunCommand: typeof parseRunCommand;
|
|
135
|
+
parseRunResult: typeof parseRunResult;
|
|
136
|
+
planAgentScenarioAssignments: typeof planAgentScenarioAssignments;
|
|
137
|
+
recordOrUndefined: typeof recordOrUndefined;
|
|
138
|
+
sanitizeToken: typeof sanitizeToken;
|
|
139
|
+
sleep: typeof sleep;
|
|
140
|
+
stringOrDefault: typeof stringOrDefault;
|
|
141
|
+
};
|
|
142
|
+
export {};
|