@artilleryio/int-core 2.24.0 → 2.25.0-37061d0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/engine_http.js +106 -6
- package/lib/engine_socketio.js +4 -0
- package/lib/runner.js +22 -1
- package/package.json +5 -5
package/lib/engine_http.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
const async = require('async');
|
|
6
6
|
const _ = require('lodash');
|
|
7
|
-
const request = require('got');
|
|
8
7
|
const tough = require('tough-cookie');
|
|
9
8
|
const debug = require('debug')('http');
|
|
10
9
|
const debugRequests = require('debug')('http:request');
|
|
@@ -30,6 +29,30 @@ const crypto = require('node:crypto');
|
|
|
30
29
|
|
|
31
30
|
module.exports = HttpEngine;
|
|
32
31
|
|
|
32
|
+
const GOT_OPTION_NAMES = [
|
|
33
|
+
'url',
|
|
34
|
+
'searchParams',
|
|
35
|
+
'method',
|
|
36
|
+
'headers',
|
|
37
|
+
'body',
|
|
38
|
+
'json',
|
|
39
|
+
'form',
|
|
40
|
+
'allowGetBody',
|
|
41
|
+
'timeout',
|
|
42
|
+
'retry',
|
|
43
|
+
'encoding',
|
|
44
|
+
'cookieJar',
|
|
45
|
+
'followRedirect',
|
|
46
|
+
'maxRedirects',
|
|
47
|
+
'decompress',
|
|
48
|
+
'http2',
|
|
49
|
+
'agent',
|
|
50
|
+
'username',
|
|
51
|
+
'password',
|
|
52
|
+
'https',
|
|
53
|
+
'throwHttpErrors'
|
|
54
|
+
];
|
|
55
|
+
|
|
33
56
|
const DEFAULT_AGENT_OPTIONS = {
|
|
34
57
|
keepAlive: true,
|
|
35
58
|
keepAliveMsec: 1000
|
|
@@ -126,6 +149,66 @@ function HttpEngine(script) {
|
|
|
126
149
|
}
|
|
127
150
|
}
|
|
128
151
|
|
|
152
|
+
HttpEngine.prototype.init = async function () {
|
|
153
|
+
this.request = (await import('got')).default;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
HttpEngine.prototype._isDistributedTracingEnabled = function (config) {
|
|
157
|
+
const dtConfig = config.http?.distributedTracing;
|
|
158
|
+
if (!dtConfig) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Handle both boolean and object forms
|
|
163
|
+
if (typeof dtConfig === 'boolean') {
|
|
164
|
+
return dtConfig;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (typeof dtConfig === 'object' && dtConfig.enabled !== undefined) {
|
|
168
|
+
return dtConfig.enabled;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Default to true if distributedTracing is set but enabled is not specified
|
|
172
|
+
return true;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
HttpEngine.prototype._generateTraceparent = function (config) {
|
|
176
|
+
// W3C Trace Context format: version-trace-id-parent-id-trace-flags
|
|
177
|
+
const version = '00';
|
|
178
|
+
|
|
179
|
+
// Get configuration
|
|
180
|
+
const dtConfig = config.http?.distributedTracing;
|
|
181
|
+
let sampled = true; // Default to sampled
|
|
182
|
+
let traceIdPrefix = 'a9'; // Default prefix
|
|
183
|
+
|
|
184
|
+
if (typeof dtConfig === 'object') {
|
|
185
|
+
if (dtConfig.sampled !== undefined) {
|
|
186
|
+
sampled = dtConfig.sampled;
|
|
187
|
+
}
|
|
188
|
+
if (dtConfig.traceIdPrefix !== undefined) {
|
|
189
|
+
traceIdPrefix = dtConfig.traceIdPrefix;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Validate and normalize prefix (must be valid hex, max 8 chars)
|
|
194
|
+
traceIdPrefix = traceIdPrefix.toLowerCase().replace(/[^0-9a-f]/g, '').slice(0, 8);
|
|
195
|
+
if (traceIdPrefix.length === 0) {
|
|
196
|
+
traceIdPrefix = 'a9'; // Fallback to default if invalid
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Generate trace-id with prefix (32 hex chars total)
|
|
200
|
+
const remainingBytes = Math.ceil((32 - traceIdPrefix.length) / 2);
|
|
201
|
+
const randomPart = crypto.randomBytes(remainingBytes).toString('hex');
|
|
202
|
+
const traceId = (traceIdPrefix + randomPart).slice(0, 32);
|
|
203
|
+
|
|
204
|
+
// Generate 8-byte parent-id (16 hex chars)
|
|
205
|
+
const parentId = crypto.randomBytes(8).toString('hex');
|
|
206
|
+
|
|
207
|
+
const traceFlags = sampled ? '01' : '00';
|
|
208
|
+
|
|
209
|
+
return `${version}-${traceId}-${parentId}-${traceFlags}`;
|
|
210
|
+
};
|
|
211
|
+
|
|
129
212
|
HttpEngine.prototype.createScenario = function (scenarioSpec, ee) {
|
|
130
213
|
ensurePropertyIsAList(scenarioSpec, 'beforeRequest');
|
|
131
214
|
ensurePropertyIsAList(scenarioSpec, 'afterResponse');
|
|
@@ -274,7 +357,7 @@ HttpEngine.prototype.step = function step(requestSpec, ee, opts) {
|
|
|
274
357
|
const requestParams = _.extend(_.clone(params), {
|
|
275
358
|
url: maybePrependBase(params.url || params.uri, config), // *NOT* templating here
|
|
276
359
|
method: method,
|
|
277
|
-
timeout: timeout
|
|
360
|
+
timeout: timeout,
|
|
278
361
|
uuid: crypto.randomUUID()
|
|
279
362
|
});
|
|
280
363
|
|
|
@@ -683,10 +766,21 @@ HttpEngine.prototype.step = function step(requestSpec, ee, opts) {
|
|
|
683
766
|
);
|
|
684
767
|
}
|
|
685
768
|
|
|
686
|
-
requestParams.retry = 0; // disable retries - ignored when using streams
|
|
769
|
+
requestParams.retry = { limit: 0 }; // disable retries - ignored when using streams
|
|
770
|
+
// Convert scalar seconds to Got v14 timeout object right before request
|
|
771
|
+
const gotOptions = _.pick(requestParams, GOT_OPTION_NAMES);
|
|
772
|
+
gotOptions.timeout = { response: requestParams.timeout * 1000 };
|
|
773
|
+
|
|
774
|
+
// Add W3C Trace Context headers if distributed tracing is enabled
|
|
775
|
+
if (self._isDistributedTracingEnabled(config)) {
|
|
776
|
+
const traceparent = self._generateTraceparent(config);
|
|
777
|
+
gotOptions.headers = gotOptions.headers || {};
|
|
778
|
+
gotOptions.headers.traceparent = traceparent;
|
|
779
|
+
}
|
|
687
780
|
|
|
688
781
|
let totalDownloaded = 0;
|
|
689
|
-
|
|
782
|
+
self
|
|
783
|
+
.request(gotOptions)
|
|
690
784
|
.on('request', (req) => {
|
|
691
785
|
ee.emit('trace:http:request', requestParams, requestParams.uuid);
|
|
692
786
|
|
|
@@ -937,10 +1031,16 @@ HttpEngine.prototype.compile = function compile(tasks, _scenarioSpec, ee) {
|
|
|
937
1031
|
context = await promisify(task)(context);
|
|
938
1032
|
} catch (taskErr) {
|
|
939
1033
|
ee.emit('error', taskErr.code || taskErr.message);
|
|
940
|
-
|
|
1034
|
+
if (callback) {
|
|
1035
|
+
return callback(taskErr, context);
|
|
1036
|
+
}
|
|
1037
|
+
throw taskErr;
|
|
941
1038
|
}
|
|
942
1039
|
}
|
|
943
|
-
|
|
1040
|
+
if (callback) {
|
|
1041
|
+
return callback(null, context);
|
|
1042
|
+
}
|
|
1043
|
+
return context;
|
|
944
1044
|
};
|
|
945
1045
|
};
|
|
946
1046
|
|
package/lib/engine_socketio.js
CHANGED
|
@@ -23,6 +23,10 @@ function SocketIoEngine(script) {
|
|
|
23
23
|
this.httpDelegate = new EngineHttp(script);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
SocketIoEngine.prototype.init = async function () {
|
|
27
|
+
await this.httpDelegate.init();
|
|
28
|
+
};
|
|
29
|
+
|
|
26
30
|
SocketIoEngine.prototype.createScenario = function (scenarioSpec, ee) {
|
|
27
31
|
// Adds scenario overridden configuration into the static config
|
|
28
32
|
this.socketioOpts = { ...this.socketioOpts, ...scenarioSpec.socketio };
|
package/lib/runner.js
CHANGED
|
@@ -163,6 +163,16 @@ async function runner(script, payload, options, callback) {
|
|
|
163
163
|
warnings
|
|
164
164
|
);
|
|
165
165
|
|
|
166
|
+
for (const e of runnerEngines) {
|
|
167
|
+
if (
|
|
168
|
+
e &&
|
|
169
|
+
typeof e.init === 'function' &&
|
|
170
|
+
e.init.constructor.name === 'AsyncFunction'
|
|
171
|
+
) {
|
|
172
|
+
await e.init();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
166
176
|
const promise = new Promise((resolve, _reject) => {
|
|
167
177
|
ee.run = (contextVars) => {
|
|
168
178
|
const runState = {
|
|
@@ -506,12 +516,23 @@ function $randomString(length = 10) {
|
|
|
506
516
|
return s;
|
|
507
517
|
}
|
|
508
518
|
|
|
509
|
-
function handleScriptHook(hook, script, hookEvents, contextVars = {}) {
|
|
519
|
+
async function handleScriptHook(hook, script, hookEvents, contextVars = {}) {
|
|
510
520
|
if (!script[hook]) {
|
|
511
521
|
return {};
|
|
512
522
|
}
|
|
513
523
|
|
|
514
524
|
const { loadedEngines: engines } = loadEngines(script, hookEvents);
|
|
525
|
+
|
|
526
|
+
for (const e of engines) {
|
|
527
|
+
if (
|
|
528
|
+
e &&
|
|
529
|
+
typeof e.init === 'function' &&
|
|
530
|
+
e.init.constructor.name === 'AsyncFunction'
|
|
531
|
+
) {
|
|
532
|
+
await e.init();
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
515
536
|
const ee = new EventEmitter();
|
|
516
537
|
|
|
517
538
|
return new Promise((resolve, reject) => {
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@artilleryio/int-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.0-37061d0",
|
|
4
4
|
"main": "./index.js",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@artilleryio/int-commons": "2.
|
|
7
|
+
"@artilleryio/int-commons": "2.21.0-37061d0",
|
|
8
8
|
"@artilleryio/sketches-js": "^2.1.1",
|
|
9
9
|
"agentkeepalive": "^4.6.0",
|
|
10
10
|
"arrivals": "^2.1.2",
|
|
11
11
|
"async": "^2.6.4",
|
|
12
12
|
"chalk": "^2.4.2",
|
|
13
|
-
"cheerio": "^1.
|
|
13
|
+
"cheerio": "^1.2.0",
|
|
14
14
|
"cookie-parser": "^1.4.7",
|
|
15
15
|
"csv-parse": "^4.16.3",
|
|
16
16
|
"debug": "^4.4.3",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"fast-deep-equal": "^3.1.3",
|
|
23
23
|
"filtrex": "^0.5.4",
|
|
24
24
|
"form-data": "^4.0.5",
|
|
25
|
-
"got": "^
|
|
25
|
+
"got": "^14.6.6",
|
|
26
26
|
"hpagent": "^0.1.1",
|
|
27
27
|
"https-proxy-agent": "^5.0.0",
|
|
28
|
-
"lodash": "^4.
|
|
28
|
+
"lodash": "^4.18.0",
|
|
29
29
|
"ms": "^2.1.3",
|
|
30
30
|
"protobufjs": "^7.5.4",
|
|
31
31
|
"socket.io-client": "^4.8.3",
|