Merging spenceralger:travis_and_coveralls. Summary of changes:

- removed several unneeded devDeps
- removed old get_spec.js script
- the client's ping method will now send back true as the body when the ping
  succceeds, and false when it does not. When the ping fails, the error will
  still be sent back and the connection's status will still be set to "dead".
- All of the client's methods now have a spec property, which will provide the
  JSON spec used to run that method.
- The yaml test runner will only camelCase param names that are documented, uses
  the client's method's new spec property
- Trace log events will now have their proper original query string parameters
- The "tracer" logger will now write to elasticsearch-tracer.log by default, and
  will truncate the file if it already exists.
- When running the integration tests, the client will now use a tracer logger which
  writes to stderr. The default level is "warning", but with the VERBOSE environment
  var it becomes "trace" and the logger will write to it's default file
- Added .idea to the .gitignore, it was being published to NPM
- Cleanup of the grunt tasks. Consilidated several tiny files into seperate moderately sized ones.
This commit is contained in:
Spencer Alger
2013-12-18 13:21:40 -07:00
parent 4c3bd0080d
commit 96b44ebf8b
25 changed files with 199 additions and 229 deletions

3
.gitignore vendored
View File

@ -5,6 +5,7 @@ node_modules
scripts/scratch* scripts/scratch*
test/integration/yaml_suite/log test/integration/yaml_suite/log
.aws-config.json .aws-config.json
.idea
## generated files ## generated files
scripts/last_rest_spec_update.sha scripts/last_rest_spec_update.sha
@ -12,5 +13,5 @@ test/integration/browser_yaml_suite/yaml_tests.js
test/integration/yaml_suite/yaml_tests.json test/integration/yaml_suite/yaml_tests.json
junit-*.xml junit-*.xml
test.log test.log
elasticsearch.log elasticsearch*.log
coverage.html coverage.html

View File

@ -5,4 +5,6 @@ node_js:
services: services:
- elasticsearch - elasticsearch
before_script: before_script:
- npm install -g grunt-cli - npm install -g grunt-cli
script:
- grunt travis

View File

