@testsmith/perfornium 0.6.4 → 0.6.6

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.
Files changed (194) hide show
  1. package/dist/cli/cli.js +16 -1
  2. package/dist/cli/commands/distributed.js +2 -2
  3. package/dist/cli/commands/report.js +2 -2
  4. package/dist/cli/commands/run.js +2 -0
  5. package/dist/config/parser.js +2 -2
  6. package/dist/config/types/global-config.d.ts +82 -2
  7. package/dist/config/types/scenario-config.d.ts +2 -2
  8. package/dist/config/types/step-types.d.ts +1 -1
  9. package/dist/core/data/data-manager.d.ts +70 -0
  10. package/dist/core/data/data-manager.js +186 -0
  11. package/dist/core/data/data-provider.d.ts +85 -0
  12. package/dist/core/data/data-provider.js +468 -0
  13. package/dist/core/data/index.d.ts +8 -0
  14. package/dist/core/data/index.js +13 -0
  15. package/dist/core/execution/check-evaluator.d.ts +10 -0
  16. package/dist/core/execution/check-evaluator.js +79 -0
  17. package/dist/core/execution/data-extractor.d.ts +6 -0
  18. package/dist/core/execution/data-extractor.js +70 -0
  19. package/dist/core/execution/index.d.ts +3 -0
  20. package/dist/core/execution/index.js +9 -0
  21. package/dist/core/execution/json-payload-processor.d.ts +7 -0
  22. package/dist/core/execution/json-payload-processor.js +140 -0
  23. package/dist/core/factories/index.d.ts +2 -0
  24. package/dist/core/factories/index.js +7 -0
  25. package/dist/core/factories/output-handler-factory.d.ts +10 -0
  26. package/dist/core/factories/output-handler-factory.js +91 -0
  27. package/dist/core/factories/protocol-handler-factory.d.ts +12 -0
  28. package/dist/core/factories/protocol-handler-factory.js +96 -0
  29. package/dist/core/index.d.ts +3 -2
  30. package/dist/core/index.js +8 -3
  31. package/dist/core/reporting/dashboard-reporter.d.ts +17 -0
  32. package/dist/core/reporting/dashboard-reporter.js +127 -0
  33. package/dist/core/reporting/index.d.ts +1 -0
  34. package/dist/core/reporting/index.js +5 -0
  35. package/dist/core/step-executor.d.ts +6 -20
  36. package/dist/core/step-executor.js +72 -366
  37. package/dist/core/strategies/index.d.ts +2 -0
  38. package/dist/core/strategies/index.js +7 -0
  39. package/dist/core/strategies/scenario-selector.d.ts +13 -0
  40. package/dist/core/strategies/scenario-selector.js +37 -0
  41. package/dist/core/strategies/think-time-strategy.d.ts +15 -0
  42. package/dist/core/strategies/think-time-strategy.js +71 -0
  43. package/dist/core/test-runner.d.ts +4 -11
  44. package/dist/core/test-runner.js +105 -312
  45. package/dist/core/virtual-user.d.ts +7 -37
  46. package/dist/core/virtual-user.js +29 -269
  47. package/dist/dashboard/routes/api.d.ts +64 -0
  48. package/dist/dashboard/routes/api.js +569 -0
  49. package/dist/dashboard/routes/index.d.ts +2 -0
  50. package/dist/dashboard/routes/index.js +7 -0
  51. package/dist/dashboard/routes/static.d.ts +6 -0
  52. package/dist/dashboard/routes/static.js +76 -0
  53. package/dist/dashboard/server.d.ts +8 -84
  54. package/dist/dashboard/server.js +76 -2007
  55. package/dist/dashboard/services/file-scanner.d.ts +7 -0
  56. package/dist/dashboard/services/file-scanner.js +114 -0
  57. package/dist/dashboard/services/index.d.ts +5 -0
  58. package/dist/dashboard/services/index.js +13 -0
  59. package/dist/dashboard/services/influxdb-service.d.ts +41 -0
  60. package/dist/dashboard/services/influxdb-service.js +329 -0
  61. package/dist/dashboard/services/metrics-parser.d.ts +12 -0
  62. package/dist/dashboard/services/metrics-parser.js +209 -0
  63. package/dist/dashboard/services/results-manager.d.ts +17 -0
  64. package/dist/dashboard/services/results-manager.js +311 -0
  65. package/dist/dashboard/services/test-executor.d.ts +41 -0
  66. package/dist/dashboard/services/test-executor.js +250 -0
  67. package/dist/dashboard/services/workers-manager.d.ts +13 -0
  68. package/dist/dashboard/services/workers-manager.js +81 -0
  69. package/dist/dashboard/templates/index.html +122 -0
  70. package/dist/dashboard/templates/scripts/main.js +3280 -0
  71. package/dist/dashboard/templates/styles.css +402 -0
  72. package/dist/dashboard/types.d.ts +168 -0
  73. package/dist/dashboard/types.js +2 -0
  74. package/dist/distributed/result-aggregator.js +1 -3
  75. package/dist/metrics/batch/batch-processor.d.ts +27 -0
  76. package/dist/metrics/batch/batch-processor.js +85 -0
  77. package/dist/metrics/batch/index.d.ts +1 -0
  78. package/dist/metrics/batch/index.js +5 -0
  79. package/dist/metrics/collector.d.ts +46 -45
  80. package/dist/metrics/collector.js +179 -640
  81. package/dist/metrics/core/error-tracker.d.ts +9 -0
  82. package/dist/metrics/core/error-tracker.js +52 -0
  83. package/dist/metrics/core/index.d.ts +3 -0
  84. package/dist/metrics/core/index.js +9 -0
  85. package/dist/metrics/core/result-storage.d.ts +19 -0
  86. package/dist/metrics/core/result-storage.js +56 -0
  87. package/dist/metrics/core/statistics-engine.d.ts +27 -0
  88. package/dist/metrics/core/statistics-engine.js +91 -0
  89. package/dist/metrics/output/file-writer.d.ts +19 -0
  90. package/dist/metrics/output/file-writer.js +129 -0
  91. package/dist/metrics/output/index.d.ts +2 -0
  92. package/dist/metrics/output/index.js +10 -0
  93. package/dist/metrics/output/influxdb-writer.d.ts +89 -0
  94. package/dist/metrics/output/influxdb-writer.js +404 -0
  95. package/dist/metrics/realtime/dispatcher.d.ts +18 -0
  96. package/dist/metrics/realtime/dispatcher.js +45 -0
  97. package/dist/metrics/realtime/endpoints/graphite.d.ts +3 -0
  98. package/dist/metrics/realtime/endpoints/graphite.js +61 -0
  99. package/dist/metrics/realtime/endpoints/influxdb.d.ts +3 -0
  100. package/dist/metrics/realtime/endpoints/influxdb.js +35 -0
  101. package/dist/metrics/realtime/endpoints/webhook.d.ts +3 -0
  102. package/dist/metrics/realtime/endpoints/webhook.js +22 -0
  103. package/dist/metrics/realtime/endpoints/websocket.d.ts +3 -0
  104. package/dist/metrics/realtime/endpoints/websocket.js +25 -0
  105. package/dist/metrics/realtime/index.d.ts +5 -0
  106. package/dist/metrics/realtime/index.js +13 -0
  107. package/dist/metrics/reporting/index.d.ts +3 -0
  108. package/dist/metrics/reporting/index.js +9 -0
  109. package/dist/metrics/reporting/step-statistics.d.ts +6 -0
  110. package/dist/metrics/reporting/step-statistics.js +59 -0
  111. package/dist/metrics/reporting/summary-generator.d.ts +16 -0
  112. package/dist/metrics/reporting/summary-generator.js +46 -0
  113. package/dist/metrics/reporting/timeline-calculator.d.ts +7 -0
  114. package/dist/metrics/reporting/timeline-calculator.js +86 -0
  115. package/dist/metrics/types.d.ts +58 -0
  116. package/dist/outputs/csv.d.ts +2 -0
  117. package/dist/outputs/csv.js +21 -2
  118. package/dist/outputs/json.js +6 -2
  119. package/dist/protocols/rest/handler.d.ts +4 -53
  120. package/dist/protocols/rest/handler.js +73 -454
  121. package/dist/protocols/rest/request/auth-handler.d.ts +4 -0
  122. package/dist/protocols/rest/request/auth-handler.js +30 -0
  123. package/dist/protocols/rest/request/body-processor.d.ts +11 -0
  124. package/dist/protocols/rest/request/body-processor.js +62 -0
  125. package/dist/protocols/rest/request/index.d.ts +2 -0
  126. package/dist/protocols/rest/request/index.js +7 -0
  127. package/dist/protocols/rest/response/checks.d.ts +6 -0
  128. package/dist/protocols/rest/response/checks.js +71 -0
  129. package/dist/protocols/rest/response/index.d.ts +2 -0
  130. package/dist/protocols/rest/response/index.js +7 -0
  131. package/dist/protocols/rest/response/size-calculator.d.ts +12 -0
  132. package/dist/protocols/rest/response/size-calculator.js +64 -0
  133. package/dist/protocols/web/browser/highlight.d.ts +7 -0
  134. package/dist/protocols/web/browser/highlight.js +47 -0
  135. package/dist/protocols/web/browser/index.d.ts +4 -0
  136. package/dist/protocols/web/browser/index.js +11 -0
  137. package/dist/protocols/web/browser/manager.d.ts +20 -0
  138. package/dist/protocols/web/browser/manager.js +189 -0
  139. package/dist/protocols/web/browser/screenshot.d.ts +8 -0
  140. package/dist/protocols/web/browser/screenshot.js +69 -0
  141. package/dist/protocols/web/browser/storage.d.ts +5 -0
  142. package/dist/protocols/web/browser/storage.js +45 -0
  143. package/dist/protocols/web/commands/index.d.ts +5 -0
  144. package/dist/protocols/web/commands/index.js +11 -0
  145. package/dist/protocols/web/commands/interaction.d.ts +13 -0
  146. package/dist/protocols/web/commands/interaction.js +68 -0
  147. package/dist/protocols/web/commands/measurement.d.ts +16 -0
  148. package/dist/protocols/web/commands/measurement.js +33 -0
  149. package/dist/protocols/web/commands/navigation.d.ts +11 -0
  150. package/dist/protocols/web/commands/navigation.js +43 -0
  151. package/dist/protocols/web/commands/types.d.ts +12 -0
  152. package/dist/protocols/web/commands/types.js +2 -0
  153. package/dist/protocols/web/commands/verification.d.ts +12 -0
  154. package/dist/protocols/web/commands/verification.js +118 -0
  155. package/dist/protocols/web/handler.d.ts +19 -30
  156. package/dist/protocols/web/handler.js +164 -651
  157. package/dist/protocols/web/network/capture.d.ts +19 -0
  158. package/dist/protocols/web/network/capture.js +225 -0
  159. package/dist/protocols/web/network/filters.d.ts +5 -0
  160. package/dist/protocols/web/network/filters.js +49 -0
  161. package/dist/protocols/web/network/index.d.ts +4 -0
  162. package/dist/protocols/web/network/index.js +9 -0
  163. package/dist/protocols/web/network/types.d.ts +13 -0
  164. package/dist/protocols/web/network/types.js +2 -0
  165. package/dist/protocols/web/network/utils.d.ts +8 -0
  166. package/dist/protocols/web/network/utils.js +29 -0
  167. package/dist/recorder/continue-recorder.d.ts +11 -0
  168. package/dist/recorder/continue-recorder.js +872 -0
  169. package/dist/reporting/chart-data/index.d.ts +5 -0
  170. package/dist/reporting/chart-data/index.js +13 -0
  171. package/dist/reporting/chart-data/network.d.ts +25 -0
  172. package/dist/reporting/chart-data/network.js +78 -0
  173. package/dist/reporting/chart-data/scenario.d.ts +37 -0
  174. package/dist/reporting/chart-data/scenario.js +76 -0
  175. package/dist/reporting/chart-data/step-statistics.d.ts +24 -0
  176. package/dist/reporting/chart-data/step-statistics.js +94 -0
  177. package/dist/reporting/chart-data/throughput.d.ts +16 -0
  178. package/dist/reporting/chart-data/throughput.js +24 -0
  179. package/dist/reporting/chart-data/timeline.d.ts +17 -0
  180. package/dist/reporting/chart-data/timeline.js +46 -0
  181. package/dist/reporting/handlebars-helpers.d.ts +1 -0
  182. package/dist/reporting/handlebars-helpers.js +63 -0
  183. package/dist/reporting/{enhanced-html-generator.d.ts → html-generator.d.ts} +1 -1
  184. package/dist/reporting/{enhanced-html-generator.js → html-generator.js} +10 -7
  185. package/dist/reporting/templates/{enhanced-report.hbs → report.hbs} +9 -9
  186. package/dist/utils/data-utils.d.ts +17 -0
  187. package/dist/utils/data-utils.js +129 -0
  188. package/dist/utils/template.js +2 -2
  189. package/package.json +5 -2
  190. package/dist/core/csv-data-provider.d.ts +0 -47
  191. package/dist/core/csv-data-provider.js +0 -265
  192. package/dist/reporting/generator.d.ts +0 -42
  193. package/dist/reporting/generator.js +0 -1217
  194. package/dist/reporting/templates/html.hbs +0 -2453
