@artilleryio/int-core 2.1.0 → 2.2.0-15fcca7
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 +3 -1
- package/lib/engine_socketio.js +33 -9
- package/lib/runner.js +55 -8
- package/lib/ssms.js +1 -0
- package/package.json +3 -2
package/lib/engine_http.js
CHANGED
|
@@ -167,7 +167,7 @@ HttpEngine.prototype.createScenario = function (scenarioSpec, ee) {
|
|
|
167
167
|
});
|
|
168
168
|
});
|
|
169
169
|
|
|
170
|
-
return self.compile(tasks, scenarioSpec
|
|
170
|
+
return self.compile(tasks, scenarioSpec, ee);
|
|
171
171
|
};
|
|
172
172
|
|
|
173
173
|
HttpEngine.prototype.step = function step(requestSpec, ee, opts) {
|
|
@@ -712,6 +712,7 @@ HttpEngine.prototype.step = function step(requestSpec, ee, opts) {
|
|
|
712
712
|
})
|
|
713
713
|
.catch((gotErr) => {
|
|
714
714
|
// TODO: Handle the error properly with run hooks
|
|
715
|
+
debug(gotErr);
|
|
715
716
|
return callback(gotErr, context);
|
|
716
717
|
});
|
|
717
718
|
}
|
|
@@ -868,6 +869,7 @@ HttpEngine.prototype.compile = function compile(tasks, scenarioSpec, ee) {
|
|
|
868
869
|
|
|
869
870
|
return async function scenario(initialContext, callback) {
|
|
870
871
|
initialContext = self.setInitialContext(initialContext);
|
|
872
|
+
|
|
871
873
|
ee.emit('started');
|
|
872
874
|
let context = initialContext;
|
|
873
875
|
for (const task of tasks) {
|
package/lib/engine_socketio.js
CHANGED
|
@@ -52,7 +52,9 @@ function markEndTime(ee, _, startedAt) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function isResponseRequired(spec) {
|
|
55
|
-
return
|
|
55
|
+
return (
|
|
56
|
+
spec.emit && spec.response && (spec.response.channel || spec.response.on)
|
|
57
|
+
);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
function isAcknowledgeRequired(spec) {
|
|
@@ -60,8 +62,20 @@ function isAcknowledgeRequired(spec) {
|
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
function processResponse(ee, data, response, context, callback) {
|
|
65
|
+
function isValid(data, response) {
|
|
66
|
+
if (!Array.isArray(response.data)) {
|
|
67
|
+
//`json` key is added at some point to the response.data object, to use with `captureOrMatch` function
|
|
68
|
+
//we should omit it when comparing the response to the data
|
|
69
|
+
const responseDataWithoutJson = _.isObject(response.data)
|
|
70
|
+
? _.omit(response.data, 'json')
|
|
71
|
+
: response.data;
|
|
72
|
+
return deepEqual(data[0], responseDataWithoutJson);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return deepEqual(data, response.data);
|
|
76
|
+
}
|
|
63
77
|
// Do we have supplied data to validate?
|
|
64
|
-
if (response.data && !
|
|
78
|
+
if (response.data && !isValid(data, response)) {
|
|
65
79
|
debug('data is not valid:');
|
|
66
80
|
debug(data);
|
|
67
81
|
debug(response);
|
|
@@ -186,9 +200,12 @@ SocketIoEngine.prototype.step = function (requestSpec, ee) {
|
|
|
186
200
|
}
|
|
187
201
|
|
|
188
202
|
if (isAcknowledgeRequired(requestSpec)) {
|
|
189
|
-
const ackCallback = function () {
|
|
203
|
+
const ackCallback = function (...args) {
|
|
190
204
|
const response = {
|
|
191
|
-
data: template(
|
|
205
|
+
data: template(
|
|
206
|
+
requestSpec.acknowledge.data || requestSpec.acknowledge.args,
|
|
207
|
+
context
|
|
208
|
+
),
|
|
192
209
|
capture: template(requestSpec.acknowledge.capture, context),
|
|
193
210
|
match: template(requestSpec.acknowledge.match, context)
|
|
194
211
|
};
|
|
@@ -198,8 +215,9 @@ SocketIoEngine.prototype.step = function (requestSpec, ee) {
|
|
|
198
215
|
r.json = '$.0'; // Default to the first callback argument
|
|
199
216
|
}
|
|
200
217
|
});
|
|
218
|
+
|
|
201
219
|
// Acknowledge data can take up multiple arguments of the emit callback
|
|
202
|
-
processResponse(ee,
|
|
220
|
+
processResponse(ee, args, response, context, function (err) {
|
|
203
221
|
if (!err) {
|
|
204
222
|
markEndTime(ee, context, startedAt);
|
|
205
223
|
}
|
|
@@ -225,8 +243,14 @@ SocketIoEngine.prototype.step = function (requestSpec, ee) {
|
|
|
225
243
|
|
|
226
244
|
if (isResponseRequired(requestSpec)) {
|
|
227
245
|
const response = {
|
|
228
|
-
channel: template(
|
|
229
|
-
|
|
246
|
+
channel: template(
|
|
247
|
+
requestSpec.response.channel || requestSpec.response.on,
|
|
248
|
+
context
|
|
249
|
+
),
|
|
250
|
+
data: template(
|
|
251
|
+
requestSpec.response.data || requestSpec.response.args,
|
|
252
|
+
context
|
|
253
|
+
),
|
|
230
254
|
capture: template(requestSpec.response.capture, context),
|
|
231
255
|
match: template(requestSpec.response.match, context)
|
|
232
256
|
};
|
|
@@ -234,9 +258,9 @@ SocketIoEngine.prototype.step = function (requestSpec, ee) {
|
|
|
234
258
|
// Listen for the socket.io response on the specified channel
|
|
235
259
|
let done = false;
|
|
236
260
|
|
|
237
|
-
socketio.on(response.channel, function receive(
|
|
261
|
+
socketio.on(response.channel, function receive(...args) {
|
|
238
262
|
done = true;
|
|
239
|
-
processResponse(ee,
|
|
263
|
+
processResponse(ee, args, response, context, function (err) {
|
|
240
264
|
if (!err) {
|
|
241
265
|
markEndTime(ee, context, startedAt);
|
|
242
266
|
}
|
package/lib/runner.js
CHANGED
|
@@ -200,7 +200,13 @@ function run(script, ee, options, runState, contextVars) {
|
|
|
200
200
|
if (runState.pendingScenarios >= spec.maxVusers) {
|
|
201
201
|
metrics.counter('vusers.skipped', 1);
|
|
202
202
|
} else {
|
|
203
|
-
scenarioContext = runScenario(
|
|
203
|
+
scenarioContext = runScenario(
|
|
204
|
+
script,
|
|
205
|
+
metrics,
|
|
206
|
+
runState,
|
|
207
|
+
contextVars,
|
|
208
|
+
options
|
|
209
|
+
);
|
|
204
210
|
}
|
|
205
211
|
});
|
|
206
212
|
phaser.on('phaseStarted', function (spec) {
|
|
@@ -242,7 +248,7 @@ function run(script, ee, options, runState, contextVars) {
|
|
|
242
248
|
phaser.run();
|
|
243
249
|
}
|
|
244
250
|
|
|
245
|
-
function runScenario(script, metrics, runState, contextVars) {
|
|
251
|
+
function runScenario(script, metrics, runState, contextVars, options) {
|
|
246
252
|
const start = process.hrtime();
|
|
247
253
|
|
|
248
254
|
//
|
|
@@ -263,7 +269,7 @@ function runScenario(script, metrics, runState, contextVars) {
|
|
|
263
269
|
const w = engineUtil.template(scenario.weight, {
|
|
264
270
|
vars: variableValues
|
|
265
271
|
});
|
|
266
|
-
scenario.weight = isNaN(parseInt(w)) ? 0 : parseInt(w);
|
|
272
|
+
scenario.weight = isNaN(parseInt(w)) ? 0 : parseInt(w); //eslint-disable-line radix
|
|
267
273
|
debug(
|
|
268
274
|
`scenario ${scenario.name} weight has been set to ${scenario.weight}`
|
|
269
275
|
);
|
|
@@ -299,16 +305,45 @@ function runScenario(script, metrics, runState, contextVars) {
|
|
|
299
305
|
|
|
300
306
|
runState.compiledScenarios = _.map(
|
|
301
307
|
script.scenarios,
|
|
302
|
-
function (scenarioSpec) {
|
|
308
|
+
function (scenarioSpec, scenarioIndex) {
|
|
303
309
|
const name = scenarioSpec.engine || script.config.engine || 'http';
|
|
304
310
|
const engine = runState.engines.find((e) => e.__name === name);
|
|
311
|
+
|
|
312
|
+
if (typeof engine === 'undefined') {
|
|
313
|
+
const scenarioNameOrIndex = scenarioSpec.name || scenarioIndex;
|
|
314
|
+
throw new Error(
|
|
315
|
+
`Failed to run scenario "${scenarioNameOrIndex}": unknown engine "${name}". Did you forget to include it in "config.engines.${name}"?`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
305
319
|
return engine.createScenario(scenarioSpec, runState.scenarioEvents);
|
|
306
320
|
}
|
|
307
321
|
);
|
|
308
322
|
}
|
|
309
323
|
|
|
324
|
+
//default to weighted picked scenario
|
|
310
325
|
let i = runState.picker()[0];
|
|
311
326
|
|
|
327
|
+
if (options.scenarioName) {
|
|
328
|
+
let foundIndex;
|
|
329
|
+
const foundScenario = script.scenarios.filter((scenario, index) => {
|
|
330
|
+
foundIndex = index;
|
|
331
|
+
return new RegExp(options.scenarioName).test(scenario.name);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
if (foundScenario?.length === 0) {
|
|
335
|
+
throw new Error(
|
|
336
|
+
`Scenario ${options.scenarioName} not found in script. Make sure your chosen scenario matches the one in your script exactly.`
|
|
337
|
+
);
|
|
338
|
+
} else if (foundScenario.length > 1) {
|
|
339
|
+
throw new Error(
|
|
340
|
+
`Multiple scenarios for ${options.scenarioName} found in script. Make sure you give unique names to your scenarios in your script.`
|
|
341
|
+
);
|
|
342
|
+
} else {
|
|
343
|
+
debug(`Scenario ${options.scenarioName} found in script. running it!`);
|
|
344
|
+
i = foundIndex;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
312
347
|
debug(
|
|
313
348
|
'picking scenario %s (%s) weight = %s',
|
|
314
349
|
i,
|
|
@@ -320,7 +355,9 @@ function runScenario(script, metrics, runState, contextVars) {
|
|
|
320
355
|
metrics.counter('vusers.created', 1);
|
|
321
356
|
|
|
322
357
|
const scenarioStartedAt = process.hrtime();
|
|
323
|
-
const scenarioContext = createContext(script, contextVars
|
|
358
|
+
const scenarioContext = createContext(script, contextVars, {
|
|
359
|
+
scenario: script.scenarios[i]
|
|
360
|
+
});
|
|
324
361
|
|
|
325
362
|
const finish = process.hrtime(start);
|
|
326
363
|
const runScenarioDelta = finish[0] * 1e9 + finish[1];
|
|
@@ -383,7 +420,13 @@ function inlineVariables(script) {
|
|
|
383
420
|
/**
|
|
384
421
|
* Create initial context for a scenario.
|
|
385
422
|
*/
|
|
386
|
-
function createContext(script, contextVars) {
|
|
423
|
+
function createContext(script, contextVars, additionalProperties = {}) {
|
|
424
|
+
//allow for additional properties to be passed in, but not override vars and funcs
|
|
425
|
+
const additionalPropertiesWithoutOverride = _.omit(additionalProperties, [
|
|
426
|
+
'vars',
|
|
427
|
+
'funcs'
|
|
428
|
+
]);
|
|
429
|
+
|
|
387
430
|
const INITIAL_CONTEXT = {
|
|
388
431
|
vars: Object.assign(
|
|
389
432
|
{
|
|
@@ -398,7 +441,8 @@ function createContext(script, contextVars) {
|
|
|
398
441
|
$randomNumber: $randomNumber,
|
|
399
442
|
$randomString: $randomString,
|
|
400
443
|
$template: (input) => engineUtil.template(input, { vars: result.vars })
|
|
401
|
-
}
|
|
444
|
+
},
|
|
445
|
+
...additionalPropertiesWithoutOverride
|
|
402
446
|
};
|
|
403
447
|
|
|
404
448
|
let result = INITIAL_CONTEXT;
|
|
@@ -445,7 +489,10 @@ function handleScriptHook(hook, script, hookEvents, contextVars = {}) {
|
|
|
445
489
|
const name = script[hook].engine || 'http';
|
|
446
490
|
const engine = engines.find((e) => e.__name === name);
|
|
447
491
|
const hookScenario = engine.createScenario(script[hook], ee);
|
|
448
|
-
const hookContext = createContext(script, contextVars
|
|
492
|
+
const hookContext = createContext(script, contextVars, {
|
|
493
|
+
scenario: script[hook]
|
|
494
|
+
});
|
|
495
|
+
|
|
449
496
|
hookScenario(hookContext, function (err, context) {
|
|
450
497
|
if (err) {
|
|
451
498
|
debug(err);
|
package/lib/ssms.js
CHANGED
|
@@ -626,6 +626,7 @@ function summarizeHistogram(h) {
|
|
|
626
626
|
min: round(h.min, 1),
|
|
627
627
|
max: round(h.max, 1),
|
|
628
628
|
count: h.count,
|
|
629
|
+
mean: round(h.sum/h.count, 1),
|
|
629
630
|
p50: round(h.getValueAtQuantile(0.5), 1),
|
|
630
631
|
median: round(h.getValueAtQuantile(0.5), 1), // Here for compatibility
|
|
631
632
|
p75: round(h.getValueAtQuantile(0.75), 1),
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@artilleryio/int-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0-15fcca7",
|
|
4
4
|
"main": "./index.js",
|
|
5
|
+
"license": "MPL-2.0",
|
|
5
6
|
"dependencies": {
|
|
6
|
-
"@artilleryio/int-commons": "
|
|
7
|
+
"@artilleryio/int-commons": "2.0.2-15fcca7",
|
|
7
8
|
"@artilleryio/sketches-js": "^2.1.1",
|
|
8
9
|
"agentkeepalive": "^4.1.0",
|
|
9
10
|
"arrivals": "^2.1.2",
|