removing mocha, switch to nodeunit

This commit is contained in:
Spencer Alger
2013-09-17 09:01:35 -07:00
parent a305581d9c
commit 0ac81e1989
19 changed files with 373 additions and 209 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "spec/es_api"]
path = spec/es_api
url = git@github.com:elasticsearch/elasticsearch-rest-api-spec.git
[submodule "es_api_spec"]
path = es_api_spec
url = git@github.com:elasticsearch/elasticsearch-rest-api-spec.git

View File

@ -13,7 +13,7 @@ module.exports = function (grunt) {
'src/transport.js'
];
var post = ['src/client.js','src/post.js'];
var post = ['src/client.js', 'src/post.js'];
// Project configuration.
grunt.initConfig({
@ -30,36 +30,45 @@ module.exports = function (grunt) {
banner: '<%= meta.banner %>'
},
node: {
src: pre.concat(['src/transport/elasticsearch-node.js'],post),
src: pre.concat(['src/transport/elasticsearch-node.js'], post),
dest: 'dist/elasticsearch-node.js'
}
},
mochaTest: {
test: {
options: {
reporter: 'spec',
require: [
'should'
]
},
src: ['spec/**/*.js']
nodeunit: {
nodeunit: {
all: [
'test/**/*.test.js'
]
}
},
jshint: {
cwd: 'src',
files: ['../Gruntfile.js', '**/*.js' ],
options: {
jshintrc: 'src/.jshintrc'
source: {
src: [
'Gruntfile.js',
'src/**/*.js',
],
options: {
jshintrc: 'src/.jshintrc'
}
},
tests: {
src: [
'test/**/*.js'
],
options: {
jshintrc: 'test/.jshintrc'
}
}
}
});
// load plugins
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-contrib-nodeunit');
grunt.loadNpmTasks('grunt-contrib-jshint');
// Default task.
grunt.registerTask('default', [/*'jshint',*/ 'mochaTest']);
grunt.registerTask('default', ['jshint', 'nodeunit']);
grunt.registerTask('test', ['nodeunit']);
};

View File

@ -11,9 +11,8 @@
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-jshint": "~0.6.0",
"grunt-contrib-nodeunit": "~0.2.0",
"mocha": "~1.12.1",
"grunt-mocha-test": "~0.6.3",
"should": "~1.3.0"
"should": "~1.3.0",
"nodeunit": "~0.8.1"
},
"license": "Apache License",
"dependencies": {

Submodule spec/es_api deleted from 9831a98e42

View File

@ -1,58 +0,0 @@
/* node transport function tests */
// TODO: add check to see if any data in ES, fail if so.
'use strict';
var esj = require('../dist/elasticsearch-node.js');
var _c = new esj.Client();
/*
======== A Handy Little Nodeunit Reference ========
https://github.com/caolan/nodeunit
Test methods:
test.expect(numAssertions)
test.done()
Test assertions:
test.ok(value, [message])
test.equal(actual, expected, [message])
test.notEqual(actual, expected, [message])
test.deepEqual(actual, expected, [message])
test.notDeepEqual(actual, expected, [message])
test.strictEqual(actual, expected, [message])
test.notStrictEqual(actual, expected, [message])
test.throws(block, [error], [message])
test.doesNotThrow(block, [error], [message])
test.ifError(value)
*/
exports.logger = {
setUp: function(done) {
// Suppress console messages (this, sadly, applies globally)
//console.error = console.warn = console.info = console.log = function() {}
done();
},
'log': function(test) {
test.expect(5);
// Test defaults
test.equal(_c.logger.error('error'),'error','Error should be logged');
test.equal(_c.logger.warn('warn'),'warn','Warn should be logged');
test.equal(_c.logger.info('info'),false,'Info should not be logged');
test.equal(_c.logger.debug('debug'),false,'Debug should not be logged');
// Turn on info logging in first client
_c.logger.options.info = true;
test.equal(_c.logger.info('info'),'info','Info should be logged');
test.done();
},
'trace': function(test) {
test.expect(2);
// Test defaults
test.equal(_c.tracer.info('info'),false,'Info should not be logged');
test.equal(_c.tracer.trace('trace'),false,'Trace should not be logged');
test.done();
}
};

View File

@ -1,59 +0,0 @@
/* selector function tests */
'use strict';
var esj = require('../dist/elasticsearch-node.js');
var _c = new esj.Client();
/*
======== A Handy Little Nodeunit Reference ========
https://github.com/caolan/nodeunit
Test methods:
test.expect(numAssertions)
test.done()
Test assertions:
test.ok(value, [message])
test.equal(actual, expected, [message])
test.notEqual(actual, expected, [message])
test.deepEqual(actual, expected, [message])
test.notDeepEqual(actual, expected, [message])
test.strictEqual(actual, expected, [message])
test.notStrictEqual(actual, expected, [message])
test.throws(block, [error], [message])
test.doesNotThrow(block, [error], [message])
test.ifError(value)
*/
exports.selector = {
setUp: function(done) {
done();
},
'exists': function(test) {
test.expect(3);
test.ok(esj.Selector,'Should exist');
test.ok(esj.Selector.roundRobin,'Should exist');
test.ok(esj.Selector.random,'Should exist');
test.done();
},
'roundRobin' : function(test) {
test.expect(4);
var hosts = ['foo','bar','baz'];
test.equal(esj.Selector.roundRobin(hosts),'baz','Should be baz');
test.equal(esj.Selector.roundRobin(hosts),'bar','Should be bar');
test.equal(esj.Selector.roundRobin(hosts),'foo','Should be foo');
hosts = ['foo'];
test.equal(esj.Selector.roundRobin(hosts),'foo','Should be foo');
test.done();
},
'random' : function(test) {
test.expect(2);
var hosts = ['bar','baz','foo'];
test.ok(esj.Selector.roundRobin(hosts),'Should return something');
// This is how underscore.js tests its shuffle, will have to suffice
test.deepEqual(hosts.sort(),['bar','baz','foo'],'Should contain the same elements');
test.done();
}
};

View File

@ -1,5 +1,6 @@
var _ = require('./Utils')
, transports = _.requireDir(module, './transports');
, transports = _.requireDir(module, './transports')
, Log = require('./Log');
// Expose the client object
function Client(config) {
@ -9,7 +10,7 @@ function Client(config) {
// For convenience
// this.transport = this.options.transport || new transports.NodeHttp(this.options);
this.logger = config.logger || new es.Log(this.logger);
this.logger = config.logger || new Log(this.logger);
// this.serializer = this.options.serializer || new es.Serializer.json();
}

View File

@ -1,9 +1,7 @@
var _ = require('../Utils'),
events = require('events'),
loggers = _.requireDir(module, './loggers');
var _ = require('./Utils'),
EventEmitter = require('events').EventEmitter;
/**
*
* Log bridge, which writes using one or more Logger's. Setup these loggers by
* specifying their config with the first argument, or by calling addOutput.
*
@ -20,13 +18,13 @@ function Log(output) {
output = output || 2;
if (_.isString(output)) {
if (_.isString(output) || _.isFinite(output)) {
output = [
{
level: output
}
];
} else if (_.isObject(output)) {
} else if (_.isPlainObject(output)) {
output = [output];
} else if (_.isArray(output)) {
for (i = 0; i < output.length; i++) {
@ -46,14 +44,12 @@ function Log(output) {
* A list of the log streams, which are listening to this logger.
* @type {Array}
*/
this.outputs = [];
for (i = 0; i < output.length; i++) {
this.addLogger(output[i]);
this.addOutput(output[i]);
}
}
_.inherits(Log, events.EventEmitter);
_.inherits(Log, EventEmitter);
/**
* Levels observed by the loggers, with their rank
@ -76,7 +72,7 @@ Log.levelsInverted = _.invert(Log.levels);
/**
* Converts a log identifier to an integer representing it's level
* @private
* @static
* @param {*} ident - The identifying to convert, if invalid then the default will be returned
* @param {Integer} default - The default log level to use if the identifier is not valid
* @return {Integer} - The number reprsenting the log level
@ -93,6 +89,21 @@ Log.level = function (ident, def) {
}
};
/**
* Combine the array-like param into a simple string
* @param {*} arrayish - An array like object that can be itterated by _.each
* @return {String} - The final string.
*/
Log.join = function (arrayish) {
return _.map(arrayish, function (item) {
if (_.isPlainObject(item)) {
return _.inspect(item, { showHidden: true, depth: null, color: true}) + '\n';
} else {
return item.toString();
}
}).join(' ');
};
/**
* Create a new logger, based on the config.
* @param {object} config An object with config options for the logger. Type is used to find the
@ -102,15 +113,12 @@ Log.level = function (ident, def) {
*/
Log.prototype.addOutput = function (config) {
_.defaults(config, {
type: 'stdio',
type: 'StdIo',
level: Log.level(config.type, 2)
});
if (loggers[config.type]) {
return this.outputs[this.outputs.push(new loggers[config.type](config, this)) - 1];
} else {
throw new TypeError('Invalid logger type ' + config.type);
}
var Logger = require('./loggers/' + config.type);
return new Logger(config, this);
};
/**
@ -119,17 +127,21 @@ Log.prototype.addOutput = function (config) {
* @return {undefined}
*/
Log.prototype.error = function (e) {
this.emit('error', e instanceof Error ? e : new Error(e));
if (EventEmitter.listenerCount(this, 'error')) {
return this.emit('error', e instanceof Error ? e : new Error(e));
}
};
/**
* Log a warning message
* @param {String} message The warning message
* @param {...*} msg - Any amount of messages that will be joined before logged
* @return {undefined}
*/
Log.prototype.warning = function (message) {
this.emit('warning', message);
Log.prototype.warning = function (/* ...msg */) {
if (EventEmitter.listenerCount(this, 'warning')) {
return this.emit('warning', Log.join(arguments));
}
};
/** @alias Log.warning */
Log.prototype.warn = Log.prototype.warning;
@ -137,29 +149,35 @@ Log.prototype.warn = Log.prototype.warning;
/**
* Log useful info about what's going on
* @param {String} message The warning message
* @param {...*} msg - Any amount of messages that will be joined before logged
* @return {undefined}
*/
Log.prototype.info = function (message) {
this.emit('info', message);
Log.prototype.info = function (/* ...msg */) {
if (EventEmitter.listenerCount(this, 'info')) {
return this.emit('info', Log.join(arguments));
}
};
/**
* Log a debug level message
* @param {String} message The warning message
* @param {...*} msg - Any amount of messages that will be joined before logged
* @return {undefined}
*/
Log.prototype.debug = function (message) {
this.emit('debug', message);
Log.prototype.debug = function (/* ...msg */) {
if (EventEmitter.listenerCount(this, 'debug')) {
return this.emit('debug', Log.join(arguments));
}
};
/**
* Log a trace level message
* @param {String} message The warning message
* @param {...*} msg - Any amount of messages that will be joined before logged
* @return {undefined}
*/
Log.prototype.trace = function (message) {
this.emit('trace', message);
Log.prototype.trace = function (/* ...msg */) {
if (EventEmitter.listenerCount(this, 'trace')) {
return this.emit('trace', Log.join(arguments));
}
};

View File

@ -20,7 +20,12 @@ mixins.joinPath = path.join;
* @param {Module} module The module object which will own the required modules.
* @param {String} path Path to the directory which will be traversed
*/
mixins.requireDir = requireDir;
mixins.requireDir = function (module, dirPath) {
if (dirPath && dirPath[0] === '.') {
dirPath = path.join(path.dirname(module.filename), dirPath);
}
return requireDir(module, dirPath);
};
/**
* isArrayOf(Strings|Objects|Arrays|Finites|Functions|RegExps)
@ -38,6 +43,28 @@ mixins.requireDir = requireDir;
};
});
var origBind = _.bind;
/**
* Slightly modified version of bind, which can accept the context as the first
* arg and the method name as the second, like jquery's proxy
* @param {Function|Object} func - The method to bind, or the context if the method will be
* specified using a string in param 2
* @param {Object|String} context - The context when `func` is a function, or the method name to bind
* when func is an object
* @param {...*} [args] Args to be bound to the function
* @return {Function} The bound function
*/
mixins.bind = function (func, context) {
var args = _.rest(arguments, 2);
if (typeof context === 'string') {
// args[1] is actually a method name, like _.bind(this, 'method');
args.unshift(func[context], func);
} else {
args.unshift(func, context);
}
return origBind.apply(_, args);
};
_.mixin(mixins);
module.exports = _;

View File

@ -15,10 +15,12 @@ function StdIo(config, bridge) {
var handlers = this.handlers = {};
this.color = true;
_.each(Log.levels, function (i, name) {
// create a version of each log event handler that is bound to "this"
handlers[Log.levels[name]] = 'on' + name.subString(0, 1).toUpperCase() + name.subString(1).toLowerCase();
});
handlers[Log.levels[name]] = _.bind(this, 'on' + name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase());
}, this);
this.setupListeners(config.level);
}
@ -28,7 +30,7 @@ function StdIo(config, bridge) {
* @return {undefined}
*/
StdIo.prototype.setupListeners = function (level) {
this.removeListeners();
this.cleanUpListeners();
for (this.listeningLevel = level; level > 0; level--) {
this.bridge.on(Log.levelsInverted[level], this.handlers[level]);
}
@ -39,27 +41,12 @@ StdIo.prototype.setupListeners = function (level) {
* @return {undefined}
*/
StdIo.prototype.cleanUpListeners = function () {
for (; this.listeningLevel < 0; this.listeningLevel--) {
for (; this.listeningLevel > 0; this.listeningLevel--) {
// remove the listeners for each event
this.bridge.removeListener(Log.levelsInverted[this.listeningLevel], this.handlers[this.listeningLevel]);
}
};
/**
* Combine the array_like param into a simple string
* @param {Array|Object} array_like - An array like object that can be itterated by _.each
* @return {String} - The final string.
*/
function join(array_like) {
return _.map(array_like, function (item) {
if (_.isPlainObject(item)) {
return _.inspect(item, { showHidden: true, depth: null, color: true}) + '\n';
} else {
return item.toString();
}
}).join(' ');
}
/**
* Sends output to a stream, does some formatting first
* @param {WriteableStream} to - The stream that should receive this message
@ -72,7 +59,7 @@ StdIo.prototype.write = function (to, label, colorize, what) {
if (this.color) {
label = colorize(label);
}
to.write(label + ': ' + (typeof what === 'object' ? join(what) : what));
to.write(label + ': ' + what + '\n');
};
/**
@ -81,43 +68,43 @@ StdIo.prototype.write = function (to, label, colorize, what) {
* @return {undefined}
*/
StdIo.prototype.onError = function (e) {
this.write(process.strderr, 'ERROR', clc.red.bold, e.name + ': ' + e.message + '\nStack Trace:\n' + e.stack);
this.write(process.stderr, e.name === 'Error' ? 'ERROR' : e.name, clc.red.bold, [e.message, '\n\nStack Trace:\n' + e.stack]);
};
/**
* Handler for the bridges "warning" event
* @param {...*} msg - Any amount of messages that will be joined before logged
* @param {String} msg - The message to be logged
* @return {undefined}
*/
StdIo.prototype.onWarning = function (/* ...msg */) {
this.write(process.strderr, 'warning', clc.yellow.bold, arguments);
StdIo.prototype.onWarning = function (msg) {
this.write(process.stderr, 'WARNING', clc.yellow.bold, msg);
};
/**
* Handler for the bridges "info" event
* @param {...*} msg - Any amount of messages that will be joined before logged
* @param {String} msg - The message to be logged
* @return {undefined}
*/
StdIo.prototype.onInfo = function (/* ...msg */) {
this.write(process.stdout, 'INFO', clc.cyan.bold, arguments);
StdIo.prototype.onInfo = function (msg) {
this.write(process.stdout, 'INFO', clc.cyan.bold, msg);
};
/**
* Handler for the bridges "debug" event
* @param {...*} msg - Any amount of messages that will be joined before logged
* @param {String} msg - The message to be logged
* @return {undefined}
*/
StdIo.prototype.onDebug = function (/* ...msg */) {
this.write(process.stdout, 'DEBUG', clc.magentaBright.bold, arguments);
StdIo.prototype.onDebug = function (msg) {
this.write(process.stdout, 'DEBUG', clc.magentaBright.bold, msg);
};
/**
* Handler for the bridges "trace" event
* @param {...*} msg - Any amount of messages that will be joined before logged
* @param {String} msg - The message to be logged
* @return {undefined}
*/
StdIo.prototype.onTrace = function (/* ...msg */) {
this.write(process.stdout, 'TRACE', clc.cyanBright.bold, arguments);
StdIo.prototype.onTrace = function (msg) {
this.write(process.stdout, 'TRACE', clc.cyanBright.bold, msg);
};
module.exports = StdIo;

View File

@ -1,6 +1,6 @@
/* elasticsearch-js nodejs transport */
var http = require('http');
var http = require('http')
, _ = require('../Utils');
function NodeHttp() {
@ -55,12 +55,12 @@ function NodeHttp() {
request.on('error', errorcb);
}
if(method !== 'GET' && method !== 'HEAD') {
if (method !== 'GET' && method !== 'HEAD') {
request.write(body);
}
request.end();
};
}
// Public functions
return {
@ -71,4 +71,6 @@ function NodeHttp() {
head : _.bind(performRequest, this, 'HEAD')
};
} ());
}
module.exports = NodeHttp;

52
test/Log.test.js Normal file
View File

@ -0,0 +1,52 @@
describe('Log (the log bridge)', function () {
var Log = require('../src/lib/Log');
describe('level', function () {
it('should return 2 for "warning"', function () {
Log.level('warning', 1)
.should.equal(2);
});
it('should return 2 for 2', function () {
Log.level('2', 1)
.should.equal(2);
});
it('should return the default for an invalid level', function () {
Log.level('invalid level', 2)
.should.equal(2);
});
});
describe('join', function () {
it('should join strings', function () {
Log.join(['one', 'two']).should.equal('one two');
});
it('should flatten nested arrays', function () {
Log.join(['one', ['three', 'four']])
.should.equal('one three,four');
});
it('should flatten arguments', function () {
(function() {
Log.join(arguments).should.equal('one two');
}('one', 'two'));
});
});
describe('When an instance has no outputs', function () {
var log = new Log([]); // no log outputs
it('error should not emit an event and return false', function () {
});
});
});

72
test/Loggers.test.js Normal file
View File

@ -0,0 +1,72 @@
describe('StdIo Logger', function () {
var Log = require('../src/lib/Log')
, log = new Log([])
, StdIo = require('../src/lib/loggers/StdIo')
, warningLogger;
beforeEach(function () {
if (warningLogger) {
warningLogger.cleanUpListeners();
}
// new logger in warning mode
warningLogger = new StdIo({
level: 2,
type: 'StdIo'
}, log);
});
it('should log error messages', function (done) {
warningLogger.write = function (to, label, colorize, what) {
label.should.equal('ERROR');
what.should.be.an.instanceof(Array);
what[0].should.equal('Test Error Message');
done();
};
log.error('Test Error Message');
});
it('should log warnings', function (done) {
warningLogger.write = function (to, label, colorize, what) {
label.should.equal('WARNING');
what.should.equal('Test Warning Message');
done();
};
log.warn('Test Warning', 'Message');
});
it('should NOT log info messages', function (done) {
if (log.info('Info')) {
done(new Error('There shouldn\'t be listeners for info logs'));
} else {
done();
}
});
it('should NOT log debug messages', function (done) {
if (log.debug('Debug')) {
done(new Error('There shouldn\'t be listeners for debug logs'));
} else {
done();
}
});
it('should NOT log trace messages', function (done) {
if (log.trace('curl "http://localhost:9200" -d "{ \"query\": ... }"')) {
done(new Error('There shouldn\'t be listeners for trace logs'));
} else {
done();
}
});
});

107
test/Utils.test.js Normal file
View File

@ -0,0 +1,107 @@
var _ = require('../src/lib/Utils');
describe('Utils', function () {
describe('isArrayOfObjects', function () {
var is;
beforeEach(function () {
is = [{}, {}];
});
it('should identify an array of objects', function () {
_.isArrayOfObjects(is).should.equal(true);
});
it('should identify a non object in the array', function () {
is.push(' not ');
_.isArrayOfObjects(is).should.equal(false);
});
});
describe('isArrayOfStrings', function () {
var is;
beforeEach(function () {
is = ['spencer', 'poop'];
});
it('should identify an array of strings', function () {
_.isArrayOfStrings(is).should.equal(true);
});
it('should identify a non string in the array', function () {
is.push({});
_.isArrayOfStrings(is).should.equal(false);
});
});
describe('isArrayOfArrays', function () {
var is;
beforeEach(function () {
is = [['im'], ['usefull']];
});
it('should identify an array of arrays', function () {
_.isArrayOfArrays(is).should.equal(true);
});
it('should identify a non array in the array', function () {
is.push({});
_.isArrayOfArrays(is).should.equal(false);
});
});
describe('isArrayOfFinites', function () {
var is;
beforeEach(function () {
is = [11123, 666];
});
it('should identify an array of objects', function () {
_.isArrayOfFinites(is).should.equal(true);
});
it('should identify a non object in the array', function () {
is.push(Infinity);
_.isArrayOfFinites(is).should.equal(false);
});
});
describe('isArrayOfFunctions', function () {
var is;
beforeEach(function () {
is = [console.error, console.log];
});
it('should identify an array of functions', function () {
_.isArrayOfFunctions(is).should.equal(true);
});
it('should identify a non function in the array', function () {
is.push('not');
_.isArrayOfFunctions(is).should.equal(false);
});
});
describe('isArrayOfRegExps', function () {
var is;
beforeEach(function () {
is = [/.*/, new RegExp('a')];
});
it('should identify an array of regular expressions', function () {
_.isArrayOfRegExps(is).should.equal(true);
});
it('should identify a non regular expression in the array', function () {
is.push('not');
_.isArrayOfRegExps(is).should.equal(false);
});
});
});

5
test/mocha.opts Normal file
View File

@ -0,0 +1,5 @@
--recursive
--require should
--reporter spec
--ui bdd
--g *.test.js