Simon Priet e69a613a37 feat: Created a mini nodeJS server with NewMan for testing without PostMan GUI.
This will mimic a run in a CD/CI environment or docker container.
2021-09-08 14:01:19 +02:00

137 lines
5.1 KiB
JavaScript

var _ = require('lodash'),
backpack = require('../backpack'),
Run = require('./run'),
extractRunnableItems = require('./extract-runnable-items').extractRunnableItems,
Runner,
defaultTimeouts = {
global: 3 * 60 * 1000, // 3 minutes
request: Infinity,
script: Infinity
};
/**
* @typedef {runCallback}
* @property {Function} [done]
* @property {Function} [error]
* @property {Function} [success]
*/
/**
* @constructor
*
* @param {Object} [options]
*/
Runner = function PostmanCollectionRunner (options) { // eslint-disable-line func-name-matching
this.options = _.assign({}, options);
};
_.assign(Runner.prototype, {
/**
* Prepares `run` config by combining `runner` config with given run options.
*
* @param {Object} [options]
* @param {Object} [options.timeout]
* @param {Object} [options.timeout.global]
* @param {Object} [options.timeout.request]
* @param {Object} [options.timeout.script]
*/
prepareRunConfig: function (options) {
// combine runner config and make a copy
var runOptions = _.merge(_.omit(options, ['environment', 'globals', 'data']), this.options.run) || {};
// start timeout sanitization
!runOptions.timeout && (runOptions.timeout = {});
_.mergeWith(runOptions.timeout, defaultTimeouts, function (userTimeout, defaultTimeout) {
// non numbers, Infinity and missing values are set to default
if (!_.isFinite(userTimeout)) { return defaultTimeout; }
// 0 and negative numbers are set to Infinity, which only leaves positive numbers
return userTimeout > 0 ? userTimeout : Infinity;
});
return runOptions;
},
/**
* Runs a collection or a folder.
*
* @param {Collection} collection
* @param {Object} [options]
* @param {Array.<Item>} options.items
* @param {Array.<Object>} [options.data]
* @param {Object} [options.globals]
* @param {Object} [options.environment]
* @param {Number} [options.iterationCount]
* @param {CertificateList} [options.certificates]
* @param {ProxyConfigList} [options.proxies]
* @param {Array} [options.data]
* @param {Object} [options.entrypoint]
* @param {String} [options.entrypoint.execute] ID of the item-group to be run.
* Can be Name if `entrypoint.lookupStrategy` is `idOrName`
* @param {String} [options.entrypoint.lookupStrategy=idOrName] strategy to lookup the entrypoint [idOrName, path]
* @param {Array<String>} [options.entrypoint.path] path to lookup
* @param {Object} [options.run] Run-specific options, such as options related to the host
*
* @param {Function} callback
*/
run: function (collection, options, callback) {
var self = this,
runOptions = this.prepareRunConfig(options);
callback = backpack.normalise(callback);
!_.isObject(options) && (options = {});
// @todo make the extract runnables interface better defined and documented
// - give the ownership of error to each strategy lookup functions
// - think about moving these codes into an extension command prior to waterfall
// - the third argument in callback that returns control, is ambiguous and can be removed if error is controlled
// by each lookup function.
// - the interface can be further broken down to have the "flattenNode" action be made common and not be
// required to be coded in each lookup strategy
//
// serialise the items into a linear array based on the lookup strategy provided as input
extractRunnableItems(collection, options.entrypoint, function (err, runnableItems, entrypoint) {
if (err || !runnableItems) { return callback(new Error('Error fetching run items')); }
// Bail out only if: abortOnError is set and the returned entrypoint is invalid
if (options.abortOnError && !entrypoint) {
// eslint-disable-next-line max-len
return callback(new Error(`Unable to find a folder or request: ${_.get(options, 'entrypoint.execute')}`));
}
// ensure data is an array
!_.isArray(options.data) && (options.data = [{}]);
// get iterationCount from data if not set
if (!runOptions.iterationCount) {
runOptions.iterationCount = options.data.length;
}
return callback(null, (new Run({
items: runnableItems,
data: options.data,
environment: options.environment,
globals: _.has(options, 'globals') ? options.globals : self.options.globals,
// @todo Move to item level to support Item and ItemGroup variables
collectionVariables: collection.variables,
certificates: options.certificates,
proxies: options.proxies
}, runOptions)));
});
}
});
_.assign(Runner, {
/**
* Expose Run instance for testability
*
* @type {Run}
*/
Run: Run
});
module.exports = Runner;