Skip to content

Instantly share code, notes, and snippets.

@runk
Created October 27, 2015 04:37
Show Gist options
  • Save runk/df0caf517bcc1a65d6e0 to your computer and use it in GitHub Desktop.
Save runk/df0caf517bcc1a65d6e0 to your computer and use it in GitHub Desktop.
var child = require('child_process');
var q = require('q');
var TaskLogger = require('./taskLogger.js');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var log = require('./logger.js');
/**
* A runner for running a specified task (capabilities + specs).
* The TaskRunner can either run the task from the current process (via
* './runner.js') or from a new process (via './runnerCli.js').
*
* @constructor
* @param {string} configFile Path of test configuration.
* @param {object} additionalConfig Additional configuration.
* @param {object} task Task to run.
* @param {boolean} runInFork Whether to run test in a forked process.
* @constructor
*/
var TaskRunner = function(configFile, additionalConfig, task, runInFork) {
this.configFile = configFile;
this.additionalConfig = additionalConfig;
this.task = task;
this.runInFork = runInFork;
};
util.inherits(TaskRunner, EventEmitter);
/**
* Sends the run command.
* @return {q.Promise} A promise that will resolve when the task finishes
* running. The promise contains the following parameters representing the
* result of the run:
* taskId, specs, capabilities, failedCount, exitCode, specResults
*/
TaskRunner.prototype.run = function() {
// console.log('zzzz run', new Error().stack)
var runResults = {
taskId: this.task.taskId,
specs: this.task.specs,
capabilities: this.task.capabilities,
// The following are populated while running the test:
failedCount: 0,
exitCode: -1,
specResults: []
};
var self = this;
if (this.retries == null) this.retries = 3
if (this.runInFork) {
var deferred = q.defer();
var execTask = function() {
var childProcess = child.fork(
__dirname + '/runnerCli.js',
process.argv.slice(2), {
cwd: process.cwd(),
silent: true
}
);
var taskLogger = new TaskLogger(self.task, childProcess.pid);
// stdout pipe
childProcess.stdout.on('data', function(data) {
taskLogger.log(data);
});
// stderr pipe
childProcess.stderr.on('data', function(data) {
taskLogger.log(data);
});
childProcess.on('message', function(m) {
console.log('zzz msg', self.task.taskId, m.event);
switch (m.event) {
case 'testPass':
log.print('.');
break;
case 'testFail':
log.print('F');
break;
case 'testsDone':
runResults.failedCount = m.results.failedCount;
runResults.specResults = m.results.specResults;
break;
}
})
.on('error', function(err) {
console.log('zzz error', self.task.taskId, err);
taskLogger.flush();
if (--self.retries > 0) {
console.log('zzz retrying on err', self.task.taskId);
return execTask()
}
deferred.reject(err);
})
.on('exit', function(code) {
console.log('zzz exit', self.task.taskId, code);
if (code === 1 && --self.retries > 0) {
console.log('zzz retrying on exit code', self.task.taskId, code);
return execTask()
}
taskLogger.flush();
runResults.exitCode = code;
deferred.resolve(runResults);
});
childProcess.send({
command: 'run',
configFile: self.configFile,
additionalConfig: self.additionalConfig,
capabilities: self.task.capabilities,
specs: self.task.specs
});
}
execTask()
return deferred.promise;
} else {
var ConfigParser = require('./configParser');
var configParser = new ConfigParser();
if (this.configFile) {
configParser.addFileConfig(this.configFile);
}
if (this.additionalConfig) {
configParser.addConfig(this.additionalConfig);
}
var config = configParser.getConfig();
config.capabilities = this.task.capabilities;
config.specs = this.task.specs;
var Runner = require('./runner');
var runner = new Runner(config);
runner.on('testsDone', function(results) {
runResults.failedCount = results.failedCount;
runResults.specResults = results.specResults;
});
return runner.run().then(function(exitCode) {
runResults.exitCode = exitCode;
return runResults;
});
}
};
module.exports = TaskRunner;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment