@artilleryio/int-core 2.1.0 → 2.2.0-18ad4ac

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.
@@ -167,7 +167,7 @@ HttpEngine.prototype.createScenario = function (scenarioSpec, ee) {
167
167
  });
168
168
  });
169
169
 
170
- return self.compile(tasks, scenarioSpec.flow, ee);
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) {
@@ -52,7 +52,9 @@ function markEndTime(ee, _, startedAt) {
52
52
  }
53
53
 
54
54
  function isResponseRequired(spec) {
55
- return spec.emit && spec.response && spec.response.channel;
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 && !deepEqual(data, 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(requestSpec.acknowledge.data, context),
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, arguments, response, context, function (err) {
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(requestSpec.response.channel, context),
229
- data: template(requestSpec.response.data, context),
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(data) {
261
+ socketio.on(response.channel, function receive(...args) {
238
262
  done = true;
239
- processResponse(ee, data, response, context, function (err) {
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(script, metrics, runState, contextVars);
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.1.0",
3
+ "version": "2.2.0-18ad4ac",
4
4
  "main": "./index.js",
5
+ "license": "MPL-2.0",
5
6
  "dependencies": {
6
- "@artilleryio/int-commons": "latest",
7
+ "@artilleryio/int-commons": "2.0.2-18ad4ac",
7
8
  "@artilleryio/sketches-js": "^2.1.1",
8
9
  "agentkeepalive": "^4.1.0",
9
10
  "arrivals": "^2.1.2",