@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,7 @@
1
+ import { RESTStep, VUContext } from '../../config';
2
+ export declare class JSONPayloadProcessor {
3
+ private templateProcessor;
4
+ processJsonFile(step: RESTStep, context: VUContext): RESTStep;
5
+ applyOverrides(obj: any, overrides: Record<string, any>, context: VUContext): any;
6
+ setNestedValue(obj: any, path: string, value: any): void;
7
+ }
@@ -0,0 +1,140 @@
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.JSONPayloadProcessor = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const template_1 = require("../../utils/template");
40
+ class JSONPayloadProcessor {
41
+ constructor() {
42
+ this.templateProcessor = new template_1.TemplateProcessor();
43
+ }
44
+ processJsonFile(step, context) {
45
+ if (!step.jsonFile) {
46
+ return step;
47
+ }
48
+ // Resolve file path relative to CWD
49
+ const filePath = path.resolve(process.cwd(), step.jsonFile);
50
+ if (!fs.existsSync(filePath)) {
51
+ throw new Error(`JSON payload file not found: ${step.jsonFile}`);
52
+ }
53
+ // Load and parse JSON file
54
+ let payload;
55
+ try {
56
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
57
+ payload = JSON.parse(fileContent);
58
+ }
59
+ catch (error) {
60
+ throw new Error(`Failed to parse JSON file ${step.jsonFile}: ${error.message}`);
61
+ }
62
+ // Apply overrides if specified
63
+ if (step.overrides) {
64
+ payload = this.applyOverrides(payload, step.overrides, context);
65
+ }
66
+ // Return new step with json property set (removing jsonFile and overrides)
67
+ const { jsonFile, overrides, ...restOfStep } = step;
68
+ return {
69
+ ...restOfStep,
70
+ json: payload
71
+ };
72
+ }
73
+ applyOverrides(obj, overrides, context) {
74
+ // Deep clone the object to avoid mutating the original
75
+ const result = JSON.parse(JSON.stringify(obj));
76
+ const contextData = {
77
+ __VU: context.vu_id,
78
+ __ITER: context.iteration,
79
+ vu_id: context.vu_id,
80
+ iteration: context.iteration,
81
+ variables: context.variables || {},
82
+ extracted_data: context.extracted_data || {},
83
+ ...context.variables,
84
+ ...context.extracted_data
85
+ };
86
+ for (const [path, value] of Object.entries(overrides)) {
87
+ // Process template expressions in override values
88
+ let processedValue = value;
89
+ if (typeof value === 'string') {
90
+ processedValue = this.templateProcessor.process(value, contextData);
91
+ // Try to parse as JSON if it looks like a number, boolean, or object
92
+ if (processedValue === 'true')
93
+ processedValue = true;
94
+ else if (processedValue === 'false')
95
+ processedValue = false;
96
+ else if (!isNaN(Number(processedValue)) && processedValue !== '') {
97
+ processedValue = Number(processedValue);
98
+ }
99
+ }
100
+ this.setNestedValue(result, path, processedValue);
101
+ }
102
+ return result;
103
+ }
104
+ setNestedValue(obj, path, value) {
105
+ const keys = path.split('.');
106
+ let current = obj;
107
+ for (let i = 0; i < keys.length - 1; i++) {
108
+ const key = keys[i];
109
+ // Handle array indices like 'items[0]'
110
+ const arrayMatch = key.match(/^(.+)\[(\d+)]$/);
111
+ if (arrayMatch) {
112
+ const [, prop, index] = arrayMatch;
113
+ if (!current[prop])
114
+ current[prop] = [];
115
+ if (!current[prop][parseInt(index)])
116
+ current[prop][parseInt(index)] = {};
117
+ current = current[prop][parseInt(index)];
118
+ }
119
+ else {
120
+ if (!current[key] || typeof current[key] !== 'object') {
121
+ current[key] = {};
122
+ }
123
+ current = current[key];
124
+ }
125
+ }
126
+ const lastKey = keys[keys.length - 1];
127
+ // Handle array index in last key
128
+ const arrayMatch = lastKey.match(/^(.+)\[(\d+)]$/);
129
+ if (arrayMatch) {
130
+ const [, prop, index] = arrayMatch;
131
+ if (!current[prop])
132
+ current[prop] = [];
133
+ current[prop][parseInt(index)] = value;
134
+ }
135
+ else {
136
+ current[lastKey] = value;
137
+ }
138
+ }
139
+ }
140
+ exports.JSONPayloadProcessor = JSONPayloadProcessor;
@@ -0,0 +1,2 @@
1
+ export { ProtocolHandlerFactory } from './protocol-handler-factory';
2
+ export { OutputHandlerFactory } from './output-handler-factory';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OutputHandlerFactory = exports.ProtocolHandlerFactory = void 0;
4
+ var protocol_handler_factory_1 = require("./protocol-handler-factory");
5
+ Object.defineProperty(exports, "ProtocolHandlerFactory", { enumerable: true, get: function () { return protocol_handler_factory_1.ProtocolHandlerFactory; } });
6
+ var output_handler_factory_1 = require("./output-handler-factory");
7
+ Object.defineProperty(exports, "OutputHandlerFactory", { enumerable: true, get: function () { return output_handler_factory_1.OutputHandlerFactory; } });
@@ -0,0 +1,10 @@
1
+ import { OutputConfig } from '../../config';
2
+ import { OutputHandler } from '../../outputs/base';
3
+ export declare class OutputHandlerFactory {
4
+ private testName;
5
+ constructor(testName: string);
6
+ createOutputs(outputConfigs?: OutputConfig[]): Promise<OutputHandler[]>;
7
+ private createOutput;
8
+ private processTemplateFilePath;
9
+ static finalizeOutputs(outputs: OutputHandler[], summary: any): Promise<void>;
10
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OutputHandlerFactory = void 0;
4
+ const csv_1 = require("../../outputs/csv");
5
+ const json_1 = require("../../outputs/json");
6
+ const influxdb_1 = require("../../outputs/influxdb");
7
+ const graphite_1 = require("../../outputs/graphite");
8
+ const webhook_1 = require("../../outputs/webhook");
9
+ const file_manager_1 = require("../../utils/file-manager");
10
+ const logger_1 = require("../../utils/logger");
11
+ class OutputHandlerFactory {
12
+ constructor(testName) {
13
+ this.testName = testName;
14
+ }
15
+ async createOutputs(outputConfigs) {
16
+ if (!outputConfigs)
17
+ return [];
18
+ const outputs = [];
19
+ for (const outputConfig of outputConfigs) {
20
+ // Skip disabled outputs
21
+ if (outputConfig.enabled === false) {
22
+ continue;
23
+ }
24
+ try {
25
+ const output = await this.createOutput(outputConfig);
26
+ if (output) {
27
+ await output.initialize();
28
+ outputs.push(output);
29
+ logger_1.logger.debug(`${outputConfig.type} output initialized`);
30
+ }
31
+ }
32
+ catch (error) {
33
+ logger_1.logger.warn(`Failed to initialize ${outputConfig.type} output:`, error);
34
+ }
35
+ }
36
+ return outputs;
37
+ }
38
+ async createOutput(config) {
39
+ // Process timestamp templates in file paths
40
+ const processedFilePath = this.processTemplateFilePath(config.file);
41
+ switch (config.type) {
42
+ case 'csv':
43
+ return new csv_1.CSVOutput(processedFilePath);
44
+ case 'json':
45
+ return new json_1.JSONOutput(processedFilePath);
46
+ case 'influxdb':
47
+ return new influxdb_1.InfluxDBOutput(config.url, config.database, config.tags);
48
+ case 'graphite': {
49
+ const [host, port] = (config.url || 'localhost:2003').split(':');
50
+ return new graphite_1.GraphiteOutput(host, parseInt(port || '2003'), 'perfornium');
51
+ }
52
+ case 'webhook':
53
+ return new webhook_1.WebhookOutput(config.url, config.headers || {}, 'json', config.template);
54
+ default:
55
+ logger_1.logger.warn(`Unsupported output type: ${config.type}`);
56
+ return null;
57
+ }
58
+ }
59
+ processTemplateFilePath(filePath) {
60
+ if (!filePath) {
61
+ return `results/${this.testName}-{{timestamp}}.csv`;
62
+ }
63
+ // If no timestamp placeholder exists, automatically add one before the extension
64
+ let processedPath = filePath;
65
+ if (!filePath.includes('{{timestamp}}')) {
66
+ const lastDot = filePath.lastIndexOf('.');
67
+ if (lastDot > 0) {
68
+ const name = filePath.substring(0, lastDot);
69
+ const ext = filePath.substring(lastDot);
70
+ processedPath = `${name}-{{timestamp}}${ext}`;
71
+ }
72
+ else {
73
+ processedPath = `${filePath}-{{timestamp}}`;
74
+ }
75
+ }
76
+ // Use FileManager to process timestamp templates
77
+ return file_manager_1.FileManager.processFilePath(processedPath);
78
+ }
79
+ static async finalizeOutputs(outputs, summary) {
80
+ for (const output of outputs) {
81
+ try {
82
+ await output.writeSummary(summary);
83
+ await output.finalize();
84
+ }
85
+ catch (error) {
86
+ logger_1.logger.warn('Output finalization failed:', error);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ exports.OutputHandlerFactory = OutputHandlerFactory;
@@ -0,0 +1,12 @@
1
+ import { TestConfiguration } from '../../config';
2
+ import { ProtocolHandler } from '../../protocols/base';
3
+ import { MetricsCollector } from '../../metrics/collector';
4
+ export declare class ProtocolHandlerFactory {
5
+ private config;
6
+ private metricsCollector?;
7
+ constructor(config: TestConfiguration, metricsCollector?: MetricsCollector);
8
+ createHandlers(): Promise<Map<string, ProtocolHandler>>;
9
+ private getRequiredProtocols;
10
+ private findWSDLUrl;
11
+ static cleanupHandlers(handlers: Map<string, ProtocolHandler>): Promise<void>;
12
+ }
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProtocolHandlerFactory = void 0;
4
+ const handler_1 = require("../../protocols/rest/handler");
5
+ const handler_2 = require("../../protocols/soap/handler");
6
+ const handler_3 = require("../../protocols/web/handler");
7
+ const logger_1 = require("../../utils/logger");
8
+ class ProtocolHandlerFactory {
9
+ constructor(config, metricsCollector) {
10
+ this.config = config;
11
+ this.metricsCollector = metricsCollector;
12
+ }
13
+ async createHandlers() {
14
+ const handlers = new Map();
15
+ const protocolsNeeded = this.getRequiredProtocols();
16
+ const debugConfig = this.config.debug || this.config.global?.debug;
17
+ // Initialize REST handler if needed
18
+ if (protocolsNeeded.has('rest')) {
19
+ const handler = new handler_1.RESTHandler(this.config.global?.base_url, this.config.global?.headers || {}, this.config.global?.timeout, debugConfig);
20
+ handlers.set('rest', handler);
21
+ logger_1.logger.debug('REST handler initialized');
22
+ }
23
+ // Initialize SOAP handler if needed
24
+ if (protocolsNeeded.has('soap')) {
25
+ const wsdlUrl = this.findWSDLUrl();
26
+ if (wsdlUrl) {
27
+ const handler = new handler_2.SOAPHandler(wsdlUrl);
28
+ await handler.initialize();
29
+ handlers.set('soap', handler);
30
+ logger_1.logger.debug('SOAP handler initialized');
31
+ }
32
+ }
33
+ // Initialize Web handler if needed
34
+ if (protocolsNeeded.has('web')) {
35
+ const browserConfig = this.config.global?.web || this.config.global?.browser || {};
36
+ const webConfig = {
37
+ type: browserConfig.type || 'chromium',
38
+ headless: browserConfig.headless ?? true,
39
+ base_url: browserConfig.base_url || this.config.global?.base_url,
40
+ viewport: browserConfig.viewport,
41
+ slow_mo: browserConfig.slow_mo,
42
+ highlight: browserConfig.highlight,
43
+ clear_storage: browserConfig.clear_storage,
44
+ screenshot_on_failure: browserConfig.screenshot_on_failure,
45
+ network_capture: browserConfig.network_capture
46
+ };
47
+ // Pass network call callback to record calls in InfluxDB
48
+ const networkCallCallback = this.metricsCollector
49
+ ? (call) => this.metricsCollector.recordNetworkCall(call)
50
+ : undefined;
51
+ const handler = new handler_3.WebHandler(webConfig, networkCallCallback);
52
+ await handler.initialize();
53
+ handlers.set('web', handler);
54
+ logger_1.logger.debug('Web handler initialized');
55
+ }
56
+ return handlers;
57
+ }
58
+ getRequiredProtocols() {
59
+ const protocols = new Set();
60
+ for (const scenario of this.config.scenarios) {
61
+ for (const step of scenario.steps) {
62
+ protocols.add(step.type || 'rest');
63
+ }
64
+ }
65
+ return protocols;
66
+ }
67
+ findWSDLUrl() {
68
+ // First check global config
69
+ if (this.config.global?.wsdl_url) {
70
+ return this.config.global.wsdl_url;
71
+ }
72
+ // Fallback: check individual steps (for backward compatibility)
73
+ for (const scenario of this.config.scenarios) {
74
+ for (const step of scenario.steps) {
75
+ if (step.type === 'soap' && 'wsdl' in step && step.wsdl) {
76
+ return step.wsdl;
77
+ }
78
+ }
79
+ }
80
+ return null;
81
+ }
82
+ static async cleanupHandlers(handlers) {
83
+ logger_1.logger.debug('Cleaning up handlers...');
84
+ for (const [name, handler] of handlers) {
85
+ try {
86
+ if (handler.cleanup) {
87
+ await handler.cleanup();
88
+ }
89
+ }
90
+ catch (error) {
91
+ logger_1.logger.warn(`Error cleaning up ${name} handler:`, error);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ exports.ProtocolHandlerFactory = ProtocolHandlerFactory;
@@ -1,7 +1,8 @@
1
1
  export { TestRunner } from './test-runner';
2
2
  export { VirtualUser } from './virtual-user';
3
3
  export { StepExecutor } from './step-executor';
4
- export { CSVDataProvider } from './csv-data-provider';
5
- export type { CSVDataRow } from './csv-data-provider';
6
4
  export { RendezvousManager } from './rendezvous';
7
5
  export type { RendezvousConfig, RendezvousResult, RendezvousStats } from './rendezvous';
6
+ export { DataProvider, DataManager, DataRow, DataResult, DataOptions, DataContext } from './data';
7
+ export { DataProvider as CSVDataProvider } from './data';
8
+ export type { DataRow as CSVDataRow } from './data';
@@ -1,13 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RendezvousManager = exports.CSVDataProvider = exports.StepExecutor = exports.VirtualUser = exports.TestRunner = void 0;
3
+ exports.CSVDataProvider = exports.DataManager = exports.DataProvider = exports.RendezvousManager = exports.StepExecutor = exports.VirtualUser = exports.TestRunner = void 0;
4
4
  var test_runner_1 = require("./test-runner");
5
5
  Object.defineProperty(exports, "TestRunner", { enumerable: true, get: function () { return test_runner_1.TestRunner; } });
6
6
  var virtual_user_1 = require("./virtual-user");
7
7
  Object.defineProperty(exports, "VirtualUser", { enumerable: true, get: function () { return virtual_user_1.VirtualUser; } });
8
8
  var step_executor_1 = require("./step-executor");
9
9
  Object.defineProperty(exports, "StepExecutor", { enumerable: true, get: function () { return step_executor_1.StepExecutor; } });
10
- var csv_data_provider_1 = require("./csv-data-provider");
11
- Object.defineProperty(exports, "CSVDataProvider", { enumerable: true, get: function () { return csv_data_provider_1.CSVDataProvider; } });
12
10
  var rendezvous_1 = require("./rendezvous");
13
11
  Object.defineProperty(exports, "RendezvousManager", { enumerable: true, get: function () { return rendezvous_1.RendezvousManager; } });
12
+ // Data exports
13
+ var data_1 = require("./data");
14
+ Object.defineProperty(exports, "DataProvider", { enumerable: true, get: function () { return data_1.DataProvider; } });
15
+ Object.defineProperty(exports, "DataManager", { enumerable: true, get: function () { return data_1.DataManager; } });
16
+ // Backward compatibility aliases
17
+ var data_2 = require("./data");
18
+ Object.defineProperty(exports, "CSVDataProvider", { enumerable: true, get: function () { return data_2.DataProvider; } });
@@ -0,0 +1,17 @@
1
+ import { MetricsCollector } from '../../metrics/collector';
2
+ import { VirtualUser } from '../virtual-user';
3
+ export interface DashboardReporterConfig {
4
+ testId: string;
5
+ testName: string;
6
+ }
7
+ export declare class DashboardReporter {
8
+ private testId;
9
+ private testName;
10
+ private dashboardInterval;
11
+ private lastReportedResultIndex;
12
+ private isRunning;
13
+ constructor(config: DashboardReporterConfig);
14
+ start(metrics: MetricsCollector, getActiveVUs: () => VirtualUser[], isRunningChecker: () => boolean): void;
15
+ stop(): void;
16
+ private outputProgress;
17
+ }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DashboardReporter = void 0;
4
+ const dashboard_1 = require("../../dashboard");
5
+ class DashboardReporter {
6
+ constructor(config) {
7
+ this.dashboardInterval = null;
8
+ this.lastReportedResultIndex = 0;
9
+ this.isRunning = false;
10
+ this.testId = config.testId;
11
+ this.testName = config.testName;
12
+ }
13
+ start(metrics, getActiveVUs, isRunningChecker) {
14
+ this.isRunning = true;
15
+ this.lastReportedResultIndex = 0;
16
+ const dashboard = (0, dashboard_1.getDashboard)();
17
+ // If running standalone (no dashboard singleton), output progress to stdout for dashboard parsing
18
+ const outputProgress = !dashboard && process.env.PERFORNIUM_PROGRESS !== '0';
19
+ if (dashboard) {
20
+ // Report initial state to in-process dashboard
21
+ dashboard.reportLiveUpdate(this.testId, {
22
+ id: this.testId,
23
+ name: this.testName,
24
+ startTime: new Date(),
25
+ status: 'running',
26
+ metrics: {
27
+ requests: 0,
28
+ errors: 0,
29
+ avgResponseTime: 0,
30
+ currentVUs: 0
31
+ }
32
+ });
33
+ }
34
+ // Track last request count to detect activity
35
+ let lastRequestCount = 0;
36
+ // Report updates every 500ms
37
+ this.dashboardInterval = setInterval(() => {
38
+ if (!isRunningChecker())
39
+ return;
40
+ const summary = metrics.getSummary();
41
+ const currentVUs = getActiveVUs().filter(vu => vu.isRunning()).length;
42
+ const currentRequests = summary.total_requests || 0;
43
+ // Skip reporting if VUs are 0 and no new requests (test is winding down)
44
+ const hasActivity = currentVUs > 0 || currentRequests > lastRequestCount;
45
+ lastRequestCount = currentRequests;
46
+ if (dashboard) {
47
+ dashboard.reportLiveUpdate(this.testId, {
48
+ metrics: {
49
+ requests: currentRequests,
50
+ errors: summary.failed_requests || 0,
51
+ avgResponseTime: summary.avg_response_time || 0,
52
+ currentVUs
53
+ }
54
+ });
55
+ }
56
+ // Output machine-readable progress for dashboard parsing (only when there's activity)
57
+ if (outputProgress && hasActivity) {
58
+ this.outputProgress(metrics, summary, currentVUs);
59
+ }
60
+ }, 500);
61
+ }
62
+ stop() {
63
+ this.isRunning = false;
64
+ if (this.dashboardInterval) {
65
+ clearInterval(this.dashboardInterval);
66
+ this.dashboardInterval = null;
67
+ }
68
+ const dashboard = (0, dashboard_1.getDashboard)();
69
+ if (dashboard) {
70
+ dashboard.reportTestComplete(this.testId);
71
+ }
72
+ }
73
+ outputProgress(metrics, summary, currentVUs) {
74
+ const currentRequests = summary.total_requests || 0;
75
+ const rps = summary.requests_per_second || 0;
76
+ const p50 = summary.percentiles?.[50] || 0;
77
+ const p90 = summary.percentiles?.[90] || 0;
78
+ const p95 = summary.percentiles?.[95] || 0;
79
+ const p99 = summary.percentiles?.[99] || 0;
80
+ const successRate = summary.success_rate || 0;
81
+ // Main progress line with percentiles
82
+ console.log(`[PROGRESS] VUs: ${currentVUs} | Requests: ${currentRequests} | Errors: ${summary.failed_requests || 0} | Avg RT: ${(summary.avg_response_time || 0).toFixed(0)}ms | RPS: ${rps.toFixed(1)} | P50: ${p50.toFixed(0)}ms | P90: ${p90.toFixed(0)}ms | P95: ${p95.toFixed(0)}ms | P99: ${p99.toFixed(0)}ms | Success: ${successRate.toFixed(1)}%`);
83
+ // Output step statistics if available
84
+ if (summary.step_statistics && summary.step_statistics.length > 0) {
85
+ const stepData = summary.step_statistics.map((s) => ({
86
+ n: s.step_name,
87
+ s: s.scenario,
88
+ r: s.total_requests,
89
+ e: s.failed_requests,
90
+ a: Math.round(s.avg_response_time),
91
+ p50: Math.round(s.percentiles?.[50] || 0),
92
+ p95: Math.round(s.percentiles?.[95] || 0),
93
+ p99: Math.round(s.percentiles?.[99] || 0),
94
+ sr: Math.round(s.success_rate * 10) / 10
95
+ }));
96
+ console.log(`[STEPS] ${JSON.stringify(stepData)}`);
97
+ }
98
+ // Output individual response times (last 50 new results)
99
+ const allResults = metrics.getResults();
100
+ if (allResults.length > this.lastReportedResultIndex) {
101
+ const newResults = allResults.slice(this.lastReportedResultIndex, this.lastReportedResultIndex + 50);
102
+ const rtData = newResults.map(r => ({
103
+ t: r.timestamp,
104
+ v: Math.round(r.duration),
105
+ s: r.success ? 1 : 0,
106
+ n: r.step_name || r.action || 'unknown'
107
+ }));
108
+ if (rtData.length > 0) {
109
+ console.log(`[RT] ${JSON.stringify(rtData)}`);
110
+ }
111
+ this.lastReportedResultIndex = Math.min(allResults.length, this.lastReportedResultIndex + 50);
112
+ }
113
+ // Output top 10 errors if any
114
+ if (summary.error_details && summary.error_details.length > 0) {
115
+ const topErrors = summary.error_details.slice(0, 10).map((e) => ({
116
+ scenario: e.scenario,
117
+ action: e.action,
118
+ status: e.status,
119
+ error: e.error?.substring(0, 200),
120
+ url: e.request_url,
121
+ count: e.count
122
+ }));
123
+ console.log(`[ERRORS] ${JSON.stringify(topErrors)}`);
124
+ }
125
+ }
126
+ }
127
+ exports.DashboardReporter = DashboardReporter;
@@ -0,0 +1 @@
1
+ export { DashboardReporter, DashboardReporterConfig } from './dashboard-reporter';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DashboardReporter = void 0;
4
+ var dashboard_reporter_1 = require("./dashboard-reporter");
5
+ Object.defineProperty(exports, "DashboardReporter", { enumerable: true, get: function () { return dashboard_reporter_1.DashboardReporter; } });
@@ -5,26 +5,17 @@ export declare class StepExecutor {
5
5
  private handlers;
6
6
  private templateProcessor;
7
7
  private testName;
8
+ private checkEvaluator;
9
+ private dataExtractor;
10
+ private jsonPayloadProcessor;
8
11
  constructor(handlers: Map<string, ProtocolHandler>, testName?: string);
9
12
  executeStep(step: Step, context: VUContext, scenarioName: string): Promise<TestResult>;
13
+ private createErrorResult;
10
14
  executeStepInternal(step: Step, context: VUContext, scenarioName: string, startTime: number): Promise<TestResult>;
15
+ private createSkippedResult;
16
+ private buildTestResult;
11
17
  private shouldRecordStep;
12
18
  private executeRESTStep;
13
- /**
14
- * Load JSON payload from file and apply overrides
15
- * Supports dot notation for nested paths in overrides
16
- */
17
- private processJsonFile;
18
- /**
19
- * Apply overrides to a JSON object using dot notation for nested paths
20
- * Override values are processed through the template processor
21
- */
22
- private applyOverrides;
23
- /**
24
- * Set a value at a nested path using dot notation
25
- * Example: setNestedValue(obj, 'user.profile.name', 'John')
26
- */
27
- private setNestedValue;
28
19
  private executeSOAPStep;
29
20
  private executeWebStep;
30
21
  private executeCustomStep;
@@ -34,9 +25,4 @@ export declare class StepExecutor {
34
25
  private executeScript;
35
26
  private evaluateCondition;
36
27
  private processTemplate;
37
- private runChecks;
38
- private checkCustom;
39
- private extractData;
40
- private extractCustom;
41
- private getJsonPath;
42
28
  }