@@ -0,0 +1,9 @@
1
+ import { ErrorDetail, TestResult } from '../types';
2
+ export declare class ErrorTracker {
3
+ private errorDetails;
4
+ clear(): void;
5
+ trackError(result: TestResult): void;
6
+ getErrorDetails(): ErrorDetail[];
7
+ getErrorDistribution(results: TestResult[]): Record<string, number>;
8
+ getStatusDistribution(results: TestResult[]): Record<number, number>;
9
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorTracker = void 0;
4
+ class ErrorTracker {
5
+ constructor() {
6
+ this.errorDetails = new Map();
7
+ }
8
+ clear() {
9
+ this.errorDetails.clear();
10
+ }
11
+ trackError(result) {
12
+ const errorKey = `${result.scenario}:${result.action}:${result.status || 'NO_STATUS'}:${result.error}`;
13
+ const existing = this.errorDetails.get(errorKey);
14
+ if (existing) {
15
+ existing.count++;
16
+ }
17
+ else {
18
+ this.errorDetails.set(errorKey, {
19
+ timestamp: result.timestamp,
20
+ vu_id: result.vu_id,
21
+ scenario: result.scenario,
22
+ action: result.action,
23
+ status: result.status,
24
+ error: result.error || 'Unknown error',
25
+ request_url: result.request_url,
26
+ response_body: result.response_body,
27
+ count: 1
28
+ });
29
+ }
30
+ }
31
+ getErrorDetails() {
32
+ return Array.from(this.errorDetails.values()).sort((a, b) => b.count - a.count);
33
+ }
34
+ getErrorDistribution(results) {
35
+ const distribution = {};
36
+ results.filter(r => !r.success).forEach(r => {
37
+ const error = r.error || 'Unknown error';
38
+ distribution[error] = (distribution[error] || 0) + 1;
39
+ });
40
+ return distribution;
41
+ }
42
+ getStatusDistribution(results) {
43
+ const distribution = {};
44
+ results.forEach(r => {
45
+ if (r.status) {
46
+ distribution[r.status] = (distribution[r.status] || 0) + 1;
47
+ }
48
+ });
49
+ return distribution;
50
+ }
51
+ }
52
+ exports.ErrorTracker = ErrorTracker;
@@ -0,0 +1,3 @@
1
+ export { StatisticsEngine, RunningStats } from './statistics-engine';
2
+ export { ErrorTracker } from './error-tracker';
3
+ export { ResultStorage } from './result-storage';
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResultStorage = exports.ErrorTracker = exports.StatisticsEngine = void 0;
4
+ var statistics_engine_1 = require("./statistics-engine");
5
+ Object.defineProperty(exports, "StatisticsEngine", { enumerable: true, get: function () { return statistics_engine_1.StatisticsEngine; } });
6
+ var error_tracker_1 = require("./error-tracker");
7
+ Object.defineProperty(exports, "ErrorTracker", { enumerable: true, get: function () { return error_tracker_1.ErrorTracker; } });
8
+ var result_storage_1 = require("./result-storage");
9
+ Object.defineProperty(exports, "ResultStorage", { enumerable: true, get: function () { return result_storage_1.ResultStorage; } });
@@ -0,0 +1,19 @@
1
+ import { TestResult, VUStartEvent } from '../types';
2
+ export declare class ResultStorage {
3
+ private results;
4
+ private vuStartEvents;
5
+ private loadPatternType;
6
+ private readonly maxStoredResults;
7
+ constructor(maxStoredResults?: number);
8
+ clear(): void;
9
+ setLoadPatternType(pattern: string): void;
10
+ recordVUStart(vuId: number): void;
11
+ addResult(result: TestResult): boolean;
12
+ getResults(): TestResult[];
13
+ getVUStartEvents(): VUStartEvent[];
14
+ getResultCount(): number;
15
+ isAtCapacity(): boolean;
16
+ getResponseSizes(): number[];
17
+ getActiveVUsAtTime(time: number): number;
18
+ getResultsInInterval(startTime: number, endTime: number): TestResult[];
19
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResultStorage = void 0;
4
+ class ResultStorage {
5
+ constructor(maxStoredResults = 50000) {
6
+ this.results = [];
7
+ this.vuStartEvents = [];
8
+ this.loadPatternType = 'basic';
9
+ this.maxStoredResults = maxStoredResults;
10
+ }
11
+ clear() {
12
+ this.results = [];
13
+ this.vuStartEvents = [];
14
+ }
15
+ setLoadPatternType(pattern) {
16
+ this.loadPatternType = pattern;
17
+ }
18
+ recordVUStart(vuId) {
19
+ this.vuStartEvents.push({
20
+ vu_id: vuId,
21
+ start_time: Date.now(),
22
+ load_pattern: this.loadPatternType
23
+ });
24
+ }
25
+ addResult(result) {
26
+ if (this.results.length < this.maxStoredResults) {
27
+ this.results.push(result);
28
+ return true;
29
+ }
30
+ return false;
31
+ }
32
+ getResults() {
33
+ return [...this.results];
34
+ }
35
+ getVUStartEvents() {
36
+ return [...this.vuStartEvents];
37
+ }
38
+ getResultCount() {
39
+ return this.results.length;
40
+ }
41
+ isAtCapacity() {
42
+ return this.results.length >= this.maxStoredResults;
43
+ }
44
+ getResponseSizes() {
45
+ return this.results
46
+ .filter(r => r.response_size)
47
+ .map(r => r.response_size);
48
+ }
49
+ getActiveVUsAtTime(time) {
50
+ return this.vuStartEvents.filter(vu => vu.start_time <= time).length;
51
+ }
52
+ getResultsInInterval(startTime, endTime) {
53
+ return this.results.filter(r => r.timestamp >= startTime && r.timestamp < endTime);
54
+ }
55
+ }
56
+ exports.ResultStorage = ResultStorage;
@@ -0,0 +1,27 @@
1
+ export interface RunningStats {
2
+ totalRequests: number;
3
+ successfulRequests: number;
4
+ failedRequests: number;
5
+ totalDuration: number;
6
+ minDuration: number;
7
+ maxDuration: number;
8
+ durations: number[];
9
+ }
10
+ export declare class StatisticsEngine {
11
+ private readonly maxDurationsForPercentiles;
12
+ private stats;
13
+ constructor(maxDurationsForPercentiles?: number);
14
+ private createEmptyStats;
15
+ reset(): void;
16
+ recordResult(duration: number, success: boolean): void;
17
+ getStats(): RunningStats;
18
+ getAverageResponseTime(): number;
19
+ getMinDuration(): number;
20
+ getMaxDuration(): number;
21
+ getDurations(): number[];
22
+ calculatePercentiles(values?: number[]): Record<number, number>;
23
+ getSuccessRate(): number;
24
+ getTotalRequests(): number;
25
+ getSuccessfulRequests(): number;
26
+ getFailedRequests(): number;
27
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StatisticsEngine = void 0;
4
+ class StatisticsEngine {
5
+ constructor(maxDurationsForPercentiles = 10000) {
6
+ this.maxDurationsForPercentiles = maxDurationsForPercentiles;
7
+ this.stats = this.createEmptyStats();
8
+ }
9
+ createEmptyStats() {
10
+ return {
11
+ totalRequests: 0,
12
+ successfulRequests: 0,
13
+ failedRequests: 0,
14
+ totalDuration: 0,
15
+ minDuration: Infinity,
16
+ maxDuration: 0,
17
+ durations: []
18
+ };
19
+ }
20
+ reset() {
21
+ this.stats = this.createEmptyStats();
22
+ }
23
+ recordResult(duration, success) {
24
+ this.stats.totalRequests++;
25
+ if (success) {
26
+ this.stats.successfulRequests++;
27
+ this.stats.totalDuration += duration;
28
+ this.stats.minDuration = Math.min(this.stats.minDuration, duration);
29
+ this.stats.maxDuration = Math.max(this.stats.maxDuration, duration);
30
+ // Keep limited durations for percentile calculation (reservoir sampling)
31
+ if (this.stats.durations.length < this.maxDurationsForPercentiles) {
32
+ this.stats.durations.push(duration);
33
+ }
34
+ else {
35
+ // Randomly replace an existing duration (reservoir sampling)
36
+ const replaceIndex = Math.floor(Math.random() * this.stats.totalRequests);
37
+ if (replaceIndex < this.maxDurationsForPercentiles) {
38
+ this.stats.durations[replaceIndex] = duration;
39
+ }
40
+ }
41
+ }
42
+ else {
43
+ this.stats.failedRequests++;
44
+ }
45
+ }
46
+ getStats() {
47
+ return { ...this.stats };
48
+ }
49
+ getAverageResponseTime() {
50
+ return this.stats.successfulRequests > 0
51
+ ? this.stats.totalDuration / this.stats.successfulRequests
52
+ : 0;
53
+ }
54
+ getMinDuration() {
55
+ return this.stats.minDuration === Infinity ? 0 : this.stats.minDuration;
56
+ }
57
+ getMaxDuration() {
58
+ return this.stats.maxDuration;
59
+ }
60
+ getDurations() {
61
+ return [...this.stats.durations];
62
+ }
63
+ calculatePercentiles(values) {
64
+ const durations = values || this.stats.durations;
65
+ if (durations.length === 0)
66
+ return {};
67
+ const sorted = [...durations].sort((a, b) => a - b);
68
+ const percentileValues = [50, 90, 95, 99, 99.9, 99.99];
69
+ const result = {};
70
+ percentileValues.forEach(p => {
71
+ const index = Math.ceil((p / 100) * sorted.length) - 1;
72
+ result[p] = sorted[Math.max(0, index)];
73
+ });
74
+ return result;
75
+ }
76
+ getSuccessRate() {
77
+ return this.stats.totalRequests > 0
78
+ ? (this.stats.successfulRequests / this.stats.totalRequests) * 100
79
+ : 0;
80
+ }
81
+ getTotalRequests() {
82
+ return this.stats.totalRequests;
83
+ }
84
+ getSuccessfulRequests() {
85
+ return this.stats.successfulRequests;
86
+ }
87
+ getFailedRequests() {
88
+ return this.stats.failedRequests;
89
+ }
90
+ }
91
+ exports.StatisticsEngine = StatisticsEngine;
@@ -0,0 +1,19 @@
1
+ import { TestResult } from '../types';
2
+ export interface FileOutputConfig {
3
+ enabled: boolean;
4
+ path: string;
5
+ format: 'jsonl' | 'csv';
6
+ }
7
+ export interface IncrementalFilesConfig {
8
+ enabled: boolean;
9
+ jsonPath?: string;
10
+ }
11
+ export declare class FileWriter {
12
+ private incrementalConfig;
13
+ initialize(config: IncrementalFilesConfig): Promise<void>;
14
+ reset(): void;
15
+ writeBatchToFile(batch: TestResult[], config: FileOutputConfig, batchNumber: number): Promise<void>;
16
+ private formatBatchAsCSV;
17
+ updateIncrementalFiles(batch: TestResult[]): Promise<void>;
18
+ private updateIncrementalJSON;
19
+ }
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.FileWriter = void 0;
37
+ const fs = __importStar(require("fs/promises"));
38
+ const path = __importStar(require("path"));
39
+ const logger_1 = require("../../utils/logger");
40
+ class FileWriter {
41
+ constructor() {
42
+ this.incrementalConfig = null;
43
+ }
44
+ async initialize(config) {
45
+ this.incrementalConfig = config;
46
+ if (!config.enabled)
47
+ return;
48
+ try {
49
+ // Initialize JSON file
50
+ if (config.jsonPath) {
51
+ const dir = path.dirname(config.jsonPath);
52
+ await fs.mkdir(dir, { recursive: true });
53
+ await fs.writeFile(config.jsonPath, '[]');
54
+ logger_1.logger.debug(`Initialized incremental JSON file: ${config.jsonPath}`);
55
+ }
56
+ }
57
+ catch (error) {
58
+ logger_1.logger.error('Failed to initialize incremental files:', error);
59
+ }
60
+ }
61
+ reset() {
62
+ // No state to reset
63
+ }
64
+ async writeBatchToFile(batch, config, batchNumber) {
65
+ if (!config.enabled)
66
+ return;
67
+ try {
68
+ const dir = path.dirname(config.path);
69
+ await fs.mkdir(dir, { recursive: true });
70
+ let content;
71
+ if (config.format === 'csv') {
72
+ content = this.formatBatchAsCSV(batch, batchNumber);
73
+ }
74
+ else {
75
+ // JSONL format (default)
76
+ content = batch.map(result => JSON.stringify({
77
+ ...result,
78
+ timestamp: new Date(result.timestamp).toISOString(),
79
+ batch_number: batchNumber
80
+ })).join('\n') + '\n';
81
+ }
82
+ await fs.appendFile(config.path, content);
83
+ }
84
+ catch (error) {
85
+ logger_1.logger.error('Failed to write batch to file:', error);
86
+ }
87
+ }
88
+ formatBatchAsCSV(batch, batchNumber) {
89
+ return batch.map(result => [
90
+ new Date(result.timestamp).toISOString(),
91
+ batchNumber,
92
+ result.vu_id,
93
+ result.scenario,
94
+ result.action,
95
+ result.step_name || '',
96
+ result.duration,
97
+ result.success,
98
+ result.status || '',
99
+ (result.error || '').replace(/"/g, '""')
100
+ ].join(',')).join('\n') + '\n';
101
+ }
102
+ async updateIncrementalFiles(batch) {
103
+ if (!this.incrementalConfig?.enabled)
104
+ return;
105
+ try {
106
+ if (this.incrementalConfig.jsonPath) {
107
+ await this.updateIncrementalJSON(batch, this.incrementalConfig.jsonPath);
108
+ }
109
+ }
110
+ catch (error) {
111
+ logger_1.logger.error('Failed to update incremental files:', error);
112
+ }
113
+ }
114
+ async updateIncrementalJSON(batch, filePath) {
115
+ try {
116
+ const existingContent = await fs.readFile(filePath, 'utf8');
117
+ let existingData = [];
118
+ if (existingContent.trim()) {
119
+ existingData = JSON.parse(existingContent);
120
+ }
121
+ const updatedData = [...existingData, ...batch];
122
+ await fs.writeFile(filePath, JSON.stringify(updatedData, null, 2));
123
+ }
124
+ catch (error) {
125
+ await fs.writeFile(filePath, JSON.stringify(batch, null, 2));
126
+ }
127
+ }
128
+ }
129
+ exports.FileWriter = FileWriter;
@@ -0,0 +1,2 @@
1
+ export { FileWriter, FileOutputConfig, IncrementalFilesConfig } from './file-writer';
2
+ export { InfluxDBWriter, InfluxDBWriterConfig, TestMetricsQueryOptions, getInfluxDBWriter, setInfluxDBWriter, initInfluxDBWriter } from './influxdb-writer';
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initInfluxDBWriter = exports.setInfluxDBWriter = exports.getInfluxDBWriter = exports.InfluxDBWriter = exports.FileWriter = void 0;
4
+ var file_writer_1 = require("./file-writer");
5
+ Object.defineProperty(exports, "FileWriter", { enumerable: true, get: function () { return file_writer_1.FileWriter; } });
6
+ var influxdb_writer_1 = require("./influxdb-writer");
7
+ Object.defineProperty(exports, "InfluxDBWriter", { enumerable: true, get: function () { return influxdb_writer_1.InfluxDBWriter; } });
8
+ Object.defineProperty(exports, "getInfluxDBWriter", { enumerable: true, get: function () { return influxdb_writer_1.getInfluxDBWriter; } });
9
+ Object.defineProperty(exports, "setInfluxDBWriter", { enumerable: true, get: function () { return influxdb_writer_1.setInfluxDBWriter; } });
10
+ Object.defineProperty(exports, "initInfluxDBWriter", { enumerable: true, get: function () { return influxdb_writer_1.initInfluxDBWriter; } });
@@ -0,0 +1,89 @@
1
+ import { TestResult, MetricsSummary, CapturedNetworkCall } from '../types';
2
+ export interface InfluxDBWriterConfig {
3
+ url: string;
4
+ token: string;
5
+ org: string;
6
+ bucket: string;
7
+ /** Batch size for writing points (default: 100) */
8
+ batchSize?: number;
9
+ /** Flush interval in ms (default: 1000) */
10
+ flushInterval?: number;
11
+ }
12
+ export interface TestMetricsQueryOptions {
13
+ testId?: string;
14
+ testName?: string;
15
+ startTime?: Date;
16
+ endTime?: Date;
17
+ scenario?: string;
18
+ limit?: number;
19
+ }
20
+ /**
21
+ * InfluxDB writer for test metrics (response times, network calls, etc.)
22
+ * This is optional - test results can still be stored as JSON files.
23
+ */
24
+ export declare class InfluxDBWriter {
25
+ private client;
26
+ private writeApi;
27
+ private queryApi;
28
+ private config;
29
+ private enabled;
30
+ private currentTestId;
31
+ private currentTestName;
32
+ constructor(config?: Partial<InfluxDBWriterConfig>);
33
+ connect(): Promise<boolean>;
34
+ isEnabled(): boolean;
35
+ /**
36
+ * Start a new test run - sets the test ID and name for all subsequent writes
37
+ */
38
+ startTest(testId: string, testName: string): void;
39
+ /**
40
+ * Write a single test result to InfluxDB
41
+ */
42
+ writeResult(result: TestResult): Promise<void>;
43
+ /**
44
+ * Write a batch of test results to InfluxDB
45
+ */
46
+ writeBatch(results: TestResult[]): Promise<void>;
47
+ /**
48
+ * Write a network call to InfluxDB
49
+ */
50
+ writeNetworkCall(call: CapturedNetworkCall): Promise<void>;
51
+ /**
52
+ * Write test summary to InfluxDB
53
+ */
54
+ writeSummary(summary: MetricsSummary): Promise<void>;
55
+ /**
56
+ * Query test results from InfluxDB
57
+ */
58
+ queryResults(options?: TestMetricsQueryOptions): Promise<TestResult[]>;
59
+ /**
60
+ * Query network calls from InfluxDB
61
+ */
62
+ queryNetworkCalls(options?: TestMetricsQueryOptions): Promise<CapturedNetworkCall[]>;
63
+ /**
64
+ * Get list of test runs
65
+ */
66
+ getTestRuns(limit?: number): Promise<Array<{
67
+ testId: string;
68
+ testName: string;
69
+ timestamp: Date;
70
+ }>>;
71
+ /**
72
+ * Export test data for a specific test run
73
+ */
74
+ exportTestData(testId: string, format?: 'json' | 'csv'): Promise<string>;
75
+ /**
76
+ * Finalize the current test - flush all pending writes
77
+ */
78
+ finalize(): Promise<void>;
79
+ /**
80
+ * Close the connection
81
+ */
82
+ close(): Promise<void>;
83
+ private rowsToResults;
84
+ private rowsToNetworkCalls;
85
+ private resultsToCSV;
86
+ }
87
+ export declare function getInfluxDBWriter(): InfluxDBWriter | null;
88
+ export declare function setInfluxDBWriter(writer: InfluxDBWriter): void;
89
+ export declare function initInfluxDBWriter(config?: Partial<InfluxDBWriterConfig>): Promise<InfluxDBWriter>;