@loadstrike/loadstrike-sdk 1.0.21301 → 1.0.22001
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/reporting.js +214 -75
- package/dist/cjs/runtime.js +1 -1
- package/dist/esm/reporting.js +214 -75
- package/dist/esm/runtime.js +1 -1
- package/package.json +1 -1
package/dist/cjs/reporting.js
CHANGED
|
@@ -51,6 +51,61 @@ function reportValue(source, ...keys) {
|
|
|
51
51
|
}
|
|
52
52
|
return undefined;
|
|
53
53
|
}
|
|
54
|
+
function reportDurationValue(source) {
|
|
55
|
+
return reportValue(source, "durationMs", "DurationMs", "duration", "Duration");
|
|
56
|
+
}
|
|
57
|
+
function reportBytesValue(source) {
|
|
58
|
+
return reportValue(source, "allBytes", "AllBytes", "totalBytes", "TotalBytes");
|
|
59
|
+
}
|
|
60
|
+
function reportTotalBytes(nodeStats, scenarios) {
|
|
61
|
+
const totalBytes = asInt(reportBytesValue(nodeStats));
|
|
62
|
+
if (totalBytes !== 0) {
|
|
63
|
+
return totalBytes;
|
|
64
|
+
}
|
|
65
|
+
return scenarios.reduce((sum, scenario) => sum + asInt(reportBytesValue(scenario)), 0);
|
|
66
|
+
}
|
|
67
|
+
function reportRequestCountValue(source) {
|
|
68
|
+
return asInt(reportValue(source, "allRequestCount", "AllRequestCount", "requestCount", "RequestCount"));
|
|
69
|
+
}
|
|
70
|
+
function reportOkCountValue(source) {
|
|
71
|
+
return asInt(reportValue(source, "allOkCount", "AllOkCount", "okCount", "OkCount"));
|
|
72
|
+
}
|
|
73
|
+
function reportFailCountValue(source) {
|
|
74
|
+
return asInt(reportValue(source, "allFailCount", "AllFailCount", "failCount", "FailCount"));
|
|
75
|
+
}
|
|
76
|
+
function reportTotalRequestCount(nodeStats, scenarios) {
|
|
77
|
+
const total = reportRequestCountValue(nodeStats);
|
|
78
|
+
return total !== 0 || scenarios.length === 0
|
|
79
|
+
? total
|
|
80
|
+
: scenarios.reduce((sum, scenario) => sum + reportRequestCountValue(scenario), 0);
|
|
81
|
+
}
|
|
82
|
+
function reportTotalOkCount(nodeStats, scenarios) {
|
|
83
|
+
const total = reportOkCountValue(nodeStats);
|
|
84
|
+
return total !== 0 || scenarios.length === 0
|
|
85
|
+
? total
|
|
86
|
+
: scenarios.reduce((sum, scenario) => sum + reportOkCountValue(scenario), 0);
|
|
87
|
+
}
|
|
88
|
+
function reportTotalFailCount(nodeStats, scenarios) {
|
|
89
|
+
const total = reportFailCountValue(nodeStats);
|
|
90
|
+
return total !== 0 || scenarios.length === 0
|
|
91
|
+
? total
|
|
92
|
+
: scenarios.reduce((sum, scenario) => sum + reportFailCountValue(scenario), 0);
|
|
93
|
+
}
|
|
94
|
+
function reportScenarios(nodeStats) {
|
|
95
|
+
return sortBySortIndex(reportArray(nodeStats, "scenarioStats", "ScenarioStats"));
|
|
96
|
+
}
|
|
97
|
+
function reportSteps(scenario) {
|
|
98
|
+
return sortBySortIndex(reportArray(scenario, "stepStats", "StepStats"));
|
|
99
|
+
}
|
|
100
|
+
function reportThresholds(nodeStats) {
|
|
101
|
+
return reportArray(nodeStats, "thresholds", "Thresholds", "thresholdResults", "ThresholdResults");
|
|
102
|
+
}
|
|
103
|
+
function reportMetrics(nodeStats) {
|
|
104
|
+
return reportObject(nodeStats, "metrics", "Metrics", "metricStats", "MetricStats");
|
|
105
|
+
}
|
|
106
|
+
function reportMetricName(source) {
|
|
107
|
+
return asString(reportValue(source, "metricName", "MetricName", "name", "Name"));
|
|
108
|
+
}
|
|
54
109
|
function reportObject(source, ...keys) {
|
|
55
110
|
const value = reportValue(source, ...keys);
|
|
56
111
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
@@ -84,6 +139,16 @@ function asFloat(value) {
|
|
|
84
139
|
const parsed = Number.parseFloat(asString(value));
|
|
85
140
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
86
141
|
}
|
|
142
|
+
function asBool(value) {
|
|
143
|
+
if (typeof value === "boolean") {
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
147
|
+
return value !== 0;
|
|
148
|
+
}
|
|
149
|
+
const normalized = asString(value).trim().toLowerCase();
|
|
150
|
+
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "y" || normalized === "on";
|
|
151
|
+
}
|
|
87
152
|
function formatCellValue(value) {
|
|
88
153
|
if (value == null) {
|
|
89
154
|
return "";
|
|
@@ -303,7 +368,7 @@ function buildDotnetTableHtml(rows, wrapInCard = true) {
|
|
|
303
368
|
appendReportLine(parts, "<table>");
|
|
304
369
|
appendReportLine(parts, "<thead><tr>");
|
|
305
370
|
for (const header of headers) {
|
|
306
|
-
appendReportLine(parts, `<th>${escapeHtml(header)}</th>`);
|
|
371
|
+
appendReportLine(parts, `<th>${escapeHtml(formatReportTableHeader(header))}</th>`);
|
|
307
372
|
}
|
|
308
373
|
appendReportLine(parts, "</tr></thead><tbody>");
|
|
309
374
|
for (const row of rows) {
|
|
@@ -319,6 +384,14 @@ function buildDotnetTableHtml(rows, wrapInCard = true) {
|
|
|
319
384
|
}
|
|
320
385
|
return parts.join("");
|
|
321
386
|
}
|
|
387
|
+
function formatReportTableHeader(header) {
|
|
388
|
+
if (header === "LatencyStdDev") {
|
|
389
|
+
return "LatencyStdDev (ms)";
|
|
390
|
+
}
|
|
391
|
+
return header.endsWith("Ms") && header.length > "Ms".length
|
|
392
|
+
? `${header.slice(0, -"Ms".length)} (ms)`
|
|
393
|
+
: header;
|
|
394
|
+
}
|
|
322
395
|
function buildFailedStatusRows(scenarios) {
|
|
323
396
|
const rows = [];
|
|
324
397
|
for (const scenario of scenarios) {
|
|
@@ -341,7 +414,7 @@ function buildFailedStatusRows(scenarios) {
|
|
|
341
414
|
IsError: isError
|
|
342
415
|
});
|
|
343
416
|
}
|
|
344
|
-
for (const step of
|
|
417
|
+
for (const step of reportSteps(scenario)) {
|
|
345
418
|
const stepName = asString(reportValue(step, "stepName", "StepName"));
|
|
346
419
|
const stepFail = reportObject(step, "fail", "Fail");
|
|
347
420
|
for (const code of reportArray(stepFail, "statusCodes", "StatusCodes")) {
|
|
@@ -593,6 +666,65 @@ function buildMeasurementRow(scope, scenarioName, stepName, resultName, measurem
|
|
|
593
666
|
BytesStdDev: formatReportNumber(reportValue(dataTransfer, "stdDev", "StdDev"))
|
|
594
667
|
};
|
|
595
668
|
}
|
|
669
|
+
function pushMeasurementRowIfData(rows, scope, scenarioName, stepName, resultName, measurement) {
|
|
670
|
+
if (hasMeasurementData(measurement)) {
|
|
671
|
+
rows.push(buildMeasurementRow(scope, scenarioName, stepName, resultName, measurement));
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
function hasMeasurementData(measurement) {
|
|
675
|
+
if (Object.keys(measurement).length === 0) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
const request = reportObject(measurement, "request", "Request");
|
|
679
|
+
if (asInt(reportValue(request, "count", "Count")) !== 0 ||
|
|
680
|
+
asInt(reportValue(request, "percent", "Percent")) !== 0 ||
|
|
681
|
+
asFloat(reportValue(request, "rps", "RPS")) !== 0) {
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
const latency = reportObject(measurement, "latency", "Latency");
|
|
685
|
+
const latencyKeys = [
|
|
686
|
+
["minMs", "MinMs"],
|
|
687
|
+
["meanMs", "MeanMs"],
|
|
688
|
+
["percent50", "Percent50"],
|
|
689
|
+
["percent75", "Percent75"],
|
|
690
|
+
["percent95", "Percent95"],
|
|
691
|
+
["percent99", "Percent99"],
|
|
692
|
+
["maxMs", "MaxMs"],
|
|
693
|
+
["stdDev", "StdDev"]
|
|
694
|
+
];
|
|
695
|
+
if (latencyKeys.some(([camelKey, pascalKey]) => asFloat(reportValue(latency, camelKey, pascalKey)) !== 0)) {
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
const latencyCount = reportObject(latency, "latencyCount", "LatencyCount");
|
|
699
|
+
const latencyCountKeys = [
|
|
700
|
+
["lessOrEq800", "LessOrEq800"],
|
|
701
|
+
["more800Less1200", "More800Less1200"],
|
|
702
|
+
["moreOrEq1200", "MoreOrEq1200"]
|
|
703
|
+
];
|
|
704
|
+
if (latencyCountKeys.some(([camelKey, pascalKey]) => asInt(reportValue(latencyCount, camelKey, pascalKey)) !== 0)) {
|
|
705
|
+
return true;
|
|
706
|
+
}
|
|
707
|
+
const dataTransfer = reportObject(measurement, "dataTransfer", "DataTransfer");
|
|
708
|
+
const dataTransferKeys = [
|
|
709
|
+
["allBytes", "AllBytes"],
|
|
710
|
+
["minBytes", "MinBytes"],
|
|
711
|
+
["meanBytes", "MeanBytes"],
|
|
712
|
+
["percent50", "Percent50"],
|
|
713
|
+
["percent75", "Percent75"],
|
|
714
|
+
["percent95", "Percent95"],
|
|
715
|
+
["percent99", "Percent99"],
|
|
716
|
+
["maxBytes", "MaxBytes"],
|
|
717
|
+
["stdDev", "StdDev"]
|
|
718
|
+
];
|
|
719
|
+
if (dataTransferKeys.some(([camelKey, pascalKey]) => asFloat(reportValue(dataTransfer, camelKey, pascalKey)) !== 0)) {
|
|
720
|
+
return true;
|
|
721
|
+
}
|
|
722
|
+
return reportArray(measurement, "statusCodes", "StatusCodes").some((code) => asInt(reportValue(code, "count", "Count")) !== 0 ||
|
|
723
|
+
asInt(reportValue(code, "percent", "Percent")) !== 0 ||
|
|
724
|
+
asBool(reportValue(code, "isError", "IsError")) ||
|
|
725
|
+
asString(reportValue(code, "statusCode", "StatusCode")).trim().length > 0 ||
|
|
726
|
+
asString(reportValue(code, "message", "Message")).trim().length > 0);
|
|
727
|
+
}
|
|
596
728
|
function appendChartCard(parts, id, title) {
|
|
597
729
|
appendReportLine(parts, `<div class="chart-card"><h3>${escapeHtml(title)}</h3><canvas id="${escapeHtml(id)}" class="chart-canvas"></canvas></div>`);
|
|
598
730
|
}
|
|
@@ -611,24 +743,27 @@ function hasNonEmptyHints(plugin) {
|
|
|
611
743
|
return reportArray(plugin, "hints", "Hints").some((hint) => asString(hint).trim().length > 0);
|
|
612
744
|
}
|
|
613
745
|
function buildDotnetScenarioRows(nodeStats) {
|
|
614
|
-
return
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
746
|
+
return reportScenarios(nodeStats).map((scenario) => {
|
|
747
|
+
const requestCount = reportRequestCountValue(scenario);
|
|
748
|
+
return {
|
|
749
|
+
Scenario: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
750
|
+
Simulation: asString(reportValue(reportObject(scenario, "loadSimulationStats", "LoadSimulationStats"), "simulationName", "SimulationName")),
|
|
751
|
+
SimulationValue: asInt(reportValue(reportObject(scenario, "loadSimulationStats", "LoadSimulationStats"), "value", "Value")),
|
|
752
|
+
Requests: requestCount,
|
|
753
|
+
OK: reportOkCountValue(scenario),
|
|
754
|
+
FAIL: reportFailCountValue(scenario),
|
|
755
|
+
Duration: formatDotnetTimeSpan(reportDurationValue(scenario)),
|
|
756
|
+
RPS: formatReportNumber(reportDurationSeconds(reportDurationValue(scenario)) <= 0 ? 0 : requestCount / reportDurationSeconds(reportDurationValue(scenario))),
|
|
757
|
+
LatencyP95Ms: formatReportNumber(Math.max(asFloat(reportValue(reportObject(reportObject(scenario, "ok", "Ok"), "latency", "Latency"), "percent95", "Percent95")), asFloat(reportValue(reportObject(reportObject(scenario, "fail", "Fail"), "latency", "Latency"), "percent95", "Percent95")))),
|
|
758
|
+
LatencyP99Ms: formatReportNumber(Math.max(asFloat(reportValue(reportObject(reportObject(scenario, "ok", "Ok"), "latency", "Latency"), "percent99", "Percent99")), asFloat(reportValue(reportObject(reportObject(scenario, "fail", "Fail"), "latency", "Latency"), "percent99", "Percent99")))),
|
|
759
|
+
CurrentOperation: asString(reportValue(scenario, "currentOperation", "CurrentOperation"))
|
|
760
|
+
};
|
|
761
|
+
});
|
|
627
762
|
}
|
|
628
763
|
function buildDotnetStepRows(nodeStats) {
|
|
629
764
|
const rows = [];
|
|
630
|
-
for (const scenario of
|
|
631
|
-
for (const step of
|
|
765
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
766
|
+
for (const step of reportSteps(scenario)) {
|
|
632
767
|
rows.push({
|
|
633
768
|
Scenario: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
634
769
|
Step: asString(reportValue(step, "stepName", "StepName")),
|
|
@@ -646,28 +781,28 @@ function buildDotnetStepRows(nodeStats) {
|
|
|
646
781
|
}
|
|
647
782
|
function buildDotnetScenarioMeasurementRows(nodeStats) {
|
|
648
783
|
const rows = [];
|
|
649
|
-
for (const scenario of
|
|
784
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
650
785
|
const scenarioName = asString(reportValue(scenario, "scenarioName", "ScenarioName"));
|
|
651
|
-
rows
|
|
652
|
-
rows
|
|
786
|
+
pushMeasurementRowIfData(rows, "Scenario", scenarioName, "", "OK", reportObject(scenario, "ok", "Ok"));
|
|
787
|
+
pushMeasurementRowIfData(rows, "Scenario", scenarioName, "", "FAIL", reportObject(scenario, "fail", "Fail"));
|
|
653
788
|
}
|
|
654
789
|
return rows;
|
|
655
790
|
}
|
|
656
791
|
function buildDotnetStepMeasurementRows(nodeStats) {
|
|
657
792
|
const rows = [];
|
|
658
|
-
for (const scenario of
|
|
793
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
659
794
|
const scenarioName = asString(reportValue(scenario, "scenarioName", "ScenarioName"));
|
|
660
|
-
for (const step of
|
|
795
|
+
for (const step of reportSteps(scenario)) {
|
|
661
796
|
const stepName = asString(reportValue(step, "stepName", "StepName"));
|
|
662
|
-
rows
|
|
663
|
-
rows
|
|
797
|
+
pushMeasurementRowIfData(rows, "Step", scenarioName, stepName, "OK", reportObject(step, "ok", "Ok"));
|
|
798
|
+
pushMeasurementRowIfData(rows, "Step", scenarioName, stepName, "FAIL", reportObject(step, "fail", "Fail"));
|
|
664
799
|
}
|
|
665
800
|
}
|
|
666
801
|
return rows;
|
|
667
802
|
}
|
|
668
803
|
function buildDotnetStatusCodeRows(nodeStats) {
|
|
669
804
|
const rows = [];
|
|
670
|
-
for (const scenario of
|
|
805
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
671
806
|
const scenarioName = asString(reportValue(scenario, "scenarioName", "ScenarioName"));
|
|
672
807
|
for (const code of reportArray(reportObject(scenario, "ok", "Ok"), "statusCodes", "StatusCodes")) {
|
|
673
808
|
rows.push({ Scope: "Scenario", Scenario: scenarioName, Step: "", Result: "OK", StatusCode: asString(reportValue(code, "statusCode", "StatusCode")), Message: asString(reportValue(code, "message", "Message")), Count: asInt(reportValue(code, "count", "Count")), Percent: asInt(reportValue(code, "percent", "Percent")), IsError: Boolean(reportValue(code, "isError", "IsError")) });
|
|
@@ -675,7 +810,7 @@ function buildDotnetStatusCodeRows(nodeStats) {
|
|
|
675
810
|
for (const code of reportArray(reportObject(scenario, "fail", "Fail"), "statusCodes", "StatusCodes")) {
|
|
676
811
|
rows.push({ Scope: "Scenario", Scenario: scenarioName, Step: "", Result: "FAIL", StatusCode: asString(reportValue(code, "statusCode", "StatusCode")), Message: asString(reportValue(code, "message", "Message")), Count: asInt(reportValue(code, "count", "Count")), Percent: asInt(reportValue(code, "percent", "Percent")), IsError: Boolean(reportValue(code, "isError", "IsError")) });
|
|
677
812
|
}
|
|
678
|
-
for (const step of
|
|
813
|
+
for (const step of reportSteps(scenario)) {
|
|
679
814
|
const stepName = asString(reportValue(step, "stepName", "StepName"));
|
|
680
815
|
for (const code of reportArray(reportObject(step, "ok", "Ok"), "statusCodes", "StatusCodes")) {
|
|
681
816
|
rows.push({ Scope: "Step", Scenario: scenarioName, Step: stepName, Result: "OK", StatusCode: asString(reportValue(code, "statusCode", "StatusCode")), Message: asString(reportValue(code, "message", "Message")), Count: asInt(reportValue(code, "count", "Count")), Percent: asInt(reportValue(code, "percent", "Percent")), IsError: Boolean(reportValue(code, "isError", "IsError")) });
|
|
@@ -688,7 +823,7 @@ function buildDotnetStatusCodeRows(nodeStats) {
|
|
|
688
823
|
return rows;
|
|
689
824
|
}
|
|
690
825
|
function buildDotnetThresholdRows(nodeStats) {
|
|
691
|
-
return
|
|
826
|
+
return reportThresholds(nodeStats).map((threshold) => ({
|
|
692
827
|
Scenario: asString(reportValue(threshold, "scenarioName", "ScenarioName")),
|
|
693
828
|
Step: asString(reportValue(threshold, "stepName", "StepName")),
|
|
694
829
|
Check: asString(reportValue(threshold, "checkExpression", "CheckExpression")),
|
|
@@ -698,13 +833,13 @@ function buildDotnetThresholdRows(nodeStats) {
|
|
|
698
833
|
}));
|
|
699
834
|
}
|
|
700
835
|
function buildDotnetMetricRows(nodeStats) {
|
|
701
|
-
const metrics =
|
|
836
|
+
const metrics = reportMetrics(nodeStats);
|
|
702
837
|
const rows = [];
|
|
703
838
|
for (const counter of reportArray(metrics, "counters", "Counters")) {
|
|
704
839
|
rows.push({
|
|
705
840
|
Type: "Counter",
|
|
706
841
|
Scenario: asString(reportValue(counter, "scenarioName", "ScenarioName")),
|
|
707
|
-
Name:
|
|
842
|
+
Name: reportMetricName(counter),
|
|
708
843
|
Unit: asString(reportValue(counter, "unitOfMeasure", "UnitOfMeasure")),
|
|
709
844
|
Value: asInt(reportValue(counter, "value", "Value"))
|
|
710
845
|
});
|
|
@@ -713,7 +848,7 @@ function buildDotnetMetricRows(nodeStats) {
|
|
|
713
848
|
rows.push({
|
|
714
849
|
Type: "Gauge",
|
|
715
850
|
Scenario: asString(reportValue(gauge, "scenarioName", "ScenarioName")),
|
|
716
|
-
Name:
|
|
851
|
+
Name: reportMetricName(gauge),
|
|
717
852
|
Unit: asString(reportValue(gauge, "unitOfMeasure", "UnitOfMeasure")),
|
|
718
853
|
Value: formatReportNumber(reportValue(gauge, "value", "Value"))
|
|
719
854
|
});
|
|
@@ -738,15 +873,15 @@ function buildDotnetStatusCodeClassChart(scenarios) {
|
|
|
738
873
|
].filter((entry) => entry.value > 0);
|
|
739
874
|
}
|
|
740
875
|
function buildDotnetChartData(nodeStats) {
|
|
741
|
-
const scenarios =
|
|
876
|
+
const scenarios = reportScenarios(nodeStats);
|
|
742
877
|
return {
|
|
743
878
|
overallOutcome: [
|
|
744
|
-
{ label: "OK", value:
|
|
745
|
-
{ label: "FAIL", value:
|
|
879
|
+
{ label: "OK", value: reportTotalOkCount(nodeStats, scenarios), color: "#18a957" },
|
|
880
|
+
{ label: "FAIL", value: reportTotalFailCount(nodeStats, scenarios), color: "#d14343" }
|
|
746
881
|
],
|
|
747
882
|
scenarioRequests: scenarios.map((scenario) => ({
|
|
748
883
|
label: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
749
|
-
value:
|
|
884
|
+
value: reportRequestCountValue(scenario),
|
|
750
885
|
color: "#3b82f6"
|
|
751
886
|
})),
|
|
752
887
|
scenarioP95Latency: scenarios.map((scenario) => ({
|
|
@@ -756,21 +891,21 @@ function buildDotnetChartData(nodeStats) {
|
|
|
756
891
|
})),
|
|
757
892
|
scenarioRps: scenarios.map((scenario) => ({
|
|
758
893
|
label: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
759
|
-
value: reportDurationSeconds(
|
|
894
|
+
value: reportDurationSeconds(reportDurationValue(scenario)) <= 0
|
|
760
895
|
? 0
|
|
761
|
-
:
|
|
896
|
+
: reportRequestCountValue(scenario) / reportDurationSeconds(reportDurationValue(scenario)),
|
|
762
897
|
color: "#10b981"
|
|
763
898
|
})),
|
|
764
899
|
scenarioFailRate: scenarios.map((scenario) => ({
|
|
765
900
|
label: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
766
|
-
value:
|
|
901
|
+
value: reportRequestCountValue(scenario) <= 0
|
|
767
902
|
? 0
|
|
768
|
-
: (
|
|
903
|
+
: (reportFailCountValue(scenario) * 100 / reportRequestCountValue(scenario)),
|
|
769
904
|
color: "#ef4444"
|
|
770
905
|
})),
|
|
771
906
|
scenarioBytes: scenarios.map((scenario) => ({
|
|
772
907
|
label: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
773
|
-
value: asInt(
|
|
908
|
+
value: asInt(reportBytesValue(scenario)),
|
|
774
909
|
color: "#0ea5e9"
|
|
775
910
|
})),
|
|
776
911
|
statusCodeClasses: buildDotnetStatusCodeClassChart(scenarios),
|
|
@@ -786,21 +921,24 @@ function buildDotnetChartData(nodeStats) {
|
|
|
786
921
|
};
|
|
787
922
|
}
|
|
788
923
|
function buildDotnetSummaryHtml(nodeStats) {
|
|
789
|
-
const scenarios =
|
|
790
|
-
const
|
|
924
|
+
const scenarios = reportScenarios(nodeStats);
|
|
925
|
+
const allRequests = reportTotalRequestCount(nodeStats, scenarios);
|
|
926
|
+
const allOk = reportTotalOkCount(nodeStats, scenarios);
|
|
927
|
+
const allFail = reportTotalFailCount(nodeStats, scenarios);
|
|
928
|
+
const successRate = allRequests <= 0
|
|
791
929
|
? 0
|
|
792
|
-
: (
|
|
793
|
-
const failRate =
|
|
930
|
+
: (allOk * 100 / allRequests);
|
|
931
|
+
const failRate = allRequests <= 0
|
|
794
932
|
? 0
|
|
795
|
-
: (
|
|
796
|
-
const overallRps = reportDurationSeconds(
|
|
933
|
+
: (allFail * 100 / allRequests);
|
|
934
|
+
const overallRps = reportDurationSeconds(reportDurationValue(nodeStats)) <= 0
|
|
797
935
|
? 0
|
|
798
|
-
:
|
|
936
|
+
: allRequests / reportDurationSeconds(reportDurationValue(nodeStats));
|
|
799
937
|
const topScenario = scenarios.reduce((winner, scenario) => {
|
|
800
938
|
if (!winner) {
|
|
801
939
|
return scenario;
|
|
802
940
|
}
|
|
803
|
-
return
|
|
941
|
+
return reportRequestCountValue(scenario) > reportRequestCountValue(winner)
|
|
804
942
|
? scenario
|
|
805
943
|
: winner;
|
|
806
944
|
}, undefined);
|
|
@@ -811,14 +949,15 @@ function buildDotnetSummaryHtml(nodeStats) {
|
|
|
811
949
|
const chartData = buildDotnetChartData(nodeStats);
|
|
812
950
|
const testInfo = reportObject(nodeStats, "testInfo", "TestInfo");
|
|
813
951
|
const nodeInfo = reportObject(nodeStats, "nodeInfo", "NodeInfo");
|
|
952
|
+
const totalBytes = reportTotalBytes(nodeStats, scenarios);
|
|
814
953
|
const parts = [];
|
|
815
954
|
appendReportLine(parts, "<div class=\"card-grid\">");
|
|
816
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Total Requests</div><div class="stat-value">${
|
|
817
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Success</div><div class="stat-value value-ok">${
|
|
818
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Fail</div><div class="stat-value value-fail">${
|
|
955
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Total Requests</div><div class="stat-value">${allRequests}</div></div>`);
|
|
956
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Success</div><div class="stat-value value-ok">${allOk} (${formatDotnetPercent(successRate)}%)</div></div>`);
|
|
957
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Fail</div><div class="stat-value value-fail">${allFail} (${formatDotnetPercent(failRate)}%)</div></div>`);
|
|
819
958
|
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Overall RPS</div><div class="stat-value">${formatReportNumber(overallRps)}</div></div>`);
|
|
820
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Duration</div><div class="stat-value">${escapeHtml(formatDotnetTimeSpan(
|
|
821
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Total Bytes</div><div class="stat-value">${
|
|
959
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Duration</div><div class="stat-value">${escapeHtml(formatDotnetTimeSpan(reportDurationValue(nodeStats)))}</div></div>`);
|
|
960
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Total Bytes</div><div class="stat-value">${totalBytes}</div></div>`);
|
|
822
961
|
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Top Scenario</div><div class="stat-value">${escapeHtml(topScenario ? reportValue(topScenario, "scenarioName", "ScenarioName") : "n/a")}</div></div>`);
|
|
823
962
|
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Node</div><div class="stat-value">${loadStrikeNodeTypeTag(reportValue(nodeInfo, "nodeType", "NodeType"))}</div></div>`);
|
|
824
963
|
appendReportLine(parts, "</div>");
|
|
@@ -893,7 +1032,7 @@ function buildDotnetStatusCodeHtml(nodeStats) {
|
|
|
893
1032
|
return buildDotnetTableHtml(buildDotnetStatusCodeRows(nodeStats));
|
|
894
1033
|
}
|
|
895
1034
|
function buildDotnetFailedResponseHtml(nodeStats) {
|
|
896
|
-
const failedStatusRows = buildFailedStatusRows(
|
|
1035
|
+
const failedStatusRows = buildFailedStatusRows(reportScenarios(nodeStats));
|
|
897
1036
|
const failedEventRows = buildFailedEventRows(reportArray(nodeStats, "pluginsData", "PluginsData"));
|
|
898
1037
|
return buildDotnetFailedResponseContent(failedStatusRows, failedEventRows);
|
|
899
1038
|
}
|
|
@@ -984,7 +1123,7 @@ function buildDotnetHtmlTabs(nodeStats) {
|
|
|
984
1123
|
if (statusCodeRows.length) {
|
|
985
1124
|
tabs.push(["status-codes", "Status Codes", buildDotnetTableHtml(statusCodeRows)]);
|
|
986
1125
|
}
|
|
987
|
-
const failedStatusRows = buildFailedStatusRows(
|
|
1126
|
+
const failedStatusRows = buildFailedStatusRows(reportScenarios(nodeStats));
|
|
988
1127
|
const failedEventRows = buildFailedEventRows(reportArray(nodeStats, "pluginsData", "PluginsData"));
|
|
989
1128
|
if (failedStatusRows.length || failedEventRows.length) {
|
|
990
1129
|
tabs.push(["failed-responses", "Failed Responses", buildDotnetFailedResponseContent(failedStatusRows, failedEventRows)]);
|
|
@@ -1042,7 +1181,7 @@ function buildDotnetHtmlTabs(nodeStats) {
|
|
|
1042
1181
|
* Exposes the build dotnet txt report operation. Use this when interacting with the SDK through this surface.
|
|
1043
1182
|
*/
|
|
1044
1183
|
function buildDotnetTxtReport(nodeStats) {
|
|
1045
|
-
const scenarios =
|
|
1184
|
+
const scenarios = reportScenarios(nodeStats);
|
|
1046
1185
|
const testInfo = reportObject(nodeStats, "testInfo", "TestInfo");
|
|
1047
1186
|
const nodeInfo = reportObject(nodeStats, "nodeInfo", "NodeInfo");
|
|
1048
1187
|
const lines = [
|
|
@@ -1050,25 +1189,25 @@ function buildDotnetTxtReport(nodeStats) {
|
|
|
1050
1189
|
`TestName: ${asString(reportValue(testInfo, "testName", "TestName"))}`,
|
|
1051
1190
|
`SessionId: ${asString(reportValue(testInfo, "sessionId", "SessionId"))}`,
|
|
1052
1191
|
`NodeType: ${loadStrikeNodeTypeTag(reportValue(nodeInfo, "nodeType", "NodeType"))}`,
|
|
1053
|
-
`Duration: ${formatDotnetTimeSpan(
|
|
1054
|
-
`Requests: ${
|
|
1192
|
+
`Duration: ${formatDotnetTimeSpan(reportDurationValue(nodeStats))}`,
|
|
1193
|
+
`Requests: ${reportTotalRequestCount(nodeStats, scenarios)} OK: ${reportTotalOkCount(nodeStats, scenarios)} FAIL: ${reportTotalFailCount(nodeStats, scenarios)}`,
|
|
1055
1194
|
"",
|
|
1056
1195
|
"Scenarios:"
|
|
1057
1196
|
];
|
|
1058
1197
|
for (const scenario of scenarios) {
|
|
1059
|
-
lines.push(`- ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))}: req=${
|
|
1198
|
+
lines.push(`- ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))}: req=${reportRequestCountValue(scenario)} ok=${reportOkCountValue(scenario)} fail=${reportFailCountValue(scenario)} duration=${formatDotnetTimeSpan(reportDurationValue(scenario))}`);
|
|
1060
1199
|
}
|
|
1061
|
-
if (scenarios.some((scenario) =>
|
|
1200
|
+
if (scenarios.some((scenario) => reportSteps(scenario).length > 0)) {
|
|
1062
1201
|
lines.push("", "Steps:");
|
|
1063
1202
|
for (const scenario of scenarios) {
|
|
1064
|
-
for (const step of
|
|
1203
|
+
for (const step of reportSteps(scenario)) {
|
|
1065
1204
|
const ok = asInt(reportValue(reportObject(reportObject(step, "ok", "Ok"), "request", "Request"), "count", "Count"));
|
|
1066
1205
|
const fail = asInt(reportValue(reportObject(reportObject(step, "fail", "Fail"), "request", "Request"), "count", "Count"));
|
|
1067
1206
|
lines.push(`- ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))}.${asString(reportValue(step, "stepName", "StepName"))}: req=${ok + fail} ok=${ok} fail=${fail}`);
|
|
1068
1207
|
}
|
|
1069
1208
|
}
|
|
1070
1209
|
}
|
|
1071
|
-
const thresholds =
|
|
1210
|
+
const thresholds = reportThresholds(nodeStats);
|
|
1072
1211
|
if (thresholds.length) {
|
|
1073
1212
|
lines.push("", "Thresholds:");
|
|
1074
1213
|
for (const threshold of thresholds) {
|
|
@@ -1092,10 +1231,10 @@ function buildDotnetTxtReport(nodeStats) {
|
|
|
1092
1231
|
*/
|
|
1093
1232
|
function buildDotnetCsvReport(nodeStats) {
|
|
1094
1233
|
const lines = ["ScenarioName,Requests,Ok,Fail,DurationSeconds,Rps"];
|
|
1095
|
-
for (const scenario of
|
|
1096
|
-
const durationSeconds = reportDurationSeconds(
|
|
1097
|
-
const requests =
|
|
1098
|
-
lines.push(`${escapeCsv(reportValue(scenario, "scenarioName", "ScenarioName"))},${requests},${
|
|
1234
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
1235
|
+
const durationSeconds = reportDurationSeconds(reportDurationValue(scenario));
|
|
1236
|
+
const requests = reportRequestCountValue(scenario);
|
|
1237
|
+
lines.push(`${escapeCsv(reportValue(scenario, "scenarioName", "ScenarioName"))},${requests},${reportOkCountValue(scenario)},${reportFailCountValue(scenario)},${formatReportNumber(durationSeconds)},${formatReportNumber(durationSeconds <= 0 ? 0 : requests / durationSeconds)}`);
|
|
1099
1238
|
}
|
|
1100
1239
|
return reportLines(lines);
|
|
1101
1240
|
}
|
|
@@ -1103,16 +1242,16 @@ function buildDotnetCsvReport(nodeStats) {
|
|
|
1103
1242
|
* Exposes the build dotnet markdown report operation. Use this when interacting with the SDK through this surface.
|
|
1104
1243
|
*/
|
|
1105
1244
|
function buildDotnetMarkdownReport(nodeStats) {
|
|
1106
|
-
const scenarios =
|
|
1245
|
+
const scenarios = reportScenarios(nodeStats);
|
|
1107
1246
|
const testInfo = reportObject(nodeStats, "testInfo", "TestInfo");
|
|
1108
1247
|
const lines = [
|
|
1109
1248
|
`# ${asString(reportValue(testInfo, "testSuite", "TestSuite"))} / ${asString(reportValue(testInfo, "testName", "TestName"))}`,
|
|
1110
1249
|
"",
|
|
1111
1250
|
`- Session: \`${asString(reportValue(testInfo, "sessionId", "SessionId"))}\``,
|
|
1112
|
-
`- Duration: \`${formatDotnetTimeSpan(
|
|
1113
|
-
`- Total Requests: \`${
|
|
1114
|
-
`- OK: \`${
|
|
1115
|
-
`- FAIL: \`${
|
|
1251
|
+
`- Duration: \`${formatDotnetTimeSpan(reportDurationValue(nodeStats))}\``,
|
|
1252
|
+
`- Total Requests: \`${reportTotalRequestCount(nodeStats, scenarios)}\``,
|
|
1253
|
+
`- OK: \`${reportTotalOkCount(nodeStats, scenarios)}\``,
|
|
1254
|
+
`- FAIL: \`${reportTotalFailCount(nodeStats, scenarios)}\``,
|
|
1116
1255
|
"",
|
|
1117
1256
|
"## Scenarios",
|
|
1118
1257
|
"",
|
|
@@ -1120,19 +1259,19 @@ function buildDotnetMarkdownReport(nodeStats) {
|
|
|
1120
1259
|
"|---|---:|---:|---:|---:|"
|
|
1121
1260
|
];
|
|
1122
1261
|
for (const scenario of scenarios) {
|
|
1123
|
-
lines.push(`| ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))} | ${
|
|
1262
|
+
lines.push(`| ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))} | ${reportRequestCountValue(scenario)} | ${reportOkCountValue(scenario)} | ${reportFailCountValue(scenario)} | ${formatReportNumber(reportDurationSeconds(reportDurationValue(scenario)))}s |`);
|
|
1124
1263
|
}
|
|
1125
|
-
if (scenarios.some((scenario) =>
|
|
1264
|
+
if (scenarios.some((scenario) => reportSteps(scenario).length > 0)) {
|
|
1126
1265
|
lines.push("", "## Steps", "", "| Scenario | Step | Requests | OK | FAIL |", "|---|---|---:|---:|---:|");
|
|
1127
1266
|
for (const scenario of scenarios) {
|
|
1128
|
-
for (const step of
|
|
1267
|
+
for (const step of reportSteps(scenario)) {
|
|
1129
1268
|
const ok = asInt(reportValue(reportObject(reportObject(step, "ok", "Ok"), "request", "Request"), "count", "Count"));
|
|
1130
1269
|
const fail = asInt(reportValue(reportObject(reportObject(step, "fail", "Fail"), "request", "Request"), "count", "Count"));
|
|
1131
1270
|
lines.push(`| ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))} | ${asString(reportValue(step, "stepName", "StepName"))} | ${ok + fail} | ${ok} | ${fail} |`);
|
|
1132
1271
|
}
|
|
1133
1272
|
}
|
|
1134
1273
|
}
|
|
1135
|
-
const thresholds =
|
|
1274
|
+
const thresholds = reportThresholds(nodeStats);
|
|
1136
1275
|
if (thresholds.length) {
|
|
1137
1276
|
lines.push("", "## Thresholds", "", "| Scenario | Step | Check | Failed | Errors | Exception |", "|---|---|---|---:|---:|---|");
|
|
1138
1277
|
for (const threshold of thresholds) {
|
|
@@ -1268,7 +1407,7 @@ if(btns.length>0){show(btns[0].dataset.tab);}renderAllCharts();initPanePan();win
|
|
|
1268
1407
|
.split("__TEST_SUITE__").join(escapeHtml(reportValue(testInfo, "testSuite", "TestSuite")))
|
|
1269
1408
|
.split("__TEST_NAME__").join(escapeHtml(reportValue(testInfo, "testName", "TestName")))
|
|
1270
1409
|
.split("__SESSION_ID__").join(escapeHtml(reportValue(testInfo, "sessionId", "SessionId")))
|
|
1271
|
-
.split("__DURATION__").join(escapeHtml(formatDotnetTimeSpan(
|
|
1410
|
+
.split("__DURATION__").join(escapeHtml(formatDotnetTimeSpan(reportDurationValue(nodeStats))))
|
|
1272
1411
|
.split("__BUTTONS__").join(buttonsHtml)
|
|
1273
1412
|
.split("__SECTIONS__").join(sectionsHtml)
|
|
1274
1413
|
.split("__CHART_DATA__").join(chartDataJson)
|
package/dist/cjs/runtime.js
CHANGED
|
@@ -8034,7 +8034,7 @@ function buildRichHtmlReport(result) {
|
|
|
8034
8034
|
<section id="scenarios" class="panel active">
|
|
8035
8035
|
${bars || "<div>No scenario data.</div>"}
|
|
8036
8036
|
<table>
|
|
8037
|
-
<thead><tr><th>Scenario</th><th>Requests</th><th>OK</th><th>Fail</th><th>TotalBytes</th><th>
|
|
8037
|
+
<thead><tr><th>Scenario</th><th>Requests</th><th>OK</th><th>Fail</th><th>TotalBytes</th><th>AvgLatency (ms)</th></tr></thead>
|
|
8038
8038
|
<tbody>${scenarioRows || "<tr><td colspan='6'>No rows</td></tr>"}</tbody>
|
|
8039
8039
|
</table>
|
|
8040
8040
|
</section>
|
package/dist/esm/reporting.js
CHANGED
|
@@ -44,6 +44,61 @@ function reportValue(source, ...keys) {
|
|
|
44
44
|
}
|
|
45
45
|
return undefined;
|
|
46
46
|
}
|
|
47
|
+
function reportDurationValue(source) {
|
|
48
|
+
return reportValue(source, "durationMs", "DurationMs", "duration", "Duration");
|
|
49
|
+
}
|
|
50
|
+
function reportBytesValue(source) {
|
|
51
|
+
return reportValue(source, "allBytes", "AllBytes", "totalBytes", "TotalBytes");
|
|
52
|
+
}
|
|
53
|
+
function reportTotalBytes(nodeStats, scenarios) {
|
|
54
|
+
const totalBytes = asInt(reportBytesValue(nodeStats));
|
|
55
|
+
if (totalBytes !== 0) {
|
|
56
|
+
return totalBytes;
|
|
57
|
+
}
|
|
58
|
+
return scenarios.reduce((sum, scenario) => sum + asInt(reportBytesValue(scenario)), 0);
|
|
59
|
+
}
|
|
60
|
+
function reportRequestCountValue(source) {
|
|
61
|
+
return asInt(reportValue(source, "allRequestCount", "AllRequestCount", "requestCount", "RequestCount"));
|
|
62
|
+
}
|
|
63
|
+
function reportOkCountValue(source) {
|
|
64
|
+
return asInt(reportValue(source, "allOkCount", "AllOkCount", "okCount", "OkCount"));
|
|
65
|
+
}
|
|
66
|
+
function reportFailCountValue(source) {
|
|
67
|
+
return asInt(reportValue(source, "allFailCount", "AllFailCount", "failCount", "FailCount"));
|
|
68
|
+
}
|
|
69
|
+
function reportTotalRequestCount(nodeStats, scenarios) {
|
|
70
|
+
const total = reportRequestCountValue(nodeStats);
|
|
71
|
+
return total !== 0 || scenarios.length === 0
|
|
72
|
+
? total
|
|
73
|
+
: scenarios.reduce((sum, scenario) => sum + reportRequestCountValue(scenario), 0);
|
|
74
|
+
}
|
|
75
|
+
function reportTotalOkCount(nodeStats, scenarios) {
|
|
76
|
+
const total = reportOkCountValue(nodeStats);
|
|
77
|
+
return total !== 0 || scenarios.length === 0
|
|
78
|
+
? total
|
|
79
|
+
: scenarios.reduce((sum, scenario) => sum + reportOkCountValue(scenario), 0);
|
|
80
|
+
}
|
|
81
|
+
function reportTotalFailCount(nodeStats, scenarios) {
|
|
82
|
+
const total = reportFailCountValue(nodeStats);
|
|
83
|
+
return total !== 0 || scenarios.length === 0
|
|
84
|
+
? total
|
|
85
|
+
: scenarios.reduce((sum, scenario) => sum + reportFailCountValue(scenario), 0);
|
|
86
|
+
}
|
|
87
|
+
function reportScenarios(nodeStats) {
|
|
88
|
+
return sortBySortIndex(reportArray(nodeStats, "scenarioStats", "ScenarioStats"));
|
|
89
|
+
}
|
|
90
|
+
function reportSteps(scenario) {
|
|
91
|
+
return sortBySortIndex(reportArray(scenario, "stepStats", "StepStats"));
|
|
92
|
+
}
|
|
93
|
+
function reportThresholds(nodeStats) {
|
|
94
|
+
return reportArray(nodeStats, "thresholds", "Thresholds", "thresholdResults", "ThresholdResults");
|
|
95
|
+
}
|
|
96
|
+
function reportMetrics(nodeStats) {
|
|
97
|
+
return reportObject(nodeStats, "metrics", "Metrics", "metricStats", "MetricStats");
|
|
98
|
+
}
|
|
99
|
+
function reportMetricName(source) {
|
|
100
|
+
return asString(reportValue(source, "metricName", "MetricName", "name", "Name"));
|
|
101
|
+
}
|
|
47
102
|
function reportObject(source, ...keys) {
|
|
48
103
|
const value = reportValue(source, ...keys);
|
|
49
104
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
@@ -77,6 +132,16 @@ function asFloat(value) {
|
|
|
77
132
|
const parsed = Number.parseFloat(asString(value));
|
|
78
133
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
79
134
|
}
|
|
135
|
+
function asBool(value) {
|
|
136
|
+
if (typeof value === "boolean") {
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
140
|
+
return value !== 0;
|
|
141
|
+
}
|
|
142
|
+
const normalized = asString(value).trim().toLowerCase();
|
|
143
|
+
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "y" || normalized === "on";
|
|
144
|
+
}
|
|
80
145
|
function formatCellValue(value) {
|
|
81
146
|
if (value == null) {
|
|
82
147
|
return "";
|
|
@@ -296,7 +361,7 @@ function buildDotnetTableHtml(rows, wrapInCard = true) {
|
|
|
296
361
|
appendReportLine(parts, "<table>");
|
|
297
362
|
appendReportLine(parts, "<thead><tr>");
|
|
298
363
|
for (const header of headers) {
|
|
299
|
-
appendReportLine(parts, `<th>${escapeHtml(header)}</th>`);
|
|
364
|
+
appendReportLine(parts, `<th>${escapeHtml(formatReportTableHeader(header))}</th>`);
|
|
300
365
|
}
|
|
301
366
|
appendReportLine(parts, "</tr></thead><tbody>");
|
|
302
367
|
for (const row of rows) {
|
|
@@ -312,6 +377,14 @@ function buildDotnetTableHtml(rows, wrapInCard = true) {
|
|
|
312
377
|
}
|
|
313
378
|
return parts.join("");
|
|
314
379
|
}
|
|
380
|
+
function formatReportTableHeader(header) {
|
|
381
|
+
if (header === "LatencyStdDev") {
|
|
382
|
+
return "LatencyStdDev (ms)";
|
|
383
|
+
}
|
|
384
|
+
return header.endsWith("Ms") && header.length > "Ms".length
|
|
385
|
+
? `${header.slice(0, -"Ms".length)} (ms)`
|
|
386
|
+
: header;
|
|
387
|
+
}
|
|
315
388
|
function buildFailedStatusRows(scenarios) {
|
|
316
389
|
const rows = [];
|
|
317
390
|
for (const scenario of scenarios) {
|
|
@@ -334,7 +407,7 @@ function buildFailedStatusRows(scenarios) {
|
|
|
334
407
|
IsError: isError
|
|
335
408
|
});
|
|
336
409
|
}
|
|
337
|
-
for (const step of
|
|
410
|
+
for (const step of reportSteps(scenario)) {
|
|
338
411
|
const stepName = asString(reportValue(step, "stepName", "StepName"));
|
|
339
412
|
const stepFail = reportObject(step, "fail", "Fail");
|
|
340
413
|
for (const code of reportArray(stepFail, "statusCodes", "StatusCodes")) {
|
|
@@ -586,6 +659,65 @@ function buildMeasurementRow(scope, scenarioName, stepName, resultName, measurem
|
|
|
586
659
|
BytesStdDev: formatReportNumber(reportValue(dataTransfer, "stdDev", "StdDev"))
|
|
587
660
|
};
|
|
588
661
|
}
|
|
662
|
+
function pushMeasurementRowIfData(rows, scope, scenarioName, stepName, resultName, measurement) {
|
|
663
|
+
if (hasMeasurementData(measurement)) {
|
|
664
|
+
rows.push(buildMeasurementRow(scope, scenarioName, stepName, resultName, measurement));
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
function hasMeasurementData(measurement) {
|
|
668
|
+
if (Object.keys(measurement).length === 0) {
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
const request = reportObject(measurement, "request", "Request");
|
|
672
|
+
if (asInt(reportValue(request, "count", "Count")) !== 0 ||
|
|
673
|
+
asInt(reportValue(request, "percent", "Percent")) !== 0 ||
|
|
674
|
+
asFloat(reportValue(request, "rps", "RPS")) !== 0) {
|
|
675
|
+
return true;
|
|
676
|
+
}
|
|
677
|
+
const latency = reportObject(measurement, "latency", "Latency");
|
|
678
|
+
const latencyKeys = [
|
|
679
|
+
["minMs", "MinMs"],
|
|
680
|
+
["meanMs", "MeanMs"],
|
|
681
|
+
["percent50", "Percent50"],
|
|
682
|
+
["percent75", "Percent75"],
|
|
683
|
+
["percent95", "Percent95"],
|
|
684
|
+
["percent99", "Percent99"],
|
|
685
|
+
["maxMs", "MaxMs"],
|
|
686
|
+
["stdDev", "StdDev"]
|
|
687
|
+
];
|
|
688
|
+
if (latencyKeys.some(([camelKey, pascalKey]) => asFloat(reportValue(latency, camelKey, pascalKey)) !== 0)) {
|
|
689
|
+
return true;
|
|
690
|
+
}
|
|
691
|
+
const latencyCount = reportObject(latency, "latencyCount", "LatencyCount");
|
|
692
|
+
const latencyCountKeys = [
|
|
693
|
+
["lessOrEq800", "LessOrEq800"],
|
|
694
|
+
["more800Less1200", "More800Less1200"],
|
|
695
|
+
["moreOrEq1200", "MoreOrEq1200"]
|
|
696
|
+
];
|
|
697
|
+
if (latencyCountKeys.some(([camelKey, pascalKey]) => asInt(reportValue(latencyCount, camelKey, pascalKey)) !== 0)) {
|
|
698
|
+
return true;
|
|
699
|
+
}
|
|
700
|
+
const dataTransfer = reportObject(measurement, "dataTransfer", "DataTransfer");
|
|
701
|
+
const dataTransferKeys = [
|
|
702
|
+
["allBytes", "AllBytes"],
|
|
703
|
+
["minBytes", "MinBytes"],
|
|
704
|
+
["meanBytes", "MeanBytes"],
|
|
705
|
+
["percent50", "Percent50"],
|
|
706
|
+
["percent75", "Percent75"],
|
|
707
|
+
["percent95", "Percent95"],
|
|
708
|
+
["percent99", "Percent99"],
|
|
709
|
+
["maxBytes", "MaxBytes"],
|
|
710
|
+
["stdDev", "StdDev"]
|
|
711
|
+
];
|
|
712
|
+
if (dataTransferKeys.some(([camelKey, pascalKey]) => asFloat(reportValue(dataTransfer, camelKey, pascalKey)) !== 0)) {
|
|
713
|
+
return true;
|
|
714
|
+
}
|
|
715
|
+
return reportArray(measurement, "statusCodes", "StatusCodes").some((code) => asInt(reportValue(code, "count", "Count")) !== 0 ||
|
|
716
|
+
asInt(reportValue(code, "percent", "Percent")) !== 0 ||
|
|
717
|
+
asBool(reportValue(code, "isError", "IsError")) ||
|
|
718
|
+
asString(reportValue(code, "statusCode", "StatusCode")).trim().length > 0 ||
|
|
719
|
+
asString(reportValue(code, "message", "Message")).trim().length > 0);
|
|
720
|
+
}
|
|
589
721
|
function appendChartCard(parts, id, title) {
|
|
590
722
|
appendReportLine(parts, `<div class="chart-card"><h3>${escapeHtml(title)}</h3><canvas id="${escapeHtml(id)}" class="chart-canvas"></canvas></div>`);
|
|
591
723
|
}
|
|
@@ -604,24 +736,27 @@ function hasNonEmptyHints(plugin) {
|
|
|
604
736
|
return reportArray(plugin, "hints", "Hints").some((hint) => asString(hint).trim().length > 0);
|
|
605
737
|
}
|
|
606
738
|
function buildDotnetScenarioRows(nodeStats) {
|
|
607
|
-
return
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
739
|
+
return reportScenarios(nodeStats).map((scenario) => {
|
|
740
|
+
const requestCount = reportRequestCountValue(scenario);
|
|
741
|
+
return {
|
|
742
|
+
Scenario: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
743
|
+
Simulation: asString(reportValue(reportObject(scenario, "loadSimulationStats", "LoadSimulationStats"), "simulationName", "SimulationName")),
|
|
744
|
+
SimulationValue: asInt(reportValue(reportObject(scenario, "loadSimulationStats", "LoadSimulationStats"), "value", "Value")),
|
|
745
|
+
Requests: requestCount,
|
|
746
|
+
OK: reportOkCountValue(scenario),
|
|
747
|
+
FAIL: reportFailCountValue(scenario),
|
|
748
|
+
Duration: formatDotnetTimeSpan(reportDurationValue(scenario)),
|
|
749
|
+
RPS: formatReportNumber(reportDurationSeconds(reportDurationValue(scenario)) <= 0 ? 0 : requestCount / reportDurationSeconds(reportDurationValue(scenario))),
|
|
750
|
+
LatencyP95Ms: formatReportNumber(Math.max(asFloat(reportValue(reportObject(reportObject(scenario, "ok", "Ok"), "latency", "Latency"), "percent95", "Percent95")), asFloat(reportValue(reportObject(reportObject(scenario, "fail", "Fail"), "latency", "Latency"), "percent95", "Percent95")))),
|
|
751
|
+
LatencyP99Ms: formatReportNumber(Math.max(asFloat(reportValue(reportObject(reportObject(scenario, "ok", "Ok"), "latency", "Latency"), "percent99", "Percent99")), asFloat(reportValue(reportObject(reportObject(scenario, "fail", "Fail"), "latency", "Latency"), "percent99", "Percent99")))),
|
|
752
|
+
CurrentOperation: asString(reportValue(scenario, "currentOperation", "CurrentOperation"))
|
|
753
|
+
};
|
|
754
|
+
});
|
|
620
755
|
}
|
|
621
756
|
function buildDotnetStepRows(nodeStats) {
|
|
622
757
|
const rows = [];
|
|
623
|
-
for (const scenario of
|
|
624
|
-
for (const step of
|
|
758
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
759
|
+
for (const step of reportSteps(scenario)) {
|
|
625
760
|
rows.push({
|
|
626
761
|
Scenario: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
627
762
|
Step: asString(reportValue(step, "stepName", "StepName")),
|
|
@@ -639,28 +774,28 @@ function buildDotnetStepRows(nodeStats) {
|
|
|
639
774
|
}
|
|
640
775
|
function buildDotnetScenarioMeasurementRows(nodeStats) {
|
|
641
776
|
const rows = [];
|
|
642
|
-
for (const scenario of
|
|
777
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
643
778
|
const scenarioName = asString(reportValue(scenario, "scenarioName", "ScenarioName"));
|
|
644
|
-
rows
|
|
645
|
-
rows
|
|
779
|
+
pushMeasurementRowIfData(rows, "Scenario", scenarioName, "", "OK", reportObject(scenario, "ok", "Ok"));
|
|
780
|
+
pushMeasurementRowIfData(rows, "Scenario", scenarioName, "", "FAIL", reportObject(scenario, "fail", "Fail"));
|
|
646
781
|
}
|
|
647
782
|
return rows;
|
|
648
783
|
}
|
|
649
784
|
function buildDotnetStepMeasurementRows(nodeStats) {
|
|
650
785
|
const rows = [];
|
|
651
|
-
for (const scenario of
|
|
786
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
652
787
|
const scenarioName = asString(reportValue(scenario, "scenarioName", "ScenarioName"));
|
|
653
|
-
for (const step of
|
|
788
|
+
for (const step of reportSteps(scenario)) {
|
|
654
789
|
const stepName = asString(reportValue(step, "stepName", "StepName"));
|
|
655
|
-
rows
|
|
656
|
-
rows
|
|
790
|
+
pushMeasurementRowIfData(rows, "Step", scenarioName, stepName, "OK", reportObject(step, "ok", "Ok"));
|
|
791
|
+
pushMeasurementRowIfData(rows, "Step", scenarioName, stepName, "FAIL", reportObject(step, "fail", "Fail"));
|
|
657
792
|
}
|
|
658
793
|
}
|
|
659
794
|
return rows;
|
|
660
795
|
}
|
|
661
796
|
function buildDotnetStatusCodeRows(nodeStats) {
|
|
662
797
|
const rows = [];
|
|
663
|
-
for (const scenario of
|
|
798
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
664
799
|
const scenarioName = asString(reportValue(scenario, "scenarioName", "ScenarioName"));
|
|
665
800
|
for (const code of reportArray(reportObject(scenario, "ok", "Ok"), "statusCodes", "StatusCodes")) {
|
|
666
801
|
rows.push({ Scope: "Scenario", Scenario: scenarioName, Step: "", Result: "OK", StatusCode: asString(reportValue(code, "statusCode", "StatusCode")), Message: asString(reportValue(code, "message", "Message")), Count: asInt(reportValue(code, "count", "Count")), Percent: asInt(reportValue(code, "percent", "Percent")), IsError: Boolean(reportValue(code, "isError", "IsError")) });
|
|
@@ -668,7 +803,7 @@ function buildDotnetStatusCodeRows(nodeStats) {
|
|
|
668
803
|
for (const code of reportArray(reportObject(scenario, "fail", "Fail"), "statusCodes", "StatusCodes")) {
|
|
669
804
|
rows.push({ Scope: "Scenario", Scenario: scenarioName, Step: "", Result: "FAIL", StatusCode: asString(reportValue(code, "statusCode", "StatusCode")), Message: asString(reportValue(code, "message", "Message")), Count: asInt(reportValue(code, "count", "Count")), Percent: asInt(reportValue(code, "percent", "Percent")), IsError: Boolean(reportValue(code, "isError", "IsError")) });
|
|
670
805
|
}
|
|
671
|
-
for (const step of
|
|
806
|
+
for (const step of reportSteps(scenario)) {
|
|
672
807
|
const stepName = asString(reportValue(step, "stepName", "StepName"));
|
|
673
808
|
for (const code of reportArray(reportObject(step, "ok", "Ok"), "statusCodes", "StatusCodes")) {
|
|
674
809
|
rows.push({ Scope: "Step", Scenario: scenarioName, Step: stepName, Result: "OK", StatusCode: asString(reportValue(code, "statusCode", "StatusCode")), Message: asString(reportValue(code, "message", "Message")), Count: asInt(reportValue(code, "count", "Count")), Percent: asInt(reportValue(code, "percent", "Percent")), IsError: Boolean(reportValue(code, "isError", "IsError")) });
|
|
@@ -681,7 +816,7 @@ function buildDotnetStatusCodeRows(nodeStats) {
|
|
|
681
816
|
return rows;
|
|
682
817
|
}
|
|
683
818
|
function buildDotnetThresholdRows(nodeStats) {
|
|
684
|
-
return
|
|
819
|
+
return reportThresholds(nodeStats).map((threshold) => ({
|
|
685
820
|
Scenario: asString(reportValue(threshold, "scenarioName", "ScenarioName")),
|
|
686
821
|
Step: asString(reportValue(threshold, "stepName", "StepName")),
|
|
687
822
|
Check: asString(reportValue(threshold, "checkExpression", "CheckExpression")),
|
|
@@ -691,13 +826,13 @@ function buildDotnetThresholdRows(nodeStats) {
|
|
|
691
826
|
}));
|
|
692
827
|
}
|
|
693
828
|
function buildDotnetMetricRows(nodeStats) {
|
|
694
|
-
const metrics =
|
|
829
|
+
const metrics = reportMetrics(nodeStats);
|
|
695
830
|
const rows = [];
|
|
696
831
|
for (const counter of reportArray(metrics, "counters", "Counters")) {
|
|
697
832
|
rows.push({
|
|
698
833
|
Type: "Counter",
|
|
699
834
|
Scenario: asString(reportValue(counter, "scenarioName", "ScenarioName")),
|
|
700
|
-
Name:
|
|
835
|
+
Name: reportMetricName(counter),
|
|
701
836
|
Unit: asString(reportValue(counter, "unitOfMeasure", "UnitOfMeasure")),
|
|
702
837
|
Value: asInt(reportValue(counter, "value", "Value"))
|
|
703
838
|
});
|
|
@@ -706,7 +841,7 @@ function buildDotnetMetricRows(nodeStats) {
|
|
|
706
841
|
rows.push({
|
|
707
842
|
Type: "Gauge",
|
|
708
843
|
Scenario: asString(reportValue(gauge, "scenarioName", "ScenarioName")),
|
|
709
|
-
Name:
|
|
844
|
+
Name: reportMetricName(gauge),
|
|
710
845
|
Unit: asString(reportValue(gauge, "unitOfMeasure", "UnitOfMeasure")),
|
|
711
846
|
Value: formatReportNumber(reportValue(gauge, "value", "Value"))
|
|
712
847
|
});
|
|
@@ -731,15 +866,15 @@ function buildDotnetStatusCodeClassChart(scenarios) {
|
|
|
731
866
|
].filter((entry) => entry.value > 0);
|
|
732
867
|
}
|
|
733
868
|
function buildDotnetChartData(nodeStats) {
|
|
734
|
-
const scenarios =
|
|
869
|
+
const scenarios = reportScenarios(nodeStats);
|
|
735
870
|
return {
|
|
736
871
|
overallOutcome: [
|
|
737
|
-
{ label: "OK", value:
|
|
738
|
-
{ label: "FAIL", value:
|
|
872
|
+
{ label: "OK", value: reportTotalOkCount(nodeStats, scenarios), color: "#18a957" },
|
|
873
|
+
{ label: "FAIL", value: reportTotalFailCount(nodeStats, scenarios), color: "#d14343" }
|
|
739
874
|
],
|
|
740
875
|
scenarioRequests: scenarios.map((scenario) => ({
|
|
741
876
|
label: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
742
|
-
value:
|
|
877
|
+
value: reportRequestCountValue(scenario),
|
|
743
878
|
color: "#3b82f6"
|
|
744
879
|
})),
|
|
745
880
|
scenarioP95Latency: scenarios.map((scenario) => ({
|
|
@@ -749,21 +884,21 @@ function buildDotnetChartData(nodeStats) {
|
|
|
749
884
|
})),
|
|
750
885
|
scenarioRps: scenarios.map((scenario) => ({
|
|
751
886
|
label: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
752
|
-
value: reportDurationSeconds(
|
|
887
|
+
value: reportDurationSeconds(reportDurationValue(scenario)) <= 0
|
|
753
888
|
? 0
|
|
754
|
-
:
|
|
889
|
+
: reportRequestCountValue(scenario) / reportDurationSeconds(reportDurationValue(scenario)),
|
|
755
890
|
color: "#10b981"
|
|
756
891
|
})),
|
|
757
892
|
scenarioFailRate: scenarios.map((scenario) => ({
|
|
758
893
|
label: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
759
|
-
value:
|
|
894
|
+
value: reportRequestCountValue(scenario) <= 0
|
|
760
895
|
? 0
|
|
761
|
-
: (
|
|
896
|
+
: (reportFailCountValue(scenario) * 100 / reportRequestCountValue(scenario)),
|
|
762
897
|
color: "#ef4444"
|
|
763
898
|
})),
|
|
764
899
|
scenarioBytes: scenarios.map((scenario) => ({
|
|
765
900
|
label: asString(reportValue(scenario, "scenarioName", "ScenarioName")),
|
|
766
|
-
value: asInt(
|
|
901
|
+
value: asInt(reportBytesValue(scenario)),
|
|
767
902
|
color: "#0ea5e9"
|
|
768
903
|
})),
|
|
769
904
|
statusCodeClasses: buildDotnetStatusCodeClassChart(scenarios),
|
|
@@ -779,21 +914,24 @@ function buildDotnetChartData(nodeStats) {
|
|
|
779
914
|
};
|
|
780
915
|
}
|
|
781
916
|
function buildDotnetSummaryHtml(nodeStats) {
|
|
782
|
-
const scenarios =
|
|
783
|
-
const
|
|
917
|
+
const scenarios = reportScenarios(nodeStats);
|
|
918
|
+
const allRequests = reportTotalRequestCount(nodeStats, scenarios);
|
|
919
|
+
const allOk = reportTotalOkCount(nodeStats, scenarios);
|
|
920
|
+
const allFail = reportTotalFailCount(nodeStats, scenarios);
|
|
921
|
+
const successRate = allRequests <= 0
|
|
784
922
|
? 0
|
|
785
|
-
: (
|
|
786
|
-
const failRate =
|
|
923
|
+
: (allOk * 100 / allRequests);
|
|
924
|
+
const failRate = allRequests <= 0
|
|
787
925
|
? 0
|
|
788
|
-
: (
|
|
789
|
-
const overallRps = reportDurationSeconds(
|
|
926
|
+
: (allFail * 100 / allRequests);
|
|
927
|
+
const overallRps = reportDurationSeconds(reportDurationValue(nodeStats)) <= 0
|
|
790
928
|
? 0
|
|
791
|
-
:
|
|
929
|
+
: allRequests / reportDurationSeconds(reportDurationValue(nodeStats));
|
|
792
930
|
const topScenario = scenarios.reduce((winner, scenario) => {
|
|
793
931
|
if (!winner) {
|
|
794
932
|
return scenario;
|
|
795
933
|
}
|
|
796
|
-
return
|
|
934
|
+
return reportRequestCountValue(scenario) > reportRequestCountValue(winner)
|
|
797
935
|
? scenario
|
|
798
936
|
: winner;
|
|
799
937
|
}, undefined);
|
|
@@ -804,14 +942,15 @@ function buildDotnetSummaryHtml(nodeStats) {
|
|
|
804
942
|
const chartData = buildDotnetChartData(nodeStats);
|
|
805
943
|
const testInfo = reportObject(nodeStats, "testInfo", "TestInfo");
|
|
806
944
|
const nodeInfo = reportObject(nodeStats, "nodeInfo", "NodeInfo");
|
|
945
|
+
const totalBytes = reportTotalBytes(nodeStats, scenarios);
|
|
807
946
|
const parts = [];
|
|
808
947
|
appendReportLine(parts, "<div class=\"card-grid\">");
|
|
809
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Total Requests</div><div class="stat-value">${
|
|
810
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Success</div><div class="stat-value value-ok">${
|
|
811
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Fail</div><div class="stat-value value-fail">${
|
|
948
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Total Requests</div><div class="stat-value">${allRequests}</div></div>`);
|
|
949
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Success</div><div class="stat-value value-ok">${allOk} (${formatDotnetPercent(successRate)}%)</div></div>`);
|
|
950
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Fail</div><div class="stat-value value-fail">${allFail} (${formatDotnetPercent(failRate)}%)</div></div>`);
|
|
812
951
|
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Overall RPS</div><div class="stat-value">${formatReportNumber(overallRps)}</div></div>`);
|
|
813
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Duration</div><div class="stat-value">${escapeHtml(formatDotnetTimeSpan(
|
|
814
|
-
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Total Bytes</div><div class="stat-value">${
|
|
952
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Duration</div><div class="stat-value">${escapeHtml(formatDotnetTimeSpan(reportDurationValue(nodeStats)))}</div></div>`);
|
|
953
|
+
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Total Bytes</div><div class="stat-value">${totalBytes}</div></div>`);
|
|
815
954
|
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Top Scenario</div><div class="stat-value">${escapeHtml(topScenario ? reportValue(topScenario, "scenarioName", "ScenarioName") : "n/a")}</div></div>`);
|
|
816
955
|
appendReportLine(parts, `<div class="stat-card"><div class="stat-label">Node</div><div class="stat-value">${loadStrikeNodeTypeTag(reportValue(nodeInfo, "nodeType", "NodeType"))}</div></div>`);
|
|
817
956
|
appendReportLine(parts, "</div>");
|
|
@@ -886,7 +1025,7 @@ function buildDotnetStatusCodeHtml(nodeStats) {
|
|
|
886
1025
|
return buildDotnetTableHtml(buildDotnetStatusCodeRows(nodeStats));
|
|
887
1026
|
}
|
|
888
1027
|
function buildDotnetFailedResponseHtml(nodeStats) {
|
|
889
|
-
const failedStatusRows = buildFailedStatusRows(
|
|
1028
|
+
const failedStatusRows = buildFailedStatusRows(reportScenarios(nodeStats));
|
|
890
1029
|
const failedEventRows = buildFailedEventRows(reportArray(nodeStats, "pluginsData", "PluginsData"));
|
|
891
1030
|
return buildDotnetFailedResponseContent(failedStatusRows, failedEventRows);
|
|
892
1031
|
}
|
|
@@ -977,7 +1116,7 @@ function buildDotnetHtmlTabs(nodeStats) {
|
|
|
977
1116
|
if (statusCodeRows.length) {
|
|
978
1117
|
tabs.push(["status-codes", "Status Codes", buildDotnetTableHtml(statusCodeRows)]);
|
|
979
1118
|
}
|
|
980
|
-
const failedStatusRows = buildFailedStatusRows(
|
|
1119
|
+
const failedStatusRows = buildFailedStatusRows(reportScenarios(nodeStats));
|
|
981
1120
|
const failedEventRows = buildFailedEventRows(reportArray(nodeStats, "pluginsData", "PluginsData"));
|
|
982
1121
|
if (failedStatusRows.length || failedEventRows.length) {
|
|
983
1122
|
tabs.push(["failed-responses", "Failed Responses", buildDotnetFailedResponseContent(failedStatusRows, failedEventRows)]);
|
|
@@ -1035,7 +1174,7 @@ function buildDotnetHtmlTabs(nodeStats) {
|
|
|
1035
1174
|
* Exposes the build dotnet txt report operation. Use this when interacting with the SDK through this surface.
|
|
1036
1175
|
*/
|
|
1037
1176
|
export function buildDotnetTxtReport(nodeStats) {
|
|
1038
|
-
const scenarios =
|
|
1177
|
+
const scenarios = reportScenarios(nodeStats);
|
|
1039
1178
|
const testInfo = reportObject(nodeStats, "testInfo", "TestInfo");
|
|
1040
1179
|
const nodeInfo = reportObject(nodeStats, "nodeInfo", "NodeInfo");
|
|
1041
1180
|
const lines = [
|
|
@@ -1043,25 +1182,25 @@ export function buildDotnetTxtReport(nodeStats) {
|
|
|
1043
1182
|
`TestName: ${asString(reportValue(testInfo, "testName", "TestName"))}`,
|
|
1044
1183
|
`SessionId: ${asString(reportValue(testInfo, "sessionId", "SessionId"))}`,
|
|
1045
1184
|
`NodeType: ${loadStrikeNodeTypeTag(reportValue(nodeInfo, "nodeType", "NodeType"))}`,
|
|
1046
|
-
`Duration: ${formatDotnetTimeSpan(
|
|
1047
|
-
`Requests: ${
|
|
1185
|
+
`Duration: ${formatDotnetTimeSpan(reportDurationValue(nodeStats))}`,
|
|
1186
|
+
`Requests: ${reportTotalRequestCount(nodeStats, scenarios)} OK: ${reportTotalOkCount(nodeStats, scenarios)} FAIL: ${reportTotalFailCount(nodeStats, scenarios)}`,
|
|
1048
1187
|
"",
|
|
1049
1188
|
"Scenarios:"
|
|
1050
1189
|
];
|
|
1051
1190
|
for (const scenario of scenarios) {
|
|
1052
|
-
lines.push(`- ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))}: req=${
|
|
1191
|
+
lines.push(`- ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))}: req=${reportRequestCountValue(scenario)} ok=${reportOkCountValue(scenario)} fail=${reportFailCountValue(scenario)} duration=${formatDotnetTimeSpan(reportDurationValue(scenario))}`);
|
|
1053
1192
|
}
|
|
1054
|
-
if (scenarios.some((scenario) =>
|
|
1193
|
+
if (scenarios.some((scenario) => reportSteps(scenario).length > 0)) {
|
|
1055
1194
|
lines.push("", "Steps:");
|
|
1056
1195
|
for (const scenario of scenarios) {
|
|
1057
|
-
for (const step of
|
|
1196
|
+
for (const step of reportSteps(scenario)) {
|
|
1058
1197
|
const ok = asInt(reportValue(reportObject(reportObject(step, "ok", "Ok"), "request", "Request"), "count", "Count"));
|
|
1059
1198
|
const fail = asInt(reportValue(reportObject(reportObject(step, "fail", "Fail"), "request", "Request"), "count", "Count"));
|
|
1060
1199
|
lines.push(`- ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))}.${asString(reportValue(step, "stepName", "StepName"))}: req=${ok + fail} ok=${ok} fail=${fail}`);
|
|
1061
1200
|
}
|
|
1062
1201
|
}
|
|
1063
1202
|
}
|
|
1064
|
-
const thresholds =
|
|
1203
|
+
const thresholds = reportThresholds(nodeStats);
|
|
1065
1204
|
if (thresholds.length) {
|
|
1066
1205
|
lines.push("", "Thresholds:");
|
|
1067
1206
|
for (const threshold of thresholds) {
|
|
@@ -1085,10 +1224,10 @@ export function buildDotnetTxtReport(nodeStats) {
|
|
|
1085
1224
|
*/
|
|
1086
1225
|
export function buildDotnetCsvReport(nodeStats) {
|
|
1087
1226
|
const lines = ["ScenarioName,Requests,Ok,Fail,DurationSeconds,Rps"];
|
|
1088
|
-
for (const scenario of
|
|
1089
|
-
const durationSeconds = reportDurationSeconds(
|
|
1090
|
-
const requests =
|
|
1091
|
-
lines.push(`${escapeCsv(reportValue(scenario, "scenarioName", "ScenarioName"))},${requests},${
|
|
1227
|
+
for (const scenario of reportScenarios(nodeStats)) {
|
|
1228
|
+
const durationSeconds = reportDurationSeconds(reportDurationValue(scenario));
|
|
1229
|
+
const requests = reportRequestCountValue(scenario);
|
|
1230
|
+
lines.push(`${escapeCsv(reportValue(scenario, "scenarioName", "ScenarioName"))},${requests},${reportOkCountValue(scenario)},${reportFailCountValue(scenario)},${formatReportNumber(durationSeconds)},${formatReportNumber(durationSeconds <= 0 ? 0 : requests / durationSeconds)}`);
|
|
1092
1231
|
}
|
|
1093
1232
|
return reportLines(lines);
|
|
1094
1233
|
}
|
|
@@ -1096,16 +1235,16 @@ export function buildDotnetCsvReport(nodeStats) {
|
|
|
1096
1235
|
* Exposes the build dotnet markdown report operation. Use this when interacting with the SDK through this surface.
|
|
1097
1236
|
*/
|
|
1098
1237
|
export function buildDotnetMarkdownReport(nodeStats) {
|
|
1099
|
-
const scenarios =
|
|
1238
|
+
const scenarios = reportScenarios(nodeStats);
|
|
1100
1239
|
const testInfo = reportObject(nodeStats, "testInfo", "TestInfo");
|
|
1101
1240
|
const lines = [
|
|
1102
1241
|
`# ${asString(reportValue(testInfo, "testSuite", "TestSuite"))} / ${asString(reportValue(testInfo, "testName", "TestName"))}`,
|
|
1103
1242
|
"",
|
|
1104
1243
|
`- Session: \`${asString(reportValue(testInfo, "sessionId", "SessionId"))}\``,
|
|
1105
|
-
`- Duration: \`${formatDotnetTimeSpan(
|
|
1106
|
-
`- Total Requests: \`${
|
|
1107
|
-
`- OK: \`${
|
|
1108
|
-
`- FAIL: \`${
|
|
1244
|
+
`- Duration: \`${formatDotnetTimeSpan(reportDurationValue(nodeStats))}\``,
|
|
1245
|
+
`- Total Requests: \`${reportTotalRequestCount(nodeStats, scenarios)}\``,
|
|
1246
|
+
`- OK: \`${reportTotalOkCount(nodeStats, scenarios)}\``,
|
|
1247
|
+
`- FAIL: \`${reportTotalFailCount(nodeStats, scenarios)}\``,
|
|
1109
1248
|
"",
|
|
1110
1249
|
"## Scenarios",
|
|
1111
1250
|
"",
|
|
@@ -1113,19 +1252,19 @@ export function buildDotnetMarkdownReport(nodeStats) {
|
|
|
1113
1252
|
"|---|---:|---:|---:|---:|"
|
|
1114
1253
|
];
|
|
1115
1254
|
for (const scenario of scenarios) {
|
|
1116
|
-
lines.push(`| ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))} | ${
|
|
1255
|
+
lines.push(`| ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))} | ${reportRequestCountValue(scenario)} | ${reportOkCountValue(scenario)} | ${reportFailCountValue(scenario)} | ${formatReportNumber(reportDurationSeconds(reportDurationValue(scenario)))}s |`);
|
|
1117
1256
|
}
|
|
1118
|
-
if (scenarios.some((scenario) =>
|
|
1257
|
+
if (scenarios.some((scenario) => reportSteps(scenario).length > 0)) {
|
|
1119
1258
|
lines.push("", "## Steps", "", "| Scenario | Step | Requests | OK | FAIL |", "|---|---|---:|---:|---:|");
|
|
1120
1259
|
for (const scenario of scenarios) {
|
|
1121
|
-
for (const step of
|
|
1260
|
+
for (const step of reportSteps(scenario)) {
|
|
1122
1261
|
const ok = asInt(reportValue(reportObject(reportObject(step, "ok", "Ok"), "request", "Request"), "count", "Count"));
|
|
1123
1262
|
const fail = asInt(reportValue(reportObject(reportObject(step, "fail", "Fail"), "request", "Request"), "count", "Count"));
|
|
1124
1263
|
lines.push(`| ${asString(reportValue(scenario, "scenarioName", "ScenarioName"))} | ${asString(reportValue(step, "stepName", "StepName"))} | ${ok + fail} | ${ok} | ${fail} |`);
|
|
1125
1264
|
}
|
|
1126
1265
|
}
|
|
1127
1266
|
}
|
|
1128
|
-
const thresholds =
|
|
1267
|
+
const thresholds = reportThresholds(nodeStats);
|
|
1129
1268
|
if (thresholds.length) {
|
|
1130
1269
|
lines.push("", "## Thresholds", "", "| Scenario | Step | Check | Failed | Errors | Exception |", "|---|---|---|---:|---:|---|");
|
|
1131
1270
|
for (const threshold of thresholds) {
|
|
@@ -1261,7 +1400,7 @@ if(btns.length>0){show(btns[0].dataset.tab);}renderAllCharts();initPanePan();win
|
|
|
1261
1400
|
.split("__TEST_SUITE__").join(escapeHtml(reportValue(testInfo, "testSuite", "TestSuite")))
|
|
1262
1401
|
.split("__TEST_NAME__").join(escapeHtml(reportValue(testInfo, "testName", "TestName")))
|
|
1263
1402
|
.split("__SESSION_ID__").join(escapeHtml(reportValue(testInfo, "sessionId", "SessionId")))
|
|
1264
|
-
.split("__DURATION__").join(escapeHtml(formatDotnetTimeSpan(
|
|
1403
|
+
.split("__DURATION__").join(escapeHtml(formatDotnetTimeSpan(reportDurationValue(nodeStats))))
|
|
1265
1404
|
.split("__BUTTONS__").join(buttonsHtml)
|
|
1266
1405
|
.split("__SECTIONS__").join(sectionsHtml)
|
|
1267
1406
|
.split("__CHART_DATA__").join(chartDataJson)
|
package/dist/esm/runtime.js
CHANGED
|
@@ -8014,7 +8014,7 @@ function buildRichHtmlReport(result) {
|
|
|
8014
8014
|
<section id="scenarios" class="panel active">
|
|
8015
8015
|
${bars || "<div>No scenario data.</div>"}
|
|
8016
8016
|
<table>
|
|
8017
|
-
<thead><tr><th>Scenario</th><th>Requests</th><th>OK</th><th>Fail</th><th>TotalBytes</th><th>
|
|
8017
|
+
<thead><tr><th>Scenario</th><th>Requests</th><th>OK</th><th>Fail</th><th>TotalBytes</th><th>AvgLatency (ms)</th></tr></thead>
|
|
8018
8018
|
<tbody>${scenarioRows || "<tr><td colspan='6'>No rows</td></tr>"}</tbody>
|
|
8019
8019
|
</table>
|
|
8020
8020
|
</section>
|
package/package.json
CHANGED