@testsmith/perfornium 0.1.0

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 (164) hide show
  1. package/README.md +360 -0
  2. package/dist/cli/cli.d.ts +2 -0
  3. package/dist/cli/cli.js +192 -0
  4. package/dist/cli/commands/distributed.d.ts +11 -0
  5. package/dist/cli/commands/distributed.js +179 -0
  6. package/dist/cli/commands/import.d.ts +23 -0
  7. package/dist/cli/commands/import.js +461 -0
  8. package/dist/cli/commands/init.d.ts +7 -0
  9. package/dist/cli/commands/init.js +923 -0
  10. package/dist/cli/commands/mock.d.ts +7 -0
  11. package/dist/cli/commands/mock.js +281 -0
  12. package/dist/cli/commands/report.d.ts +5 -0
  13. package/dist/cli/commands/report.js +70 -0
  14. package/dist/cli/commands/run.d.ts +12 -0
  15. package/dist/cli/commands/run.js +260 -0
  16. package/dist/cli/commands/validate.d.ts +3 -0
  17. package/dist/cli/commands/validate.js +35 -0
  18. package/dist/cli/commands/worker.d.ts +27 -0
  19. package/dist/cli/commands/worker.js +320 -0
  20. package/dist/config/index.d.ts +2 -0
  21. package/dist/config/index.js +20 -0
  22. package/dist/config/parser.d.ts +19 -0
  23. package/dist/config/parser.js +330 -0
  24. package/dist/config/types/global-config.d.ts +74 -0
  25. package/dist/config/types/global-config.js +2 -0
  26. package/dist/config/types/hooks.d.ts +58 -0
  27. package/dist/config/types/hooks.js +3 -0
  28. package/dist/config/types/import-types.d.ts +33 -0
  29. package/dist/config/types/import-types.js +2 -0
  30. package/dist/config/types/index.d.ts +11 -0
  31. package/dist/config/types/index.js +27 -0
  32. package/dist/config/types/load-config.d.ts +32 -0
  33. package/dist/config/types/load-config.js +9 -0
  34. package/dist/config/types/output-config.d.ts +10 -0
  35. package/dist/config/types/output-config.js +2 -0
  36. package/dist/config/types/report-config.d.ts +10 -0
  37. package/dist/config/types/report-config.js +2 -0
  38. package/dist/config/types/runtime-types.d.ts +6 -0
  39. package/dist/config/types/runtime-types.js +2 -0
  40. package/dist/config/types/scenario-config.d.ts +30 -0
  41. package/dist/config/types/scenario-config.js +2 -0
  42. package/dist/config/types/step-types.d.ts +139 -0
  43. package/dist/config/types/step-types.js +2 -0
  44. package/dist/config/types/test-configuration.d.ts +18 -0
  45. package/dist/config/types/test-configuration.js +2 -0
  46. package/dist/config/types/worker-config.d.ts +12 -0
  47. package/dist/config/types/worker-config.js +2 -0
  48. package/dist/config/validator.d.ts +19 -0
  49. package/dist/config/validator.js +198 -0
  50. package/dist/core/csv-data-provider.d.ts +47 -0
  51. package/dist/core/csv-data-provider.js +265 -0
  52. package/dist/core/hooks-manager.d.ts +33 -0
  53. package/dist/core/hooks-manager.js +129 -0
  54. package/dist/core/index.d.ts +5 -0
  55. package/dist/core/index.js +11 -0
  56. package/dist/core/script-executor.d.ts +14 -0
  57. package/dist/core/script-executor.js +290 -0
  58. package/dist/core/step-executor.d.ts +41 -0
  59. package/dist/core/step-executor.js +680 -0
  60. package/dist/core/test-runner.d.ts +34 -0
  61. package/dist/core/test-runner.js +465 -0
  62. package/dist/core/threshold-evaluator.d.ts +43 -0
  63. package/dist/core/threshold-evaluator.js +170 -0
  64. package/dist/core/virtual-user-pool.d.ts +42 -0
  65. package/dist/core/virtual-user-pool.js +136 -0
  66. package/dist/core/virtual-user.d.ts +51 -0
  67. package/dist/core/virtual-user.js +488 -0
  68. package/dist/distributed/coordinator.d.ts +34 -0
  69. package/dist/distributed/coordinator.js +158 -0
  70. package/dist/distributed/health-monitor.d.ts +18 -0
  71. package/dist/distributed/health-monitor.js +72 -0
  72. package/dist/distributed/load-distributor.d.ts +17 -0
  73. package/dist/distributed/load-distributor.js +106 -0
  74. package/dist/distributed/remote-worker.d.ts +37 -0
  75. package/dist/distributed/remote-worker.js +241 -0
  76. package/dist/distributed/result-aggregator.d.ts +43 -0
  77. package/dist/distributed/result-aggregator.js +146 -0
  78. package/dist/dsl/index.d.ts +3 -0
  79. package/dist/dsl/index.js +11 -0
  80. package/dist/dsl/test-builder.d.ts +111 -0
  81. package/dist/dsl/test-builder.js +514 -0
  82. package/dist/importers/har-importer.d.ts +17 -0
  83. package/dist/importers/har-importer.js +172 -0
  84. package/dist/importers/open-api-importer.d.ts +23 -0
  85. package/dist/importers/open-api-importer.js +181 -0
  86. package/dist/importers/wsdl-importer.d.ts +42 -0
  87. package/dist/importers/wsdl-importer.js +440 -0
  88. package/dist/index.d.ts +5 -0
  89. package/dist/index.js +17 -0
  90. package/dist/load-patterns/arrivals.d.ts +7 -0
  91. package/dist/load-patterns/arrivals.js +118 -0
  92. package/dist/load-patterns/base.d.ts +9 -0
  93. package/dist/load-patterns/base.js +2 -0
  94. package/dist/load-patterns/basic.d.ts +7 -0
  95. package/dist/load-patterns/basic.js +117 -0
  96. package/dist/load-patterns/stepping.d.ts +6 -0
  97. package/dist/load-patterns/stepping.js +122 -0
  98. package/dist/metrics/collector.d.ts +72 -0
  99. package/dist/metrics/collector.js +662 -0
  100. package/dist/metrics/types.d.ts +135 -0
  101. package/dist/metrics/types.js +2 -0
  102. package/dist/outputs/base.d.ts +7 -0
  103. package/dist/outputs/base.js +2 -0
  104. package/dist/outputs/csv.d.ts +13 -0
  105. package/dist/outputs/csv.js +163 -0
  106. package/dist/outputs/graphite.d.ts +13 -0
  107. package/dist/outputs/graphite.js +126 -0
  108. package/dist/outputs/influxdb.d.ts +12 -0
  109. package/dist/outputs/influxdb.js +82 -0
  110. package/dist/outputs/json.d.ts +14 -0
  111. package/dist/outputs/json.js +107 -0
  112. package/dist/outputs/streaming-csv.d.ts +37 -0
  113. package/dist/outputs/streaming-csv.js +254 -0
  114. package/dist/outputs/streaming-json.d.ts +43 -0
  115. package/dist/outputs/streaming-json.js +353 -0
  116. package/dist/outputs/webhook.d.ts +16 -0
  117. package/dist/outputs/webhook.js +96 -0
  118. package/dist/protocols/base.d.ts +33 -0
  119. package/dist/protocols/base.js +2 -0
  120. package/dist/protocols/rest/handler.d.ts +67 -0
  121. package/dist/protocols/rest/handler.js +776 -0
  122. package/dist/protocols/soap/handler.d.ts +12 -0
  123. package/dist/protocols/soap/handler.js +165 -0
  124. package/dist/protocols/web/core-web-vitals.d.ts +121 -0
  125. package/dist/protocols/web/core-web-vitals.js +373 -0
  126. package/dist/protocols/web/handler.d.ts +50 -0
  127. package/dist/protocols/web/handler.js +706 -0
  128. package/dist/recorder/native-recorder.d.ts +14 -0
  129. package/dist/recorder/native-recorder.js +533 -0
  130. package/dist/recorder/scenario-recorder.d.ts +55 -0
  131. package/dist/recorder/scenario-recorder.js +296 -0
  132. package/dist/reporting/constants.d.ts +94 -0
  133. package/dist/reporting/constants.js +82 -0
  134. package/dist/reporting/enhanced-html-generator.d.ts +55 -0
  135. package/dist/reporting/enhanced-html-generator.js +965 -0
  136. package/dist/reporting/generator.d.ts +42 -0
  137. package/dist/reporting/generator.js +1217 -0
  138. package/dist/reporting/statistics.d.ts +144 -0
  139. package/dist/reporting/statistics.js +742 -0
  140. package/dist/reporting/templates/enhanced-report.hbs +2812 -0
  141. package/dist/reporting/templates/html.hbs +2453 -0
  142. package/dist/utils/faker-manager.d.ts +55 -0
  143. package/dist/utils/faker-manager.js +166 -0
  144. package/dist/utils/file-manager.d.ts +33 -0
  145. package/dist/utils/file-manager.js +154 -0
  146. package/dist/utils/handlebars-manager.d.ts +42 -0
  147. package/dist/utils/handlebars-manager.js +172 -0
  148. package/dist/utils/logger.d.ts +16 -0
  149. package/dist/utils/logger.js +46 -0
  150. package/dist/utils/template.d.ts +80 -0
  151. package/dist/utils/template.js +513 -0
  152. package/dist/utils/test-output-writer.d.ts +56 -0
  153. package/dist/utils/test-output-writer.js +643 -0
  154. package/dist/utils/time.d.ts +3 -0
  155. package/dist/utils/time.js +23 -0
  156. package/dist/utils/timestamp-helper.d.ts +17 -0
  157. package/dist/utils/timestamp-helper.js +53 -0
  158. package/dist/workers/manager.d.ts +18 -0
  159. package/dist/workers/manager.js +95 -0
  160. package/dist/workers/server.d.ts +21 -0
  161. package/dist/workers/server.js +205 -0
  162. package/dist/workers/worker.d.ts +19 -0
  163. package/dist/workers/worker.js +147 -0
  164. package/package.json +102 -0