@ -1,6 +1,8 @@
# elasticsearch.js # elasticsearch.js
The official low-level Elasticsearch client for Node.js and the browser. [![Build Status](https://build.elasticsearch.org/job/es-js_nightly/badge/icon)](https://build.elasticsearch.org/job/es-js_nightly/) The official low-level Elasticsearch client for Node.js and the browser.
[![Build Status](https://travis-ci.org/elasticsearch/elasticsearch-js.png?branch=master)](https://travis-ci.org/elasticsearch/elasticsearch-js) [![Coverage Status](https://coveralls.io/repos/elasticsearch/elasticsearch-js/badge.png)](https://coveralls.io/r/elasticsearch/elasticsearch-js) [![Build Status](https://build.elasticsearch.org/job/es-js_nightly/badge/icon)](https://build.elasticsearch.org/job/es-js_nightly/)
## Features ## Features

69
grunt/browser_clients.js Normal file
View File

@ -0,0 +1,69 @@
module.exports = function (grunt) {
grunt.registerTask('browser_clients:test', [
'build',
'run:browser_unit_tests',
'run:browser_integration_tests'
]);
grunt.registerTask('browser_clients:build', [
'clean:dist',
'browserify',
'uglify:dist',
'concat:dist_banners'
]);
grunt.registerTask('browser_clients:publish', [
'browser_clients_build',
'compress:dist_zip',
'compress:dist_tarball',
's3:latest'
]);
grunt.registerTask('browser_clients:release', [
'prompt:confirm_release',
'__check_for_confirmation',
'browser_clients_build',
'compress:dist_zip',
'compress:dist_tarball',
's3:release'
]);
grunt.registerTask('__check_for_confirmation', function () {
if (grunt.config.get('confirm.release')) {
grunt.log.verbose.writeln('release confirmed');
} else {
throw new Error('Aborting release');
}
});
// grunt.registerTask('browser_clients:export_all', function () {
// grunt.task.run([
// 'build',
// 'export_client:angular:../bower-elasticsearch-angular',
// 'export_client::../bower-elasticsearch-browser',
// 'export_client:jquery:../bower-elasticsearch-jquery'
// ]);
// });
// grunt.registerTask('browser_clients:export_client', function (build, outDir) {
// var path = require('path');
// grunt.config.set('copy.export_client', {
// expand: true,
// cwd: './dist/',
// src: 'elasticsearch' + (build ? '.' + build : '') + '{.min,}.js',
// dest: outDir,
// rename: function (dest, src) {
// return path.join(dest, 'elasticsearch' + (~src.indexOf('.min') ? '.min' : '') + '.js');
// }
// });
// this.requires('build');
// grunt.task.run([
// 'copy:export_client'
// ]);
// });
};

View File

@ -1,8 +0,0 @@
module.exports = function (grunt) {
grunt.registerTask('browser_clients_build', [
'clean:dist',
'browserify',
'uglify:dist',
'concat:dist_banners'
]);
};

View File

@ -1,30 +0,0 @@
module.exports = function (grunt) {
grunt.registerTask('export_client', function (build, outDir) {
var path = require('path');
grunt.config.set('copy.export_client', {
expand: true,
cwd: './dist/',
src: 'elasticsearch' + (build ? '.' + build : '') + '{.min,}.js',
dest: outDir,
rename: function (dest, src) {
return path.join(dest, 'elasticsearch' + (~src.indexOf('.min') ? '.min' : '') + '.js');
}
});
this.requires('build');
grunt.task.run([
'copy:export_client'
]);
});
grunt.registerTask('export_all_clients', function () {
grunt.task.run([
'build',
'export_client:angular:../bower-elasticsearch-angular',
'export_client::../bower-elasticsearch-browser',
'export_client:jquery:../bower-elasticsearch-jquery'
]);
});
};

View File

@ -1,10 +0,0 @@
module.exports = function (grunt) {
grunt.registerTask('browser_clients_publish', [
'browser_clients_build',
'compress:dist_zip',
'compress:dist_tarball',
's3:latest'
]);
};

View File

@ -1,20 +0,0 @@
module.exports = function (grunt) {
grunt.registerTask('browser_clients_release', [
'prompt:confirm_release',
'check_for_confirmation',
'browser_clients_build',
'compress:dist_zip',
'compress:dist_tarball',
's3:release'
]);
grunt.registerTask('check_for_confirmation', function () {
if (grunt.config.get('confirm.release')) {
grunt.log.verbose.writeln('release confirmed');
} else {
throw new Error('Aborting release');
}
});
};

32
grunt/config/mochacov.js Normal file
View File

@ -0,0 +1,32 @@
var unitTests = ['test/unit/test_*.js'];
var integrationTests = ['test/integration/yaml_suite/index.js'];
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: {
src: unitTests,
options: {
reporter: 'html-cov',
output: 'coverage.html'
}
},
};

View File

@ -2,24 +2,6 @@ module.exports = {
generate: { generate: {
exec: 'node scripts/generate' exec: 'node scripts/generate'
}, },
unit_tests: {
exec: 'node scripts/run_tests --unit --no-browsers',
options: {
passArgs: [
'port',
'host'
]
}
},
integration_tests: {
exec: 'node scripts/run_tests --integration --no-browsers',
options: {
passArgs: [
'port',
'host'
]
}
},
browser_unit_tests: { browser_unit_tests: {
exec: 'node scripts/run_tests --unit --no-server', exec: 'node scripts/run_tests --unit --no-server',
options: { options: {

View File

@ -7,7 +7,7 @@ module.exports = {
'Gruntfile.js' 'Gruntfile.js'
], ],
tasks: [ tasks: [
// 'jshint', 'jshint',
'run:unit_tests' 'run:unit_tests'
], ],
options: { options: {

View File

@ -1,9 +0,0 @@
module.exports = function (grunt) {
// Default task runs the build process.
grunt.registerTask('default', [
'run:generate',
'test'
]);
};

View File

@ -1,5 +0,0 @@
module.exports = function (grunt) {
grunt.registerTask('generate', [
'run:generate'
]);
};

29
grunt/tasks.js Normal file
View File

@ -0,0 +1,29 @@
module.exports = function (grunt) {
// Default task runs the build process.
grunt.registerTask('default', [
'generate',
'test'
]);
grunt.registerTask('generate', [
'run:generate'
]);
grunt.registerTask('test', [
'jshint',
'mochacov:unit',
'run:generate',
'mochacov:integration',
]);
grunt.registerTask('coverage', [
'mochacov:make_html_unit_cov',
'open:html_unit_cov'
]);
grunt.registerTask('travis', [
'test',
'mochacov:coverage'
]);
};

View File

@ -1,16 +0,0 @@
module.exports = function (grunt) {
grunt.registerTask('test', [
'jshint',
'run:unit_tests',
'run:generate',
'run:integration_tests'
]);
grunt.registerTask('browser_clients_test', [
'build',
'run:browser_unit_tests',
'run:browser_integration_tests'
]);
};

View File

@ -14,27 +14,21 @@
"./test/mocks/server.js": "./test/mocks/browser_server.js" "./test/mocks/server.js": "./test/mocks/browser_server.js"
}, },
"devDependencies": { "devDependencies": {
"tar": "~0.1.18",
"mocha": "~1.14.0", "mocha": "~1.14.0",
"async": "~0.2.9", "async": "~0.2.9",
"mkdirp": "~0.3.5",
"moment": "~2.4.0", "moment": "~2.4.0",
"should": "~2.1.0", "should": "~2.1.0",
"js-yaml": "~2.1.3", "js-yaml": "~2.1.3",
"optimist": "~0.6.0", "optimist": "~0.6.0",
"expect.js": "~0.2.0",
"minimatch": "~0.2.12",
"browserify": "~2.35.1", "browserify": "~2.35.1",
"grunt": "~0.4.1", "grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.7.1", "grunt-contrib-jshint": "~0.7.1",
"grunt-mocha-test": "~0.7.0",
"grunt-browserify": "~1.2.11", "grunt-browserify": "~1.2.11",
"grunt-contrib-clean": "~0.5.0", "grunt-contrib-clean": "~0.5.0",
"grunt-contrib-uglify": "~0.2.7", "grunt-contrib-uglify": "~0.2.7",
"grunt-contrib-concat": "~0.3.0", "grunt-contrib-concat": "~0.3.0",
"xmlbuilder": "~0.4.3", "xmlbuilder": "~0.4.3",
"grunt-contrib-watch": "~0.5.3", "grunt-contrib-watch": "~0.5.3",
"coveralls": "~2.6.0",
"mocha-lcov-reporter": "0.0.1", "mocha-lcov-reporter": "0.0.1",
"blanket": "~1.1.5", "blanket": "~1.1.5",
"sinon": "~1.7.3", "sinon": "~1.7.3",
@ -48,9 +42,8 @@
"relative-fs": "0.0.1", "relative-fs": "0.0.1",
"grunt-contrib-compress": "~0.5.3", "grunt-contrib-compress": "~0.5.3",
"grunt-contrib-copy": "~0.4.1", "grunt-contrib-copy": "~0.4.1",
"grunt-mocha": "~0.4.7",
"grunt-prompt": "~0.1.2", "grunt-prompt": "~0.1.2",
"readable-stream": "~1.1.9" "grunt-mocha-cov": "~0.1.1"
}, },
"license": "Apache 2.0", "license": "Apache 2.0",
"dependencies": { "dependencies": {

View File

@ -1,68 +0,0 @@
var EventEmitter = require('events').EventEmitter;
var Minimatch = require('minimatch').Minimatch;
var https = require('https');
var tar = require('tar');
var zlib = require('zlib');
var path = require('path');
var _ = require('lodash');
var url = require('url');
var tarUrl = 'https://github.com/elasticsearch/elasticsearch-rest-api-spec/tarball/master';
var topDir = null; // remove the lowest directory, which changes with each commit.
exports.get = function (pattern) {
var stream = new EventEmitter();
var matcher = new Minimatch(pattern);
var req = https.get(tarUrl, function receiveTarBall(incoming) {
if (incoming.statusCode !== 200) {
req.abort();
if (incoming.headers.location) {
req = https.get(_.extend(
url.parse(tarUrl),
url.parse(incoming.headers.location)
),
receiveTarBall
);
} else {
console.error('request failed', incoming.statusCode, incoming.headers);
}
} else {
incoming
.pipe(zlib.createGunzip())
.pipe(tar.Parse())
.on('entry', function (entry) {
if (!topDir) {
topDir = entry.path.split('/').shift();
}
entry.path = path.relative(topDir, entry.path);
if (matcher.match(entry.path)) {
collectData(entry);
} else {
entry.resume();
}
})
.on('end', function () {
stream.emit('end');
});
}
});
function collectData(entry) {
entry.data = '';
entry.on('data', onData);
entry.on('end', onEnd);
function onData(chunk) {
entry.data += chunk;
}
function onEnd() {
entry.removeListener('data', onData);
entry.removeListener('end', onEnd);
stream.emit('entry', entry);
}
}
return stream;
};

View File

@ -66,6 +66,7 @@ Client.prototype.ping = ca({
url: { url: {
fmt: '/' fmt: '/'
}, },
castExists: true,
requestTimeout: 100 requestTimeout: 100
}); });

View File

@ -16,7 +16,7 @@ function ClientAction(spec) {
spec.method = 'GET'; spec.method = 'GET';
} }
return function (params, cb) { function action(params, cb) {
if (typeof params === 'function') { if (typeof params === 'function') {
cb = params; cb = params;
params = {}; params = {};
@ -34,7 +34,11 @@ function ClientAction(spec) {
return when.reject(e); return when.reject(e);
} }
} }
}; }
action.spec = spec;
return action;
} }
var castType = { var castType = {

View File

@ -271,12 +271,15 @@ Log.prototype.trace = function (method, requestUrl, body, responseBody, response
if (this.listenerCount('trace')) { if (this.listenerCount('trace')) {
if (typeof requestUrl === 'string') { if (typeof requestUrl === 'string') {
requestUrl = url.parse(requestUrl, true, true); requestUrl = url.parse(requestUrl, true, true);
} else if (requestUrl.path) {
requestUrl.query = url.parse(requestUrl.path, true, false).query;
} }
requestUrl = _.defaults({ requestUrl = _.defaults({
host: 'localhost:9200', host: 'localhost:9200',
query: _.defaults({ query: _.defaults(requestUrl.query || {}, {
pretty: true pretty: true
}, requestUrl.query) })
}, requestUrl); }, requestUrl);
delete requestUrl.auth; delete requestUrl.auth;

View File

@ -12,13 +12,20 @@
module.exports = Tracer; module.exports = Tracer;
var FileLogger = require('./file'); var StreamLogger = require('./stream');
var fs = require('fs');
var _ = require('../utils'); var _ = require('../utils');
function Tracer(log, config) { function Tracer(log, config) {
FileLogger.call(this, log, config); if (config.path === false) {
config.stream = process.stderr;
} else {
config.stream = fs.createWriteStream(config.path || 'elasticsearch-tracer.log');
}
StreamLogger.call(this, log, config);
} }
_.inherits(Tracer, FileLogger); _.inherits(Tracer, StreamLogger);
Tracer.prototype.onTrace = _.handler(function (message, curlCall) { Tracer.prototype.onTrace = _.handler(function (message, curlCall) {
this.write('TRACE', message, curlCall); this.write('TRACE', message, curlCall);

View File

@ -6,8 +6,7 @@ var defaults = {
clusterName: 'yaml-test-runner', clusterName: 'yaml-test-runner',
dataPath: '/tmp/yaml-test-runner', dataPath: '/tmp/yaml-test-runner',
host: 'localhost', host: 'localhost',
port: '9200', port: '9200'
match: '**'
}; };
if (process.browser) { if (process.browser) {

View File

@ -1,4 +1,7 @@
if (process.browser) { var BROWSER = process.env.browser;
var VERBOSE = process.env.VERBOSE;
if (BROWSER) {
/* jshint browser: true */ /* jshint browser: true */
var es = window.elasticsearch; var es = window.elasticsearch;
} else { } else {
@ -69,8 +72,15 @@ module.exports = {
} }
], ],
log: { log: {
type: process.browser ? 'console' : 'stdio', type: BROWSER
level: process.env.VERBOSE ? 'trace' : 'warning' ? 'console'
: VERBOSE
? 'tracer'
: 'stdio',
level: VERBOSE
? 'trace'
: 'warning',
path: VERBOSE ? undefined : false
} }
}); });

View File

@ -1,15 +1,12 @@
var path = require('path'); var path = require('path');
var async = require('async'); var async = require('async');
var jsYaml = require('js-yaml'); var jsYaml = require('js-yaml');
var expect = require('expect.js');
var YamlFile = require('./yaml_file'); var YamlFile = require('./yaml_file');
var _ = require('../../../src/lib/utils'); var _ = require('../../../src/lib/utils');
var es = require('../../../src/elasticsearch'); var es = require('../../../src/elasticsearch');
var clientManager = require('./client_manager'); var clientManager = require('./client_manager');
var Minimatch = require('minimatch').Minimatch;
var argv = require('./argv'); var argv = require('./argv');
var testDir = path.resolve(__dirname, './tests'); var testDir = path.resolve(__dirname, './tests');
var doPattern = new Minimatch(argv.match);
describe('integration', function () { describe('integration', function () {
this.timeout(30000); this.timeout(30000);
@ -30,9 +27,7 @@ describe('integration', function () {
}); });
var files = _.map(require('./yaml_tests.json'), function (docs, filename) { var files = _.map(require('./yaml_tests.json'), function (docs, filename) {
if (doPattern.match(filename)) { return new YamlFile(filename, docs);
return new YamlFile(filename, docs);
}
}); });
}); });

View File

@ -8,8 +8,8 @@
module.exports = YamlDoc; module.exports = YamlDoc;
var _ = require('../../../src/lib/utils'); var _ = require('../../../src/lib/utils');
var should = require('should');
var clientManager = require('./client_manager'); var clientManager = require('./client_manager');
var expect = require('expect.js');
/** /**
* The version that ES is running, in comparable string form XXX-XXX-XXX, fetched when needed * The version that ES is running, in comparable string form XXX-XXX-XXX, fetched when needed
@ -42,7 +42,7 @@ function getVersionFromES(done) {
if (err) { if (err) {
throw new Error('unable to get info about ES'); throw new Error('unable to get info about ES');
} }
expect(resp.version.number).to.match(versionRE); should(resp.version.number).match(versionRE);
ES_VERSION = versionToComparableString(versionRE.exec(resp.version.number)[1]); ES_VERSION = versionToComparableString(versionRE.exec(resp.version.number)[1]);
done(); done();
}); });
@ -77,7 +77,7 @@ function versionToComparableString(version) {
*/ */
function rangeMatchesCurrentVersion(rangeString, done) { function rangeMatchesCurrentVersion(rangeString, done) {
function doWork() { function doWork() {
expect(rangeString).to.match(versionRangeRE); should(rangeString).match(versionRangeRE);
var range = versionRangeRE.exec(rangeString); var range = versionRangeRE.exec(rangeString);
range = _.map(_.last(range, 2), versionToComparableString); range = _.map(_.last(range, 2), versionToComparableString);
@ -114,7 +114,7 @@ function YamlDoc(doc, file) {
var method = self['do_' + action.name]; var method = self['do_' + action.name];
// check that it's a function // check that it's a function
expect(method).to.be.a('function'); should(method).have.type('function');
if (_.isPlainObject(action.args)) { if (_.isPlainObject(action.args)) {
action.name += ' ' + _.keys(action.args).join(', '); action.name += ' ' + _.keys(action.args).join(', ');
@ -306,11 +306,18 @@ YamlDoc.prototype = {
var action = Object.keys(args).pop(); var action = Object.keys(args).pop();
var clientActionName = _.map(action.split('.'), _.camelCase).join('.'); var clientActionName = _.map(action.split('.'), _.camelCase).join('.');
var clientAction = this.get(clientActionName, client); var clientAction = this.get(clientActionName, client);
var params = _.transform(args[action], function (note, val, name) { var params = _.transform(args[action], function (params, val, name) {
note[_.camelCase(name)] = (typeof val === 'string' && val[0] === '$') ? this.get(val) : val; var camelName = _.camelCase(name);
// undocumented params should be passed through as-is
var paramName = name;
if (clientAction && clientAction.spec && clientAction.spec.params && clientAction.spec.params[camelName]) {
paramName = camelName;
}
params[paramName] = (typeof val === 'string' && val[0] === '$') ? this.get(val) : val;
}, {}, this); }, {}, this);
expect(clientAction || clientActionName).to.be.a('function'); should(clientAction || clientActionName).have.type('function');
if (typeof clientAction === 'function') { if (typeof clientAction === 'function') {
if (_.isNumeric(catcher)) { if (_.isNumeric(catcher)) {
@ -325,11 +332,11 @@ YamlDoc.prototype = {
if (catcher) { if (catcher) {
if (catcher instanceof RegExp) { if (catcher instanceof RegExp) {
// error message should match the regexp // error message should match the regexp
expect(error.message).to.match(catcher); should(error.message).match(catcher);
error = null; error = null;
} else if (typeof catcher === 'function') { } else if (typeof catcher === 'function') {
// error should be an instance of // error should be an instance of
expect(error).to.be.a(catcher); should(error).be.an.instanceOf(catcher);
error = null; error = null;
} else { } else {
return done(new Error('Invalid catcher ' + catcher)); return done(new Error('Invalid catcher ' + catcher));
@ -373,7 +380,7 @@ YamlDoc.prototype = {
* @return {undefined} * @return {undefined}
*/ */
do_is_true: function (path) { do_is_true: function (path) {
expect(this.get(path)).to.be.ok; should(Boolean(this.get(path))).equal(true, 'path: ' + path);
}, },
/** /**
@ -384,7 +391,7 @@ YamlDoc.prototype = {
* @return {undefined} * @return {undefined}
*/ */
do_is_false: function (path) { do_is_false: function (path) {
expect(this.get(path)).to.not.be.ok; should(Boolean(this.get(path))).equal(false, 'path: ' + path);
}, },
/** /**
@ -398,7 +405,7 @@ YamlDoc.prototype = {
if (val[0] === '$') { if (val[0] === '$') {
val = this.get(val); val = this.get(val);
} }
expect(this.get(path)).to.eql(val); should(this.get(path)).eql(val, 'path: ' + path);
}, this); }, this);
}, },
@ -410,7 +417,7 @@ YamlDoc.prototype = {
*/ */
do_lt: function (args) { do_lt: function (args) {
_.forOwn(args, function (num, path) { _.forOwn(args, function (num, path) {
expect(this.get(path)).to.be.below(num); should(this.get(path)).be.below(num, 'path: ' + path);
}, this); }, this);
}, },
@ -422,7 +429,7 @@ YamlDoc.prototype = {
*/ */
do_gt: function (args) { do_gt: function (args) {
_.forOwn(args, function (num, path) { _.forOwn(args, function (num, path) {
expect(this.get(path)).to.be.above(num); should(this.get(path)).be.above(num, 'path: ' + path);
}, this); }, this);
}, },
@ -435,7 +442,7 @@ YamlDoc.prototype = {
*/ */
do_length: function (args) { do_length: function (args) {
_.forOwn(args, function (len, path) { _.forOwn(args, function (len, path) {
expect(_.size(this.get(path))).to.be(len); should(_.size(this.get(path))).eql(len, 'path: ' + path);
}, this); }, this);
} }
}; };