From 3057c25c26d4ccf8592f980afeef76d0cd1134a0 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 18 Dec 2013 13:28:42 -0700 Subject: [PATCH 1/2] Setup `grunt coverage` task --- grunt/config/open.js | 6 ++++++ package.json | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 grunt/config/open.js diff --git a/grunt/config/open.js b/grunt/config/open.js new file mode 100644 index 000000000..65a2ff836 --- /dev/null +++ b/grunt/config/open.js @@ -0,0 +1,6 @@ +module.exports = { + html_unit_cov: { + path: 'coverage.html', + app: 'Google Chrome' + } +}; \ No newline at end of file diff --git a/package.json b/package.json index a286c4d8c..9edb61ffb 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,8 @@ "grunt-contrib-compress": "~0.5.3", "grunt-contrib-copy": "~0.4.1", "grunt-prompt": "~0.1.2", - "grunt-mocha-cov": "~0.1.1" + "grunt-mocha-cov": "~0.1.1", + "grunt-open": "~0.2.2" }, "license": "Apache 2.0", "dependencies": { From 50be1e86b39d567ec05a940107706184f2bf9fa7 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Wed, 18 Dec 2013 17:11:32 -0700 Subject: [PATCH 2/2] Summary of Changes: - Polished some Grunt config options while testing livereload capabilities in grunt-watch - tests for connection_pool selection with no living connections - tests for connection abstract's mini request implementation for ping. --- grunt/config/mochacov.js | 24 ++++++----- grunt/config/open.js | 2 +- grunt/config/watch.js | 6 +-- grunt/tasks.js | 9 ++-- package.json | 1 - test/unit/test_client.js | 6 +++ test/unit/test_connection_abstract.js | 60 ++++++++++++++++++++++++++- test/unit/test_connection_pool.js | 51 ++++++++++++++++++++--- 8 files changed, 131 insertions(+), 28 deletions(-) diff --git a/grunt/config/mochacov.js b/grunt/config/mochacov.js index 8997628ec..6c0ced367 100644 --- a/grunt/config/mochacov.js +++ b/grunt/config/mochacov.js @@ -5,23 +5,15 @@ module.exports = { options: { require: ['should'] }, - coverage: { - src: unitTests, - options: { - reporter: 'mocha-lcov-reporter', - coveralls: { - serviceName: 'travis-ci', - repoToken: process.env.ESJS_COVERALS_REPO_TOKEN - } - } - }, unit: { src: unitTests }, integration: { src: integrationTests }, - make_html_unit_cov: { + + // run the unit tests, and update coverage.html + make_coverage_html: { src: unitTests, options: { reporter: 'html-cov', @@ -29,4 +21,14 @@ module.exports = { } }, + // for use by travis + ship_coverage: { + src: unitTests, + options: { + reporter: 'mocha-lcov-reporter', + coveralls: { + serviceName: 'travis-ci' + } + } + } }; \ No newline at end of file diff --git a/grunt/config/open.js b/grunt/config/open.js index 65a2ff836..f67d0ab53 100644 --- a/grunt/config/open.js +++ b/grunt/config/open.js @@ -1,5 +1,5 @@ module.exports = { - html_unit_cov: { + coverage: { path: 'coverage.html', app: 'Google Chrome' } diff --git a/grunt/config/watch.js b/grunt/config/watch.js index 68362eda1..b8521f6fb 100644 --- a/grunt/config/watch.js +++ b/grunt/config/watch.js @@ -2,16 +2,16 @@ module.exports = { source: { files: [ 'src/**/*.js', - 'test/unit/**/*.js', 'grunt/**/*.js', + 'test/unit/**/*.js', 'Gruntfile.js' ], tasks: [ 'jshint', - 'run:unit_tests' + 'mochacov:unit' ], options: { - interrupt: true, + interrupt: true } } }; \ No newline at end of file diff --git a/grunt/tasks.js b/grunt/tasks.js index 97b382766..44560fd2e 100644 --- a/grunt/tasks.js +++ b/grunt/tasks.js @@ -2,7 +2,6 @@ module.exports = function (grunt) { // Default task runs the build process. grunt.registerTask('default', [ - 'generate', 'test' ]); @@ -13,17 +12,17 @@ module.exports = function (grunt) { grunt.registerTask('test', [ 'jshint', 'mochacov:unit', - 'run:generate', + 'generate', 'mochacov:integration', ]); grunt.registerTask('coverage', [ - 'mochacov:make_html_unit_cov', - 'open:html_unit_cov' + 'mochacov:make_coverage_html', + 'open:coverage' ]); grunt.registerTask('travis', [ 'test', - 'mochacov:coverage' + 'mochacov:ship_coverage' ]); }; \ No newline at end of file diff --git a/package.json b/package.json index 9edb61ffb..705c16255 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,6 @@ }, "scripts": { "test": "grunt test", - "coverage": "mocha test/unit/test_*.js --require blanket -R html-cov > coverage.html && open -a \"Google Chrome\" ./coverage.html", "blanket": { "pattern": "src" } diff --git a/test/unit/test_client.js b/test/unit/test_client.js index ba73ba6b3..c8fff09f3 100644 --- a/test/unit/test_client.js +++ b/test/unit/test_client.js @@ -17,6 +17,12 @@ describe('Client instances creation', function () { }).should.throw(/previous "elasticsearch" module/); }); + it('Succeeds even not called with new', function () { + var client = es.Client(); + client.bulk.should.eql(api.bulk); + client.cluster.nodeStats.should.eql(api.cluster.prototype.nodeStats); + }); + it('inherits the api', function () { client.bulk.should.eql(api.bulk); client.cluster.nodeStats.should.eql(api.cluster.prototype.nodeStats); diff --git a/test/unit/test_connection_abstract.js b/test/unit/test_connection_abstract.js index 9ead90e03..eff59bca1 100644 --- a/test/unit/test_connection_abstract.js +++ b/test/unit/test_connection_abstract.js @@ -1,7 +1,9 @@ var ConnectionAbstract = require('../../src/lib/connection'); var Host = require('../../src/lib/host'); var sinon = require('sinon'); +var should = require('should'); var _ = require('lodash'); +var errors = require('../../src/lib/errors'); var stub = require('./auto_release_stub').make(); @@ -72,8 +74,62 @@ describe('Connection Abstract', function () { conn.request.callCount.should.eql(1); }); - it('sets a timer for the request'); - it('aborts the request if it takes too long'); + it('sets a timer for the request', function (done) { + var conn = new ConnectionAbstract(host); + var clock = sinon.useFakeTimers('setTimeout', 'clearTimeout'); + var order = 0; + + stub(conn, 'request', function (params, cb) { + setTimeout(function () { + should(++order).eql(2); + cb(); + }, 10001); + }); + + conn.ping({ + requestTimeout: 100 + }, function (err) { + should(++order).eql(1); + err.should.be.an.instanceOf(errors.RequestTimeout); + }); + + process.nextTick(function () { + clock.tick(1000); + clock.tick(10000); + clock.restore(); + done(); + }); + }); + it('calls the requestAborter if req takes too long', function (done) { + var conn = new ConnectionAbstract(host); + var clock = sinon.useFakeTimers('setTimeout', 'clearTimeout'); + var order = 0; + + stub(conn, 'request', function (params, cb) { + setTimeout(function () { + should(++order).eql(3); + cb(); + }, 10001); + + return function () { + should(++order).eql(1); + }; + }); + + conn.ping({ + requestTimeout: 100 + }, function (err) { + should(++order).eql(2); + err.should.be.an.instanceOf(errors.RequestTimeout); + }); + + process.nextTick(function () { + clock.tick(1000); + clock.tick(10000); + clock.restore(); + done(); + }); + }); it('ignores the response from the request if it already aborted'); }); diff --git a/test/unit/test_connection_pool.js b/test/unit/test_connection_pool.js index 3bfe07de3..9e647fd31 100644 --- a/test/unit/test_connection_pool.js +++ b/test/unit/test_connection_pool.js @@ -1,10 +1,12 @@ var ConnectionPool = require('../../src/lib/connection_pool'); var Host = require('../../src/lib/host'); +var errors = require('../../src/lib/errors'); var ConnectionAbstract = require('../../src/lib/connection'); var _ = require('lodash'); var EventEmitter = require('events').EventEmitter; var should = require('should'); var sinon = require('sinon'); +var stub = require('./auto_release_stub').make(); function listenerCount(emitter, event) { if (EventEmitter.listenerCount) { @@ -157,14 +159,53 @@ describe('Connection Pool', function () { }); }); - it('should automatically select the dead connection with the shortest timeout when there no living connections', + }); + + describe('Connection selection with no living nodes', function () { + it('should ping all of the dead nodes, in order of oldest timeout, and return the first that\'s okay', function (done) { - pool.setHosts([]); - pool._conns.alive = []; - pool._conns.dead = [1, 2, 3]; + var clock = sinon.useFakeTimers('setTimeout', 'clearTimeout'); + var pool = new ConnectionPool({ + deadTimeout: 10000 + }); + + var connections = [ + new ConnectionAbstract(new Host('http://localhost:9200')), + new ConnectionAbstract(new Host('http://localhost:9201')), + new ConnectionAbstract(new Host('http://localhost:9202')), + new ConnectionAbstract(new Host('http://localhost:9203')) + ]; + var pingQueue = _.shuffle(connections); + var expectedSelection = pingQueue[pingQueue.length - 1]; + + pingQueue.forEach(function (conn) { + pool.addConnection(conn); + stub(conn, 'ping', function (params, cb) { + if (typeof params === 'function') { + cb = params; + } + var expectedConn = pingQueue.shift(); + conn.should.be.exactly(expectedConn); + if (pingQueue.length) { + process.nextTick(function () { + cb(new Error('keep trying')); + }); + } else { + process.nextTick(function () { + cb(null, true); + }); + } + }); + conn.setStatus('dead'); + clock.tick(500); + }); pool.select(function (err, selection) { - // selection.should.be.exactly(1); + clock.restore(); + selection.should.be.exactly(expectedSelection); + pingQueue.should.have.length(0); + pool.setHosts([]); + should.not.exist(err); done(); }); });