@@ -0,0 +1,135 @@
1
+ export interface TestResult {
2
+ shouldRecord?: any;
3
+ id?: string;
4
+ vu_id: number;
5
+ iteration?: number;
6
+ scenario: string;
7
+ name?: string;
8
+ action?: string;
9
+ step_name?: string;
10
+ thread_name?: string;
11
+ timestamp: number;
12
+ sample_start?: number;
13
+ duration?: number;
14
+ response_time?: number;
15
+ success: boolean;
16
+ status?: number;
17
+ status_text?: string;
18
+ error?: string;
19
+ error_code?: string;
20
+ response_size?: number;
21
+ response_headers?: Record<string, string>;
22
+ response_body?: string;
23
+ request_url?: string;
24
+ request_method?: string;
25
+ request_headers?: Record<string, string>;
26
+ request_body?: string;
27
+ connect_time?: number;
28
+ latency?: number;
29
+ sent_bytes?: number;
30
+ headers_size_sent?: number;
31
+ body_size_sent?: number;
32
+ headers_size_received?: number;
33
+ body_size_received?: number;
34
+ data_type?: 'text' | 'bin' | '';
35
+ custom_metrics?: Record<string, any>;
36
+ }
37
+ export interface VUStartEvent {
38
+ vu_id: number;
39
+ start_time: number;
40
+ load_pattern: string;
41
+ }
42
+ export interface StepStatistics {
43
+ step_name: string;
44
+ scenario: string;
45
+ total_requests: number;
46
+ successful_requests: number;
47
+ failed_requests: number;
48
+ success_rate: number;
49
+ avg_response_time: number;
50
+ min_response_time: number;
51
+ max_response_time: number;
52
+ percentiles: Record<number, number>;
53
+ response_times: number[];
54
+ error_distribution: Record<string, number>;
55
+ status_distribution: Record<number, number>;
56
+ }
57
+ export interface TestSummary {
58
+ total_requests: number;
59
+ successful_requests: number;
60
+ failed_requests: number;
61
+ success_rate: number;
62
+ avg_response_time: number;
63
+ min_response_time: number;
64
+ max_response_time: number;
65
+ percentiles: Record<string, number>;
66
+ requests_per_second: number;
67
+ bytes_per_second: number;
68
+ bytes_received?: number;
69
+ total_duration: number;
70
+ error_distribution?: Record<string, number>;
71
+ status_distribution: Record<number, number>;
72
+ error_details: ErrorDetail[];
73
+ }
74
+ export interface MetricsSummary {
75
+ total_requests: number;
76
+ successful_requests: number;
77
+ failed_requests: number;
78
+ success_rate: number;
79
+ avg_response_time: number;
80
+ min_response_time: number;
81
+ max_response_time: number;
82
+ percentiles: Record<number, number>;
83
+ requests_per_second: number;
84
+ bytes_per_second: number;
85
+ total_duration: number;
86
+ error_distribution: Record<string, number>;
87
+ status_distribution: Record<number, number>;
88
+ error_details: ErrorDetail[];
89
+ step_statistics: StepStatistics[];
90
+ vu_ramp_up: VUStartEvent[];
91
+ timeline_data: TimelineData[];
92
+ web_vitals_data?: {
93
+ lcp?: number;
94
+ fid?: number;
95
+ cls?: number;
96
+ fcp?: number;
97
+ ttfb?: number;
98
+ tti?: number;
99
+ tbt?: number;
100
+ speedIndex?: number;
101
+ };
102
+ vitals_score?: 'good' | 'needs-improvement' | 'poor';
103
+ vitals_details?: Record<string, {
104
+ value: number;
105
+ score: 'good' | 'needs-improvement' | 'poor';
106
+ }>;
107
+ verification_metrics?: {
108
+ total_verifications: number;
109
+ success_rate: number;
110
+ average_duration: number;
111
+ p95_duration: number;
112
+ slowest_step: any;
113
+ fastest_step: any;
114
+ };
115
+ }
116
+ export interface TimelineData {
117
+ timestamp: number;
118
+ time_label: string;
119
+ active_vus: number;
120
+ requests_count: number;
121
+ avg_response_time: number;
122
+ success_rate: number;
123
+ throughput: number;
124
+ }
125
+ export interface ErrorDetail {
126
+ timestamp: number;
127
+ vu_id: number;
128
+ scenario: string;
129
+ action: string;
130
+ status?: number;
131
+ error: string;
132
+ request_url?: string;
133
+ response_body?: string;
134
+ count: number;
135
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ import { TestResult, MetricsSummary } from '../metrics/types';
2
+ export interface OutputHandler {
3
+ initialize(): Promise<void>;
4
+ writeResult(result: TestResult): Promise<void>;
5
+ writeSummary(summary: MetricsSummary): Promise<void>;
6
+ finalize(): Promise<void>;
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ import { OutputHandler } from './base';
2
+ import { TestResult, MetricsSummary } from '../metrics/types';
3
+ export declare class CSVOutput implements OutputHandler {
4
+ private filePath;
5
+ private csvWriter;
6
+ private results;
7
+ constructor(filePath: string);
8
+ initialize(): Promise<void>;
9
+ writeResult(result: TestResult): Promise<void>;
10
+ private transformResult;
11
+ writeSummary(summary: MetricsSummary): Promise<void>;
12
+ finalize(): Promise<void>;
13
+ }
@@ -0,0 +1,163 @@
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.CSVOutput = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const csv_writer_1 = require("csv-writer");
40
+ class CSVOutput {
41
+ constructor(filePath) {
42
+ this.results = [];
43
+ this.filePath = filePath;
44
+ }
45
+ async initialize() {
46
+ // Ensure directory exists
47
+ const dir = path.dirname(this.filePath);
48
+ if (!fs.existsSync(dir)) {
49
+ fs.mkdirSync(dir, { recursive: true });
50
+ }
51
+ this.csvWriter = (0, csv_writer_1.createObjectCsvWriter)({
52
+ path: this.filePath,
53
+ header: [
54
+ { id: 'timestamp', title: 'timestamp' },
55
+ { id: 'vu_id', title: 'vu_id' },
56
+ { id: 'iteration', title: 'iteration' },
57
+ { id: 'scenario', title: 'scenario' },
58
+ { id: 'action', title: 'action' },
59
+ { id: 'step_name', title: 'step_name' },
60
+ { id: 'duration', title: 'duration_ms' },
61
+ { id: 'success', title: 'success' },
62
+ { id: 'status', title: 'http_status' },
63
+ { id: 'error', title: 'error' },
64
+ { id: 'response_size', title: 'response_size_bytes' },
65
+ // JMeter-style metrics
66
+ { id: 'latency', title: 'latency_ms' },
67
+ { id: 'connect_time', title: 'connect_time_ms' },
68
+ { id: 'sent_bytes', title: 'sent_bytes' },
69
+ { id: 'data_type', title: 'data_type' },
70
+ // Web Vitals columns
71
+ { id: 'lcp', title: 'lcp_ms' },
72
+ { id: 'cls', title: 'cls_score' },
73
+ { id: 'inp', title: 'inp_ms' },
74
+ { id: 'ttfb', title: 'ttfb_ms' },
75
+ { id: 'fcp', title: 'fcp_ms' },
76
+ { id: 'fid', title: 'fid_ms' },
77
+ { id: 'vitals_score', title: 'vitals_score' },
78
+ // Verification metrics
79
+ { id: 'verification_duration', title: 'verification_duration_ms' },
80
+ { id: 'verification_success', title: 'verification_success' },
81
+ { id: 'verification_step_name', title: 'verification_step_name' },
82
+ // Page info
83
+ { id: 'page_url', title: 'page_url' },
84
+ { id: 'page_title', title: 'page_title' }
85
+ ]
86
+ });
87
+ }
88
+ async writeResult(result) {
89
+ // Write immediately to file (incremental during test)
90
+ this.results.push(result); // Keep for finalize summary
91
+ // Transform and write single result
92
+ const record = this.transformResult(result);
93
+ await this.csvWriter.writeRecords([record]);
94
+ }
95
+ transformResult(result) {
96
+ return {
97
+ timestamp: result.timestamp,
98
+ vu_id: result.vu_id,
99
+ iteration: result.iteration,
100
+ scenario: result.scenario,
101
+ action: result.action,
102
+ step_name: result.step_name || result.action,
103
+ duration: result.duration,
104
+ success: result.success,
105
+ status: result.status,
106
+ error: result.error || '',
107
+ response_size: result.response_size || 0,
108
+ // JMeter-style metrics
109
+ latency: result.latency || 0,
110
+ connect_time: result.connect_time || 0,
111
+ sent_bytes: result.sent_bytes || 0,
112
+ data_type: result.data_type || '',
113
+ // Web Vitals
114
+ lcp: result.custom_metrics?.web_vitals?.lcp || null,
115
+ cls: result.custom_metrics?.web_vitals?.cls || null,
116
+ inp: result.custom_metrics?.web_vitals?.inp || null,
117
+ ttfb: result.custom_metrics?.web_vitals?.ttfb || null,
118
+ fcp: result.custom_metrics?.web_vitals?.fcp || null,
119
+ fid: result.custom_metrics?.web_vitals?.fid || null,
120
+ vitals_score: result.custom_metrics?.web_vitals?.score || null,
121
+ // Verification
122
+ verification_duration: result.custom_metrics?.verification?.duration || null,
123
+ verification_success: result.custom_metrics?.verification?.success || null,
124
+ verification_step_name: result.custom_metrics?.verification?.step_name || null,
125
+ // Page info
126
+ page_url: result.custom_metrics?.page_url || null,
127
+ page_title: result.custom_metrics?.page_title || null
128
+ };
129
+ }
130
+ async writeSummary(summary) {
131
+ // Summary will be written to a separate file
132
+ const summaryPath = this.filePath.replace('.csv', '_summary.csv');
133
+ const summaryWriter = (0, csv_writer_1.createObjectCsvWriter)({
134
+ path: summaryPath,
135
+ header: [
136
+ { id: 'metric', title: 'metric' },
137
+ { id: 'value', title: 'value' },
138
+ { id: 'unit', title: 'unit' }
139
+ ]
140
+ });
141
+ const summaryData = [
142
+ { metric: 'total_requests', value: summary.total_requests, unit: 'count' },
143
+ { metric: 'successful_requests', value: summary.successful_requests, unit: 'count' },
144
+ { metric: 'failed_requests', value: summary.failed_requests, unit: 'count' },
145
+ { metric: 'success_rate', value: summary.success_rate.toFixed(2), unit: 'percent' },
146
+ { metric: 'avg_response_time', value: summary.avg_response_time.toFixed(2), unit: 'ms' },
147
+ { metric: 'min_response_time', value: summary.min_response_time, unit: 'ms' },
148
+ { metric: 'max_response_time', value: summary.max_response_time, unit: 'ms' },
149
+ { metric: 'requests_per_second', value: summary.requests_per_second.toFixed(2), unit: 'req/s' },
150
+ { metric: 'total_duration', value: summary.total_duration, unit: 'ms' },
151
+ { metric: 'p50_response_time', value: summary.percentiles[50] || 0, unit: 'ms' },
152
+ { metric: 'p90_response_time', value: summary.percentiles[90] || 0, unit: 'ms' },
153
+ { metric: 'p95_response_time', value: summary.percentiles[95] || 0, unit: 'ms' },
154
+ { metric: 'p99_response_time', value: summary.percentiles[99] || 0, unit: 'ms' }
155
+ ];
156
+ await summaryWriter.writeRecords(summaryData);
157
+ }
158
+ async finalize() {
159
+ // Results already written incrementally during test
160
+ // No need to write them again
161
+ }
162
+ }
163
+ exports.CSVOutput = CSVOutput;
@@ -0,0 +1,13 @@
1
+ import { OutputHandler } from './base';
2
+ import { TestResult, MetricsSummary } from '../metrics/types';
3
+ export declare class GraphiteOutput implements OutputHandler {
4
+ private host;
5
+ private port;
6
+ private prefix;
7
+ private client?;
8
+ constructor(host?: string, port?: number, prefix?: string);
9
+ initialize(): Promise<void>;
10
+ writeResult(result: TestResult): Promise<void>;
11
+ writeSummary(summary: MetricsSummary): Promise<void>;
12
+ finalize(): Promise<void>;
13
+ }
@@ -0,0 +1,126 @@
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.GraphiteOutput = void 0;
37
+ const net = __importStar(require("net"));
38
+ const logger_1 = require("../utils/logger");
39
+ class GraphiteOutput {
40
+ constructor(host = 'localhost', port = 2003, prefix = 'perfornium') {
41
+ this.host = host;
42
+ this.port = port;
43
+ this.prefix = prefix;
44
+ }
45
+ async initialize() {
46
+ try {
47
+ this.client = new net.Socket();
48
+ return new Promise((resolve, reject) => {
49
+ const timeout = setTimeout(() => {
50
+ reject(new Error('Graphite connection timeout'));
51
+ }, 5000);
52
+ this.client.connect(this.port, this.host, () => {
53
+ clearTimeout(timeout);
54
+ logger_1.logger.debug(`📊 Connected to Graphite at ${this.host}:${this.port}`);
55
+ resolve();
56
+ });
57
+ this.client.on('error', (error) => {
58
+ clearTimeout(timeout);
59
+ logger_1.logger.warn('⚠️ Graphite connection error:', error);
60
+ reject(error);
61
+ });
62
+ });
63
+ }
64
+ catch (error) {
65
+ logger_1.logger.warn('⚠️ Failed to connect to Graphite:', error);
66
+ throw error;
67
+ }
68
+ }
69
+ async writeResult(result) {
70
+ if (!this.client || this.client.destroyed) {
71
+ return; // Skip if not connected
72
+ }
73
+ try {
74
+ const timestamp = Math.floor(result.timestamp / 1000);
75
+ const metricPrefix = `${this.prefix}.${result.scenario}.${result.action}`;
76
+ const metrics = [
77
+ `${metricPrefix}.duration ${result.duration} ${timestamp}`,
78
+ `${metricPrefix}.success ${result.success ? 1 : 0} ${timestamp}`
79
+ ];
80
+ if (result.status) {
81
+ metrics.push(`${metricPrefix}.status ${result.status} ${timestamp}`);
82
+ }
83
+ if (result.response_size) {
84
+ metrics.push(`${metricPrefix}.response_size ${result.response_size} ${timestamp}`);
85
+ }
86
+ const data = metrics.join('\n') + '\n';
87
+ this.client.write(data);
88
+ }
89
+ catch (error) {
90
+ logger_1.logger.warn('⚠️ Failed to write to Graphite:', error);
91
+ }
92
+ }
93
+ async writeSummary(summary) {
94
+ if (!this.client || this.client.destroyed) {
95
+ return;
96
+ }
97
+ try {
98
+ const timestamp = Math.floor(Date.now() / 1000);
99
+ const summaryPrefix = `${this.prefix}.summary`;
100
+ const metrics = [
101
+ `${summaryPrefix}.total_requests ${summary.total_requests} ${timestamp}`,
102
+ `${summaryPrefix}.successful_requests ${summary.successful_requests} ${timestamp}`,
103
+ `${summaryPrefix}.failed_requests ${summary.failed_requests} ${timestamp}`,
104
+ `${summaryPrefix}.success_rate ${summary.success_rate} ${timestamp}`,
105
+ `${summaryPrefix}.avg_response_time ${summary.avg_response_time} ${timestamp}`,
106
+ `${summaryPrefix}.requests_per_second ${summary.requests_per_second} ${timestamp}`,
107
+ `${summaryPrefix}.total_duration ${summary.total_duration} ${timestamp}`
108
+ ];
109
+ // Add percentiles
110
+ Object.entries(summary.percentiles).forEach(([percentile, value]) => {
111
+ metrics.push(`${summaryPrefix}.p${percentile} ${value} ${timestamp}`);
112
+ });
113
+ const data = metrics.join('\n') + '\n';
114
+ this.client.write(data);
115
+ }
116
+ catch (error) {
117
+ logger_1.logger.warn('⚠️ Failed to write summary to Graphite:', error);
118
+ }
119
+ }
120
+ async finalize() {
121
+ if (this.client && !this.client.destroyed) {
122
+ this.client.end();
123
+ }
124
+ }
125
+ }
126
+ exports.GraphiteOutput = GraphiteOutput;
@@ -0,0 +1,12 @@
1
+ import { OutputHandler } from './base';
2
+ import { TestResult, MetricsSummary } from '../metrics/types';
3
+ export declare class InfluxDBOutput implements OutputHandler {
4
+ private client;
5
+ private database;
6
+ private tags;
7
+ constructor(url: string, database: string, tags?: Record<string, string>);
8
+ initialize(): Promise<void>;
9
+ writeResult(result: TestResult): Promise<void>;
10
+ writeSummary(summary: MetricsSummary): Promise<void>;
11
+ finalize(): Promise<void>;
12
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InfluxDBOutput = void 0;
4
+ const influx_1 = require("influx");
5
+ const logger_1 = require("../utils/logger");
6
+ class InfluxDBOutput {
7
+ constructor(url, database, tags = {}) {
8
+ this.client = new influx_1.InfluxDB(url);
9
+ this.database = database;
10
+ this.tags = tags;
11
+ }
12
+ async initialize() {
13
+ try {
14
+ const databases = await this.client.getDatabaseNames();
15
+ if (!databases.includes(this.database)) {
16
+ await this.client.createDatabase(this.database);
17
+ }
18
+ logger_1.logger.debug(`📊 InfluxDB output initialized: ${this.database}`);
19
+ }
20
+ catch (error) {
21
+ logger_1.logger.warn('⚠️ Could not initialize InfluxDB:', error);
22
+ throw error;
23
+ }
24
+ }
25
+ async writeResult(result) {
26
+ try {
27
+ const point = {
28
+ measurement: 'performance_test',
29
+ tags: {
30
+ ...this.tags,
31
+ scenario: result.scenario,
32
+ action: result.action,
33
+ success: result.success.toString(),
34
+ vu_id: result.vu_id.toString()
35
+ },
36
+ fields: {
37
+ duration: result.duration,
38
+ response_size: result.response_size || 0,
39
+ status: result.status || 0
40
+ },
41
+ timestamp: new Date(result.timestamp)
42
+ };
43
+ if (result.error) {
44
+ point.tags.error = result.error;
45
+ }
46
+ await this.client.writePoints([point], { database: this.database });
47
+ }
48
+ catch (error) {
49
+ logger_1.logger.warn('⚠️ Could not write to InfluxDB:', error);
50
+ }
51
+ }
52
+ async writeSummary(summary) {
53
+ try {
54
+ const summaryPoints = [
55
+ {
56
+ measurement: 'test_summary',
57
+ tags: this.tags,
58
+ fields: {
59
+ total_requests: summary.total_requests,
60
+ successful_requests: summary.successful_requests,
61
+ failed_requests: summary.failed_requests,
62
+ success_rate: summary.success_rate,
63
+ avg_response_time: summary.avg_response_time,
64
+ min_response_time: summary.min_response_time,
65
+ max_response_time: summary.max_response_time,
66
+ requests_per_second: summary.requests_per_second,
67
+ total_duration: summary.total_duration
68
+ },
69
+ timestamp: new Date()
70
+ }
71
+ ];
72
+ await this.client.writePoints(summaryPoints, { database: this.database });
73
+ }
74
+ catch (error) {
75
+ logger_1.logger.warn('⚠️ Could not write summary to InfluxDB:', error);
76
+ }
77
+ }
78
+ async finalize() {
79
+ // InfluxDB doesn't need explicit finalization
80
+ }
81
+ }
82
+ exports.InfluxDBOutput = InfluxDBOutput;
@@ -0,0 +1,14 @@
1
+ import { OutputHandler } from './base';
2
+ import { TestResult, MetricsSummary } from '../metrics/types';
3
+ export declare class JSONOutput implements OutputHandler {
4
+ private filePath;
5
+ private results;
6
+ private summary?;
7
+ private fileStream?;
8
+ private firstWrite;
9
+ constructor(filePath: string);
10
+ initialize(): Promise<void>;
11
+ writeResult(result: TestResult): Promise<void>;
12
+ writeSummary(summary: MetricsSummary): Promise<void>;
13
+ finalize(): Promise<void>;
14
+ }