diff --git a/lib/node.js b/lib/node.js new file mode 100644 index 0000000..9801aee --- /dev/null +++ b/lib/node.js @@ -0,0 +1,42 @@ +'use strict'; + +var _ = require('underscore'), + createExecutor = require('./executor').createExecutor; + + +function Node(params) { + this.type = params.type; + this.maxExecutorsCount = params.maxExecutorsCount; + this.executors = {}; +} + +exports.Node = Node; + +Node.prototype.hasFreeExecutor = function(project) { + return ( + // can't build same project twice at the same time on same node + project.name in this.executors === false && + _(this.executors).size() < this.maxExecutorsCount + ); +} + +Node.prototype._createExecutor = function(project) { + return createExecutor({ + type: this.type, + project: project + }); +}; + +Node.prototype.run = function(project, params, callback) { + var self = this; + if (!this.hasFreeExecutor(project)) { + throw new Error('No free executors for project: ' + project.name); + } + + this.executors[project.name] = this._createExecutor(project); + + this.executors[project.name].run(params, function(err) { + delete self.executors[project.name]; + callback(err); + }); +}; diff --git a/test/executor.js b/test/executor.js index 6032b3c..7884aee 100644 --- a/test/executor.js +++ b/test/executor.js @@ -32,6 +32,7 @@ var expect = require('expect.js'), type: type, project: { dir: __dirname, + name: 'test project', scm: { type: 'mercurial', repository: path.join(__dirname, 'repos', 'mercurial'), diff --git a/test/index.js b/test/index.js index 5071165..9d5df3a 100644 --- a/test/index.js +++ b/test/index.js @@ -1,5 +1,6 @@ 'use strict'; require('./commands'); -require('./scm') -require('./executor') +require('./scm'); +require('./executor'); +require('./node'); diff --git a/test/node.js b/test/node.js new file mode 100644 index 0000000..add084d --- /dev/null +++ b/test/node.js @@ -0,0 +1,63 @@ +'use strict'; + +var Node = require('../lib/node').Node, + expect = require('expect.js'); + + +describe('Node', function() { + var node, + project1 = {name: 'project1'}, + project2 = {name: 'project2'}; + + var expectNodeHasFreeExecutor = function(project, value) { + it('should' + (value ? ' ' : ' not ') + 'has free executors for ' + + project.name, function() { + expect(node.hasFreeExecutor(project)).equal(value); + } + ); + }; + + describe('basic', function() { + it('instance should be created without errors', function() { + node = new Node({ + type: 'local', + maxExecutorsCount: 1 + }); + }); + + expectNodeHasFreeExecutor(project1, true); + expectNodeHasFreeExecutor(project2, true); + }); + + describe('with 100 ms project', function() { + var originalCreateExecutor; + before(function() { + originalCreateExecutor = node._createExecutor; + node._createExecutor = function() { + return {run: function(params, callback) { + setTimeout(callback, 100); + }}; + }; + }); + + it('should run without errors', function() { + node.run(project1, {}, function(err) { + expect(err).not.ok(); + }); + }); + + expectNodeHasFreeExecutor(project1, false); + expectNodeHasFreeExecutor(project2, false); + + it('wait for project done (should no errors)', function(done) { + setTimeout(done, 100); + }); + + expectNodeHasFreeExecutor(project1, true); + expectNodeHasFreeExecutor(project2, true); + + after(function() { + node._createExecutor = originalCreateExecutor; + }); + }); +});