Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'refs/heads/release-2.0.1'

  • Loading branch information...
commit 93be370712385730a23efab0fc6d7a543de1a4d8 2 parents c7c048c + bde1b22
@kilianc authored
Showing with 502 additions and 366 deletions.
  1. +0 −2  .gitignore
  2. +47 −43 README.md
  3. +105 −75 lib/fnqueue.js
  4. +22 −18 package.json
  5. +328 −228 test/fnqueue-test.js
View
2  .gitignore
@@ -1,2 +0,0 @@
-node_modules/
-npm-debug.log
View
90 README.md
@@ -13,25 +13,36 @@ A powerful utility for function chaining (inspired by [async](https://github.com
## Syntax
```javascript
-new FnQueue(functionsList[, callback, concurrencyLevel]);
+new FnQueue(functionsList[, callback, concurrencyLevel, isStopped]);
```
##Parameters
1. `functionsList` __(Object)__ a list of Functions. Each function can declare implicit dependencies as arguments and assume you provide a single callback as the last argument.
-2. `callback` __(Function(err, data))__ the complete callback in the conventional form of `function (err, data){ ... }`
+2. `callback` __(Function(err, data))__ the complete callback in the conventional form of `function (err, data) { ... }`
3. `concurrencyLevel` __(Number/String: defaults to 'auto')__ the concurrency level of the chain execution, can be `'auto'` or `N* = { 1, 2, ... }`
+4. `isStopped` __(Boolean: defaults to false)__ if true you must call the start method in order to execute the function list.
+
+##Methods
+
+* __start__: will start the execution, used in combination with `isStopped = true` constructor parameter
+
+##Attributes
+
+* __isVerbose__ _(Boolean)_: will change the instance verbose mode
##Notes
FnQueue runs a list of functions, each passing their results to the dependent function in the list. However, if any of the functions pass an error to the callback, the next function is not executed and the main callback is immediately called with the error.
Each dependency/argument must be named with the label of the dependent function in the `functionsList` (the first constructor argument).
-Each function with a dependency will be called with the result of the dependent function as expected. __(YES this is a fucking cool introspection!)__
+Each function with a dependency will be called with the result of the dependent function as expected. __(Introspection by [introspect](https://github.com/kilianc/introspect))__
The global callback is called once, on the first error or at the end of the execution. A data object will be provided with the indexed result of the functions.
FnQueue magically resolves all dependencies and executes functions in the right order with the provided concurrency level.
+##Example
+
```javascript
var FnQueue = require('fnqueue');
```
@@ -44,48 +55,41 @@ Example:
```javascript
new FnQueue({
- // this will wait for 'processSomething' and 'searchSomething' and will be called with the respective results
- funnyStuff: function(processSomething, searchSomething, callback){
- // do something silly
- callback(null, 'ciao!');
- },
- // this will be called instantly
- searchSomething: function(callback){
- // do something with database
- callback(err, results);
- },
- // this will wait 'searchSomething'
- update: function(searchSomething, callback){
- // change values inside results and save to db
- callback(err); // no needs to return values
- },
- // this will wait 'searchSomething'
- processSomething: function(searchSomething, callback){
- var start = new Date().getTime();
- // do something slow
- var elapsedTime = new Date().getTime() - start;
- callback(err, elapsedTime);
- }]
-},function(err, data){
-
- if(err)
- throw err;
-
- console.log(data.searchSomething); // results
- console.log(data.update); // undefined
- console.log(data.processSomething); // elapsedTime
- console.log(data.funnyStuff); // 'ciao!'
+ // this will wait for 'processSomething' and 'searchSomething' and will be called with the respective results
+ funnyStuff: function (processSomething, searchSomething, callback) {
+ // do something silly
+ callback(null, 'ciao!');
+ },
+ // this will be called instantly
+ searchSomething: function (callback) {
+ // do something with database
+ callback(err, results);
+ },
+ // this will wait 'searchSomething'
+ update: function (searchSomething, callback) {
+ // change values inside results and save to db
+ callback(err); // no needs to return values
+ },
+ // this will wait 'searchSomething'
+ processSomething: function (searchSomething, callback) {
+ var start = new Date().getTime();
+ // do something slow
+ var elapsedTime = new Date().getTime() - start;
+ callback(err, elapsedTime);
+ }]
+}, function (err, data) {
+
+ if (err) {
+ throw err;
+ }
+
+ console.log(data.searchSomething); // results
+ console.log(data.update); // undefined
+ console.log(data.processSomething); // elapsedTime
+ console.log(data.funnyStuff); // 'ciao!'
}, 1);
```
-##Introspection profiling results
-
-Profiling results are pretty good, Function.toString() took up __~2 seconds__ every __1 Million__ of executions.
-
- Lines of code time (ms) Platform
- ---------------------------------------------------------------------------------------------------
- 800 1808ms OSX Lion 2.2 GHz Intel Core i7 / nodejs v6.0.1
-
## Test
Tests depends on http://vowsjs.org/ then
@@ -94,7 +98,7 @@ Tests depends on http://vowsjs.org/ then
npm install
npm test
-![tests](http://cl.ly/1R2q3h0G2c3a41303R1I/fnqueue_test_v2.png)
+![tests](http://f.cl.ly/items/03432M3A0l0r3M142B2w/fnqueue_test_v2.0.2.png)
## License
View
180 lib/fnqueue.js
@@ -1,121 +1,151 @@
-function FnQueue(tasks, callback, concurrecyLevel, stop) {
- this.tasks = tasks;
- this.callback = callback;
- this.callSequence = [];
- this.results = {};
- this.gotError = false;
- this.concurrecyLevel = concurrecyLevel || 'auto';
- this.runningNb = 0;
- !stop && this.callNextFunction();
+var
+ introspect = require('introspect');
+
+function FnQueue(tasks, callback, concurrecyLevel, isStopped) {
+ this.tasks = tasks;
+ this.taskDependencies = {};
+ this.callback = callback;
+ this.callSequence = [];
+ this.results = {};
+ this.gotError = false;
+ this.concurrecyLevel = concurrecyLevel || 'auto';
+ this.runningNb = 0;
+ this.loadDependencies();
+
+ if (typeof this.concurrecyLevel !== 'string' && typeof this.concurrecyLevel !== 'number') {
+ this.onTaskComplete(null, new Error('Invalid concurrecyLevel: ' + typeof this.concurrecyLevel + ', must be a Number or \'auto\''));
+ return;
+ } else if (typeof this.concurrecyLevel === 'number' && this.concurrecyLevel < 1) {
+ this.onTaskComplete(null, new Error('Invalid concurrecyLevel: ' + this.concurrecyLevel + ' < 1'));
+ return;
+ } else if (typeof this.concurrecyLevel === 'string' && this.concurrecyLevel !== 'auto') {
+ this.onTaskComplete(null, new Error('Invalid concurrecyLevel: ' + this.concurrecyLevel + ' < 1'));
+ return;
+ }
+
+ !isStopped && this.callNextFunction();
}
FnQueue.verbose = function () {
- FnQueue.prototype.isVerbose = true;
- return FnQueue;
+ FnQueue.prototype.isVerbose = true;
+ return FnQueue;
};
FnQueue.prototype.isVerbose = false;
+FnQueue.prototype.loadDependencies = function() {
+
+ for(var taskName in this.tasks) {
+
+ if (typeof this.tasks[taskName] !== 'function') {
+ this.onTaskComplete(null, new Error('Invalid Function in list: ' + taskName + ' is not a function'));
+ return;
+ }
+
+ if (this.tasks[taskName].length === 0) {
+ this.onTaskComplete(null, new Error('Invalid Function in list: missing callback parameter in ' + taskName));
+ return;
+ }
+
+ this.taskDependencies[taskName] = introspect(this.tasks[taskName]).slice(0, -1);
+ }
+};
+
FnQueue.prototype.onTaskComplete = function (taskName, err, result) {
- if (this.gotError)
- return;
+ if (this.gotError) {
+ return;
+ }
- this.runningNb--;
+ this.runningNb--;
- if (err) {
- this.gotError = true;
- this.callback && this.callback(err, this.getResults());
- return;
- }
+ if (err) {
+ this.gotError = true;
+ this.callback && this.callback(err, this.getResults());
+ return;
+ }
- this.results[taskName] = { result: result };
- this.callNextFunction();
+ this.results[taskName] = { result: result };
+ this.callNextFunction();
};
FnQueue.prototype.getResults = function () {
- var results = {};
- for(var taskName in this.results)
- results[taskName] = this.results[taskName].result;
- return results;
+ var results = {};
+ for(var taskName in this.results) {
+ results[taskName] = this.results[taskName].result;
+ }
+ return results;
};
FnQueue.prototype.callNextFunction = function () {
- var nextFunction, dependencies, finish = true, args;
-
- for(var taskName in this.tasks) {
-
- finish = false;
+ var nextFunction, dependencies, finish = true, args;
- if (this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel)
- return;
+ for(var taskName in this.tasks) {
- nextFunction = this.tasks[taskName];
+ finish = false;
- if (nextFunction.length === 0) {
- this.onTaskComplete(null, new Error('Invalid Function in chain: missing callback parameter'));
- return;
- }
+ if (this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel) {
+ return;
+ }
- dependencies = this.getFunctionArguments(nextFunction).slice(0, -1);
- args = this.getDependencies(dependencies);
+ nextFunction = this.tasks[taskName];
+ dependencies = this.taskDependencies[taskName];
+ args = this.getDependencies(dependencies);
- if (args) {
- args.push(this.onTaskComplete.bind(this, taskName));
+ if (args) {
+ args.push(this.onTaskComplete.bind(this, taskName));
- this.isVerbose && console.log(' - FnQueue: executing: ' + taskName + '(' + dependencies.join(',') + ') { ... }');
+ this.isVerbose && console.log(' - FnQueue: executing: ' + taskName + '(' + dependencies.join(',') + ') { ... }');
- this.runningNb++;
- delete this.tasks[taskName];
- this.callSequence.push(taskName);
- nextFunction.apply(null, args);
+ this.runningNb++;
+ delete this.tasks[taskName];
+ this.callSequence.push(taskName);
+ nextFunction.apply(null, args);
- if (this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel)
- return;
- }
- }
+ if (this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel) {
+ return;
+ }
+ }
+ }
- if (!finish && this.runningNb === 0) {
- this.onTaskComplete(null, new Error('Unresolvable dependencies: function "' + taskName + '" requires [' + dependencies.join(',') + ']'));
- return;
- }
+ if (!finish && this.runningNb === 0) {
+ this.onTaskComplete(null, new Error('Unresolvable dependencies: function "' + taskName + '" requires [' + dependencies.join(',') + ']'));
+ return;
+ }
- if (finish && !this.runningNb && this.callback) {
- this.callback(null, this.getResults());
- this.destroy();
- }
+ if (finish && !this.runningNb && this.callback) {
+ this.callback(null, this.getResults());
+ this.destroy();
+ }
};
FnQueue.prototype.start = FnQueue.prototype.callNextFunction;
-FnQueue.prototype.getFunctionArguments = function (fn) {
- return (/^function.+\(([a-z0-9\n\r\t ,]*)\)/i).exec(fn.toString())[1].trim().split(/[ ,\n\r\t]+/);
-};
-
FnQueue.prototype.getDependencies = function (dependencies) {
- var args = [];
+ var args = [];
- for(var i = 0; i < dependencies.length; i++) {
+ for(var i = 0; i < dependencies.length; i++) {
- if (this.results[dependencies[i]] === undefined) {
- return false;
- }
+ if (this.results[dependencies[i]] === undefined) {
+ return false;
+ }
- var arg = this.results[dependencies[i]];
+ var arg = this.results[dependencies[i]];
- if (arg !== undefined)
- args.push(arg.result);
- }
+ if (arg !== undefined) {
+ args.push(arg.result);
+ }
+ }
- return args;
+ return args;
};
FnQueue.prototype.destroy = function () {
- delete this.results;
- delete this.callback;
- delete this.tasks;
+ delete this.results;
+ delete this.callback;
+ delete this.tasks;
};
module.exports = FnQueue;
View
40 package.json
@@ -1,20 +1,24 @@
{
- "author": "Kilian Ciuffolo <me@nailik.org> (http://nailik.org)",
- "name": "fnqueue",
- "main" : "./lib/fnqueue.js",
- "description": "A powerful utility for function chaining",
- "version": "2.0.0",
- "engines": {
- "node": ">= v0.4.7"
- },
- "scripts": {
- "test": "vows test/*-test.js --spec"
- },
- "repository": {
- "type": "git",
- "url": "http://github.com/kilianc/node-fnqueue.git"
- },
- "devDependencies": {
- "vows": "0.5.x >= 0.5.13"
- }
+ "author": "Kilian Ciuffolo <me@nailik.org> (http://nailik.org)",
+ "name": "fnqueue",
+ "main" : "./lib/fnqueue.js",
+ "description": "A powerful utility for function chaining",
+ "keywords": ["async", "queue", "promise", "flow", "parallel", "chain"],
+ "version": "2.0.1",
+ "engines": {
+ "node": ">= v0.4.7"
+ },
+ "scripts": {
+ "test": "vows test/*-test.js --spec"
+ },
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/kilianc/node-fnqueue.git"
+ },
+ "dependencies": {
+ "introspect": "0.0.x"
+ },
+ "devDependencies": {
+ "vows": "0.5.x >= 0.5.13"
+ }
}
View
556 test/fnqueue-test.js
@@ -1,243 +1,343 @@
var
- vows = require('vows'),
- assert = require('assert'),
- FnQueue = require('../lib/fnqueue');
+ vows = require('vows'),
+ assert = require('assert'),
+ FnQueue = require('../lib/fnqueue');
function returnsArguments(askedResults, exptectedResults) {
- return function (results) {
- assert.deepEqual(FnQueue.prototype.getDependencies.apply(results, [askedResults]), exptectedResults);
- };
+ return function (results) {
+ assert.deepEqual(FnQueue.prototype.getDependencies.apply(results, [askedResults]), exptectedResults);
+ };
}
vows.describe('FnQueue').addBatch({
- 'When we require FnQueue': {
- topic: FnQueue.prototype,
- 'FnQueue.verbose should be false by default': function (prototype) {
- assert.isFalse(prototype.isVerbose);
- }
- }
+ 'When we require FnQueue': {
+ topic: FnQueue.prototype,
+ 'FnQueue.verbose should be false by default': function (prototype) {
+ assert.isFalse(prototype.isVerbose);
+ }
+ }
}).addBatch({
- 'FnQueue.getFunctionArguments should success': {
- 'without spaces': function () {
- assert.deepEqual(FnQueue.prototype.getFunctionArguments(function (foo,bar,callback) {}), ['foo', 'bar', 'callback']);
- },
- 'with spaces': function () {
- assert.deepEqual(FnQueue.prototype.getFunctionArguments(function ( foo , bar , callback ) { }), ['foo', 'bar', 'callback']);
- },
- 'with newline': function () {
- assert.deepEqual(FnQueue.prototype.getFunctionArguments(function (
- foo,
- bar,
- callback
- ) {//foo bar
- //foo bar
- var a = 5;
- for(var b = 0; b < 1000; b ++) { }
- if (a == 5) { }
- }), ['foo', 'bar', 'callback']);
- }
- }
+ 'Given an object of results': {
+ topic: {
+ results: {
+ foo1: { result: 'foo1-result' },
+ bar1: { result: 'bar1-result' },
+ foo2: { result: 'foo2-result' },
+ bar2: { result: 'bar2-result' }
+ }
+ },
+ 'FnQueue.getDependencies should return': {
+ 'foo1-result, bar1-result': returnsArguments(['foo1', 'bar1'], ['foo1-result', 'bar1-result']),
+ 'bar2-result, foo1-result, foo1-result': returnsArguments(['bar2', 'foo1', 'foo1'], ['bar2-result', 'foo1-result', 'foo1-result']),
+ 'false': returnsArguments(['foo1', 'bar1', 'youShouldNotFindMe'], false),
+ },
+ 'FnQueue.getResults should return': {
+ '{ foo1: "foo1-result", bar1: "bar1-result", foo2: "foo2-result", bar2: "bar2-result" }': function (result) {
+ assert.deepEqual(FnQueue.prototype.getResults.apply(result), { foo1: "foo1-result", bar1: "bar1-result", foo2: "foo2-result", bar2: "bar2-result" });
+ }
+ }
+ },
+ 'Given an empty object of results': {
+ topic: { results: {} },
+ 'FnQueue.getDependencies should return': {
+ 'false for [foo1, bar1]': returnsArguments(['foo1', 'bar1'], false),
+ 'false for [bar2, foo1]': returnsArguments(['bar2', 'foo1', 'foo1'], false),
+ 'false for [foo1, bar1, youShouldnotFindMe]': returnsArguments(['foo1', 'bar1', 'youShouldNotFindMe'], false),
+ },
+ 'FnQueue.getResults should return': {
+ '{}': function (result) {
+ assert.deepEqual(FnQueue.prototype.getResults.apply(result), {});
+ }
+ }
+ },
+ 'FnQueue.destroy, given a dummy object': {
+ topic: { results: {}, callback: {}, tasks: {} },
+ 'should delete results, callback and tasks properties': function (obj) {
+ FnQueue.prototype.destroy.apply(obj);
+ assert.isEmpty(obj);
+ }
+ },
+ 'FnQueue.loadDependencies, given a function queue': {
+ topic: function () {
+ var queue = new FnQueue({
+ fn1: function (fn2, callback) {
+ setTimeout(callback.bind(null, null, 'fn1'), 500);
+ },
+ fn2: function (fn4, callback) {
+ setTimeout(callback.bind(null, null, 'fn2'), 500);
+ },
+ fn3: function (fn1, fn2, fn4, callback) {
+ setTimeout(callback.bind(null, null, undefined), 500);
+ },
+ fn4: function (callback) {
+ setTimeout(callback.bind(null, null, false), 500);
+ }
+ }, null, 1, true);
+ return queue;
+ },
+ 'should load dependencies correctly': function (queue) {
+ assert.deepEqual(queue.taskDependencies, {
+ fn1: ['fn2'],
+ fn2: ['fn4'],
+ fn3: ['fn1', 'fn2', 'fn4'],
+ fn4: []
+ });
+ }
+ },
+ 'FnQueue.loadDependencies, given a wrong function queue (missing callback)': {
+ topic: function () {
+ var queue = new FnQueue({
+ fn1: function (fn2, callback) {
+ setTimeout(callback.bind(null, null, 'fn1'), 500);
+ },
+ fn2: function (fn4, callback) {
+ setTimeout(callback.bind(null, null, 'fn2'), 500);
+ },
+ fn3: function (fn1, fn2, fn4, callback) {
+ setTimeout(callback.bind(null, null, undefined), 500);
+ },
+ fn4: function () {
+ setTimeout(callback.bind(null, null, false), 500);
+ }
+ }, this.callback, 1, true);
+ },
+ 'should call the main callback with an error': function (err, data) {
+ assert.isNotNull(err);
+ },
+ 'error should match the "Invalid Function in list..." messgae': function (err, data) {
+ assert.match(err.message, /^Invalid Function in list/);
+ }
+ },
+ 'FnQueue.loadDependencies, given a wrong function queue (not a function)': {
+ topic: function () {
+ var queue = new FnQueue({
+ fn1: function (fn2, callback) {
+ setTimeout(callback.bind(null, null, 'fn1'), 500);
+ },
+ fn2: function (fn4, callback) {
+ setTimeout(callback.bind(null, null, 'fn2'), 500);
+ },
+ fn3: function (fn1, fn2, fn4, callback) {
+ setTimeout(callback.bind(null, null, undefined), 500);
+ },
+ fn4: 'ciao'
+ }, this.callback, 1, true);
+ },
+ 'should call the main callback with an error': function (err, data) {
+ assert.isNotNull(err);
+ },
+ 'error should match the "Invalid Function in list..." messgae': function (err, data) {
+ assert.match(err.message, /^Invalid Function in list/);
+ }
+ },
+ 'FnQueue with an example queue of functions': {
+ topic: function () {
+ new FnQueue({
+ fn1: function (callback) {
+ setTimeout(callback.bind(null, null, 'fn1'), 500);
+ },
+ fn2: function (callback) {
+ setTimeout(callback.bind(null, null, 'fn2'), 500);
+ },
+ fn3: function (callback) {
+ setTimeout(callback.bind(null, null, undefined), 500);
+ },
+ fn4: function (callback) {
+ setTimeout(callback.bind(null, null, false), 500);
+ }
+ }, this.callback);
+ },
+ 'should not return error': function (err, data) {
+ assert.isNull(err);
+ },
+ 'data should be an Object': function (err, data) {
+ assert.isObject(data);
+ },
+ 'data should contains all the queue results': function (err, data) {
+ assert.deepEqual(data,{
+ fn1: 'fn1',
+ fn2: 'fn2',
+ fn3: undefined,
+ fn4: false,
+ });
+ }
+ },
+ 'FnQueue with a wrong concurrency level (< 0)': {
+ topic: function () {
+ new FnQueue({
+ fn1: function (callback) {
+ setTimeout(callback.bind(null, null, 'fn1'), 500);
+ },
+ fn2: function (callback) {
+ setTimeout(callback.bind(null, null, 'fn2'), 500);
+ },
+ fn3: function (callback) {
+ setTimeout(callback.bind(null, null, undefined), 500);
+ },
+ fn4: function (callback) {
+ setTimeout(callback.bind(null, null, false), 500);
+ }
+ }, this.callback, -5);
+ },
+ 'should call the main callback with an error': function (err, data) {
+ assert.isNotNull(err);
+ },
+ 'error should match the "Invalid Function in list..." messgae': function (err, data) {
+ assert.match(err.message, /^Invalid concurrecyLevel/);
+ }
+ },
+ 'FnQueue with a wrong concurrency level (!== \'auto\')': {
+ topic: function () {
+ new FnQueue({
+ fn1: function (callback) {
+ setTimeout(callback.bind(null, null, 'fn1'), 500);
+ },
+ fn2: function (callback) {
+ setTimeout(callback.bind(null, null, 'fn2'), 500);
+ },
+ fn3: function (callback) {
+ setTimeout(callback.bind(null, null, undefined), 500);
+ },
+ fn4: function (callback) {
+ setTimeout(callback.bind(null, null, false), 500);
+ }
+ }, this.callback, 'wrong!');
+ },
+ 'should call the main callback with an error': function (err, data) {
+ assert.isNotNull(err);
+ },
+ 'error should match the "Invalid Function in list..." messgae': function (err, data) {
+ assert.match(err.message, /^Invalid concurrecyLevel/);
+ }
+ },
+ 'FnQueue with some error throwing function': {
+ topic: function () {
+ new FnQueue({
+ fn1: function (callback) {
+ setTimeout(callback.bind(null, null, 'fn1'), 200);
+ },
+ fn2: function (callback) {
+ setTimeout(callback.bind(null, new Error('This is thrown by fn2'), 'fn2'), 300);
+ },
+ fn3: function (callback) {
+ setTimeout(callback.bind(null, new Error('This is thrown by fn3'), undefined), 200);
+ },
+ fn4: function (callback) {
+ setTimeout(callback.bind(null, null, false), 200);
+ }
+ }, this.callback);
+ },
+ 'should call the main callback with an error': function (err, data) {
+ assert.isNotNull(err);
+ },
+ 'error message should be "This is thrown by fn3"': function (err, data) {
+ assert.equal(err.message, 'This is thrown by fn3');
+ },
+ 'data should contains partial results': function (err, data) {
+ assert.deepEqual(data, { fn1: 'fn1' });
+ }
+ }
}).addBatch({
- 'Given an object of results': {
- topic: {
- results: {
- foo1: { result: 'foo1-result' },
- bar1: { result: 'bar1-result' },
- foo2: { result: 'foo2-result' },
- bar2: { result: 'bar2-result' }
- }
- },
- 'FnQueue.getDependencies should return': {
- 'foo1-result, bar1-result': returnsArguments(['foo1', 'bar1'], ['foo1-result', 'bar1-result']),
- 'bar2-result, foo1-result, foo1-result': returnsArguments(['bar2', 'foo1', 'foo1'], ['bar2-result', 'foo1-result', 'foo1-result']),
- 'false': returnsArguments(['foo1', 'bar1', 'youShouldNotFindMe'], false),
- },
- 'FnQueue.getResults should return': {
- '{ foo1: "foo1-result", bar1: "bar1-result", foo2: "foo2-result", bar2: "bar2-result" }': function (result) {
- assert.deepEqual(FnQueue.prototype.getResults.apply(result), { foo1: "foo1-result", bar1: "bar1-result", foo2: "foo2-result", bar2: "bar2-result" });
- }
- }
- },
- 'Given an empty object of results': {
- topic: { results: {} },
- 'FnQueue.getDependencies should return': {
- 'false for [foo1, bar1]': returnsArguments(['foo1', 'bar1'], false),
- 'false for [bar2, foo1]': returnsArguments(['bar2', 'foo1', 'foo1'], false),
- 'false for [foo1, bar1, youShouldnotFindMe]': returnsArguments(['foo1', 'bar1', 'youShouldNotFindMe'], false),
- },
- 'FnQueue.getResults should return': {
- '{}': function (result) {
- assert.deepEqual(FnQueue.prototype.getResults.apply(result), {});
- }
- }
- },
- 'FnQueue.destroy, given a dummy object': {
- topic: { results: {}, callback: {}, tasks: {} },
- 'should delete results, callback and tasks properties': function (obj) {
- FnQueue.prototype.destroy.apply(obj);
- assert.isEmpty(obj);
- }
- },
- 'FnQueue with an example queue of functions': {
- topic: function () {
- new FnQueue({
- fn1: function (callback) {
- setTimeout(callback.bind(null, null, 'fn1'), 500);
- },
- fn2: function (callback) {
- setTimeout(callback.bind(null, null, 'fn2'), 500);
- },
- fn3: function (callback) {
- setTimeout(callback.bind(null, null, undefined), 500);
- },
- fn4: function (callback) {
- setTimeout(callback.bind(null, null, false), 500);
- }
- }, this.callback);
- },
- 'should not return error': function (err, data) {
- assert.isNull(err);
- },
- 'data should be an Object': function (err, data) {
- assert.isObject(data);
- },
- 'data should contains all the queue results': function (err, data) {
- assert.deepEqual(data,{
- fn1: 'fn1',
- fn2: 'fn2',
- fn3: undefined,
- fn4: false,
- });
- }
- },
- 'FnQueue with some error throwing function': {
- topic: function () {
- new FnQueue({
- fn1: function (callback) {
- setTimeout(callback.bind(null, null, 'fn1'), 200);
- },
- fn2: function (callback) {
- setTimeout(callback.bind(null, new Error('This is thrown by fn2'), 'fn2'), 300);
- },
- fn3: function (callback) {
- setTimeout(callback.bind(null, new Error('This is thrown by fn3'), undefined), 200);
- },
- fn4: function (callback) {
- setTimeout(callback.bind(null, null, false), 200);
- }
- }, this.callback);
- },
- 'should call the main callback with an error': function (err, data) {
- assert.isNotNull(err);
- },
- 'error message should be "This is thrown by fn3"': function (err, data) {
- assert.equal(err.message, 'This is thrown by fn3');
- },
- 'data should contains partial results': function (err, data) {
- assert.deepEqual(data, { fn1: 'fn1' });
- }
- }
+ 'FnQueue with unresolvable dependencies': {
+ topic: function () {
+ new FnQueue({
+ fn1: function (fn2, fn4, fn3, callback) {
+ setTimeout(callback.bind(null, null, 'fn1'), 100);
+ },
+ fn2: function (fn4, callback) {
+ setTimeout(callback.bind(null, null, 'fn2'), 100);
+ },
+ fn3: function (fn2, fn1, callback) {
+ setTimeout(callback.bind(null, null, undefined), 100);
+ },
+ fn4: function (callback) {
+ setTimeout(callback.bind(null, null, false), 100);
+ }
+ }, this.callback);
+ },
+ 'should call the main callback with an error': function (err, data) {
+ assert.isNotNull(err);
+ },
+ 'error should match the "Unresolvable dependencies..." messgae': function (err, data) {
+ assert.match(err.message, /^Unresolvable dependencies/);
+ },
+ 'data should contain partial results': function (err, data) {
+ assert.deepEqual(data, { fn4: false, fn2: 'fn2' });
+ }
+ }
}).addBatch({
- 'FnQueue with unresolvable dependencies': {
- topic: function () {
- new FnQueue({
- fn1: function (fn2, fn4, fn3, callback) {
- setTimeout(callback.bind(null, null, 'fn1'), 100);
- },
- fn2: function (fn4, callback) {
- setTimeout(callback.bind(null, null, 'fn2'), 100);
- },
- fn3: function (fn2, fn1, callback) {
- setTimeout(callback.bind(null, null, undefined), 100);
- },
- fn4: function (callback) {
- setTimeout(callback.bind(null, null, false), 100);
- }
- }, this.callback);
- },
- 'should call the main callback with an error': function (err, data) {
- assert.isNotNull(err);
- },
- 'error should match the "Unresolvable dependencies..." messgae': function (err, data) {
- assert.match(err.message, /^Unresolvable dependencies/);
- },
- 'data should contain partial results': function (err, data) {
- assert.deepEqual(data, { fn4: false, fn2: 'fn2' });
- }
- }
+ 'FnQueue with some dependencies': {
+ topic: function () {
+ new FnQueue({
+ fn1: function (fn2, fn4, fn3, callback) {
+ setTimeout(callback.bind(null, null, 'fn1'), 100);
+ },
+ fn2: function (fn4, callback) {
+ setTimeout(callback.bind(null, null, 'fn2'), 100);
+ },
+ fn3: function (fn2, callback) {
+ setTimeout(callback.bind(null, null, undefined), 100);
+ },
+ fn4: function (callback) {
+ setTimeout(callback.bind(null, null, false), 100);
+ }
+ }, this.callback);
+ },
+ 'should follow dependecies constrains in call sequence': function (err, data) {
+ assert.deepEqual(this.callSequence, ['fn4', 'fn2', 'fn3', 'fn1']);
+ }
+ }
}).addBatch({
- 'FnQueue with some dependencies': {
- topic: function () {
- new FnQueue({
- fn1: function (fn2, fn4, fn3, callback) {
- setTimeout(callback.bind(null, null, 'fn1'), 100);
- },
- fn2: function (fn4, callback) {
- setTimeout(callback.bind(null, null, 'fn2'), 100);
- },
- fn3: function (fn2, callback) {
- setTimeout(callback.bind(null, null, undefined), 100);
- },
- fn4: function (callback) {
- setTimeout(callback.bind(null, null, false), 100);
- }
- }, this.callback);
- },
- 'should follow dependecies constrains in call sequence': function (err, data) {
- assert.deepEqual(this.callSequence, ['fn4', 'fn2', 'fn3', 'fn1']);
- }
- }
-}).addBatch({
- 'FnQueue with an example queue of functions and a concurrency level of 2': {
- topic: function () {
+ 'FnQueue with an example queue of functions and a concurrency level of 2': {
+ topic: function () {
- var fnQueue = new FnQueue({
- fn1: function (callback) {
- setTimeout(getCallback(2, callback), 200);
- },
- fn2: function (fn9, callback) {
- setTimeout(getCallback(null, callback), 200);
- },
- fn3: function (fn9, fn8, callback) {
- setTimeout(getCallback(null, callback), 200);
- },
- fn4: function (callback) {
- setTimeout(getCallback(3, callback), 200);
- },
- fn5: function (callback) {
- setTimeout(getCallback(null, callback), 200);
- },
- fn6: function (callback) {
- setTimeout(getCallback(null, callback), 200);
- },
- fn7: function (callback) {
- setTimeout(getCallback(1, callback), 200);
- },
- fn8: function (callback) {
- setTimeout(getCallback(2, callback), 200);
- },
- fn9: function (fn7, fn8, callback) {
- setTimeout(getCallback(null, callback), 200);
- }
- }, this.callback, 1, true);
+ var fnQueue = new FnQueue({
+ fn1: function (callback) {
+ setTimeout(getCallback(2, callback), 200);
+ },
+ fn2: function (fn9, callback) {
+ setTimeout(getCallback(null, callback), 200);
+ },
+ fn3: function (fn9, fn8, callback) {
+ setTimeout(getCallback(null, callback), 200);
+ },
+ fn4: function (callback) {
+ setTimeout(getCallback(3, callback), 200);
+ },
+ fn5: function (callback) {
+ setTimeout(getCallback(null, callback), 200);
+ },
+ fn6: function (callback) {
+ setTimeout(getCallback(null, callback), 200);
+ },
+ fn7: function (callback) {
+ setTimeout(getCallback(1, callback), 200);
+ },
+ fn8: function (callback) {
+ setTimeout(getCallback(2, callback), 200);
+ },
+ fn9: function (fn7, fn8, callback) {
+ setTimeout(getCallback(null, callback), 200);
+ }
+ }, this.callback, 1, true);
- fnQueue.concurrencySequence = [];
+ fnQueue.concurrencySequence = [];
- function getCallback(concurrecyLevel, callback) {
- return function () {
- concurrecyLevel && (fnQueue.concurrecyLevel = concurrecyLevel);
- fnQueue.concurrencySequence.push(fnQueue.runningNb);
- callback(null, fnQueue.runningNb);
- };
- }
+ function getCallback(concurrecyLevel, callback) {
+ return function () {
+ concurrecyLevel && (fnQueue.concurrecyLevel = concurrecyLevel);
+ fnQueue.concurrencySequence.push(fnQueue.runningNb);
+ callback(null, fnQueue.runningNb);
+ };
+ }
- fnQueue.start();
- },
- 'should not return error': function (err, data) {
- assert.isNull(err);
- },
- 'max concurrency should follow the expected concurrency sequence': function (err, data) {
- assert.deepEqual(this.concurrencySequence, [ 1, 2, 3, 3, 2, 1, 1, 2, 1 ]);
- },
- },
+ fnQueue.start();
+ },
+ 'should not return error': function (err, data) {
+ assert.isNull(err);
+ },
+ 'max concurrency should follow the expected concurrency sequence': function (err, data) {
+ assert.deepEqual(this.concurrencySequence, [ 1, 2, 3, 3, 2, 1, 1, 2, 1 ]);
+ },
+ },
}).export(module);
Please sign in to comment.
Something went wrong with that request. Please try again.