File: lib/task/group.js
// Copyright 2014, Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.
var AbstractTask = require('../abstractTask');
var logger = require('log4js').getLogger(__filename);
var Promise = require('promise');
var utils = require('preceptor-core').utils;
var _ = require('underscore');
var staticTaskCounter = 0;
/**
* @class GroupTask
* @extends AbstractTask
* @constructor
*/
var GroupTask = AbstractTask.extend(
{
/**
* Initializes the instance
*
* @method initialize
*/
initialize: function () {
if (!_.isArray(this.getTasks())) {
this.getConfiguration().tasks = [this.getTasks()];
}
this.getOptions().configuration = utils.deepExtend({}, [
{
parallel: false,
bail: true,
tasks: []
},
this.getConfiguration()
]);
this.__super();
},
/**
* Validates the given data
*
* @method validate
*/
validate: function () {
this.__super();
if (!_.isBoolean(this.isParallel())) {
throw new Error('The "parallel" parameter is not a boolean.');
}
if (!_.isArray(this.getTasks())) {
throw new Error('The "tasks" parameter is not an array.');
}
if (!_.isBoolean(this.shouldBail())) {
throw new Error('The "bail" parameter is not a boolean.');
}
},
/**
* Run the tasks in parallel?
*
* @method isParallel
* @return {boolean}
*/
isParallel: function () {
return this.getConfiguration().parallel;
},
/**
* Gets the tasks assigned to this group
*
* @method getTasks
* @return {object[]}
*/
getTasks: function () {
return this.getConfiguration().tasks;
},
/**
* Bail execution when encountering the first error
*
* @method shouldBail
* @return {boolean}
*/
shouldBail: function () {
return this.getConfiguration().bail;
},
/**
* Applies all decorators
*
* @method applyTaskDecorators
* @param {object[]} tasks
* @param {AbstractTaskDecorator[]} decoratorList
* @return {object[]}
*/
applyTaskDecorators: function (tasks, decoratorList) {
var decoratorInstance,
resultTasks,
localTasks = tasks,
i;
// Process all decorators
_.each(decoratorList, function (Decorator) {
decoratorInstance = new Decorator();
// Process all tasks
for(i = 0; i < localTasks.length; i++) {
resultTasks = decoratorInstance.run(localTasks[i], i + staticTaskCounter);
if (_.isArray(resultTasks)) {
localTasks = localTasks.slice(0, i).concat(resultTasks, localTasks.slice(i + 1));
i += resultTasks.length - 1;
} else if (_.isObject(resultTasks)) {
localTasks[i] = resultTasks;
}
}
}, this);
staticTaskCounter += localTasks.length;
return localTasks;
},
/**
* Run the client
*
* @method _run
* @param {string} parentId
* @return {Promise}
* @private
*/
_run: function (parentId) {
var promise = Promise.resolve(),
promiseList = [],
tasks;
// Apply all decorator to get final list of tasks
tasks = this.applyTaskDecorators(this.getTasks(), this.getTaskDecoratorPlugins());
if (tasks.length === 0) {
throw new Error('A group without tasks. ' + this.getLabel())
}
// Process each task
_.each(tasks, function (taskOptions) {
var TaskClass,
taskInstance,
currentPromise;
// Find plugin
TaskClass = this.getTaskPlugin(taskOptions.type);
if (!TaskClass) {
throw new Error('Unknown task: ' + taskOptions.type + ', ' + this.getLabel());
}
// Create task instance
taskInstance = new TaskClass(
this.getGlobalConfig(),
this.getCoverageCollector(),
this.getReportManager(),
this.getPlugins(),
taskOptions
);
// Run task
currentPromise = promise.then(function () {
logger.debug('Task started.', taskInstance.getLabel());
return taskInstance.run(parentId).then(function () {
logger.debug('Task completed.', taskInstance.getLabel());
});
}.bind(this));
// Bail on execution when error or just log?
currentPromise = currentPromise.then(null, function (err) {
if (this.shouldBail()) {
throw err;
} else {
logger.error('Error', err.stack.toString());
}
}.bind(this));
// Run in parallel?
if (this.isParallel()) {
logger.debug('Run task in parallel.', taskInstance.getLabel());
promiseList.push(currentPromise);
} else {
logger.debug('Run task sequential.', taskInstance.getLabel());
promise = currentPromise;
}
}, this);
// Wait for all to finish?
if (this.isParallel()) {
promise = Promise.all(promiseList);
}
return promise;
}
});
module.exports = GroupTask;