From 8cc87637e29195a8e6e9ac8c661a22491dc77990 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Fri, 18 Oct 2013 09:40:55 -0700 Subject: [PATCH] modified the config to own the connectionPool, transport, and a few other objects --- .gitignore | 2 +- scripts/generate/js_api/templates/action.tmpl | 35 +- scripts/generate/js_api/templates/index.js | 32 +- scripts/generate/logs/index.js | 56 +- src/api/bulk.js | 20 +- src/api/clear_scroll.js | 21 +- src/api/cluster/get_settings.js | 21 +- src/api/cluster/health.js | 21 +- src/api/cluster/node_hot_threads.js | 21 +- src/api/cluster/node_info.js | 21 +- src/api/cluster/node_shutdown.js | 21 +- src/api/cluster/node_stats.js | 21 +- src/api/cluster/put_settings.js | 21 +- src/api/cluster/reroute.js | 21 +- src/api/cluster/state.js | 21 +- src/api/count.js | 18 +- src/api/create.js | 18 +- src/api/delete.js | 21 +- src/api/delete_by_query.js | 21 +- src/api/exists.js | 21 +- src/api/explain.js | 18 +- src/api/get.js | 21 +- src/api/get_source.js | 21 +- src/api/index.js | 18 +- src/api/indices/analyze.js | 18 +- src/api/indices/clear_cache.js | 18 +- src/api/indices/close.js | 21 +- src/api/indices/create.js | 18 +- src/api/indices/delete.js | 21 +- src/api/indices/delete_alias.js | 21 +- src/api/indices/delete_mapping.js | 21 +- src/api/indices/delete_template.js | 21 +- src/api/indices/delete_warmer.js | 21 +- src/api/indices/exists.js | 21 +- src/api/indices/exists_alias.js | 21 +- src/api/indices/exists_type.js | 21 +- src/api/indices/flush.js | 18 +- src/api/indices/get_alias.js | 21 +- src/api/indices/get_aliases.js | 21 +- src/api/indices/get_mapping.js | 21 +- src/api/indices/get_settings.js | 21 +- src/api/indices/get_template.js | 21 +- src/api/indices/get_warmer.js | 21 +- src/api/indices/open.js | 21 +- src/api/indices/optimize.js | 18 +- src/api/indices/put_alias.js | 21 +- src/api/indices/put_mapping.js | 18 +- src/api/indices/put_settings.js | 21 +- src/api/indices/put_template.js | 18 +- src/api/indices/put_warmer.js | 21 +- src/api/indices/refresh.js | 18 +- src/api/indices/segments.js | 21 +- src/api/indices/snapshot_index.js | 21 +- src/api/indices/stats.js | 21 +- src/api/indices/status.js | 21 +- src/api/indices/update_aliases.js | 21 +- src/api/indices/validate_query.js | 18 +- src/api/info.js | 18 +- src/api/mget.js | 18 +- src/api/mlt.js | 18 +- src/api/msearch.js | 20 +- src/api/percolate.js | 18 +- src/api/scroll.js | 18 +- src/api/search.js | 18 +- src/api/suggest.js | 18 +- src/api/update.js | 21 +- src/lib/Client.js | 74 ++- src/lib/Log.js | 13 +- src/lib/Transport.js | 66 +- src/lib/client_config.js | 50 +- src/lib/connection.js | 36 +- src/lib/connection_pool.js | 98 +-- src/lib/connections/http.js | 39 +- src/lib/errors.js | 14 +- src/lib/logger.js | 43 +- src/lib/param_helper.js | 18 - src/lib/serializers/Json.js | 17 + src/lib/utils.js | 65 +- test/integration/index.js | 579 +----------------- test/integration/network-failures/index.js | 0 test/integration/network-failures/timeout.js | 0 test/integration/{ => yaml-suite}/args.js | 0 test/integration/yaml-suite/index.js | 577 +++++++++++++++++ test/integration/{ => yaml-suite}/server.js | 2 +- test/mocks/es_server.js | 85 +++ test/unit/connection_pool.test.js | 50 +- test/unit/es_server.test.js | 80 +++ test/unit/stdio_logger.test.js | 15 +- 88 files changed, 1948 insertions(+), 1338 deletions(-) delete mode 100644 src/lib/param_helper.js create mode 100644 test/integration/network-failures/index.js create mode 100644 test/integration/network-failures/timeout.js rename test/integration/{ => yaml-suite}/args.js (100%) create mode 100644 test/integration/yaml-suite/index.js rename test/integration/{ => yaml-suite}/server.js (97%) create mode 100644 test/mocks/es_server.js create mode 100644 test/unit/es_server.test.js diff --git a/.gitignore b/.gitignore index dfdb7c547..d6dfe0922 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ node_modules -scripts/scratch.js +scripts/scratch* test/integration-test.log diff --git a/scripts/generate/js_api/templates/action.tmpl b/scripts/generate/js_api/templates/action.tmpl index eec4629fd..69a1cec06 100644 --- a/scripts/generate/js_api/templates/action.tmpl +++ b/scripts/generate/js_api/templates/action.tmpl @@ -1,5 +1,4 @@ var _ = require('<%= path2lib %>utils'), - paramHelper = require('<%= path2lib %>param_helper'), errors = require('<%= path2lib %>errors'), q = require('q');<% @@ -24,26 +23,24 @@ var <%= name %>Options = <%= stringify(options) %>;<% %> */ function do<%= _.studlyCase(name) %>(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } - var request = {<% - if (~name.indexOf('exists')) {%> - ignore: _.union([404], params.ignore)<% - } else {%> - ignore: params.ignore<% - } - if (body) { if (_.contains(['bulk', 'msearch'], name)) {%>, - body: paramHelper.bulkBody(params.body, this.client.serializer) || null<% - } else { %>, - body: params.body || null<% - } }%> - } - , parts = {} - , query = {} - , responseOpts = {}; - <% + var request = { +<%= writeRequestObjectBody(6, name, body, methods) %> + }, + parts = {}, + query = {}, + responseOpts = {}; +<% if (methods.length > 1) { %> + // figure out the method if (params.method = _.toUpperString(params.method)) { if (<%= _.map(methods, function (method) { return 'params.method === ' + stringify(method) }).join(' || ') %>) { request.method = params.method; @@ -58,8 +55,6 @@ if (methods.length > 1) { %> request.method = <%= stringify(methods[0]) %>;<% }%> }<% -} else {%> - request.method = <%= stringify(methods[0]) %>;<% } %> diff --git a/scripts/generate/js_api/templates/index.js b/scripts/generate/js_api/templates/index.js index 0a5799eba..107e6c32c 100644 --- a/scripts/generate/js_api/templates/index.js +++ b/scripts/generate/js_api/templates/index.js @@ -13,7 +13,10 @@ var _ = require('../../../../src/lib/utils') function lines(i) { function l(line) { - if (typeof line !== 'undefined') { + if (line === '') { + // no indent on empty lines + l.lines.push(''); + } else if (typeof line !== 'undefined') { l.lines.push(_.repeat(' ', l.indent) + line); } return l; @@ -158,6 +161,33 @@ var templateGlobals = { return l.toString(); }, + writeRequestObjectBody: function (indent, name, body, methods) { + var parts = [], l = lines(indent); + if (~name.indexOf('exists')) { + parts.push('ignore: _.union([404], params.ignore)'); + } else { + parts.push('ignore: params.ignore'); + } + + if (body) { + if (_.contains(['bulk', 'msearch'], name)) { + parts.push('body: this.client.config.serializer.bulkBody(params.body || null)'); + } else { + parts.push('body: params.body || null'); + } + } + + if (methods.length === 1) { + parts.push('method: ' + stringify(methods[0])); + } + + _.each(parts, function (part, i) { + l(part + (i < parts.length - 1 ? ',' : '')); + }); + + return l.toString(); + }, + /** * we want strings in code to use single-quotes, so this will JSON encode vars, but then * modify them to follow our code standards. diff --git a/scripts/generate/logs/index.js b/scripts/generate/logs/index.js index 4e64b8880..7f90773eb 100644 --- a/scripts/generate/logs/index.js +++ b/scripts/generate/logs/index.js @@ -1,6 +1,31 @@ // args -var count = parseInt(process.argv[2] || 14000, 10), - days = parseInt(process.argv[3] || 7, 10); +var argv = require('optimist') + .usage('node scripts/generate/logs [-h|--host localhost:9200] [-c|--count 14000] [-d|--days 7]') + .options({ + count: { + alias: 'c', + type: 'number', + default: 14000 + }, + days: { + alias: 'c', + type: 'number', + required: true + }, + host: { + alias: 'h', + default: 'localhost:9200' + } + }) + .argv; + +// Error.stackTraceLimit = Infinity; + +// console.log(argv); +// process.exit(); + +var count = parseInt(argv._[0] || 14000, 10), + days = parseInt(argv._[1] || 7, 10); var es = require('../../../src/elasticsearch'), _ = require('../../../src/lib/utils'), @@ -10,11 +35,22 @@ var es = require('../../../src/elasticsearch'), makeSamples = require('./samples').make, startingMoment = moment().startOf('day').subtract('days', days), endingMoment = moment().endOf('day').add('days', days), - client = new es.Client({ - log: 'info' - }); + clientConfig = { + log: { + level: ['info', 'error'] + } + }; -client.log.info('Generating', count, 'events across ±', days, 'days'); +if (argv.host) { + clientConfig.hosts = argv.host; +} else if (argv.hosts) { + clientConfig.hosts = JSON.parse(argv.hosts); +} + +var client = new es.Client(clientConfig); +var log = client.config.log; + +log.info('Generating', count, 'events across ±', days, 'days'); fillIndecies(function () { var actions = [], @@ -63,7 +99,7 @@ fillIndecies(function () { actions.push(event); if (actions.length === 3000 || i === count - 1) { - client.log.info('writing', actions.length / 2, 'documents'); + client.config.log.info('writing', actions.length / 2, 'documents'); client.bulk({ body: actions }, done); @@ -142,12 +178,12 @@ function fillIndecies(cb) { movingDate.add('day', 1); } - async.parallel(indexPushActions, function (err, responses) { + async.parralel(indexPushActions, function (err, responses) { if (err) { - client.log.error(err); + client.config.log.error(err.message = 'Unable to create indicies: ' + err.message); } else { _.each(_.groupBy(responses), function (list, did) { - client.log.info(list.length, 'indicies', did); + client.config.log.info(list.length, 'indicies', did); }); cb(); } diff --git a/src/api/bulk.js b/src/api/bulk.js index f1611d7ca..86e995625 100644 --- a/src/api/bulk.js +++ b/src/api/bulk.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -18,16 +17,23 @@ var replicationOptions = ['sync', 'async']; * @param {string} params.type - Default document type for items which don't provide one */ function doBulk(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: paramHelper.bulkBody(params.body, this.client.serializer) || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: this.client.config.serializer.bulkBody(params.body || null) + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'POST' || params.method === 'PUT') { request.method = params.method; diff --git a/src/api/clear_scroll.js b/src/api/clear_scroll.js index 4a35b8931..41b9c1f8c 100644 --- a/src/api/clear_scroll.js +++ b/src/api/clear_scroll.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -11,16 +10,22 @@ var _ = require('../lib/utils'), * @param {Object} params - An object with parameters used to carry out this action */ function doClearScroll(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'DELETE' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'DELETE'; // find the paths's params if (typeof params.scroll_id !== 'undefined') { diff --git a/src/api/cluster/get_settings.js b/src/api/cluster/get_settings.js index 794131a9e..742eb3a85 100644 --- a/src/api/cluster/get_settings.js +++ b/src/api/cluster/get_settings.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -11,16 +10,22 @@ var _ = require('../../lib/utils'), * @param {Object} params - An object with parameters used to carry out this action */ function doClusterGetSettings(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params diff --git a/src/api/cluster/health.js b/src/api/cluster/health.js index 8007eed7f..7c4b30d7c 100644 --- a/src/api/cluster/health.js +++ b/src/api/cluster/health.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -22,16 +21,22 @@ var waitForStatusOptions = ['green', 'yellow', 'red']; * @param {String} params.wait_for_status - Wait until cluster is in a specific state */ function doClusterHealth(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/cluster/node_hot_threads.js b/src/api/cluster/node_hot_threads.js index 26f2b037b..0594379b8 100644 --- a/src/api/cluster/node_hot_threads.js +++ b/src/api/cluster/node_hot_threads.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -17,16 +16,22 @@ var typeOptions = ['cpu', 'wait', 'block']; * @param {String} params.type - The type to sample (default: cpu) */ function doClusterNodeHotThreads(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.node_id !== 'undefined') { diff --git a/src/api/cluster/node_info.js b/src/api/cluster/node_info.js index 51c1be03b..69f55a8a1 100644 --- a/src/api/cluster/node_info.js +++ b/src/api/cluster/node_info.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -23,16 +22,22 @@ var _ = require('../../lib/utils'), * @param {boolean} params.transport - Return information about transport */ function doClusterNodeInfo(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.node_id !== 'undefined') { diff --git a/src/api/cluster/node_shutdown.js b/src/api/cluster/node_shutdown.js index 6d1442c82..07a624595 100644 --- a/src/api/cluster/node_shutdown.js +++ b/src/api/cluster/node_shutdown.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,16 +12,22 @@ var _ = require('../../lib/utils'), * @param {boolean} params.exit - Exit the JVM as well (default: true) */ function doClusterNodeShutdown(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'POST' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'POST'; // find the paths's params if (typeof params.node_id !== 'undefined') { diff --git a/src/api/cluster/node_stats.js b/src/api/cluster/node_stats.js index 7babde91c..42c76d64c 100644 --- a/src/api/cluster/node_stats.js +++ b/src/api/cluster/node_stats.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -26,16 +25,22 @@ var metricOptions = ['completion', 'docs', 'fielddata', 'filter_cache', 'flush', * @param {boolean} params.transport - Return information about transport */ function doClusterNodeStats(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.fields !== 'undefined') { diff --git a/src/api/cluster/put_settings.js b/src/api/cluster/put_settings.js index a1dafecb5..530db9dbd 100644 --- a/src/api/cluster/put_settings.js +++ b/src/api/cluster/put_settings.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -11,17 +10,23 @@ var _ = require('../../lib/utils'), * @param {Object} params - An object with parameters used to carry out this action */ function doClusterPutSettings(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: params.body || null, + method: 'PUT' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'PUT'; // find the paths's params diff --git a/src/api/cluster/reroute.js b/src/api/cluster/reroute.js index e5c880c49..cc45ad2e0 100644 --- a/src/api/cluster/reroute.js +++ b/src/api/cluster/reroute.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,17 +12,23 @@ var _ = require('../../lib/utils'), * @param {boolean} params.filter_metadata - Don't return cluster state metadata (default: false) */ function doClusterReroute(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: params.body || null, + method: 'POST' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'POST'; // find the paths's params diff --git a/src/api/cluster/state.js b/src/api/cluster/state.js index d86e663f9..3c26e2e17 100644 --- a/src/api/cluster/state.js +++ b/src/api/cluster/state.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -19,16 +18,22 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doClusterState(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params diff --git a/src/api/count.js b/src/api/count.js index c80e0e725..5e7b062de 100644 --- a/src/api/count.js +++ b/src/api/count.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -18,16 +17,23 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {string} params.source - The URL-encoded query definition (instead of using the request body) */ function doCount(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'POST' || params.method === 'GET') { request.method = params.method; diff --git a/src/api/create.js b/src/api/create.js index 3f3535e67..91a797e29 100644 --- a/src/api/create.js +++ b/src/api/create.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -27,16 +26,23 @@ var versionTypeOptions = ['internal', 'external']; * @param {String} params.version_type - Specific version type */ function doCreate(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'POST' || params.method === 'PUT') { request.method = params.method; diff --git a/src/api/delete.js b/src/api/delete.js index 54643d2cd..8db80f0f5 100644 --- a/src/api/delete.js +++ b/src/api/delete.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -23,16 +22,22 @@ var versionTypeOptions = ['internal', 'external']; * @param {String} params.version_type - Specific version type */ function doDelete(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'DELETE' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'DELETE'; // find the paths's params if (typeof params.id !== 'object' && params.id) { diff --git a/src/api/delete_by_query.js b/src/api/delete_by_query.js index 0ceb06b99..b445bd7e3 100644 --- a/src/api/delete_by_query.js +++ b/src/api/delete_by_query.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -26,17 +25,23 @@ var replicationOptions = ['sync', 'async']; * @param {Date|Number} params.timeout - Explicit operation timeout */ function doDeleteByQuery(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: params.body || null, + method: 'DELETE' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'DELETE'; // find the paths's params switch (typeof params.index) { diff --git a/src/api/exists.js b/src/api/exists.js index 12948f903..65630503c 100644 --- a/src/api/exists.js +++ b/src/api/exists.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -16,16 +15,22 @@ var _ = require('../lib/utils'), * @param {string} params.routing - Specific routing value */ function doExists(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: _.union([404], params.ignore) - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: _.union([404], params.ignore), + method: 'HEAD' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'HEAD'; // find the paths's params if (typeof params.id !== 'object' && params.id) { diff --git a/src/api/explain.js b/src/api/explain.js index 1e02eb0ab..2ccd71b3a 100644 --- a/src/api/explain.js +++ b/src/api/explain.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -28,16 +27,23 @@ var defaultOperatorOptions = ['AND', 'OR']; * @param {String|ArrayOfStrings|Boolean} params._source_include - A list of fields to extract and return from the _source field */ function doExplain(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/get.js b/src/api/get.js index 773ddf60b..1bfbb6af9 100644 --- a/src/api/get.js +++ b/src/api/get.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -20,16 +19,22 @@ var _ = require('../lib/utils'), * @param {String|ArrayOfStrings|Boolean} params._source_include - A list of fields to extract and return from the _source field */ function doGet(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.id !== 'object' && params.id) { diff --git a/src/api/get_source.js b/src/api/get_source.js index ad5e444fe..510752564 100644 --- a/src/api/get_source.js +++ b/src/api/get_source.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -18,16 +17,22 @@ var _ = require('../lib/utils'), * @param {string} params.routing - Specific routing value */ function doGetSource(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.id !== 'object' && params.id) { diff --git a/src/api/index.js b/src/api/index.js index 99bd23148..b3a531d17 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -28,16 +27,23 @@ var versionTypeOptions = ['internal', 'external']; * @param {String} params.version_type - Specific version type */ function doIndex(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'POST' || params.method === 'PUT') { request.method = params.method; diff --git a/src/api/indices/analyze.js b/src/api/indices/analyze.js index a87bd991b..5355d8b30 100644 --- a/src/api/indices/analyze.js +++ b/src/api/indices/analyze.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -21,16 +20,23 @@ var formatOptions = ['detailed', 'text']; * @param {String} [params.format=detailed] - Format of the output */ function doIndicesAnalyze(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/indices/clear_cache.js b/src/api/indices/clear_cache.js index 1e52b1a19..57e34b1d6 100644 --- a/src/api/indices/clear_cache.js +++ b/src/api/indices/clear_cache.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -24,15 +23,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {boolean} params.recycler - Clear the recycler cache */ function doIndicesClearCache(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'POST' || params.method === 'GET') { request.method = params.method; diff --git a/src/api/indices/close.js b/src/api/indices/close.js index a29589d2a..24774f339 100644 --- a/src/api/indices/close.js +++ b/src/api/indices/close.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,16 +12,22 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesClose(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'POST' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'POST'; // find the paths's params if (typeof params.index !== 'object' && params.index) { diff --git a/src/api/indices/create.js b/src/api/indices/create.js index c8d2bbc85..d1dd8ed50 100644 --- a/src/api/indices/create.js +++ b/src/api/indices/create.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,16 +12,23 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesCreate(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'PUT' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/indices/delete.js b/src/api/indices/delete.js index 179b7d8ef..b41847c43 100644 --- a/src/api/indices/delete.js +++ b/src/api/indices/delete.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,16 +12,22 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesDelete(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'DELETE' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'DELETE'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/delete_alias.js b/src/api/indices/delete_alias.js index ed753d9cc..8021f4beb 100644 --- a/src/api/indices/delete_alias.js +++ b/src/api/indices/delete_alias.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,16 +12,22 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesDeleteAlias(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'DELETE' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'DELETE'; // find the paths's params if (typeof params.index !== 'object' && params.index) { diff --git a/src/api/indices/delete_mapping.js b/src/api/indices/delete_mapping.js index edeeef84a..a85481796 100644 --- a/src/api/indices/delete_mapping.js +++ b/src/api/indices/delete_mapping.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -12,16 +11,22 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesDeleteMapping(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'DELETE' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'DELETE'; // find the paths's params switch (typeof params.index) { diff --git a/src/api/indices/delete_template.js b/src/api/indices/delete_template.js index 6af3ef8c5..74f0c2faa 100644 --- a/src/api/indices/delete_template.js +++ b/src/api/indices/delete_template.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,16 +12,22 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesDeleteTemplate(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'DELETE' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'DELETE'; // find the paths's params if (typeof params.name !== 'object' && params.name) { diff --git a/src/api/indices/delete_warmer.js b/src/api/indices/delete_warmer.js index 25ec5ff1d..d9fbde232 100644 --- a/src/api/indices/delete_warmer.js +++ b/src/api/indices/delete_warmer.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -12,16 +11,22 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesDeleteWarmer(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'DELETE' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'DELETE'; // find the paths's params switch (typeof params.index) { diff --git a/src/api/indices/exists.js b/src/api/indices/exists.js index 3c2e91ac9..5e6031e92 100644 --- a/src/api/indices/exists.js +++ b/src/api/indices/exists.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -11,16 +10,22 @@ var _ = require('../../lib/utils'), * @param {Object} params - An object with parameters used to carry out this action */ function doIndicesExists(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: _.union([404], params.ignore) - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: _.union([404], params.ignore), + method: 'HEAD' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'HEAD'; // find the paths's params switch (typeof params.index) { diff --git a/src/api/indices/exists_alias.js b/src/api/indices/exists_alias.js index a3ea5dd30..5dd1fe25f 100644 --- a/src/api/indices/exists_alias.js +++ b/src/api/indices/exists_alias.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -14,16 +13,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {String} [params.ignore_indices=none] - When performed on multiple indices, allows to ignore `missing` ones */ function doIndicesExistsAlias(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: _.union([404], params.ignore) - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: _.union([404], params.ignore), + method: 'HEAD' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'HEAD'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/exists_type.js b/src/api/indices/exists_type.js index 24a2bb858..fe3ae8fc4 100644 --- a/src/api/indices/exists_type.js +++ b/src/api/indices/exists_type.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -14,16 +13,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {String} [params.ignore_indices=none] - When performed on multiple indices, allows to ignore `missing` ones */ function doIndicesExistsType(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: _.union([404], params.ignore) - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: _.union([404], params.ignore), + method: 'HEAD' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'HEAD'; // find the paths's params switch (typeof params.index) { diff --git a/src/api/indices/flush.js b/src/api/indices/flush.js index a1ffd0170..a15f27fd9 100644 --- a/src/api/indices/flush.js +++ b/src/api/indices/flush.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -17,15 +16,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {boolean} params.refresh - Refresh the index after performing the operation */ function doIndicesFlush(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'POST' || params.method === 'GET') { request.method = params.method; diff --git a/src/api/indices/get_alias.js b/src/api/indices/get_alias.js index e9d02395c..8431cc480 100644 --- a/src/api/indices/get_alias.js +++ b/src/api/indices/get_alias.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -14,16 +13,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {String} [params.ignore_indices=none] - When performed on multiple indices, allows to ignore `missing` ones */ function doIndicesGetAlias(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/get_aliases.js b/src/api/indices/get_aliases.js index 4b230c09e..76d869a40 100644 --- a/src/api/indices/get_aliases.js +++ b/src/api/indices/get_aliases.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -12,16 +11,22 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.timeout - Explicit operation timeout */ function doIndicesGetAliases(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/get_mapping.js b/src/api/indices/get_mapping.js index d70ac0c6e..4a8016256 100644 --- a/src/api/indices/get_mapping.js +++ b/src/api/indices/get_mapping.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -11,16 +10,22 @@ var _ = require('../../lib/utils'), * @param {Object} params - An object with parameters used to carry out this action */ function doIndicesGetMapping(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/get_settings.js b/src/api/indices/get_settings.js index f0712d9d9..f5f12a9b7 100644 --- a/src/api/indices/get_settings.js +++ b/src/api/indices/get_settings.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -11,16 +10,22 @@ var _ = require('../../lib/utils'), * @param {Object} params - An object with parameters used to carry out this action */ function doIndicesGetSettings(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/get_template.js b/src/api/indices/get_template.js index 84cbd9f87..0a28d6c23 100644 --- a/src/api/indices/get_template.js +++ b/src/api/indices/get_template.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -11,16 +10,22 @@ var _ = require('../../lib/utils'), * @param {Object} params - An object with parameters used to carry out this action */ function doIndicesGetTemplate(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.name !== 'object' && params.name) { diff --git a/src/api/indices/get_warmer.js b/src/api/indices/get_warmer.js index 78a27e384..6a9d4701c 100644 --- a/src/api/indices/get_warmer.js +++ b/src/api/indices/get_warmer.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -11,16 +10,22 @@ var _ = require('../../lib/utils'), * @param {Object} params - An object with parameters used to carry out this action */ function doIndicesGetWarmer(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params switch (typeof params.index) { diff --git a/src/api/indices/open.js b/src/api/indices/open.js index 395448488..9c68020fe 100644 --- a/src/api/indices/open.js +++ b/src/api/indices/open.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,16 +12,22 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesOpen(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'POST' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'POST'; // find the paths's params if (typeof params.index !== 'object' && params.index) { diff --git a/src/api/indices/optimize.js b/src/api/indices/optimize.js index 4e0662857..cdace0938 100644 --- a/src/api/indices/optimize.js +++ b/src/api/indices/optimize.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -20,15 +19,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {boolean} params.wait_for_merge - Specify whether the request should block until the merge process is finished (default: true) */ function doIndicesOptimize(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'POST' || params.method === 'GET') { request.method = params.method; diff --git a/src/api/indices/put_alias.js b/src/api/indices/put_alias.js index 14b7aee14..7984e84f0 100644 --- a/src/api/indices/put_alias.js +++ b/src/api/indices/put_alias.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,17 +12,23 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesPutAlias(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: params.body || null, + method: 'PUT' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'PUT'; // find the paths's params if (typeof params.index !== 'object' && params.index) { diff --git a/src/api/indices/put_mapping.js b/src/api/indices/put_mapping.js index a63820f15..2ec112c25 100644 --- a/src/api/indices/put_mapping.js +++ b/src/api/indices/put_mapping.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -14,16 +13,23 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesPutMapping(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'PUT' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/indices/put_settings.js b/src/api/indices/put_settings.js index 340b2395d..dd3b619ce 100644 --- a/src/api/indices/put_settings.js +++ b/src/api/indices/put_settings.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -12,17 +11,23 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesPutSettings(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: params.body || null, + method: 'PUT' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'PUT'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/put_template.js b/src/api/indices/put_template.js index adcdf24e9..8bc45bccd 100644 --- a/src/api/indices/put_template.js +++ b/src/api/indices/put_template.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -14,16 +13,23 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesPutTemplate(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'PUT' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/indices/put_warmer.js b/src/api/indices/put_warmer.js index f8d847333..2524d4689 100644 --- a/src/api/indices/put_warmer.js +++ b/src/api/indices/put_warmer.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -12,17 +11,23 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesPutWarmer(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: params.body || null, + method: 'PUT' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'PUT'; // find the paths's params switch (typeof params.index) { diff --git a/src/api/indices/refresh.js b/src/api/indices/refresh.js index ce438d778..0c0bcd914 100644 --- a/src/api/indices/refresh.js +++ b/src/api/indices/refresh.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -15,15 +14,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {*} params.operation_threading - TODO: ? */ function doIndicesRefresh(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'POST' || params.method === 'GET') { request.method = params.method; diff --git a/src/api/indices/segments.js b/src/api/indices/segments.js index e32039ae0..bba1e05bb 100644 --- a/src/api/indices/segments.js +++ b/src/api/indices/segments.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -15,16 +14,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {*} params.operation_threading - TODO: ? */ function doIndicesSegments(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/snapshot_index.js b/src/api/indices/snapshot_index.js index 5c7da0dbd..b99db8f54 100644 --- a/src/api/indices/snapshot_index.js +++ b/src/api/indices/snapshot_index.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -14,16 +13,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {String} [params.ignore_indices=none] - When performed on multiple indices, allows to ignore `missing` ones */ function doIndicesSnapshotIndex(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'POST' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'POST'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/stats.js b/src/api/indices/stats.js index b800df599..6ec6cd5de 100644 --- a/src/api/indices/stats.js +++ b/src/api/indices/stats.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -34,16 +33,22 @@ var metricFamilyOptions = ['completion', 'docs', 'fielddata', 'filter_cache', 'f * @param {boolean} params.warmer - Return information about warmers */ function doIndicesStats(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.fields !== 'undefined') { diff --git a/src/api/indices/status.js b/src/api/indices/status.js index f4ceac4bd..90603c9ea 100644 --- a/src/api/indices/status.js +++ b/src/api/indices/status.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -17,16 +16,22 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {boolean} params.snapshot - TODO: ? */ function doIndicesStatus(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { - ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + ignore: params.ignore, + method: 'GET' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'GET'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/update_aliases.js b/src/api/indices/update_aliases.js index eefba4ba2..6f5d4e1b8 100644 --- a/src/api/indices/update_aliases.js +++ b/src/api/indices/update_aliases.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -13,17 +12,23 @@ var _ = require('../../lib/utils'), * @param {Date|Number} params.master_timeout - Specify timeout for connection to master */ function doIndicesUpdateAliases(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: params.body || null, + method: 'POST' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'POST'; // find the paths's params if (typeof params.index !== 'undefined') { diff --git a/src/api/indices/validate_query.js b/src/api/indices/validate_query.js index 4c47e02b6..12de7b6cc 100644 --- a/src/api/indices/validate_query.js +++ b/src/api/indices/validate_query.js @@ -1,5 +1,4 @@ var _ = require('../../lib/utils'), - paramHelper = require('../../lib/param_helper'), errors = require('../../lib/errors'), q = require('q'); @@ -18,16 +17,23 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {string} params.q - Query in the Lucene query string syntax */ function doIndicesValidateQuery(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/info.js b/src/api/info.js index 766b25515..8cf5e72f1 100644 --- a/src/api/info.js +++ b/src/api/info.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -11,15 +10,22 @@ var _ = require('../lib/utils'), * @param {Object} params - An object with parameters used to carry out this action */ function doInfo(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'HEAD') { request.method = params.method; diff --git a/src/api/mget.js b/src/api/mget.js index 72c4cfcb3..7eb28626c 100644 --- a/src/api/mget.js +++ b/src/api/mget.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -18,16 +17,23 @@ var _ = require('../lib/utils'), * @param {String|ArrayOfStrings|Boolean} params._source_include - A list of fields to extract and return from the _source field */ function doMget(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/mlt.js b/src/api/mlt.js index 9778e9f64..556df2264 100644 --- a/src/api/mlt.js +++ b/src/api/mlt.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -30,16 +29,23 @@ var _ = require('../lib/utils'), * @param {String|ArrayOfStrings|Boolean} params.stop_words - A list of stop words to be ignored */ function doMlt(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/msearch.js b/src/api/msearch.js index f941a61de..00e5539b3 100644 --- a/src/api/msearch.js +++ b/src/api/msearch.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -14,16 +13,23 @@ var searchTypeOptions = ['query_then_fetch', 'query_and_fetch', 'dfs_query_then_ * @param {String} params.search_type - Search operation type */ function doMsearch(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: paramHelper.bulkBody(params.body, this.client.serializer) || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: this.client.config.serializer.bulkBody(params.body || null) + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/percolate.js b/src/api/percolate.js index 770ddea7e..24bbf0a4b 100644 --- a/src/api/percolate.js +++ b/src/api/percolate.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -12,16 +11,23 @@ var _ = require('../lib/utils'), * @param {boolean} params.prefer_local - With `true`, specify that a local shard should be used if available, with `false`, use a random shard (default: true) */ function doPercolate(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/scroll.js b/src/api/scroll.js index d86e39372..917f0889e 100644 --- a/src/api/scroll.js +++ b/src/api/scroll.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -13,16 +12,23 @@ var _ = require('../lib/utils'), * @param {string} params.scroll_id - The scroll ID for scrolled search */ function doScroll(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/search.js b/src/api/search.js index e00f830f1..0c94e7186 100644 --- a/src/api/search.js +++ b/src/api/search.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -45,16 +44,23 @@ var suggestModeOptions = ['missing', 'popular', 'always']; * @param {boolean} params.version - Specify whether to return document version as part of a hit */ function doSearch(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'GET' || params.method === 'POST') { request.method = params.method; diff --git a/src/api/suggest.js b/src/api/suggest.js index b0a571f84..c25294b23 100644 --- a/src/api/suggest.js +++ b/src/api/suggest.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -17,16 +16,23 @@ var ignoreIndicesOptions = ['none', 'missing']; * @param {string} params.source - The URL-encoded request definition (instead of using request body) */ function doSuggest(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + }, + parts = {}, + query = {}, + responseOpts = {}; + // figure out the method if (params.method = _.toUpperString(params.method)) { if (params.method === 'POST' || params.method === 'GET') { request.method = params.method; diff --git a/src/api/update.js b/src/api/update.js index 96a7d89bf..414b73dd2 100644 --- a/src/api/update.js +++ b/src/api/update.js @@ -1,5 +1,4 @@ var _ = require('../lib/utils'), - paramHelper = require('../lib/param_helper'), errors = require('../lib/errors'), q = require('q'); @@ -29,17 +28,23 @@ var replicationOptions = ['sync', 'async']; * @param {number} params.version_type - Explicit version number for concurrency control */ function doUpdate(params, cb) { - params = params || {}; + if (typeof params === 'function') { + cb = params; + params = {}; + } else { + params = params || {}; + cb = typeof cb === 'function' ? cb : _.noop; + } var request = { ignore: params.ignore, - body: params.body || null - } - , parts = {} - , query = {} - , responseOpts = {}; + body: params.body || null, + method: 'POST' + }, + parts = {}, + query = {}, + responseOpts = {}; - request.method = 'POST'; // find the paths's params if (typeof params.id !== 'object' && params.id) { diff --git a/src/lib/Client.js b/src/lib/Client.js index d7603516e..59dcfccfc 100644 --- a/src/lib/Client.js +++ b/src/lib/Client.js @@ -4,7 +4,7 @@ * Initializing a client might look something like: * * ``` - * var client = new Elasticsearch.Client({ + * var client = new es.Client({ * hosts: [ * 'es1.net:9200', * { @@ -30,33 +30,32 @@ module.exports = Client; -var _ = require('./utils'), - ClientConfig = require('./client_config'), - api = _.reKey(_.requireDir(module, '../api'), _.camelCase), - q = require('q'), - Transport = require('./transport'), - ConnectionPool = require('./connection_pool'), - Log = require('./log'), - serializers = _.requireClasses(module, './serializers'), - errors = require('./errors'); +var _ = require('./utils'); +var ClientConfig = require('./client_config'); +var api = _.reKey(_.requireDir(module, '../api'), _.camelCase); +var q = require('q'); +var errors = require('./errors'); -// Many API commands are namespaced, like cluster.node_stats. The names of these namespaces will be +// Many API commands are namespaced, like cluster.nodeStats. The names of these namespaces will be // tracked here and the namespace objects will be instantiated by reading the values from this // array var namespaces = []; function Client(config) { this.client = this; - this.config = !config || _.isPlainObject(config) ? new ClientConfig(config) : config; + + // setup the config.. this config will be passed EVERYWHERE so for good measure it is locked down + Object.defineProperty(this, 'config', { + configurable: false, + enumerable: false, + writable: false, + value: !config || _.isPlainObject(config) ? new ClientConfig(config) : config, + }); + this.config.client = this; for (var i = 0; i < namespaces.length; i++) { this[namespaces[i]] = new this[namespaces[i]](this); } - - this.log = new Log(this); - this.transport = new Transport(this); - this.serializer = new serializers.Json(this); - this.connectionPool = new ConnectionPool(this); } /** @@ -73,9 +72,10 @@ function Client(config) { * @param {Function} cb - A function to call back with (error, responseBody, responseStatus) */ Client.prototype.request = function (params, cb) { - if (typeof cb !== 'function') { - cb = _.noop; - } + var serializer = this.config.serializer; + + // in cb isn't a function make it one + cb = typeof cb === 'function' ? cb : _.noop; // get ignore and ensure that it's an array var ignore = params.ignore; @@ -83,20 +83,34 @@ Client.prototype.request = function (params, cb) { ignore = [ignore]; } - this.transport.request(params, function (err, body, status) { + // serialize the body + if (params.body) { + params.body = serializer.serialize(params.body); + } + + this.config.transport.request(params, function (err, reqParams, body, status) { + + var parsedBody = null; + if (!err) { + if (body) { + parsedBody = serializer.unserialize(body); + if (!parsedBody) { + err = new errors.ParseError(); + } + } else if (reqParams.method === 'HEAD') { + parsedBody = (status === 200); + } + } + if (err) { - return cb(err, body, status); + return cb(err, parsedBody, status); } else if ((status >= 200 && status < 300) || ignore && _.contains(ignore, status)) { - return cb(void 0, body, status); + return cb(void 0, parsedBody, status); } else { if (errors[status]) { - return cb(new errors[status](body.error), body, status); + return cb(new errors[status](parsedBody.error), parsedBody, status); } else { - console.log({ - status: status, - body: body - }); - return cb(new errors.Generic('unknown error'), body, status); + return cb(new errors.Generic('unknown error'), parsedBody, status); } } }); @@ -109,7 +123,7 @@ Client.prototype.request = function (params, cb) { * @param {Function} cb - callback */ Client.prototype.ping = function (params, cb) { - this.transport.request({ + this.config.transport.request({ method: 'HEAD', path: '/' }, cb); diff --git a/src/lib/Log.js b/src/lib/Log.js index cf2b7d78e..abfba47c7 100644 --- a/src/lib/Log.js +++ b/src/lib/Log.js @@ -16,11 +16,11 @@ var _ = require('./utils'), * @param {string} output.level - One of the keys in Log.levels (error, warning, etc.) * @param {string} output.type - The name of the logger to use for this output */ -function Log(client) { - this.client = client; +function Log(config) { + this.config = config; var i; - var output = client.config.log || 2; + var output = config.log || 2; if (_.isString(output) || _.isFinite(output)) { output = [ @@ -160,7 +160,7 @@ Log.join = function (arrayish) { Log.prototype.addOutput = function (config) { var levels = Log.parseLevels(config.levels || config.level || 'warning'); - _.defaults(config, { + _.defaults(config || {}, { type: 'stdio', }); @@ -241,10 +241,7 @@ Log.prototype.debug = function (/* ...msg */) { Log.prototype.trace = function (method, requestUrl, body, responseBody, responseStatus) { if (EventEmitter.listenerCount(this, 'trace')) { if (typeof requestUrl === 'object') { - if (!requestUrl.protocol) { - requestUrl.protocol = 'http'; - } - requestUrl = url.format(requestUrl); + requestUrl = _.formatUrl(requestUrl); } return this.emit('trace', method, requestUrl, body, responseBody, responseStatus); } diff --git a/src/lib/Transport.js b/src/lib/Transport.js index 9b5c885c3..acd79ba8b 100644 --- a/src/lib/Transport.js +++ b/src/lib/Transport.js @@ -22,69 +22,71 @@ var _ = require('./utils'), ConnectionPool = require('./connection_pool'), errors = require('./errors'); -function Transport(client) { - this.client = client; +function Transport(config) { + this.config = config; } Transport.prototype.sniff = function (cb) { + var self = this; + + // make cb a function if it isn't cb = typeof cb === 'function' ? cb : _.noop; - var connectionPool = this.client.connectionPool, - nodesToHostCallback = _.bind(this.client.config.nodesToHostCallback, this); - - this.client.request({ - path: '/_cluster/nodes' + self.request({ + path: '/_cluster/nodes', + method: 'GET' }, function (err, resp) { if (!err && resp && resp.nodes) { - connectionPool.setHosts(nodesToHostCallback(resp.nodes)); + self.createConnections(self.config.nodesToHostCallback(resp.nodes)); } cb(err, resp); }); }; +Transport.prototype.createConnections = function (hosts) { + for (var i = 0; i < hosts.length; i++) { + this.config.connectionPool.add(new this.config.connectionConstructor( + this.config, + hosts[i] + )); + } +}; Transport.prototype.request = function (params, cb) { cb = typeof cb === 'function' ? cb : _.noop; - var client = this.client, - remainingRetries = client.config.maxRetries, - connection; + var connectionPool = this.config.connectionPool; + var log = this.config.log; + var remainingRetries = this.config.maxRetries; + var connection; - // serialize the body - params.body = client.serializer.serialize(params.body); - - function sendRequestWithConnection(err, c) { + function sendRequestWithConnection(err, _connection) { if (err) { cb(err); - } else if (c) { - connection = c; + } else if (_connection) { + connection = _connection; connection.request(params, checkRespForFailure); } else { - cb(new errors.ConnectionError('No active nodes at this time.')); + cb(new errors.ConnectionFault('No active connections.')); } } - function checkRespForFailure(err, body, status) { - // check for posotive response + function checkRespForFailure(err, reqParams, body, status) { + connection.setStatus(err ? 'dead' : 'alive'); + if (err) { - client.connectionPool.setStatus(connection, 'dead'); - checkForRetry(err, null, status); - } else { - client.connectionPool.setStatus(connection, 'alive'); - return cb(null, client.serializer.unserialize(body), status); + log.error(err); } - } - function checkForRetry(err, resp) { - client.connectionPool.setStatus(connection, 'dead'); - if (remainingRetries) { + if (err && remainingRetries) { remainingRetries--; - client.connectionPool.select(sendRequestWithConnection); + log.info('Retrying request after connection error'); + connectionPool.select(sendRequestWithConnection); } else { - return cb(err, null); + cb(err, reqParams, body, status); } } - client.connectionPool.select(sendRequestWithConnection); + connectionPool.select(sendRequestWithConnection); }; diff --git a/src/lib/client_config.js b/src/lib/client_config.js index d066ab588..344c3db4b 100644 --- a/src/lib/client_config.js +++ b/src/lib/client_config.js @@ -6,18 +6,23 @@ */ module.exports = ClientConfig; -var url = require('url'), - _ = require('./utils'), - selectors = _.reKey(_.requireDir(module, './selectors'), _.camelCase), - connections = _.requireClasses(module, './connections'), - extractHostPartsRE = /\[([^:]+):(\d+)]/, - hostProtocolRE = /^([a-z]+:)?\/\//; +var url = require('url'); +var _ = require('./utils'); +var selectors = _.reKey(_.requireDir(module, './selectors'), _.camelCase); +var connections = _.requireClasses(module, './connections'); +var serializers = _.requireClasses(module, './serializers'); +var Transport = require('./transport'); +var ConnectionPool = require('./connection_pool'); +var Log = require('./log'); + +var extractHostPartsRE = /\[([^:]+):(\d+)]/; +var hostProtocolRE = /^([a-z]+:)?\/\//; var defaultConfig = { hosts: [ { protocol: 'http:', - host: 'localhost', + hostname: 'localhost', port: 9200 } ], @@ -51,7 +56,38 @@ function ClientConfig(config) { this.hosts = [this.hosts]; } + // validate connectionConstructor + if (typeof this.connectionConstructor !== 'function') { + if (_.has(connections, this.connectionConstructor)) { + this.connectionConstructor = connections[this.connectionConstructor]; + } else { + throw new TypeError('Invalid connectionConstructor ' + this.connectionConstructor + + ', specify a function or one of ' + _.keys(connections).join(', ')); + } + } + + // validate selector + if (typeof this.selector !== 'function') { + if (_.has(selectors, this.selector)) { + this.selector = selectors[this.selector]; + } else { + throw new TypeError('Invalid Selector ' + this.selector + '. specify a function or one of ' + _.keys(selectors).join(', ')); + } + } + + this.serializer = new serializers.Json(this); this.hosts = _.map(this.hosts, this.transformHost); + + this.log = new Log(this); + this.transport = new Transport(this); + this.connectionPool = new ConnectionPool(this); + + this.transport.createConnections(this.hosts); + + if (this.randomizeHosts) { + this.connectionPool.connections.alive = _.shuffle(this.connectionPool.connections.alive); + } + } ClientConfig.prototype.transformHost = function (host) { diff --git a/src/lib/connection.js b/src/lib/connection.js index 08636f41f..c1a5c5c89 100644 --- a/src/lib/connection.js +++ b/src/lib/connection.js @@ -12,13 +12,14 @@ var _ = require('./utils'), * @class ConnectionAbstract * @constructor */ -function ConnectionAbstract(client, config, id) { +function ConnectionAbstract(config) { EventEmitter.call(this); - this.client = client; - this.id = id; + this.config = config; this.hostname = config.hostname || 'localhost'; this.port = config.port || 9200; this.timeout = config.timeout || 10000; + + _.makeBoundMethods(this); } _.inherits(ConnectionAbstract, EventEmitter); @@ -43,3 +44,32 @@ ConnectionAbstract.prototype.ping = function () { timeout: '100' }); }; + +ConnectionAbstract.prototype.setStatus = function (status) { + var origStatus = this.status; + + this.status = status; + + if (status === 'dead') { + if (this.__deadTimeout) { + clearTimeout(this.__deadTimeout); + } + this.__deadTimeout = setTimeout(this.bound.resuscitate, this.config.deadTimeout); + } + + this.emit('status changed', status, origStatus, this); +}; + +ConnectionAbstract.prototype.resuscitate = _.scheduled(function () { + var self = this; + + if (self.status === 'dead') { + self.ping(function (err) { + if (!err) { + self.setStatus('alive'); + } else { + self.emit('dead'); + } + }); + } +}); diff --git a/src/lib/connection_pool.js b/src/lib/connection_pool.js index 7d0226fc7..2bac02d6f 100644 --- a/src/lib/connection_pool.js +++ b/src/lib/connection_pool.js @@ -15,98 +15,44 @@ var _ = require('./utils'), q = require('q'), errors = require('./errors'); -function ConnectionPool(client) { - this.client = client; +function ConnectionPool(config) { + _.makeBoundMethods(this); + this.config = config; this.index = {}; this.connections = { alive: [], dead: [] }; - - var config = client.config; - - // validate connectionConstructor - if (typeof config.connectionConstructor !== 'function') { - if (_.has(connectors, config.connectionConstructor)) { - config.connectionConstructor = connectors[config.connectionConstructor]; - } else { - throw new TypeError('Invalid connectionConstructor ' + config.connectionConstructor + - ', specify a function or one of ' + _.keys(connectors).join(', ')); - } - } - - this.connectionConstructor = config.connectionConstructor; - this.setNodes(config.hosts); } -ConnectionPool.prototype.setNodes = function (nodes) { - var client = this.client; - - if (!_.isArrayOfObjects(nodes)) { - throw new TypeError('Invalid hosts: specify an Array of Objects with host and port keys'); - } - - var i, id, prevIndex = _.clone(this.index), connection; - for (i = 0; i < nodes.length; i++) { - id = nodes[i].host + ':' + nodes[i].port; - if (prevIndex[id]) { - delete prevIndex[id]; - } else { - client.log.info('Creating connection to ' + id); - connection = new this.connectionConstructor(this.client, nodes[i]); - if (!(connection instanceof EventEmitter)) { - throw new Error('ConnectionConstructor does not implement the event interface'); - } else if (!EventEmitter.listenerCount(connection, 'closed')) { - throw new Error( - 'Connection Constructor ' + this.connectionConstructor.name + - ' does not listen for the closed event. No bueno.' - ); - } - this.index[id] = connection; - this.setStatus(connection, 'alive'); - } - } - - var toRemove = _.keys(prevIndex); - for (i = 0; i < toRemove.length; i++) { - client.log.info('Closing connection to ' + toRemove[i]); - this.index[toRemove[i]].isClosed(); - delete this.index[toRemove[i]]; - } - - client.log.info('Nodes successfully changed'); -}; - ConnectionPool.prototype.select = function (cb) { - var config = this.client.config; - - if (typeof config.selector !== 'function') { - if (_.has(selectors, config.selector)) { - config.selector = selectors[config.selector]; - } else { - throw new TypeError('Invalid Selector ' + config.selector + '. specify a function or one of ' + _.keys(selectors).join(', ')); - } - } - if (this.connections.alive.length) { - if (config.selector.length > 1) { - config.selector(this.connections.alive, cb); + if (this.config.selector.length > 1) { + this.config.selector(this.connections.alive, cb); } else { - cb(null, config.selector(this.connections.alive)); + cb(null, this.config.selector(this.connections.alive)); } } else { - cb(new errors.ConnectionError('No living connections')); + cb(new errors.ConnectionFault('No active connections')); } }; +ConnectionPool.prototype.empty = function () { + _.each(this.connection.dead, function (connection) { + connection.setStatus('closed'); + }); + _.each(this.connection.alive, function (connection) { + connection.setStatus('closed'); + }); +}; -ConnectionPool.prototype.setStatus = function (connection, status) { +ConnectionPool.prototype.setStatus = _.handler(function (status, oldStatus, connection) { var origStatus = connection.status, from, to, index; if (origStatus === status) { return true; } else { - this.client.log.info('connection to', _.formatUrl(connection), 'is', status); + this.config.log.info('connection to', _.formatUrl(connection), 'is', status); } switch (status) { @@ -120,6 +66,7 @@ ConnectionPool.prototype.setStatus = function (connection, status) { break; case 'closed': from = this.connections[origStatus]; + connection.removeListener('status changed', this.bound.setStatus); break; } @@ -136,7 +83,12 @@ ConnectionPool.prototype.setStatus = function (connection, status) { to.push(connection); } } +}); - connection.status = status; - connection.emit(status, origStatus); +ConnectionPool.prototype.add = function (connection) { + if (!~this.connections.alive.indexOf(connection) && !~this.connections.dead.indexOf(connection)) { + connection.status = 'alive'; + connection.on('status changed', this.bound.setStatus); + this.connections.alive.push(connection); + } }; diff --git a/src/lib/connections/http.js b/src/lib/connections/http.js index 17e443ea3..c5c8ac31d 100644 --- a/src/lib/connections/http.js +++ b/src/lib/connections/http.js @@ -18,8 +18,8 @@ var http = require('http'), }; -function HttpConnection(client, config) { - ConnectionAbstract.call(this, client, config); +function HttpConnection(config) { + ConnectionAbstract.call(this, config); this.protocol = config.protocol || 'http:'; if (this.protocol[this.protocol.length - 1] !== ':') { @@ -30,24 +30,33 @@ function HttpConnection(client, config) { keepAlive: true, // delay between the last data packet received and the first keepalive probe keepAliveMsecs: 1000, - maxSockets: this.client.config.maxSockets, - maxFreeSockets: this.client.config.maxFreeSockets + maxSockets: 1, + maxFreeSockets: this.config.maxFreeSockets }); - this.on('closed', function () { - this.agent.destroy(); - this.removeAllListeners(); - }); + this.on('closed', this.bound.onClosed); + this.once('alive', this.bound.onAlive); + } _.inherits(HttpConnection, ConnectionAbstract); +HttpConnection.prototype.onClosed = _.handler(function () { + this.agent.destroy(); + this.removeAllListeners(); +}); + +HttpConnection.prototype.onAlive = _.handler(function () { + // only set the agents max agents config once the connection is verified to be alive + this.agent.maxSockets = this.config.maxSockets; +}); + HttpConnection.prototype.request = function (params, cb) { var request, response, status = 0, timeout = params.timeout || this.timeout, timeoutId, - log = this.client.log; + log = this.config.log; var reqParams = _.defaults({ protocol: this.protocol, @@ -62,15 +71,11 @@ HttpConnection.prototype.request = function (params, cb) { var cleanUp = function (err) { cleanUp = _.noop; - if (err) { - log.error(err); - } - clearTimeout(timeoutId); if (request) { request.removeAllListeners(); } - _.nextTick(cb, err, response, status); + _.nextTick(cb, err, reqParams, response, status); }; // ensure that "get" isn't being used with a request body @@ -92,14 +97,8 @@ HttpConnection.prototype.request = function (params, cb) { response += d; }); - incoming.on('close', function (err) { - console.log('closed'); - cleanUp(err); - }); - incoming.on('end', function requestComplete() { incoming.removeAllListeners(); - log.trace(reqParams.method, reqParams, params.body, response, status); cleanUp(); }); }); diff --git a/src/lib/errors.js b/src/lib/errors.js index b552a457f..efd2bfa4b 100644 --- a/src/lib/errors.js +++ b/src/lib/errors.js @@ -13,11 +13,11 @@ _.inherits(ErrorAbstract, Error); * Connection Error * @param {String} [msg] - An error message that will probably end up in a log. */ -errors.ConnectionError = function ConnectionError(msg) { +errors.ConnectionFault = function ConnectionFault(msg) { return new Error(msg || 'Connection Failure'); ErrorAbstract.call(this, msg || 'Connection Failure'); }; -_.inherits(errors.ConnectionError, ErrorAbstract); +_.inherits(errors.ConnectionFault, ErrorAbstract); /** * Generic Error @@ -39,6 +39,16 @@ errors.RequestTimeout = function RequestTimeout(msg) { }; _.inherits(errors.RequestTimeout, ErrorAbstract); +/** + * Request Body could not be parsed + * @param {String} [msg] - An error message that will probably end up in a log. + */ +errors.Serialization = function RequestTimeout(msg) { + return new Error(msg || 'ParseError'); + ErrorAbstract.call(this, msg || 'Unable to parse response body'); +}; +_.inherits(errors.RequestTimeout, ErrorAbstract); + var statusCodes = { diff --git a/src/lib/logger.js b/src/lib/logger.js index 4442dfaf3..4da71df0a 100644 --- a/src/lib/logger.js +++ b/src/lib/logger.js @@ -11,14 +11,12 @@ function LoggerAbstract(config, bridge) { this.bridge = bridge; this.listeningLevels = []; - // bound copies of the event handlers - this.handlers = _.reduce(Log.levels, function (handlers, name) { - handlers[name] = _.bindKey(this, 'on' + _.studlyCase(name)); - return handlers; - }, {}, this); + _.makeBoundMethods(this); - // then the bridge closes, remove our event listeners - this.bridge.on('closing', _.bindKey(this, 'cleanUpListeners')); + console.log(this.bound); + + // when the bridge closes, remove our event listeners + this.bridge.on('closing', this.bound.cleanUpListeners); this.setupListeners(config.levels); } @@ -71,7 +69,12 @@ LoggerAbstract.prototype.setupListeners = function (levels) { this.listeningLevels = levels; _.each(this.listeningLevels, function (level) { - this.bridge.on(level, this.handlers[level]); + var fnName = 'on' + _.ucfirst(level); + if (this.bound[fnName]) { + this.bridge.on(level, this.bound[fnName]); + } else { + throw new Error(fnName + ' is not a function'); + } }, this); }; @@ -82,11 +85,11 @@ LoggerAbstract.prototype.setupListeners = function (levels) { * @private * @return {undefined} */ -LoggerAbstract.prototype.cleanUpListeners = function () { +LoggerAbstract.prototype.cleanUpListeners = _.handler(function () { _.each(this.listeningLevels, function (level) { this.bridge.removeListener(level, this.handlers[level]); }, this); -}; +}); /** * Handler for the bridges "error" event @@ -96,9 +99,9 @@ LoggerAbstract.prototype.cleanUpListeners = function () { * @param {Error} e - The Error object to log * @return {undefined} */ -LoggerAbstract.prototype.onError = function (e) { +LoggerAbstract.prototype.onError = _.handler(function (e) { this.write((e.name === 'Error' ? 'ERROR' : e.name), e.stack); -}; +}); /** * Handler for the bridges "warning" event @@ -108,9 +111,9 @@ LoggerAbstract.prototype.onError = function (e) { * @param {String} msg - The message to be logged * @return {undefined} */ -LoggerAbstract.prototype.onWarning = function (msg) { +LoggerAbstract.prototype.onWarning = _.handler(function (msg) { this.write('WARNING', msg); -}; +}); /** * Handler for the bridges "info" event @@ -120,9 +123,9 @@ LoggerAbstract.prototype.onWarning = function (msg) { * @param {String} msg - The message to be logged * @return {undefined} */ -LoggerAbstract.prototype.onInfo = function (msg) { +LoggerAbstract.prototype.onInfo = _.handler(function (msg) { this.write('INFO', msg); -}; +}); /** * Handler for the bridges "debug" event @@ -132,9 +135,9 @@ LoggerAbstract.prototype.onInfo = function (msg) { * @param {String} msg - The message to be logged * @return {undefined} */ -LoggerAbstract.prototype.onDebug = function (msg) { +LoggerAbstract.prototype.onDebug = _.handler(function (msg) { this.write('DEBUG', msg); -}; +}); /** * Handler for the bridges "trace" event @@ -144,14 +147,14 @@ LoggerAbstract.prototype.onDebug = function (msg) { * @param {String} msg - The message to be logged * @return {undefined} */ -LoggerAbstract.prototype.onTrace = function (method, url, body, responseBody, responseStatus) { +LoggerAbstract.prototype.onTrace = _.handler(function (method, url, body, responseBody, responseStatus) { var message = 'curl "' + url.replace(/"/g, '\\"') + '" -X' + method.toUpperCase(); if (body) { message += ' -d "' + body.replace(/"/g, '\\"') + '"'; } message += '\n<- ' + responseStatus + '\n' + responseBody; this.write('TRACE', message); -}; +}); module.exports = LoggerAbstract; diff --git a/src/lib/param_helper.js b/src/lib/param_helper.js deleted file mode 100644 index 2f0ef6dd3..000000000 --- a/src/lib/param_helper.js +++ /dev/null @@ -1,18 +0,0 @@ -var _ = require('./utils'); - -exports.bulkBody = function (val, serializer) { - var body = '', i; - - if (_.isArray(val)) { - for (i = 0; i < val.length; i++) { - body += serializer.serialize(val[i]) + '\n'; - } - } else if (typeof val === 'string') { - // make sure the string ends in a new line - body = val + (val[val.length - 1] === '\n' ? '' : '\n'); - } else { - throw new TypeError('Bulk body should either be an Array of commands/string, or a String'); - } - - return body; -}; diff --git a/src/lib/serializers/Json.js b/src/lib/serializers/Json.js index 516c10f77..12d3d1929 100644 --- a/src/lib/serializers/Json.js +++ b/src/lib/serializers/Json.js @@ -33,3 +33,20 @@ Json.prototype.unserialize = function (str) { return str; } }; + +Json.prototype.bulkBody = function (val) { + var body = '', i; + + if (_.isArray(val)) { + for (i = 0; i < val.length; i++) { + body += this.serialize(val[i]) + '\n'; + } + } else if (typeof val === 'string') { + // make sure the string ends in a new line + body = val + (val[val.length - 1] === '\n' ? '' : '\n'); + } else { + throw new TypeError('Bulk body should either be an Array of commands/string, or a String'); + } + + return body; +}; diff --git a/src/lib/utils.js b/src/lib/utils.js index dffa648e1..486a83ad4 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -138,7 +138,7 @@ utils.deepMerge = function (to, from) { * @return {Boolean} */ 'String Object PlainObject Array Finite Function RegExp'.split(' ').forEach(function (type) { - var check = _.bind(_['is' + type], _); + var check = _.bindKey(_, 'is' + type); utils['isArrayOf' + type + 's'] = function (arr) { // quick shallow check of arrays @@ -341,7 +341,6 @@ utils.parseUrl = function (urlString) { urlString = 'http://' + urlString; } var info = url.parse(urlString); - delete info.host; return info; }; @@ -355,9 +354,9 @@ utils.parseUrl = function (urlString) { * @returns {String} */ utils.formatUrl = function (urlInfo) { - var info = _.clone(urlInfo); - if (info.port && info.host && !info.hostname) { - info.hostname = info.host; + var info = _.pick(urlInfo, ['protocol', 'hostname', 'port']); + if (info.port && urlInfo.host && !info.hostname) { + info.hostname = urlInfo.host; delete info.host; } if (!info.protocol) { @@ -406,6 +405,62 @@ utils.nextTick = function (cb) { process.nextTick(utils.bindKey(utils, 'applyArgs', cb, null, arguments, 1)); }; +/** + * Marks a method as a handler. Currently this just makes a property on the method + * flagging it to be bound to the object at object creation when "makeBoundMethods" is called + * + * ``` + * ClassName.prototype.methodName = _.handler(function () { + * // this will always be bound when called via classInstance.bound.methodName + * this === classInstance + * }); + * ``` + * + * @alias utils.scheduled + * @param {Function} func - The method that is being defined + * @return {Function} + */ +utils.handler = function (func) { + func._provideBound = true; + return func; +}; +utils.scheduled = utils.handler; + +/** + * Creates an "bound" property on an object, which all or a subset of methods from + * the object which are bound to the original object. + * + * ``` + * var obj = { + * onEvent: function () {} + * }; + * + * _.makeBoundMethods(obj); + * + * obj.bound.onEvent() // is bound to obj, and can safely be used as an event handler. + * ``` + * + * @param {Object} obj - The object to bind the methods to + * @param {Array} [methods] - The methods to bind, false values === bind them all + */ +utils.makeBoundMethods = function (obj, methods) { + obj.bound = {}; + if (!methods) { + methods = []; + for (var prop in obj) { + // dearest maintainer, we want to look through the prototype + if (typeof obj[prop] === 'function' && obj[prop]._provideBound === true) { + console.log('binding', prop); + obj.bound[prop] = utils.bind(obj[prop], obj); + } + } + } else { + _.each(methods, function (method) { + obj.bound[method] = utils.bindKey(obj, method); + }); + } +}; + utils.noop = function () {}; module.exports = utils; diff --git a/test/integration/index.js b/test/integration/index.js index 11d91afc9..00c4eec77 100644 --- a/test/integration/index.js +++ b/test/integration/index.js @@ -1,577 +1,2 @@ -var path = require('path'), - fs = require('fs'), - async = require('async'), - jsYaml = require('js-yaml'), - expect = require('expect.js'), - server = require('./server'), - _ = require('../../src/lib/utils'), - es = require('../../src/elasticsearch'); - -var argv = require('optimist') - .default('executable', path.join(process.env.ES_HOME, './bin/elasticsearch')) - .default('clusterName', 'yaml-test-runner') - .default('dataPath', '/tmp/yaml-test-runner') - .argv; - - -if (argv.hostname || argv.port) { - console.log('working with ES instance at ' + argv.hostname + ':' + argv.port); -} - -// Where do the tests live? -var TEST_DIR = path.resolve(__dirname, '../../es_api_spec/test/'); - -// test names matching this will be run -var doRE = /(^|\/)(.*)\/.*/; - -// a reference to a personal instance of ES Server -var esServer = null; - -// the client -var client = null; - -// location that the logger will write to -var logFile = path.resolve(__dirname, '../integration-test.log'); - -// empty all of the indices in ES please -function clearIndices (done) { - client.indices.delete({ - index: '*', - ignore: 404 - }, done); -} - -// before running any tests... -before(function (done) { - // start our personal ES Server - this.timeout(null); - if (argv.hostname) { - done(); - } else { - server.start(argv, function (err, server) { - esServer = server; - done(err); - }); - } -}); - -before(function (done) { - // delete the integration log - fs.unlink(logFile, function (err) { - if (err && ~err.message.indexOf('ENOENT')) { - done(); - } else { - done(err); - } - }); -}); - -before(function () { - // create the client - client = new es.Client({ - hosts: [ - { - hostname: esServer ? esServer.__hostname : argv.hostname, - port: esServer ? esServer.__port : argv.port - } - ], - log: { - type: 'file', - level: ['error', 'trace'], - path: logFile - } - }); -}); - -before(clearIndices); - -/** - * recursively crawl the directory, looking for yaml files which will be passed to loadFile - * @param {String} dir - The directory to crawl - * @return {undefined} - */ -function loadDir(dir) { - fs.readdirSync(dir).forEach(function (fileName) { - describe(fileName, function () { - var location = path.join(dir, fileName), - stat = fs.statSync(location); - - if (stat.isFile() && fileName.match(/\.yaml$/) && location.match(doRE)) { - loadFile(location); - } - else if (stat.isDirectory()) { - loadDir(location); - } - }); - }); -} - -/** - * The version that ES is running, in comparable string form XXX-XXX-XXX, fetched when needed - * @type {String} - */ -var ES_VERSION = null; - -// core expression for finding a version -var versionExp = '([\\d\\.]*\\d)(?:\\.\\w+)?'; - -/** - * Regular Expression to extract a version number from a string - * @type {RegExp} - */ -var versionRE = new RegExp(versionExp); - -/** - * Regular Expression to extract a version range from a string - * @type {RegExp} - */ -var versionRangeRE = new RegExp(versionExp + '\\s*\\-\\s*' + versionExp); - -/** - * Fetches the client.info, and parses out the version number to a comparable string - * @param done {Function} - callback - */ -function getVersionFromES(done) { - client.info({}, function (err, resp) { - if (err) { - throw new Error('unable to get info about ES'); - } - expect(resp.version.number).to.match(versionRE); - ES_VERSION = versionToComparableString(versionRE.exec(resp.version.number)[1]); - done(); - }); -} - -/** - * Transform x.x.x into xxx.xxx.xxx, striping off any text at the end like beta or pre-alpha35 - * - * @param {String} version - Version number represented as a string - * @return {String} - Version number represented as three numbers, seperated by -, all numbers are - * padded with 0 and will be three characters long so the strings can be compared. - */ -function versionToComparableString(version) { - var parts = _.map(version.split('.'), function (part) { - part = '' + _.parseInt(part); - return (new Array(4 - part.length)).join('0') + part; - }); - - while(parts.length < 3) { - parts.push('000'); - } - - return parts.join('-'); -} - -/** - * Compare a version range to the ES_VERSION, determining if the current version - * falls within the range. - * - * @param {String} rangeString - a string representing two version numbers seperated by a "-" - * @return {Boolean} - is the current version within the range (inclusive) - */ -function rangeMatchesCurrentVersion(rangeString, done) { - function doWork() { - expect(rangeString).to.match(versionRangeRE); - - var range = versionRangeRE.exec(rangeString); - range = _.map(_.last(range, 2), versionToComparableString); - - done(ES_VERSION >= range[0] && ES_VERSION <= range[1]); - } - - if (!ES_VERSION) { - getVersionFromES(doWork); - } else { - doWork(); - } -} - -/** - * read the file's contents, parse the yaml, pass to makeTest - * - * @param {String} path - Full path to yaml file - * @return {undefined} - */ -function loadFile(location) { - var docsInFile = []; - - jsYaml.loadAll( - fs.readFileSync(location, { encoding:'utf8' }), - function (testConfig) { - docsInFile.push(testConfig); - }, - { - filename: location - } - ); - - _.each(docsInFile, makeTest); -} - -/** - * Read the test descriptions from a yaml document (usually only one test, per doc but - * sometimes multiple docs per file, and because of the layout there COULD be - * multiple test per test...) - * - * @param {Object} testConfigs - The yaml document - * @return {undefined} - */ -function makeTest(testConfig, count) { - var setup; - if (_.has(testConfig, 'setup')) { - (new ActionRunner(testConfig.setup)).each(function (action, name) { - before(action); - }); - delete testConfig.setup; - } - _.forOwn(testConfig, function (test, description) { - describe(description, function () { - var actions = new ActionRunner(test); - actions.each(function (action, name) { - it(name, action); - }); - }); - }); - - // after running the tests, remove all indices - after(clearIndices); -} - -/** - * Class to wrap a single document from a yaml test file - * - * @constructor - * @class ActionRunner - * @param actions {Array} - The array of actions directly from the Yaml file - */ -function ActionRunner(actions) { - this._actions = []; - - this._stash = {}; - this._last_requests_response = null; - - // setup the actions, creating a bound and testable method for each - _.each(this.flattenTestActions(actions), function (action, i) { - // get the method that will do the action - var method = this['do_' + action.name]; - var runner = this; - - // check that it's a function - expect(method).to.be.a('function'); - - if (typeof action.args === 'object') { - action.name += ' ' + Object.keys(action.args).join(', '); - } else { - action.name += ' ' + action.args; - } - - // wrap in a check for skipping - action.bound = _.bind(method, this, action.args); - - // create a function that can be passed to - action.testable = function (done) { - if (runner.skipping) { - return done(); - } - if (method.length > 1) { - action.bound(done); - } else { - action.bound(); - done(); - } - }; - - this._actions.push(action); - }, this); -} - -ActionRunner.prototype = { - - /** - * convert tests actions - * from: [ {name:args, name:args}, {name:args}, ... ] - * to: [ {name:'', args:'' }, {name:'', args:''} ] - * so it's easier to work with - * @param {ArrayOfObjects} config - Actions to be taken as defined in the yaml specs - */ - flattenTestActions: function (config) { - // creates [ [ {name:"", args:"" }, ... ], ... ] - // from [ {name:args, name:args}, {name:args} ] - var actionSets = _.map(config, function (set) { - return _.map(_.pairs(set), function (pair) { - return { name: pair[0], args: pair[1] }; - }); - }); - - // do a single level flatten, merge=ing the nested arrays from step one - // into a master array, creating an array of action objects - return _.reduce(actionSets, function(note, set) { - return note.concat(set); - }, []); - }, - - /** - * Itterate over each of the actions, provides the testable function, and a name/description. - * return a litteral false to stop itterating - * @param {Function} ittr - The function to call for each action. - * @return {undefined} - */ - each: function (ittr) { - var action; - while(action = this._actions.shift()) { - if (ittr(action.testable, action.name) === false) { - break; - } - } - }, - - /** - * Get a value from the last response, using dot-notation - * - * Example - * === - * - * get '_source.tags.1' - * - * from { - * _source: { - * tags: [ - * 'one', - * 'two' - * ] - * } - * } - * - * returns 'two' - * - * @param {string} path - The dot-notation path to the value needed. - * @return {*} - The value requested, or undefined if it was not found - */ - get: function (path, from) { - - var i - , log = process.env.LOG_GETS && !from ? console.log.bind(console) : function () {} ; - - if (!from) { - if (path[0] === '$') { - from = this._stash; - path = path.substring(1); - } else { - from = this._last_requests_response; - } - } - - log('getting', path, 'from', from); - - var steps = path ? path.split('.') : [] - , remainingSteps; - - for (i = 0; from != null && i < steps.length; i++) { - if (typeof from[steps[i]] === 'undefined') { - remainingSteps = steps.slice(i).join('.').replace(/\\\./g, '.'); - from = from[remainingSteps]; - break; - } else { - from = from[steps[i]]; - } - } - - log('found', typeof from !== 'function' ? from : 'function'); - return from; - }, - - /** - * Do a skip operation, setting the skipping flag to true if the version matches - * the range defined in args.version - * - * @param args - * @param done - */ - do_skip: function (args, done) { - rangeMatchesCurrentVersion(args.version, _.bind(function (match) { - if (match) { - this.skipping = true; - console.log('skipping the rest of these actions' + (args.reason ? ' because ' + args.reason : '')); - } else { - this.skipping = false; - } - done(); - }, this)); - }, - - /** - * Do a request, as outlined in the args - * - * @param {[type]} args [description] - * @param {Function} done [description] - * @return {[type]} [description] - */ - do_do: function (args, done) { - var catcher; - - // resolve the catch arg to a value used for matching once the request is complete - switch(args.catch) { - case void 0: - catcher = null; - break; - case 'missing': - catcher = 404; - break; - case 'conflict': - catcher = 409; - break; - case 'forbidden': - catcher = 403; - break; - case 'request': - catcher = /.*/; - break; - case 'param': - catcher = TypeError; - break; - default: - catcher = args.catch.match(/^\/(.*)\/$/); - if (catcher) { - catcher = new RegExp(catcher[1]); - } - } - - delete args.catch; - - var action = Object.keys(args).pop() - , clientActionName = _.map(action.split('.'), _.camelCase).join('.') - , clientAction = this.get(clientActionName, client) - , params = _.map(args[action], function (val, name) { - if (typeof val === 'string' && val[0] === '$') { - return this.get(val); - } - return val; - }, this); - - expect(clientAction, clientActionName).to.be.a('function'); - - if (typeof clientAction === 'function') { - if (_.isNumeric(catcher)) { - params.ignore = _.union(params.ignore || [], [catcher]); - catcher = null; - } - - clientAction.call(client, params, _.bind(function (error, body, status) { - this._last_requests_response = body; - - if (error){ - if (catcher) { - if (catcher instanceof RegExp) { - // error message should match the regexp - expect(error.message).to.match(catcher); - } else if (typeof catcher === 'function') { - // error should be an instance of - expect(error).to.be.a(catcher); - } else { - throw new Error('Invalid catcher ' + catcher); - } - } else { - throw error; - } - } - - done(); - }, this)); - } else { - throw new Error('stepped in do_do, did not find a function'); - } - - }, - - /** - * Set a value from the respose into the stash - * - * Example - * ==== - * { _id: id } # stash the value of `response._id` as `id` - * - * @param {Object} args - The object set to the "set" key in the test - * @return {undefined} - */ - do_set: function (args) { - _.forOwn(args, function (name, path) { - this._stash[name] = this.get(path); - }, this); - }, - - /** - * Test that the specified path exists in the response and has a - * true value (eg. not 0, false, undefined, null or the empty string) - * - * @param {string} path - Path to the response value to test - * @return {undefined} - */ - do_is_true: function (path) { - expect(this.get(path)).to.be.ok; - }, - - /** - * Test that the specified path exists in the response and has a - * false value (eg. 0, false, undefined, null or the empty string) - * - * @param {string} path - Path to the response value to test - * @return {undefined} - */ - do_is_false: function (path) { - expect(this.get(path)).to.not.be.ok; - }, - - /** - * Test that the response field (arg key) matches the value specified - * - * @param {Object} args - Hash of fields->values that need to be checked - * @return {undefined} - */ - do_match: function (args) { - _.forOwn(args, function (val, path) { - if (val[0] === '$') { - val = this.get(val); - } - expect(this.get(path)).to.eql(val); - }, this); - }, - - /** - * Test that the response field (arg key) is less than the value specified - * - * @param {Object} args - Hash of fields->values that need to be checked - * @return {undefined} - */ - do_lt: function (args) { - _.forOwn(args, function (num, path) { - expect(this.get(path)).to.be.below(num); - }, this); - }, - - /** - * Test that the response field (arg key) is greater than the value specified - * - * @param {Object} args - Hash of fields->values that need to be checked - * @return {undefined} - */ - do_gt: function (args) { - _.forOwn(args, function (num, path) { - expect(this.get(path)).to.be.above(num); - }, this); - }, - - /** - * Test that the response field (arg key) has a length equal to that specified. - * For object values, checks the length of the keys. - * - * @param {Object} args - Hash of fields->values that need to be checked - * @return {undefined} - */ - do_length: function (args) { - _.forOwn(args, function (len, path) { - expect(_.size(this.get(path))).to.be(len); - }, this); - } -}; - -loadDir(TEST_DIR); +require('./yaml-suite'); +require('./network-failures'); diff --git a/test/integration/network-failures/index.js b/test/integration/network-failures/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/test/integration/network-failures/timeout.js b/test/integration/network-failures/timeout.js new file mode 100644 index 000000000..e69de29bb diff --git a/test/integration/args.js b/test/integration/yaml-suite/args.js similarity index 100% rename from test/integration/args.js rename to test/integration/yaml-suite/args.js diff --git a/test/integration/yaml-suite/index.js b/test/integration/yaml-suite/index.js new file mode 100644 index 000000000..2b79df319 --- /dev/null +++ b/test/integration/yaml-suite/index.js @@ -0,0 +1,577 @@ +var path = require('path'), + fs = require('fs'), + async = require('async'), + jsYaml = require('js-yaml'), + expect = require('expect.js'), + server = require('./server'), + _ = require('../../../src/lib/utils'), + es = require('../../../src/elasticsearch'); + +var argv = require('optimist') + .default('executable', path.join(process.env.ES_HOME, './bin/elasticsearch')) + .default('clusterName', 'yaml-test-runner') + .default('dataPath', '/tmp/yaml-test-runner') + .argv; + + +if (argv.hostname || argv.port) { + console.log('working with ES instance at ' + argv.hostname + ':' + argv.port); +} + +// Where do the tests live? +var TEST_DIR = path.resolve(__dirname, '../../../es_api_spec/test/'); + +// test names matching this will be run +var doRE = /(^|\/)(.*)\/.*/; + +// a reference to a personal instance of ES Server +var esServer = null; + +// the client +var client = null; + +// location that the logger will write to +var logFile = path.resolve(__dirname, '../integration-test.log'); + +// empty all of the indices in ES please +function clearIndices (done) { + client.indices.delete({ + index: '*', + ignore: 404 + }, done); +} + +// before running any tests... +before(function (done) { + // start our personal ES Server + this.timeout(null); + if (argv.hostname) { + done(); + } else { + server.start(argv, function (err, server) { + esServer = server; + done(err); + }); + } +}); + +before(function (done) { + // delete the integration log + fs.unlink(logFile, function (err) { + if (err && ~err.message.indexOf('ENOENT')) { + done(); + } else { + done(err); + } + }); +}); + +before(function () { + // create the client + client = new es.Client({ + hosts: [ + { + hostname: esServer ? esServer.__hostname : argv.hostname, + port: esServer ? esServer.__port : argv.port + } + ], + log: { + type: 'file', + level: ['error', 'debug', 'trace'], + path: logFile + } + }); +}); + +before(clearIndices); + +/** + * recursively crawl the directory, looking for yaml files which will be passed to loadFile + * @param {String} dir - The directory to crawl + * @return {undefined} + */ +function loadDir(dir) { + fs.readdirSync(dir).forEach(function (fileName) { + describe(fileName, function () { + var location = path.join(dir, fileName), + stat = fs.statSync(location); + + if (stat.isFile() && fileName.match(/\.yaml$/) && location.match(doRE)) { + loadFile(location); + } + else if (stat.isDirectory()) { + loadDir(location); + } + }); + }); +} + +/** + * The version that ES is running, in comparable string form XXX-XXX-XXX, fetched when needed + * @type {String} + */ +var ES_VERSION = null; + +// core expression for finding a version +var versionExp = '([\\d\\.]*\\d)(?:\\.\\w+)?'; + +/** + * Regular Expression to extract a version number from a string + * @type {RegExp} + */ +var versionRE = new RegExp(versionExp); + +/** + * Regular Expression to extract a version range from a string + * @type {RegExp} + */ +var versionRangeRE = new RegExp(versionExp + '\\s*\\-\\s*' + versionExp); + +/** + * Fetches the client.info, and parses out the version number to a comparable string + * @param done {Function} - callback + */ +function getVersionFromES(done) { + client.info({}, function (err, resp) { + if (err) { + throw new Error('unable to get info about ES'); + } + expect(resp.version.number).to.match(versionRE); + ES_VERSION = versionToComparableString(versionRE.exec(resp.version.number)[1]); + done(); + }); +} + +/** + * Transform x.x.x into xxx.xxx.xxx, striping off any text at the end like beta or pre-alpha35 + * + * @param {String} version - Version number represented as a string + * @return {String} - Version number represented as three numbers, seperated by -, all numbers are + * padded with 0 and will be three characters long so the strings can be compared. + */ +function versionToComparableString(version) { + var parts = _.map(version.split('.'), function (part) { + part = '' + _.parseInt(part); + return (new Array(4 - part.length)).join('0') + part; + }); + + while(parts.length < 3) { + parts.push('000'); + } + + return parts.join('-'); +} + +/** + * Compare a version range to the ES_VERSION, determining if the current version + * falls within the range. + * + * @param {String} rangeString - a string representing two version numbers seperated by a "-" + * @return {Boolean} - is the current version within the range (inclusive) + */ +function rangeMatchesCurrentVersion(rangeString, done) { + function doWork() { + expect(rangeString).to.match(versionRangeRE); + + var range = versionRangeRE.exec(rangeString); + range = _.map(_.last(range, 2), versionToComparableString); + + done(ES_VERSION >= range[0] && ES_VERSION <= range[1]); + } + + if (!ES_VERSION) { + getVersionFromES(doWork); + } else { + doWork(); + } +} + +/** + * read the file's contents, parse the yaml, pass to makeTest + * + * @param {String} path - Full path to yaml file + * @return {undefined} + */ +function loadFile(location) { + var docsInFile = []; + + jsYaml.loadAll( + fs.readFileSync(location, { encoding:'utf8' }), + function (testConfig) { + docsInFile.push(testConfig); + }, + { + filename: location + } + ); + + _.each(docsInFile, makeTest); +} + +/** + * Read the test descriptions from a yaml document (usually only one test, per doc but + * sometimes multiple docs per file, and because of the layout there COULD be + * multiple test per test...) + * + * @param {Object} testConfigs - The yaml document + * @return {undefined} + */ +function makeTest(testConfig, count) { + var setup; + if (_.has(testConfig, 'setup')) { + (new ActionRunner(testConfig.setup)).each(function (action, name) { + before(action); + }); + delete testConfig.setup; + } + _.forOwn(testConfig, function (test, description) { + describe(description, function () { + var actions = new ActionRunner(test); + actions.each(function (action, name) { + it(name, action); + }); + }); + }); + + // after running the tests, remove all indices + after(clearIndices); +} + +/** + * Class to wrap a single document from a yaml test file + * + * @constructor + * @class ActionRunner + * @param actions {Array} - The array of actions directly from the Yaml file + */ +function ActionRunner(actions) { + this._actions = []; + + this._stash = {}; + this._last_requests_response = null; + + // setup the actions, creating a bound and testable method for each + _.each(this.flattenTestActions(actions), function (action, i) { + // get the method that will do the action + var method = this['do_' + action.name]; + var runner = this; + + // check that it's a function + expect(method).to.be.a('function'); + + if (typeof action.args === 'object') { + action.name += ' ' + Object.keys(action.args).join(', '); + } else { + action.name += ' ' + action.args; + } + + // wrap in a check for skipping + action.bound = _.bind(method, this, action.args); + + // create a function that can be passed to + action.testable = function (done) { + if (runner.skipping) { + return done(); + } + if (method.length > 1) { + action.bound(done); + } else { + action.bound(); + done(); + } + }; + + this._actions.push(action); + }, this); +} + +ActionRunner.prototype = { + + /** + * convert tests actions + * from: [ {name:args, name:args}, {name:args}, ... ] + * to: [ {name:'', args:'' }, {name:'', args:''} ] + * so it's easier to work with + * @param {ArrayOfObjects} config - Actions to be taken as defined in the yaml specs + */ + flattenTestActions: function (config) { + // creates [ [ {name:"", args:"" }, ... ], ... ] + // from [ {name:args, name:args}, {name:args} ] + var actionSets = _.map(config, function (set) { + return _.map(_.pairs(set), function (pair) { + return { name: pair[0], args: pair[1] }; + }); + }); + + // do a single level flatten, merge=ing the nested arrays from step one + // into a master array, creating an array of action objects + return _.reduce(actionSets, function(note, set) { + return note.concat(set); + }, []); + }, + + /** + * Itterate over each of the actions, provides the testable function, and a name/description. + * return a litteral false to stop itterating + * @param {Function} ittr - The function to call for each action. + * @return {undefined} + */ + each: function (ittr) { + var action; + while(action = this._actions.shift()) { + if (ittr(action.testable, action.name) === false) { + break; + } + } + }, + + /** + * Get a value from the last response, using dot-notation + * + * Example + * === + * + * get '_source.tags.1' + * + * from { + * _source: { + * tags: [ + * 'one', + * 'two' + * ] + * } + * } + * + * returns 'two' + * + * @param {string} path - The dot-notation path to the value needed. + * @return {*} - The value requested, or undefined if it was not found + */ + get: function (path, from) { + + var i + , log = process.env.LOG_GETS && !from ? console.log.bind(console) : function () {} ; + + if (!from) { + if (path[0] === '$') { + from = this._stash; + path = path.substring(1); + } else { + from = this._last_requests_response; + } + } + + log('getting', path, 'from', from); + + var steps = path ? path.split('.') : [] + , remainingSteps; + + for (i = 0; from != null && i < steps.length; i++) { + if (typeof from[steps[i]] === 'undefined') { + remainingSteps = steps.slice(i).join('.').replace(/\\\./g, '.'); + from = from[remainingSteps]; + break; + } else { + from = from[steps[i]]; + } + } + + log('found', typeof from !== 'function' ? from : 'function'); + return from; + }, + + /** + * Do a skip operation, setting the skipping flag to true if the version matches + * the range defined in args.version + * + * @param args + * @param done + */ + do_skip: function (args, done) { + rangeMatchesCurrentVersion(args.version, _.bind(function (match) { + if (match) { + this.skipping = true; + console.log('skipping the rest of these actions' + (args.reason ? ' because ' + args.reason : '')); + } else { + this.skipping = false; + } + done(); + }, this)); + }, + + /** + * Do a request, as outlined in the args + * + * @param {[type]} args [description] + * @param {Function} done [description] + * @return {[type]} [description] + */ + do_do: function (args, done) { + var catcher; + + // resolve the catch arg to a value used for matching once the request is complete + switch(args.catch) { + case void 0: + catcher = null; + break; + case 'missing': + catcher = 404; + break; + case 'conflict': + catcher = 409; + break; + case 'forbidden': + catcher = 403; + break; + case 'request': + catcher = /.*/; + break; + case 'param': + catcher = TypeError; + break; + default: + catcher = args.catch.match(/^\/(.*)\/$/); + if (catcher) { + catcher = new RegExp(catcher[1]); + } + } + + delete args.catch; + + var action = Object.keys(args).pop() + , clientActionName = _.map(action.split('.'), _.camelCase).join('.') + , clientAction = this.get(clientActionName, client) + , params = _.map(args[action], function (val, name) { + if (typeof val === 'string' && val[0] === '$') { + return this.get(val); + } + return val; + }, this); + + expect(clientAction, clientActionName).to.be.a('function'); + + if (typeof clientAction === 'function') { + if (_.isNumeric(catcher)) { + params.ignore = _.union(params.ignore || [], [catcher]); + catcher = null; + } + + clientAction.call(client, params, _.bind(function (error, body, status) { + this._last_requests_response = body; + + if (error){ + if (catcher) { + if (catcher instanceof RegExp) { + // error message should match the regexp + expect(error.message).to.match(catcher); + } else if (typeof catcher === 'function') { + // error should be an instance of + expect(error).to.be.a(catcher); + } else { + throw new Error('Invalid catcher ' + catcher); + } + } else { + throw error; + } + } + + done(); + }, this)); + } else { + throw new Error('stepped in do_do, did not find a function'); + } + + }, + + /** + * Set a value from the respose into the stash + * + * Example + * ==== + * { _id: id } # stash the value of `response._id` as `id` + * + * @param {Object} args - The object set to the "set" key in the test + * @return {undefined} + */ + do_set: function (args) { + _.forOwn(args, function (name, path) { + this._stash[name] = this.get(path); + }, this); + }, + + /** + * Test that the specified path exists in the response and has a + * true value (eg. not 0, false, undefined, null or the empty string) + * + * @param {string} path - Path to the response value to test + * @return {undefined} + */ + do_is_true: function (path) { + expect(this.get(path)).to.be.ok; + }, + + /** + * Test that the specified path exists in the response and has a + * false value (eg. 0, false, undefined, null or the empty string) + * + * @param {string} path - Path to the response value to test + * @return {undefined} + */ + do_is_false: function (path) { + expect(this.get(path)).to.not.be.ok; + }, + + /** + * Test that the response field (arg key) matches the value specified + * + * @param {Object} args - Hash of fields->values that need to be checked + * @return {undefined} + */ + do_match: function (args) { + _.forOwn(args, function (val, path) { + if (val[0] === '$') { + val = this.get(val); + } + expect(this.get(path), path).to.eql(val, path); + }, this); + }, + + /** + * Test that the response field (arg key) is less than the value specified + * + * @param {Object} args - Hash of fields->values that need to be checked + * @return {undefined} + */ + do_lt: function (args) { + _.forOwn(args, function (num, path) { + expect(this.get(path)).to.be.below(num); + }, this); + }, + + /** + * Test that the response field (arg key) is greater than the value specified + * + * @param {Object} args - Hash of fields->values that need to be checked + * @return {undefined} + */ + do_gt: function (args) { + _.forOwn(args, function (num, path) { + expect(this.get(path)).to.be.above(num); + }, this); + }, + + /** + * Test that the response field (arg key) has a length equal to that specified. + * For object values, checks the length of the keys. + * + * @param {Object} args - Hash of fields->values that need to be checked + * @return {undefined} + */ + do_length: function (args) { + _.forOwn(args, function (len, path) { + expect(_.size(this.get(path))).to.be(len); + }, this); + } +}; + +loadDir(TEST_DIR); diff --git a/test/integration/server.js b/test/integration/yaml-suite/server.js similarity index 97% rename from test/integration/server.js rename to test/integration/yaml-suite/server.js index 2183a37a1..f0e8e1db1 100644 --- a/test/integration/server.js +++ b/test/integration/yaml-suite/server.js @@ -3,7 +3,7 @@ var childProc = require('child_process'), q = require('q'), path = require('path'), fs = require('fs'), - _ = require('../../src/lib/utils'); + _ = require('../../../src/lib/utils'); exports.start = function (params, cb) { diff --git a/test/mocks/es_server.js b/test/mocks/es_server.js new file mode 100644 index 000000000..096168e0e --- /dev/null +++ b/test/mocks/es_server.js @@ -0,0 +1,85 @@ +/** + * A mock elasticsearch server used to test network libraries quickly and easily. + * + * It is actually a server created using node's http.createServer method and + * listens on a random port by default. The server emits an "online" event once + * it is listening and ready for requests. + * + * @type {} + * @class EsServer + * @param {Object} config - An object containing config options + */ +module.exports = EsServer; + +var _ = require('../../src/lib/utils'); +var url = require('url'); +var http = require('http'); +var EventEmitter = require('events').EventEmitter; + +var pingResp = JSON.stringify({ + 'ok': true, + 'status': 200, + 'name': 'Commando', + 'version': { + 'number': '0.90.5', + 'build_hash': 'c8714e8e0620b62638f660f6144831792b9dedee', + 'build_timestamp': '2013-09-17T12:50:20Z', + 'build_snapshot': false, + 'lucene_version': '4.4' + }, + 'tagline': 'You Know, for Search' +}); + +function EsServer(config) { + this.config = _.defaults(config || {}, { + port: 0, + data: '/' + }); + + var self = this; + var server = http.createServer(); + + server.on('request', function (request, response) { + request.parsedUrl = url.parse(request.url, true); + + var routes = self.routes[request.method.toLowerCase()]; + var route = routes && routes[request.parsedUrl.pathname]; + + if (route) { + route.call(self, request, response); + } else { + response.writeHead(400); + response.end('No handler found for uri [/] and method [' + request.method + ']'); + } + }); + + self.shutdown = function (cb) { + server.close(function () { + self.emit('offline'); + cb(); + }); + }; + + self.routes = { + get: { + '/' : function (request, response) { + response.writeHead(200, { + 'Content-Type': 'application/json', + 'Content-Length': pingResp.length + }); + response.end(pingResp, 'utf8'); + } + }, + post: {}, + put: {}, + delete: {}, + head: {} + }; + + process.nextTick(function () { + server.listen(self.config.port, function () { + self.emit('online', server.address().port); + }); + }); +} +_.inherits(EsServer, EventEmitter); diff --git a/test/unit/connection_pool.test.js b/test/unit/connection_pool.test.js index e32fc2840..d2d16b6b1 100644 --- a/test/unit/connection_pool.test.js +++ b/test/unit/connection_pool.test.js @@ -4,7 +4,7 @@ describe('Connection Pool', function () { var client, pool; beforeEach(function () { client = new es.Client(); - pool = client.connectionPool; + pool = client.config.connectionPool; }); describe('default settings', function () { @@ -13,52 +13,4 @@ describe('Connection Pool', function () { pool.connections.dead.should.have.lengthOf(0); }); }); - - describe('#setNodes', function () { - it('rejects anything accept an array of objects', function () { - - (function () { - pool.setNodes([ - 'string' - ]); - }).should.throw(TypeError); - - (function () { - pool.setNodes('string'); - }).should.throw(TypeError); - - }); - - it('will clear out old nodes', function () { - // set an empty set of nodes - pool.setNodes([]); - - pool.connections.alive.should.have.lengthOf(0); - pool.connections.dead.should.have.lengthOf(0); - }); - - it('will accept a new node list', function () { - var conns = pool.connections; - - // set a list of 3 nodes - pool.setNodes([ - { - hostname: 'es-cluster.us', - port: '9200' - }, - { - hostname: 'es-cluster-1.us', - port: '9200' - }, - { - hostname: 'es-cluster-2.us', - port: '9200' - } - ]); - - conns.alive.should.have.lengthOf(3); - conns.dead.should.have.lengthOf(0); - }); - - }); }); diff --git a/test/unit/es_server.test.js b/test/unit/es_server.test.js new file mode 100644 index 000000000..47d53145a --- /dev/null +++ b/test/unit/es_server.test.js @@ -0,0 +1,80 @@ + +var EsServer = require('../mocks/es_server'); +var _ = require('../../src/lib/utils'); +var http = require('http'); + +describe('EsServer Mock', function () { + + it('should emit an online event when ready, passing it\'s port number', function (done) { + var server = new EsServer(); + server.on('online', function (port) { + port.should.have.type('number'); + server.shutdown(done); + }); + }); + + describe('when it\'s online', function () { + var server; + var port; + + function makeRequest(opts, respCb) { + opts = _.defaults(opts || {},{ + hostname: 'localhost', + port: port + }); + + var response = null; + var req = http.request(opts, function (incomming) { + response = ''; + + incomming.on('data', function (chunk) { + response+= chunk; + }); + + incomming.on('end', function () { + if (incomming.headers['content-type'] === 'application/json') { + try { + respCb(null, JSON.parse(response), incomming.statusCode); + } catch (e) { + respCb(e, response, incomming.statusCode); + } + } else { + respCb(null, response, incomming.statusCode); + } + }); + }); + + req.on('error', respCb); + + req.end(); + } + + before(function (done) { + server = new EsServer(); + server.on('online', function (_port) { + port = _port; + done(); + }); + }); + + after(function (done) { + server.shutdown(done); + }); + + it('should respond with json to a ping', function (done) { + makeRequest({ + path: '/' + }, function (err, resp, status) { + if (err) { + done(err); + } else { + status.should.be.exactly(200); + resp.version.number.should.match(/^\d+\.\d+\.\d+/); + done(); + } + }); + }); + + }); + +}); diff --git a/test/unit/stdio_logger.test.js b/test/unit/stdio_logger.test.js index fb565962a..a119c65cb 100644 --- a/test/unit/stdio_logger.test.js +++ b/test/unit/stdio_logger.test.js @@ -5,12 +5,13 @@ var es = require('../../src/elasticsearch'), expect = require('expect.js'); describe('Stdio Logger listening to levels warning and error', function () { - var client, logger; + var client, log, logger; before(function () { client = new es.Client({ log: [] }); + log = client.config.log; }); beforeEach(function () { @@ -21,7 +22,7 @@ describe('Stdio Logger listening to levels warning and error', function () { // new logger in warning mode logger = new Stdio({ levels: ['error', 'warning'] - }, client.log); + }, log); }); it('logs error messages', function (done) { @@ -32,7 +33,7 @@ describe('Stdio Logger listening to levels warning and error', function () { done(); }; - client.log.error('Test Error Message'); + log.error('Test Error Message'); }); it('logs warning messages', function (done) { @@ -42,23 +43,23 @@ describe('Stdio Logger listening to levels warning and error', function () { done(); }; - client.log.warning('Test Warning', 'Message'); + log.warning('Test Warning', 'Message'); }); it('does not log info messages', function () { - if (client.log.info('Info')) { + if (log.info('Info')) { throw new Error('There shouldn\'t be listeners for info logs'); } }); it('does not log debug messages', function () { - if (client.log.debug('Debug')) { + if (log.debug('Debug')) { throw new Error('There shouldn\'t be listeners for debug logs'); } }); it('does not log trace messages', function () { - if (client.log.trace('curl "http://localhost:9200" -d "{ \"query\": ... }"')) { + if (log.trace('curl "http://localhost:9200" -d "{ \"query\": ... }"')) { throw new Error('There shouldn\'t be listeners for trace logs'); } });