Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Refactor cli + request handling and unit tests

Move commands setup to conf/commands.json, cli handling to bag.cli.command
Move request handling to bag.http.request
Change unit tests from Mocha to Buster
  • Loading branch information...
commit f77e2995b63f64d8c0d75cd348d90cfd7ce1fd4a 1 parent e105657
@cliffano authored
View
4 .travis.yml
@@ -3,5 +3,5 @@ node_js:
- 0.9
- 0.8
- 0.6
-before_install: "npm install -g bob"
-script: "bob clean lint test coverage"
+before_install: "npm install -g bob buster"
+script: "bob clean lint; buster test"
View
4 CHANGELOG.md
@@ -1,5 +1,7 @@
### 0.0.11 (SNAPSHOT)
-*
+* Move commands setup to conf/commands.json, cli handling to bag.cli.command
+* Move request handling to bag.http.request
+* Change unit tests from Mocha to Buster
### 0.0.10
* Add stop command
View
7 buster.js
@@ -0,0 +1,7 @@
+module.exports.unit = {
+ environment: 'node',
+ tests: [
+ 'test/cli.js',
+ 'test/jenkins.js'
+ ]
+};
View
37 conf/commands.json
@@ -0,0 +1,37 @@
+{
+ "commands": {
+ "build": {
+ "desc": "Trigger a build with optional parameters\n\tnestor build <jobname> [\"param1=value1&param2=value2\"]",
+ "options": [
+ {
+ "arg": "-c, --console",
+ "desc": "Display console ouptput of the triggered build progress"
+ }
+ ]
+ },
+ "console": {
+ "desc": "Display latest build console output\n\tnestor console <jobname>"
+ },
+ "stop": {
+ "desc": "Stop the currently running build\n\tnestor stop <jobname>"
+ },
+ "dashboard": {
+ "desc": "View status of all jobs\n\tnestor dashboard"
+ },
+ "discover": {
+ "desc": "Discover Jenkins instance running on a specified host\n\tnestor discover <hostname>"
+ },
+ "executor": {
+ "desc": "View executors' status (running builds)\n\tnestor executor"
+ },
+ "job": {
+ "desc": "View job status reports\n\tnestor job <jobname>"
+ },
+ "queue": {
+ "desc": "View queued jobs\n\tnestor queue"
+ },
+ "ver": {
+ "desc": "View Jenkins version number\n\tnestor ver"
+ }
+ }
+}
View
285 lib/cli.js
@@ -1,192 +1,137 @@
var _ = require('underscore'),
bag = require('bagofholding'),
- Jenkins = require('./jenkins');
+ Jenkins = require('./jenkins'),
+ jenkins = new Jenkins(process.env.JENKINS_URL, process.env.http_proxy);
-/**
- * Execute nestor using JENKINS_URL environment variable.
- * Nestor uses http_proxy environment variable when it's available.
- */
-function exec() {
-
- var url = process.env.JENKINS_URL,
- proxy = process.env.http_proxy;
-
- function _build() {
- return function (jobName, params, args) {
- if (!args) {
- args = params || {};
- }
+function _build(jobName, params, args) {
+ if (!args) {
+ args = params || {};
+ }
- var message = 'Job %s was started successfully',
- cb;
+ var message = 'Job %s was started successfully',
+ cb;
- if (args.console) {
- cb = function (err, result) {
- if (err) {
- bag.cli.exit(err, result);
- } else {
- console.log(message, jobName);
- // wait for pending period
- setTimeout(function () {
- _console()(jobName);
- }, 5000);
- }
- };
+ if (args.console) {
+ cb = function (err, result) {
+ if (err) {
+ bag.cli.exit(err, result);
} else {
- cb = bag.cli.exitCb(null, function (result) {
- console.log(message, jobName);
- });
+ console.log(message, jobName);
+ // wait for pending period
+ setTimeout(function () {
+ _console()(jobName);
+ }, 5000);
}
-
- new Jenkins(url, proxy).build(
- jobName,
- (_.isString(params)) ? params : undefined,
- cb
- );
- };
- }
-
- function _console() {
- return function (jobName) {
- new Jenkins(url, proxy).console(
- jobName,
- bag.cli.exit
- );
};
+ } else {
+ cb = bag.cli.exitCb(null, function (result) {
+ console.log(message, jobName);
+ });
}
- function _stop() {
- return function (jobName, params) {
- new Jenkins(url, proxy).stop(
- jobName,
- bag.cli.exitCb(null, function (result) {
- console.log('Job %s was stopped successfully', jobName);
- })
- );
- };
- }
+ jenkins.build(jobName, (_.isString(params)) ? params : undefined, cb);
+}
- function _dashboard() {
- return function () {
- new Jenkins(url, proxy).dashboard(bag.cli.exitCb(null, function (result) {
- if (result.length === 0) {
- console.log('Jobless Jenkins');
- } else {
- result.forEach(function (job) {
- console.log('%s - %s', job.status, job.name);
- });
- }
- }));
- };
- }
+function _console(jobName) {
+ jenkins.console(jobName, bag.cli.exit);
+}
- function _discover() {
- return function (host) {
- new Jenkins(url, proxy).discover(host, bag.cli.exitCb(null, function (result) {
- console.log('Jenkins ver. %s is running on %s',
- result.hudson.version[0],
- (result.hudson.url && result.hudson.url[0]) ? result.hudson.url[0] : host);
- }));
- };
- }
+function _stop(jobName, params) {
+ jenkins.stop(
+ jobName,
+ bag.cli.exitCb(null, function (result) {
+ console.log('Job %s was stopped successfully', jobName);
+ })
+ );
+}
- function _executor() {
- return function () {
- new Jenkins(url, proxy).executor(bag.cli.exitCb(null, function (result) {
- if (!_.isEmpty(_.keys(result))) {
- _.keys(result).forEach(function (computer) {
- console.log('+ ' + computer);
- result[computer].forEach(function (executor) {
- if (executor.idle) {
- console.log(' - idle');
- } else {
- console.log(' - %s | %s%%s', executor.name, executor.progress, (executor.stuck) ? ' stuck!' : '');
- }
- });
- });
- } else {
- console.log('No executor found');
- }
- }));
- };
- }
+function _dashboard() {
+ jenkins.dashboard(bag.cli.exitCb(null, function (result) {
+ if (result.length === 0) {
+ console.log('Jobless Jenkins');
+ } else {
+ result.forEach(function (job) {
+ console.log('%s - %s', job.status, job.name);
+ });
+ }
+ }));
+}
+
+function _discover(host) {
+ host = (_.isString(host)) ? host : 'localhost';
+ jenkins.discover(host, bag.cli.exitCb(null, function (result) {
+ console.log('Jenkins ver. %s is running on %s',
+ result.hudson.version[0],
+ (result.hudson.url && result.hudson.url[0]) ? result.hudson.url[0] : host);
+ }));
+}
- function _job() {
- return function (name) {
- new Jenkins(url, proxy).job(name, bag.cli.exitCb(null, function (result) {
- console.log('%s | %s', name, result.status);
- result.reports.forEach(function (report) {
- console.log(' - %s', report);
+function _executor() {
+ jenkins.executor(bag.cli.exitCb(null, function (result) {
+ if (!_.isEmpty(_.keys(result))) {
+ _.keys(result).forEach(function (computer) {
+ console.log('+ ' + computer);
+ result[computer].forEach(function (executor) {
+ if (executor.idle) {
+ console.log(' - idle');
+ } else {
+ console.log(' - %s | %s%%s', executor.name, executor.progress, (executor.stuck) ? ' stuck!' : '');
+ }
});
- }));
- };
- }
+ });
+ } else {
+ console.log('No executor found');
+ }
+ }));
+}
- function _queue() {
- return function () {
- new Jenkins(url, proxy).queue(bag.cli.exitCb(null, function (result) {
- if (result.length === 0) {
- console.log('Queue is empty');
- } else {
- result.forEach(function (job) {
- console.log('- %s', job);
- });
- }
- }));
- };
- }
+function _job(name) {
+ jenkins.job(name, bag.cli.exitCb(null, function (result) {
+ console.log('%s | %s', name, result.status);
+ result.reports.forEach(function (report) {
+ console.log(' - %s', report);
+ });
+ }));
+}
- function _version() {
- return function () {
- new Jenkins(url, proxy).version(bag.cli.exitCb(null, function (result) {
- console.log('Jenkins ver. %s', result);
- }));
- };
- }
-
- var commands = {
- build: {
- desc: 'Trigger a build with optional parameters\n\tnestor build <jobname> ["param1=value1&param2=value2"]',
- options: [
- { arg: '-c, --console', desc: 'Display console ouptput of the triggered build progress' }
- ],
- action: _build()
- },
- console: {
- desc: 'Display latest build console output\n\tnestor console <jobname>',
- action: _console()
- },
- stop: {
- desc: 'Stop the currently running build\n\tnestor stop <jobname>',
- action: _stop()
- },
- dashboard: {
- desc: 'View status of all jobs\n\tnestor dashboard',
- action: _dashboard()
- },
- discover: {
- desc: 'Discover Jenkins instance running on a specified host\n\tnestor discover <hostname>',
- action: _discover()
- },
- executor: {
- desc: 'View executors\' status (running builds)\n\tnestor executor',
- action: _executor()
- },
- job: {
- desc: 'View job status reports\n\tnestor job <jobname>',
- action: _job()
- },
- queue: {
- desc: 'View queued jobs\n\tnestor queue',
- action: _queue()
- },
- ver: {
- desc: 'View Jenkins version number\n\tnestor ver',
- action: _version()
+function _queue() {
+ jenkins.queue(bag.cli.exitCb(null, function (result) {
+ if (result.length === 0) {
+ console.log('Queue is empty');
+ } else {
+ result.forEach(function (job) {
+ console.log('- %s', job);
+ });
+ }
+ }));
+}
+
+function _version() {
+ jenkins.version(bag.cli.exitCb(null, function (result) {
+ console.log('Jenkins ver. %s', result);
+ }));
+}
+
+/**
+ * Execute Nestor.
+ */
+function exec() {
+
+ var actions = {
+ commands: {
+ build: { action: _build },
+ console: { action: _console },
+ stop: { action: _stop },
+ dashboard: { action: _dashboard },
+ discover: { action: _discover },
+ executor: { action: _executor },
+ job: { action: _job },
+ queue: { action: _queue },
+ ver: { action: _version }
}
};
- bag.cli.parse(commands, __dirname);
+ bag.cli.command(__dirname, actions);
}
-exports.exec = exec;
+exports.exec = exec;
View
285 lib/jenkins.js
@@ -1,119 +1,32 @@
var _ = require('underscore'),
async = require('async'),
+ bag = require('bagofholding'),
colors = require('colors'),
dgram = require('dgram'),
request = require('request'),
xml2js = require('xml2js');
/**
- * Sends a HTTP request to a Jenkins URL and handle the following errors:
- * - request error
- * - authentication error
- * - unexpected status error
- *
- * @param {String} method: http method
- * @param {String} url: Jenkins URL without query string
- * @param {String} proxy: proxy server URL in format http://user:pass@host:port
- * @param {Object} qs: object containing URL query strings with format { name: value }
- * @param {Object} handlers: response handlers with format { statuscode: handlerfunction }
- * @param {Function} cb: standard cb(err, result) callback
- */
-function _http(method, url, proxy, queryStrings, handlers, cb) {
-
- var params = {
- method: method,
- uri: url,
- qs: queryStrings
- };
-
- if (proxy) {
- params.proxy = proxy;
- }
-
- request(params, function (err, result) {
- if (err) {
- cb(err);
- } else if (result.statusCode === 401) {
- cb(new Error('Authentication failed - incorrect username and/or password in JENKINS_URL'));
- } else if (result.statusCode === 403) {
- cb(new Error('Jenkins requires authentication - set username and password in JENKINS_URL'));
- } else if (handlers[result.statusCode]) {
- handlers[result.statusCode](result);
- } else {
- cb(new Error('Unexpected status code ' + result.statusCode + ' from Jenkins\nResponse body:\n' + result.body));
- }
- });
-}
-
-/**
- * Send UDP message to a Jenkins instance.
- *
- * @param {String} message: message to be sent to Jenkins
- * @param {String} host: Jenkins host name
- * @param {String} port: Jenkins port number
- * @param {Function} cb: standard cb(err, result) callback
- */
-function _udp(message, host, port, cb) {
-
- var socket = dgram.createSocket('udp4'),
- buffer = new Buffer(message),
- parser = new xml2js.Parser();
-
- socket.on('error', function (err) {
- socket.close();
- cb(err);
- });
-
- socket.on('message', function (result) {
- socket.close();
- parser.addListener('end', function (result) {
- cb(null, result);
- });
- parser.parseString(result);
- });
-
- socket.send(buffer, 0, buffer.length, port, host, function (err, result) {
- if (err) {
- socket.close();
- cb(err);
- }
- });
-}
-
-/**
- * Convert a color into a status.
- * Jenkins returns a mix of color, color_anime, and status in job.color field.
- *
- * @param {String} color: job color
- * @return {String} status representation of the color
- */
-function _status(color) {
-
- var colors = {
- 'blue': 'OK',
- 'green': 'OK',
- 'grey': 'ABORTED',
- 'red': 'FAIL',
- 'yellow': 'WARN'
- },
- status;
-
- // remove animation status (only for actively running job)
- color = color.replace(/_anime/, '');
-
- status = (colors[color]) ? (colors[color]) : color.toUpperCase();
- return status[color] || status.grey || status;
-}
-
-/**
* class Jenkins
*
* @param {String} url: Jenkins URL
- * @param {String} proxy: proxy server URL in format http://user:pass@host:port
+ * @param {String} proxy: optional proxy server URL in format http://user:pass@host:port
*/
function Jenkins (url, proxy) {
this.url = url || 'http://localhost:8080';
- this.proxy = proxy;
+ this.opts = {
+ proxy: proxy,
+ handlers: {
+ // authentication failed error handler
+ 401: function (result, cb) {
+ cb(new Error('Authentication failed - incorrect username and/or password in JENKINS_URL'));
+ },
+ // authentication required error handler
+ 403: function (result, cb) {
+ cb(new Error('Jenkins requires authentication - set username and password in JENKINS_URL'));
+ }
+ }
+ };
}
/**
@@ -125,18 +38,6 @@ function Jenkins (url, proxy) {
*/
Jenkins.prototype.build = function (jobName, params, cb) {
- function _success(result) {
- cb(null);
- }
-
- function _notFound(result) {
- cb(new Error('Job ' + jobName + ' does not exist'));
- }
-
- function _notAllowed(result) {
- cb(new Error('Job ' + jobName + ' requires build parameters'));
- }
-
var json = { parameter: [] },
method = 'get';
@@ -147,8 +48,24 @@ Jenkins.prototype.build = function (jobName, params, cb) {
});
method = 'post';
}
+ this.opts.queryStrings = { token: 'nestor', json: JSON.stringify(json) };
- _http(method, this.url + '/job/' + jobName + '/build', this.proxy, { token: 'nestor', json: JSON.stringify(json) }, { 200: _success, 404: _notFound, 405: _notAllowed }, cb);
+ // success handler
+ this.opts.handlers['200'] = function (result, cb) {
+ cb();
+ };
+
+ // not found error handler
+ this.opts.handlers['404'] = function _notFound(result, cb) {
+ cb(new Error('Job ' + jobName + ' does not exist'));
+ };
+
+ // parameters required error handler
+ this.opts.handlers['405'] = function (result, cb) {
+ cb(new Error('Job ' + jobName + ' requires build parameters'));
+ };
+
+ bag.http.request(method, this.url + '/job/' + jobName + '/build', this.opts, cb);
};
/**
@@ -164,29 +81,29 @@ Jenkins.prototype.build = function (jobName, params, cb) {
Jenkins.prototype.console = function (jobName, cb) {
var url = this.url + '/job/' + jobName + '/lastBuild/logText/progressiveText',
- method = 'get',
self = this;
- function _success(result) {
+ this.opts.queryStrings = { start: 0 }; // the first chunk
+
+ // success handler
+ this.opts.handlers['200'] = function (result, cb) {
if (result.body) {
process.stdout.write(result.body);
}
-
+ // stream while there are more data
async.whilst(
function () {
return result.headers['x-more-data'] === 'true';
},
function (cb) {
var params = {
- method: method,
- uri: url,
+ url: url,
qs: { start: parseInt(result.headers['x-text-size'], 10) }
};
- if (self.proxy) {
- params.proxy = self.proxy;
+ if (self.opts.proxy) {
+ params.proxy = self.opts.proxy;
}
-
- request(params, function (err, _result) {
+ request.get(params, function (err, _result) {
if (err) {
cb(err);
} else {
@@ -204,13 +121,14 @@ Jenkins.prototype.console = function (jobName, cb) {
cb(err);
}
);
- }
+ };
- function _notFound(result) {
+ // not found error handler
+ this.opts.handlers['404'] = function (result, cb) {
cb(new Error('Job ' + jobName + ' does not exist'));
- }
+ };
- _http(method, url, this.proxy, { start: 0 }, { 200: _success, 404: _notFound }, cb);
+ bag.http.request('get', url, this.opts, cb);
};
/**
@@ -221,15 +139,17 @@ Jenkins.prototype.console = function (jobName, cb) {
*/
Jenkins.prototype.stop = function (jobName, cb) {
- function _success(result) {
+ // success handler
+ this.opts.handlers['200'] = function (result, cb) {
cb(null);
- }
+ };
- function _notFound(result) {
+ // not found error handler
+ this.opts.handlers['404'] = function (result, cb) {
cb(new Error('Job ' + jobName + ' does not exist'));
- }
+ };
- _http('get', this.url + '/job/' + jobName + '/lastBuild/stop', this.proxy, {}, { 200: _success, 404: _notFound }, cb);
+ bag.http.request('get', this.url + '/job/' + jobName + '/lastBuild/stop', this.opts, cb);
};
/**
@@ -240,19 +160,21 @@ Jenkins.prototype.stop = function (jobName, cb) {
*/
Jenkins.prototype.dashboard = function (cb) {
- function _success(result) {
+ var self = this;
+
+ // success handler
+ this.opts.handlers['200'] = function (result, cb) {
var jobs = JSON.parse(result.body).jobs,
data = [];
-
if (!_.isEmpty(jobs)) {
jobs.forEach(function (job) {
- data.push({ status: _status(job.color), name: job.name });
+ data.push({ status: self._status(job.color), name: job.name });
});
}
cb(null, data);
- }
+ };
- _http('get', this.url + '/api/json', this.proxy, {}, { 200: _success }, cb);
+ bag.http.request('get', this.url + '/api/json', this.opts, cb);
};
/**
@@ -262,7 +184,30 @@ Jenkins.prototype.dashboard = function (cb) {
* @param {Function} cb: standard cb(err, result) callback
*/
Jenkins.prototype.discover = function (host, cb) {
- _udp('Long live Jenkins!', host, 33848, cb);
+
+ var socket = dgram.createSocket('udp4'),
+ buffer = new Buffer('Long live Jenkins!'),
+ parser = new xml2js.Parser();
+
+ socket.on('error', function (err) {
+ socket.close();
+ cb(err);
+ });
+
+ socket.on('message', function (result) {
+ socket.close();
+ parser.addListener('end', function (result) {
+ cb(null, result);
+ });
+ parser.parseString(result);
+ });
+
+ socket.send(buffer, 0, buffer.length, 33848, host, function (err, result) {
+ if (err) {
+ socket.close();
+ cb(err);
+ }
+ });
};
/**
@@ -272,10 +217,12 @@ Jenkins.prototype.discover = function (host, cb) {
*/
Jenkins.prototype.executor = function (cb) {
- function _success(result) {
+ this.opts.queryStrings = { depth: 1 };
+
+ // success handler
+ this.opts.handlers['200'] = function (result, cb) {
var computers = JSON.parse(result.body).computer,
data = {};
-
computers.forEach(function (computer) {
data[computer.displayName] = [];
computer.executors.forEach(function (executor) {
@@ -290,9 +237,9 @@ Jenkins.prototype.executor = function (cb) {
});
});
cb(null, data);
- }
+ };
- _http('get', this.url + '/computer/api/json', this.proxy, { depth: 1 }, { 200: _success }, cb);
+ bag.http.request('get', this.url + '/computer/api/json', this.opts, cb);
};
/**
@@ -304,23 +251,26 @@ Jenkins.prototype.executor = function (cb) {
*/
Jenkins.prototype.job = function (name, cb) {
- function _success(result) {
+ var self = this;
+
+ // success handler
+ this.opts.handlers['200'] = function (result, cb) {
var _job = JSON.parse(result.body),
data = {};
- data.status = _status(_job.color);
+ data.status = self._status(_job.color);
data.reports = [];
_job.healthReport.forEach(function (report) {
data.reports.push(report.description);
});
-
cb(null, data);
- }
+ };
- function _notFound(result) {
+ // not found error handler
+ this.opts.handlers['404'] = function (result, cb) {
cb(new Error('Job ' + name + ' does not exist'));
- }
+ };
- _http('get', this.url + '/job/' + name + '/api/json', this.proxy, {}, { 200: _success, 404: _notFound }, cb);
+ bag.http.request('get', this.url + '/job/' + name + '/api/json', this.opts, cb);
};
/**
@@ -331,19 +281,19 @@ Jenkins.prototype.job = function (name, cb) {
*/
Jenkins.prototype.queue = function (cb) {
- function _success(result) {
+ // success handler
+ this.opts.handlers['200'] = function (result, cb) {
var items = JSON.parse(result.body).items,
data = [];
-
if (!_.isEmpty(items)) {
items.forEach(function (item) {
data.push(item.task.name);
});
}
cb(null, data);
- }
+ };
- _http('get', this.url + '/queue/api/json', this.proxy, {}, { 200: _success }, cb);
+ bag.http.request('get', this.url + '/queue/api/json', this.opts, cb);
};
/**
@@ -354,15 +304,36 @@ Jenkins.prototype.queue = function (cb) {
*/
Jenkins.prototype.version = function (cb) {
- function _success(result) {
+ // success handler
+ this.opts.handlers['200'] = function (result, cb) {
if (result.headers['x-jenkins']) {
cb(null, result.headers['x-jenkins']);
} else {
cb(new Error('Not a Jenkins server'));
}
- }
+ };
+
+ bag.http.request('head', this.url, this.opts, cb);
+};
+
+Jenkins.prototype._status = function (color) {
+
+ var colors = {
+ 'blue': 'OK',
+ 'green': 'OK',
+ 'grey': 'ABORTED',
+ 'red': 'FAIL',
+ 'yellow': 'WARN'
+ },
+ status;
+
+ // Jenkins color value can contain either a color, color_anime, or status in job.color field,
+ // hence to get color/status value out of the mix we need to remove the postfix _anime,
+ // _anime postfix only exists on a job currently being built
+ color = color.replace(/_anime/, '');
- _http('head', this.url, this.proxy, {}, { 200: _success }, cb);
+ status = (colors[color]) ? (colors[color]) : color.toUpperCase();
+ return status[color] || status.grey;
};
module.exports = Jenkins;
View
6 package.json
@@ -34,13 +34,11 @@
"bagofholding": "0.0.15",
"colors": "0.6.0-1",
"request": "2.12.0",
- "underscore": "1.4.2",
+ "underscore": "1.4.3",
"xml2js": "0.2.2"
},
"devDependencies": {
- "mocha": "1.7.0",
- "sandboxed-module": "0.1.3",
- "should": "1.2.1"
+ "buster": "0.6.3"
},
"scripts": {},
"engines": {
View
73 test/cli.js
@@ -1,3 +1,75 @@
+var buster = require('buster'),
+ cli = require('../lib/cli'),
+ bag = require('bagofholding'),
+ Jenkins = new require('../lib/jenkins');
+
+/*
+buster.testCase('', {
+ '': function (done) {
+ mockRequest = function (method, url, opts, cb) {
+ assert.equals(method, '');
+ assert.equals(url, 'http://localhost:8080');
+ opts.handlers['200']({ headers: {} }, cb);
+ }
+ this.stub(bag, 'http', { request: mockRequest });
+ jenkins = new Jenkins('http://localhost:8080');
+ jenkins.version(function (err, result) {
+ done();
+ });
+ }
+});
+*/
+
+buster.testCase('exec', {
+ 'should contain commands with actions': function (done) {
+ var mockCommand = function (base, actions) {
+ assert.defined(base);
+ assert.defined(actions.commands.build.action);
+ assert.defined(actions.commands.console.action);
+ assert.defined(actions.commands.stop.action);
+ assert.defined(actions.commands.dashboard.action);
+ assert.defined(actions.commands.discover.action);
+ assert.defined(actions.commands.executor.action);
+ assert.defined(actions.commands.job.action);
+ assert.defined(actions.commands.queue.action);
+ assert.defined(actions.commands.ver.action);
+ done();
+ };
+ this.stub(bag, 'cli', { command: mockCommand });
+ cli.exec();
+ }
+});
+
+buster.testCase('ver', {
+ 'setUp': function () {
+ this.mockConsole = this.mock(console);
+ this.mockProcess = this.mock(process);
+ this.stub(bag, 'cli', {
+ command: function (base, actions) {
+ actions.commands.ver.action();
+ },
+ exitCb: bag.cli.exitCb
+ });
+ },
+ 'should log version when exec ver is called and version exists': function () {
+ this.mockConsole.expects('log').once().withExactArgs('Jenkins ver. %s', '1.2.3');
+ this.mockProcess.expects('exit').once().withExactArgs(0);
+ this.stub(Jenkins.prototype, 'version', function (cb) {
+ cb(null, '1.2.3');
+ });
+ cli.exec();
+ },
+ 'should log error when exec ver is called and version does not exist': function () {
+ this.mockConsole.expects('error').once().withExactArgs('someerror');
+ this.mockProcess.expects('exit').once().withExactArgs(1);
+ this.stub(Jenkins.prototype, 'version', function (cb) {
+ cb(new Error('someerror'));
+ });
+ cli.exec();
+ }
+});
+
+/*
var bag = require('bagofholding'),
sandbox = require('sandboxed-module'),
should = require('should'),
@@ -371,3 +443,4 @@ describe('cli', function () {
});
});
});
+*/
View
205 test/jenkins.js
@@ -1,3 +1,206 @@
+var buster = require('buster'),
+ Jenkins = require('../lib/jenkins'),
+ bag = require('bagofholding');
+
+/*
+buster.testCase('', {
+ '': function (done) {
+ var mockRequest = function (method, url, opts, cb) {
+ assert.equals(method, '');
+ assert.equals(url, 'http://localhost:8080');
+ opts.handlers['200']({ headers: {} }, cb);
+ }
+ this.stub(bag, 'http', { request: mockRequest });
+ var jenkins = new Jenkins('http://localhost:8080');
+ jenkins.version(function (err, result) {
+ done();
+ });
+ }
+});
+*/
+
+// TODO: discover
+
+buster.testCase('executor', {
+ 'should pass executor idle, stuck, and progress status when executor has them': function (done) {
+ var mockRequest = function (method, url, opts, cb) {
+ assert.equals(method, 'get');
+ assert.equals(url, 'http://localhost:8080/computer/api/json');
+ opts.handlers['200']({ statusCode: 200, body: JSON.stringify({
+ computer: [
+ {
+ displayName: 'master',
+ executors: [
+ { idle: false, likelyStuck: false, progress: 88, currentExecutable: { url: 'http://localhost:8080/job/job1/19/' } },
+ { idle: true, likelyStuck: false, progress: 0 }
+ ]
+ },
+ {
+ displayName: 'slave',
+ executors: [
+ { idle: false, likelyStuck: true, progress: 88, currentExecutable: { url: 'http://localhost:8080/job/job2/30/' } }
+ ]
+ }
+ ]
+ })}, cb);
+ };
+ this.stub(bag, 'http', { request: mockRequest });
+ var jenkins = new Jenkins('http://localhost:8080');
+ jenkins.executor(function (err, result) {
+ assert.isNull(err);
+
+ // multiple executors on a master
+ assert.equals(result.master.length, 2);
+ assert.equals(result.master[0].progress, 88);
+ assert.equals(result.master[0].stuck, false);
+ assert.equals(result.master[0].idle, false);
+ assert.equals(result.master[0].name, 'job1');
+ assert.equals(result.master[1].progress, 0);
+ assert.equals(result.master[1].stuck, false);
+ assert.equals(result.master[1].idle, true);
+ assert.equals(result.master[1].name, undefined);
+
+ // single executor on a slave
+ assert.equals(result.slave.length, 1);
+ assert.equals(result.slave[0].progress, 88);
+ assert.equals(result.slave[0].stuck, true);
+ assert.equals(result.slave[0].idle, false);
+ assert.equals(result.slave[0].name, 'job2');
+
+ done();
+ });
+ }
+});
+
+buster.testCase('job', {
+ 'should pass job status and results when job exists': function (done) {
+ var mockRequest = function (method, url, opts, cb) {
+ assert.equals(method, 'get');
+ assert.equals(url, 'http://localhost:8080/job/job1/api/json');
+ opts.handlers['200']({ statusCode: 200, body: JSON.stringify({
+ color: 'blue',
+ healthReport: [
+ { description: 'Coverage is 100%' },
+ { description: 'All system is go!' }
+ ]
+ })}, cb);
+ };
+ this.stub(bag, 'http', { request: mockRequest });
+ var jenkins = new Jenkins('http://localhost:8080');
+ jenkins.job('job1', function (err, result) {
+ assert.isNull(err);
+ assert.equals(result.status, 'OK'.blue);
+ assert.equals(result.reports[0], 'Coverage is 100%');
+ assert.equals(result.reports[1], 'All system is go!');
+ done();
+ });
+ },
+ 'should pass error when job does not exist': function (done) {
+ var mockRequest = function (method, url, opts, cb) {
+ assert.equals(method, 'get');
+ assert.equals(url, 'http://localhost:8080/job/job1/api/json');
+ opts.handlers['404']({ statusCode: 404, body: 'somenotfounderror' }, cb);
+ };
+ this.stub(bag, 'http', { request: mockRequest });
+ var jenkins = new Jenkins('http://localhost:8080');
+ jenkins.job('job1', function (err, result) {
+ assert.equals(err.message, 'Job job1 does not exist');
+ assert.equals(result, undefined);
+ done();
+ });
+ }
+});
+
+buster.testCase('queue', {
+ 'should pass job names when queue is not empty': function (done) {
+ var mockRequest = function (method, url, opts, cb) {
+ assert.equals(method, 'get');
+ assert.equals(url, 'http://localhost:8080/queue/api/json');
+ opts.handlers['200']({ statusCode: 200, body: JSON.stringify({
+ items: [
+ { task: { name: 'job1' }},
+ { task: { name: 'job2' }}
+ ]
+ })}, cb);
+ };
+ this.stub(bag, 'http', { request: mockRequest });
+ var jenkins = new Jenkins('http://localhost:8080');
+ jenkins.queue(function (err, result) {
+ assert.isNull(err);
+ assert.equals(result.length, 2);
+ assert.equals(result[0], 'job1');
+ assert.equals(result[1], 'job2');
+ done();
+ });
+ },
+ 'should pass empty job names when queue is empty': function (done) {
+ var mockRequest = function (method, url, opts, cb) {
+ assert.equals(method, 'get');
+ assert.equals(url, 'http://localhost:8080/queue/api/json');
+ opts.handlers['200']({ statusCode: 200, body: JSON.stringify({
+ items: []
+ })}, cb);
+ };
+ this.stub(bag, 'http', { request: mockRequest });
+ var jenkins = new Jenkins('http://localhost:8080');
+ jenkins.queue(function (err, result) {
+ assert.isNull(err);
+ assert.equals(result.length, 0);
+ done();
+ });
+ }
+});
+
+buster.testCase('version', {
+ 'should pass error to callback when headers do not contain x-jenkins': function (done) {
+ var mockRequest = function (method, url, opts, cb) {
+ assert.equals(method, 'head');
+ assert.equals(url, 'http://localhost:8080');
+ opts.handlers['200']({ headers: {} }, cb);
+ };
+ this.stub(bag, 'http', { request: mockRequest });
+ var jenkins = new Jenkins('http://localhost:8080');
+ jenkins.version(function (err, result) {
+ assert.equals(err.message, 'Not a Jenkins server');
+ assert.equals(result, undefined);
+ done();
+ });
+ },
+ 'should pass version to callback when headers contain x-jenkins': function (done) {
+ var mockRequest = function (method, url, opts, cb) {
+ assert.equals(method, 'head');
+ assert.equals(url, 'http://localhost:8080');
+ opts.handlers['200']({ statusCode: 200, headers: { 'x-jenkins': '1.464' }}, cb);
+ };
+ this.stub(bag, 'http', { request: mockRequest });
+ var jenkins = new Jenkins('http://localhost:8080');
+ jenkins.version(function (err, result) {
+ assert.isNull(err);
+ assert.equals(result, '1.464');
+ done();
+ });
+ }
+});
+
+buster.testCase('_status', {
+ 'should show the correct status for all supported colors': function () {
+ var jenkins = new Jenkins();
+ assert.equals(jenkins._status('blue'), 'OK'.blue);
+ assert.equals(jenkins._status('green'), 'OK'.green);
+ assert.equals(jenkins._status('grey'), 'ABORTED'.grey);
+ assert.equals(jenkins._status('red'), 'FAIL'.red);
+ assert.equals(jenkins._status('yellow'), 'WARN'.yellow);
+ },
+ 'should show the correct status for actively running build': function () {
+ var jenkins = new Jenkins();
+ assert.equals(jenkins._status('blue_anime'), 'OK'.blue);
+ },
+ 'should use grey color when status is unsupported': function () {
+ var jenkins = new Jenkins();
+ assert.equals(jenkins._status('unknown'), 'UNKNOWN'.grey);
+ }
+});
+/*
var bag = require('bagofholding'),
_jscov = require('../lib/jenkins'),
sandbox = require('sandboxed-module'),
@@ -731,3 +934,5 @@ describe('jenkins', function () {
});
});
});
+
+*/
Please sign in to comment.
Something went wrong with that request. Please try again.