Slight refactor to the api module, so it will simply extend the client like it did

This commit is contained in:
Spencer Alger
2013-10-23 14:49:00 -07:00
parent 35209ea61a
commit c14d37aa42
39 changed files with 25589 additions and 3627 deletions

View File

@ -23,19 +23,28 @@ module.exports = function (grunt) {
options: { options: {
colors: true, colors: true,
require: 'should', require: 'should',
reporter: 'dot' reporter: 'dot',
bail: true,
timeout: 11000
} }
}, },
jshint: { jshint: {
source: { source: {
src: [ src: [
'src/**/*.js', 'src/**/*.js',
'test/**/*.js',
'Gruntfile.js' 'Gruntfile.js'
] ],
},
options: { options: {
jshintrc: true jshintrc: '.jshintrc'
}
},
tests: {
src: [
'test/**/*.js'
],
options: {
jshintrc: 'test/.jshintrc'
}
} }
}, },
watch: { watch: {
@ -52,6 +61,14 @@ module.exports = function (grunt) {
options: { options: {
interupt: true interupt: true
} }
},
run: {
generate_js_api: {
cmd: 'node',
args: [
'scripts/generate/js_api/index.js'
]
}
}//, }//,
// docular: { // docular: {
// groups: [ // groups: [
@ -100,10 +117,27 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-jshint');
// Default task. // Default task.
// grunt.registerTask('docs', ['docular']); // grunt.registerTask('docs', ['docular']);
grunt.registerTask('test', ['jshint', 'mochaTest']); grunt.registerTask('test', ['jshint', 'mochaTest']);
grunt.registerTask('default', ['jshint', 'mochaTest:unit']); grunt.registerTask('default', ['jshint', 'mochaTest:unit']);
grunt.task.registerMultiTask('run', 'used to run arbitrary commands', function () {
var done = this.async();
var proc = require('child_process').spawn(
this.data.cmd,
this.data.args,
{
stdio: ['ignore', 'pipe', 'pipe']
}
);
proc.stdout.on('data', grunt.log.write);
proc.stderr.on('data', grunt.log.error);
proc.on('close', function (exitCode) {
done(!exitCode);
});
});
}; };

View File

@ -24,7 +24,8 @@
"grunt-contrib-watch": "~0.5.3", "grunt-contrib-watch": "~0.5.3",
"expect.js": "~0.2.0", "expect.js": "~0.2.0",
"async": "~0.2.9", "async": "~0.2.9",
"optimist": "~0.6.0" "optimist": "~0.6.0",
"minimatch": "~0.2.12"
}, },
"license": "Apache License", "license": "Apache License",
"dependencies": { "dependencies": {

View File

@ -4,30 +4,48 @@ var path = require('path');
var fs = require('fs'); var fs = require('fs');
var mkdirp = require('mkdirp'); var mkdirp = require('mkdirp');
var outputDir = _.joinPath(__dirname, '../../../src/api/'); var outputPath = _.joinPath(__dirname, '../../../src/lib/api.js');
var templates = require('./templates'); var templates = require('./templates');
var specs = require('./spec')(outputDir); var specs = require('./spec');
// completely delete the output directory // completely delete the output directory
function clean(path) { var clean = (function () {
if (fs.existsSync(path)) { function rmDirRecursive(path) {
fs.readdirSync(path).forEach(function (file, index) { fs.readdirSync(path).forEach(function (file, index) {
var curPath = path + '/' + file; var curPath = path + '/' + file;
if (fs.statSync(curPath).isDirectory()) { // recurse if (fs.statSync(curPath).isDirectory()) { // recurse
clean(curPath); rmDirRecursive(curPath);
} else { // delete file } else { // delete file
fs.unlinkSync(curPath); fs.unlinkSync(curPath);
} }
}); });
fs.rmdirSync(path); fs.rmdirSync(path);
} }
}
return function (path) {
try {
var stats = fs.statSync(path);
if (stats && stats.isDirectory()) {
console.log('removing', path, 'directory recursively');
rmDirRecursive(path);
} else {
console.log('removing', path);
fs.unlinkSync(path);
}
return true;
} catch (e) {
return false;
}
};
})();
exports.run = function () { exports.run = function () {
var defs = []; var defs = [];
var namespaces = []; var namespaces = [];
clean(outputPath);
var actions = _.map(specs, function (spec) { var actions = _.map(specs, function (spec) {
spec.urls = _.map( spec.urls = _.map(
_.sortBy( _.sortBy(
@ -67,9 +85,9 @@ exports.run = function () {
}); });
var docUrl = spec.docUrl; var docUrl = spec.docUrl;
var location = _.map(spec.name.split('.'), _.camelCase).join('.');
spec = _.pick(spec, [ spec = _.pick(spec, [
'name',
'methods', 'methods',
'params', 'params',
'urls', 'urls',
@ -85,7 +103,6 @@ exports.run = function () {
]); ]);
}, {}); }, {});
var location = _.map(spec.name.split('.'), _.camelCase).join('.');
if (~location.indexOf('.')) { if (~location.indexOf('.')) {
var steps = location.split('.'); var steps = location.split('.');
namespaces.push(steps.slice(0, -1).join('.')); namespaces.push(steps.slice(0, -1).join('.'));
@ -94,27 +111,18 @@ exports.run = function () {
// escape method names with "special" keywords // escape method names with "special" keywords
location = location.replace(/(^|\.)(delete|default)(\.|$)/g, '[\'$2\']'); location = location.replace(/(^|\.)(delete|default)(\.|$)/g, '[\'$2\']');
return {
return templates.clientAction({spec: spec, location: location, docUrl: docUrl }); spec: spec,
location: location,
docUrl: docUrl
};
}); });
namespaces = _.map(_.unique(namespaces.sort(), true), function (namespace) { console.log('writing', actions.length, 'api actions to', outputPath);
return templates.clientActionNamespace({ fs.writeFileSync(outputPath, templates.apiFile({
get: namespace, actions: actions,
set: namespace.replace(/\./g, '.prototype.'), namespaces: _.unique(namespaces.sort(), true)
}); }));
})
var l = templates.lines(0);
l('var ClientAction = require(\'./client_action\');');
l('var errors = require(\'./errors\');');
l('');
l('exports.attach = function (Client) {').in();
l.split(namespaces.join('') + '\n' + actions.join('\n'));
l.out('};');
fs.writeFileSync(_.joinPath(__dirname, '../../../src/lib/api.js'), l.toString());
}; };
exports.run(); exports.run();

View File

@ -0,0 +1,48 @@
var _ = require('../../../src/lib/utils')
var docs = _.requireDir(module, '../../../es_api_spec/api');
var aliases = require('./aliases');
var castNotFoundRE = /exists/;
var usesBulkBodyRE = /^(bulk|msearch)$/;
var defs = [];
// itterate all of the found docs
Object.keys(docs).forEach(function (filename) {
Object.keys(docs[filename]).forEach(function (name) {
var def = docs[filename][name];
def.name = name;
defs.push(def);
})
});
module.exports = _.map(defs, function (def) {
var name = def.name;
var steps = name.split('.');
var spec = {
name: name,
methods: _.map(def.methods, function (m) { return m.toUpperCase(); }),
docUrl: def.documentation,
urlParts: def.url.parts,
params: def.url.params,
urls: _.difference(def.url.paths, aliases[name]),
body: def.body || null,
path2lib: _.repeat('../', steps.length + 1) + 'lib/'
};
if (def.body && def.body.requires) {
spec.needBody = true;
}
if (usesBulkBodyRE.test(name)) {
spec.bulkBody = true;
}
if (castNotFoundRE.test(name)) {
spec.castNotFound = true;
}
return spec;
});

View File

@ -0,0 +1,27 @@
var ca = require('./client_action').create;
var errors = require('./errors');
var api = module.exports = {};
api._namespaces = <%= stringify(namespaces) %>;<%
_.each(actions, function (action) {
var namespace = action.location.split('.').shift();
if (_.contains(namespaces, namespace)) {
_.pull(namespaces, namespace);
var className = _.studlyCase(namespace) + 'NS';
%>
api.<%= namespace %> = function <%= className %>(client) {
if (this instanceof <%= className %>) {
this.client = client;
} else {
return new <%= className %>(client);
}
};<%
}
%>
<%= partials.client_action(action) %><%
}); %>

View File

@ -9,4 +9,4 @@ _.each(spec.params, function(param, paramName) { %>
} }
%><% }) %> %><% }) %>
*/ */
Client.prototype<%= (location[0] === '[' ? '' : '.') + location %> = ClientAction(<%= stringify(spec, true) %>); api<%= (location[0] === '[' ? '' : '.') + location %> = ca(<%= stringify(spec, true) %>);

View File

@ -268,7 +268,9 @@ var templateGlobals = {
l('this.client.request(request, cb);'); l('this.client.request(request, cb);');
} }
return l.toString(); return l.toString();
} },
partials: templates
}; };
fs.readdirSync(path.resolve(__dirname)).forEach(function (filename) { fs.readdirSync(path.resolve(__dirname)).forEach(function (filename) {
@ -288,9 +290,6 @@ fs.readdirSync(path.resolve(__dirname)).forEach(function (filename) {
templates.text = templates.string; templates.text = templates.string;
module.exports = { module.exports = {
lines: lines, apiFile: templates.api_file,
action: templates.action,
clientAction: templates.client_action,
clientActionNamespace: templates.client_action_namespace,
urlParamRE: urlParamRE urlParamRE: urlParamRE
}; };

View File

@ -32,9 +32,10 @@ module.exports = Client;
var _ = require('./utils'); var _ = require('./utils');
var ClientConfig = require('./client_config'); var ClientConfig = require('./client_config');
// var api = _.reKey(_.requireDir(module, '../api'), _.camelCase); var ca = require('./client_action').create;
var q = require('q'); var q = require('q');
var errors = require('./errors'); var errors = require('./errors');
var api = require('./api.js');
function Client(config) { function Client(config) {
this.client = this; this.client = this;
@ -48,11 +49,13 @@ function Client(config) {
}); });
this.config.client = this; this.config.client = this;
for (var i = 0; i < _namespaces.length; i++) { for (var i = 0; i < this._namespaces.length; i++) {
this[_namespaces[i]] = new this[_namespaces[i]](this); this[this._namespaces[i]] = new this[this._namespaces[i]](this);
} }
} }
Client.prototype = api;
/** /**
* Perform a request with the client's transport * Perform a request with the client's transport
* *
@ -91,7 +94,7 @@ Client.prototype.request = function (params, cb) {
} }
if (params.body && params.method === 'GET') { if (params.body && params.method === 'GET') {
_.nextTick(cb, new TypeError('Body can not be sent with method "GET"')); respond(new TypeError('Body can not be sent with method "GET"'));
return; return;
} }
@ -164,12 +167,13 @@ Client.prototype.request = function (params, cb) {
* @param {Object} params - Currently just a placeholder, no params used at this time * @param {Object} params - Currently just a placeholder, no params used at this time
* @param {Function} cb - callback * @param {Function} cb - callback
*/ */
Client.prototype.ping = function (params, cb) { Client.prototype.ping = ca({
this.request({ methods: ['HEAD'],
method: 'HEAD', params: {},
path: '/' url: {
}, cb); fmt: '/'
}; }
});
/** /**
* Ask an ES node for a list of all the nodes, add/remove nodes from the connection * Ask an ES node for a list of all the nodes, add/remove nodes from the connection
@ -193,26 +197,14 @@ Client.prototype.sniff = function (cb) {
} }
cb(err, resp); cb(err, resp);
}); });
}
var _namespaces = [];
/**
* These names of the properties that hold namespace objects in the Client prototype
* @type {Array}
*/
Client.namespace = function (namespace) {
var steps = namespace.split('.');
var path = [];
var on = Client;
var i;
for (i = 0; i < steps.length; i ++) {
path.push(steps[i]);
_namespaces.push(path.join('.'));
on.prototype[steps[i]] = function ClientActionNamespace(client) {
this.client = client;
};
}
}; };
require('./api.js').attach(Client);
/**
* Shutdown the connections, log outputs, and clear timers
*/
Client.prototype.close = function () {
this.config.log.close();
this.config.connectionPool.close();
};

View File

@ -51,6 +51,15 @@ function Log(config) {
} }
_.inherits(Log, EventEmitter); _.inherits(Log, EventEmitter);
Log.prototype.close = function () {
this.emit('closing');
if (EventEmitter.listenerCount(this)) {
console.error('Something is still listening for log events, but the logger is closing.');
this.clearAllListeners();
}
}
/** /**
* Levels observed by the loggers, ordered by rank * Levels observed by the loggers, ordered by rank
* *

File diff suppressed because it is too large Load Diff

View File

@ -32,9 +32,10 @@ module.exports = Client;
var _ = require('./utils'); var _ = require('./utils');
var ClientConfig = require('./client_config'); var ClientConfig = require('./client_config');
// var api = _.reKey(_.requireDir(module, '../api'), _.camelCase); var ca = require('./client_action').create;
var q = require('q'); var q = require('q');
var errors = require('./errors'); var errors = require('./errors');
var api = require('./api.js');
function Client(config) { function Client(config) {
this.client = this; this.client = this;
@ -48,11 +49,13 @@ function Client(config) {
}); });
this.config.client = this; this.config.client = this;
for (var i = 0; i < _namespaces.length; i++) { for (var i = 0; i < this._namespaces.length; i++) {
this[_namespaces[i]] = new this[_namespaces[i]](this); this[this._namespaces[i]] = new this[this._namespaces[i]](this);
} }
} }
Client.prototype = api;
/** /**
* Perform a request with the client's transport * Perform a request with the client's transport
* *
@ -91,7 +94,7 @@ Client.prototype.request = function (params, cb) {
} }
if (params.body && params.method === 'GET') { if (params.body && params.method === 'GET') {
_.nextTick(cb, new TypeError('Body can not be sent with method "GET"')); respond(new TypeError('Body can not be sent with method "GET"'));
return; return;
} }
@ -164,12 +167,13 @@ Client.prototype.request = function (params, cb) {
* @param {Object} params - Currently just a placeholder, no params used at this time * @param {Object} params - Currently just a placeholder, no params used at this time
* @param {Function} cb - callback * @param {Function} cb - callback
*/ */
Client.prototype.ping = function (params, cb) { Client.prototype.ping = ca({
this.request({ methods: ['HEAD'],
method: 'HEAD', params: {},
path: '/' url: {
}, cb); fmt: '/'
}; }
});
/** /**
* Ask an ES node for a list of all the nodes, add/remove nodes from the connection * Ask an ES node for a list of all the nodes, add/remove nodes from the connection
@ -193,26 +197,14 @@ Client.prototype.sniff = function (cb) {
} }
cb(err, resp); cb(err, resp);
}); });
}
var _namespaces = [];
/**
* These names of the properties that hold namespace objects in the Client prototype
* @type {Array}
*/
Client.namespace = function (namespace) {
var steps = namespace.split('.');
var path = [];
var on = Client;
var i;
for (i = 0; i < steps.length; i ++) {
path.push(steps[i]);
_namespaces.push(path.join('.'));
on.prototype[steps[i]] = function ClientActionNamespace(client) {
this.client = client;
};
}
}; };
require('./api.js').attach(Client);
/**
* Shutdown the connections, log outputs, and clear timers
*/
Client.prototype.close = function () {
this.config.log.close();
this.config.connectionPool.close();
};

View File

@ -2,10 +2,10 @@
* Constructs a function that can be called to make a request to ES * Constructs a function that can be called to make a request to ES
* @type {[type]} * @type {[type]}
*/ */
module.exports = function clientAction(spec) { exports.create = function clientAction(spec) {
return function (params, cb) { return function (params, cb) {
return exec(this.client, spec, params, cb); return exec(this.client, spec, params, cb);
} };
}; };
var errors = require('./errors'); var errors = require('./errors');
@ -75,8 +75,8 @@ var castType = {
} }
}; };
function resolveUrl (url, params) { function resolveUrl(url, params) {
var vars = {}, name, i, key; var vars = {}, i, key;
if (url.req) { if (url.req) {
// url has required params // url has required params
@ -128,7 +128,7 @@ function resolveUrl (url, params) {
// remove it from the params so that it isn't sent to the final request // remove it from the params so that it isn't sent to the final request
delete params[name]; delete params[name];
}, {})); }, {}));
}; }
function exec(client, spec, params, cb) { function exec(client, spec, params, cb) {
if (typeof params === 'function') { if (typeof params === 'function') {
@ -139,20 +139,25 @@ function exec(client, spec, params, cb) {
cb = typeof cb === 'function' ? cb : _.noop; cb = typeof cb === 'function' ? cb : _.noop;
} }
var request = { var request = {};
ignore: params.ignore
};
var parts = {}; var parts = {};
var query = {}; var query = {};
var i; var i;
if (spec.needsBody && !params.body) { if (spec.needsBody && !params.body) {
return _.nextTick(cb, new TyperError(spec.name + ' requires a request body.')); return _.nextTick(cb, new TypeError('A request body is required.'));
} }
if (params.body) { if (params.body) {
request.body = params.body; request.body = params.body;
request.bulkBody = spec.bulkBody; }
if (spec.bulkBody) {
request.bulkBody = true;
}
if (params.ignore) {
request.ignore = _.isArray(params.ignore) ? params.ignore : [params.ignore];
} }
if (spec.methods.length === 1) { if (spec.methods.length === 1) {
@ -238,4 +243,4 @@ function exec(client, spec, params, cb) {
} else { } else {
client.request(request, cb); client.request(request, cb);
} }
}; }

View File

@ -94,7 +94,7 @@ ClientConfig.prototype.prepareHosts = function (hosts) {
hosts = [hosts]; hosts = [hosts];
} }
for(i = 0; i < hosts.length; i++) { for (i = 0; i < hosts.length; i++) {
host = hosts[i]; host = hosts[i];
if (typeof host === 'object') { if (typeof host === 'object') {
if (host.protocol) { if (host.protocol) {

View File

@ -54,12 +54,14 @@ ConnectionAbstract.prototype.setStatus = function (status) {
this.status = status; this.status = status;
if (status === 'dead') { if (status === 'dead' || status === 'closed') {
if (this.__deadTimeout) { if (this.__deadTimeout) {
clearTimeout(this.__deadTimeout); clearTimeout(this.__deadTimeout);
} }
if (status === 'dead') {
this.__deadTimeout = setTimeout(this.bound.resuscitate, this.config.deadTimeout); this.__deadTimeout = setTimeout(this.bound.resuscitate, this.config.deadTimeout);
} }
}
this.emit('status changed', status, origStatus, this); this.emit('status changed', status, origStatus, this);
}; };

View File

@ -93,13 +93,15 @@ ConnectionPool.prototype._remove = function (connection) {
connection.setStatus('closed'); connection.setStatus('closed');
connection.removeListener('status changed', this.bound.onStatusChanged); connection.removeListener('status changed', this.bound.onStatusChanged);
} }
} };
ConnectionPool.prototype.setNodes = function (nodeConfigs) { ConnectionPool.prototype.setNodes = function (nodeConfigs) {
var i;
var connection; var connection;
var i;
var id;
var node; var node;
var toRemove = _.clone(this.index); var toRemove = _.clone(this.index);
for (i = 0; i < nodeConfigs.length; i++) { for (i = 0; i < nodeConfigs.length; i++) {
node = nodeConfigs[i]; node = nodeConfigs[i];
if (node.hostname && node.port) { if (node.hostname && node.port) {
@ -115,9 +117,9 @@ ConnectionPool.prototype.setNodes = function (nodeConfigs) {
} }
_.each(toRemove, this._remove, this); _.each(toRemove, this._remove, this);
} };
ConnectionPool.prototype.close = function () {
ConnectionPool.prototype.empty = function () {
this.setNodes([]); this.setNodes([]);
}; };
ConnectionPool.prototype.empty = ConnectionPool.prototype.close;

View File

@ -70,8 +70,6 @@ HttpConnection.prototype.request = function (params, cb) {
headers: _.defaults(params.headers || {}, defaultHeaders) headers: _.defaults(params.headers || {}, defaultHeaders)
}); });
log.debug('starting request', requestId);
// general clean-up procedure to run after the request, can only run once // general clean-up procedure to run after the request, can only run once
var cleanUp = function (err) { var cleanUp = function (err) {
clearTimeout(timeoutId); clearTimeout(timeoutId);
@ -80,7 +78,7 @@ HttpConnection.prototype.request = function (params, cb) {
incoming && incoming.removeAllListeners(); incoming && incoming.removeAllListeners();
log.debug('calling back request', requestId, err ? 'with error "' + err.message + '"' : ''); log.debug('calling back request', requestId, err ? 'with error "' + err.message + '"' : '');
_.nextTick(cb, err, reqParams, response, status); cb(err, reqParams, response, status);
// override so this doesn't get called again // override so this doesn't get called again
cleanUp = _.noop; cleanUp = _.noop;
@ -88,9 +86,7 @@ HttpConnection.prototype.request = function (params, cb) {
reqParams.agent = this.agent; reqParams.agent = this.agent;
request = http.request(reqParams); request = http.request(reqParams, function (_incoming) {
request.on('response', function (_incoming) {
incoming = _incoming; incoming = _incoming;
status = incoming.statusCode; status = incoming.statusCode;
incoming.setEncoding('utf8'); incoming.setEncoding('utf8');

View File

@ -51,6 +51,15 @@ function Log(config) {
} }
_.inherits(Log, EventEmitter); _.inherits(Log, EventEmitter);
Log.prototype.close = function () {
this.emit('closing');
if (EventEmitter.listenerCount(this)) {
console.error('Something is still listening for log events, but the logger is closing.');
this.clearAllListeners();
}
}
/** /**
* Levels observed by the loggers, ordered by rank * Levels observed by the loggers, ordered by rank
* *

View File

@ -85,7 +85,7 @@ LoggerAbstract.prototype.setupListeners = function (levels) {
*/ */
LoggerAbstract.prototype.cleanUpListeners = _.handler(function () { LoggerAbstract.prototype.cleanUpListeners = _.handler(function () {
_.each(this.listeningLevels, function (level) { _.each(this.listeningLevels, function (level) {
this.bridge.removeListener(level, this.handlers[level]); this.bridge.removeListener(level, this.bound['on' + _.ucfirst(level)]);
}, this); }, this);
}); });

View File

@ -295,7 +295,7 @@ utils.inherits = function (constructor, superConstructor) {
* @returns {String} * @returns {String}
*/ */
utils.trim = function (str) { utils.trim = function (str) {
return typeof str !== 'string' ? str.replace(/^\s+|\s+$/g, '') : ''; return typeof str === 'string' ? str.replace(/^\s+|\s+$/g, '') : '';
}; };
utils.collectMatches = function (text, regExp) { utils.collectMatches = function (text, regExp) {
@ -385,8 +385,13 @@ utils.applyArgs = function (func, context, args, sliceIndex) {
* @return {[type]} [description] * @return {[type]} [description]
*/ */
_.nextTick = function (cb) { _.nextTick = function (cb) {
console.log('tick');
var args = Array.prototype.slice.call(arguments, 1);
// bind the function and schedule it // bind the function and schedule it
process.nextTick(_.bindKey(_, 'applyArgs', cb, null, arguments, 1)); process.nextTick(function () {
console.log('tock');
cb.apply(null, args);
});
}; };
/** /**

View File

@ -1,2 +0,0 @@
// exports['cluster.node_info'] =
// '//TODO: this enpoint ***needs*** work, many of the possible urls are not supported';

View File

@ -1,54 +0,0 @@
var _ = require('../../../src/lib/utils')
var docs = _.requireDir(module, '../../../es_api_spec/api');
var aliases = require('./aliases');
var notes = require('./notes');
var castNotFoundRE = /exists/;
var usesBulkBodyRE = /^(bulk|msearch)$/;
var defs = [];
// itterate all of the found docs
Object.keys(docs).forEach(function (filename) {
Object.keys(docs[filename]).forEach(function (name) {
var def = docs[filename][name];
def.name = name;
defs.push(def);
})
});
module.exports = function (outputDir) {
return _.map(defs, function (def) {
var name = def.name;
var steps = name.split('.');
var spec = {
fileName: steps.pop() + '.js',
dirName: _.joinPath(outputDir, steps.join('/') || './'),
name: name,
methods: _.map(def.methods, function (m) { return m.toUpperCase(); }),
docUrl: def.documentation,
urlParts: def.url.parts,
params: def.url.params,
urls: _.difference(def.url.paths, aliases[name]),
body: def.body || null,
path2lib: _.repeat('../', steps.length + 1) + 'lib/',
notes: notes[name],
};
if (def.body && def.body.requires) {
spec.needBody = true;
}
if (usesBulkBodyRE.test(name)) {
spec.bulkBody = true;
}
if (castNotFoundRE.test(name)) {
spec.castNotFound = true;
}
return spec;
});
};

View File

@ -1 +0,0 @@
<%= set %> = <%= get %>;

View File

@ -1,7 +0,0 @@
if (<%= get %>.toLowerCase && (<%= get %> = <%= get %>.toLowerCase())
&& (<%= get %> === 'no' || <%= get %> === 'off')
) {
<%= set %> = false;
} else {
<%= set %> = !!<%= get %>;
}

View File

@ -1 +0,0 @@
Client.namespace(<%= stringify(get) %>);

View File

@ -1,5 +0,0 @@
if (_.isNumeric(<%= get %>) || _.isInterval(<%= get %>)) {
<%= set %> = <%= get %>;
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be a number or in interval notation (an integer followed by one of Mwdhmsy).');
}

View File

@ -1,8 +0,0 @@
if (_.contains(<%= _.camelCase(name) %>Options, <%= get %>)) {
<%= set %> = <%= get %>;
} else {
throw new TypeError(
'Invalid <%= name %>: ' + <%= get %> +
' should be one of ' + <%= _.camelCase(name) %>Options.join(', ') + '.'
);
}

View File

@ -1,14 +0,0 @@
switch (typeof <%= get %>) {
case 'string':
<%= set %> = <%= get %>;
break;
case 'object':
if (_.isArray(<%= get %>)) {
<%= set %> = <%= get %>.join(',');
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be a comma seperated list, array, or boolean.');
}
break;
default:
<%= set %> = !!<%= get %>;
}

View File

@ -1,5 +0,0 @@
if (_.isNumeric(<%= get %>)) {
<%= set %> = <%= get %> * 1;
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be a number.');
}

View File

@ -1,5 +0,0 @@
if (typeof <%= get %> !== 'object' && <%= get %>) {
<%= set %> = '' + <%= get %>;
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be a string.');
}

View File

@ -1,7 +0,0 @@
if (<%= get %> instanceof Date) {
<%= set %> = <%= get %>.getTime();
} else if (_.isNumeric(<%= get %>)) {
<%= set %> = <%= get %>;
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be be some sort of time.');
}

View File

@ -5,23 +5,25 @@ var path = require('path'),
expect = require('expect.js'), expect = require('expect.js'),
server = require('./server'), server = require('./server'),
_ = require('../../../src/lib/utils'), _ = require('../../../src/lib/utils'),
es = require('../../../src/elasticsearch'); es = require('../../../src/elasticsearch'),
Minimatch = require('minimatch').Minimatch;
var argv = require('optimist') var argv = require('optimist')
.default('executable', path.join(process.env.ES_HOME, './bin/elasticsearch')) .default('executable', path.join(process.env.ES_HOME, './bin/elasticsearch'))
.default('clusterName', 'yaml-test-runner') .default('clusterName', 'yaml-test-runner')
.default('dataPath', '/tmp/yaml-test-runner') .default('dataPath', '/tmp/yaml-test-runner')
.default('hostname', 'localhost')
.default('port', '9200')
.default('match', '**')
.boolean('createServer')
.argv; .argv;
// if (argv.hostname || argv.port) { Error.stackTraceLimit = Infinity;
// console.log('working with ES instance at ' + argv.hostname + ':' + argv.port);
// }
// Where do the tests live? // Where do the tests live?
var TEST_DIR = path.resolve(__dirname, '../../../es_api_spec/test/'); var TEST_DIR = path.resolve(__dirname, '../../../es_api_spec/test/');
// test names matching this will be run var doPattern = new Minimatch(argv.match);
var doRE = /(^|\/)(.*)\/.*/;
// a reference to a personal instance of ES Server // a reference to a personal instance of ES Server
var esServer = null; var esServer = null;
@ -40,17 +42,49 @@ function clearIndices(done) {
}, done); }, done);
} }
// before running any tests... function createClient() {
before(function (done) { if (client) {
// start our personal ES Server client.close();
this.timeout(null); }
if (argv.hostname) {
done(); client = new es.Client({
} else { hosts: [
{
hostname: esServer ? esServer.__hostname : argv.hostname,
port: esServer ? esServer.__port : argv.port
}
],
// log: null
log: {
type: 'file',
level: 'trace',
path: logFile
}
});
}
function createServer(done) {
server.start(argv, function (err, server) { server.start(argv, function (err, server) {
esServer = server; esServer = server;
done(err); done(err);
}); });
}
// before running any tests...
before(function (done) {
// start our personal ES Server
this.timeout(null);
if (argv.createServer) {
createServer(done);
} else {
createClient();
client.ping(function (err) {
if (err) {
createServer(done);
} else {
done();
}
})
} }
}); });
@ -66,22 +100,7 @@ before(function (done) {
}); });
before(function () { before(function () {
Error.stackTraceLimit = Infinity; createClient();
// create the client
client = new es.Client({
hosts: [
{
hostname: esServer ? esServer.__hostname : argv.hostname,
port: esServer ? esServer.__port : argv.port
}
],
log: null
// log: {
// type: 'file',
// level: ['error', 'warning', 'trace'],
// path: logFile
// }
});
}); });
before(clearIndices); before(clearIndices);
@ -97,7 +116,7 @@ function loadDir(dir) {
var location = path.join(dir, fileName), var location = path.join(dir, fileName),
stat = fs.statSync(location); stat = fs.statSync(location);
if (stat.isFile() && fileName.match(/\.yaml$/) && location.match(doRE)) { if (stat.isFile() && fileName.match(/\.yaml$/) && doPattern.match(path.relative(TEST_DIR, location))) {
loadFile(location); loadFile(location);
} }
else if (stat.isDirectory()) { else if (stat.isDirectory()) {
@ -188,25 +207,21 @@ function rangeMatchesCurrentVersion(rangeString, done) {
} }
/** /**
* read the file's contents, parse the yaml, pass to makeTest * read the file's contents, parse the yaml, pass to makeTestFromYamlDoc
* *
* @param {String} path - Full path to yaml file * @param {String} path - Full path to yaml file
* @return {undefined} * @return {undefined}
*/ */
function loadFile(location) { function loadFile(location) {
var docsInFile = [];
jsYaml.loadAll( jsYaml.loadAll(
fs.readFileSync(location, { encoding: 'utf8' }), fs.readFileSync(location, { encoding: 'utf8' }),
function (testConfig) { function (doc) {
docsInFile.push(testConfig); makeTestFromYamlDoc(doc);
}, },
{ {
filename: location filename: location
} }
); );
_.each(docsInFile, makeTest);
} }
/** /**
@ -217,15 +232,15 @@ function loadFile(location) {
* @param {Object} testConfigs - The yaml document * @param {Object} testConfigs - The yaml document
* @return {undefined} * @return {undefined}
*/ */
function makeTest(testConfig, count) { function makeTestFromYamlDoc(yamlDoc, count) {
var setup; var setup;
if (_.has(testConfig, 'setup')) { if (_.has(yamlDoc, 'setup')) {
(new ActionRunner(testConfig.setup)).each(function (action, name) { (new ActionRunner(yamlDoc.setup)).each(function (action, name) {
before(action); before(action);
}); });
delete testConfig.setup; delete yamlDoc.setup;
} }
_.forOwn(testConfig, function (test, description) { _.forOwn(yamlDoc, function (test, description) {
describe(description, function () { describe(description, function () {
var actions = new ActionRunner(test); var actions = new ActionRunner(test);
actions.each(function (action, name) { actions.each(function (action, name) {
@ -462,21 +477,23 @@ ActionRunner.prototype = {
if (catcher instanceof RegExp) { if (catcher instanceof RegExp) {
// error message should match the regexp // error message should match the regexp
expect(error.message).to.match(catcher); expect(error.message).to.match(catcher);
error = null;
} else if (typeof catcher === 'function') { } else if (typeof catcher === 'function') {
// error should be an instance of // error should be an instance of
expect(error).to.be.a(catcher); expect(error).to.be.a(catcher);
error = null;
} else { } else {
throw new Error('Invalid catcher ' + catcher); return done(new Error('Invalid catcher ' + catcher));
} }
} else { } else {
throw error; return done(error);
} }
} }
done(); done(error);
}, this)); }, this));
} else { } else {
throw new Error('stepped in do_do, did not find a function'); done(new Error('stepped in do_do, did not find a function'));
} }
}, },

File diff suppressed because it is too large Load Diff

View File

@ -15,12 +15,12 @@ exports.start = function (params, cb) {
params.executable, params.executable,
[ [
'-f', '-f',
'-D es.cluster.name=' + params.clusterName, '-Des.cluster.name=' + params.clusterName,
params.port ? '-D es.http.port=' + params.port : undefined, '-Des.path.data=' + params.dataPath,
'-D es.path.data=' + params.dataPath, '-Des.logger.level=DEBUG',
'-D es.gateway.type=none', '-Des.gateway.type=none',
'-D es.index.store.type=memory', '-Des.index.store.type=memory',
'-D es.discovery.zen.ping.multicast.enabled=false', '-Des.discovery.zen.ping.multicast.enabled=false',
], ],
{ {
cwd: undefined, cwd: undefined,
@ -34,15 +34,14 @@ exports.start = function (params, cb) {
); );
server.stdout.on('data', function (line) { server.stdout.on('data', function (line) {
line = line.toString(); line = _.trim(line.toString());
var match; var match;
// console.log(_.trim(line)); if (match = line.match(/bound_address \{inet\[\/?([^:]+):(\d+)\]\}/)) {
if (!params.port && (match = line.match(/bound_address \{inet\[\/?([^:]+):(\d+)\]\}/))) {
server.__hostname = match[1]; server.__hostname = match[1];
server.__port = match[2]; server.__port = match[2];
} }
if (line.match(/started\s*$/)) { if (line.match(/started\s*$/m)) {
console.log('Personal ES Server started at', server.__hostname + ':' + server.__port); console.log('Personal ES Server started at', server.__hostname + ':' + server.__port);
server.stdout.removeAllListeners(); server.stdout.removeAllListeners();
server.stderr.removeAllListeners(); server.stderr.removeAllListeners();
@ -51,9 +50,13 @@ exports.start = function (params, cb) {
}); });
server.stderr.on('data', function (line) { server.stderr.on('data', function (line) {
console.error(_.trim(line)); console.error(_.trim(line.toString()));
}); });
server.on('exit', function (code) {
console.log('Personal ES Server Shutdown with exit code', code);
})
process.on('exit', function () { process.on('exit', function () {
server.kill(); server.kill();
}); });

View File

@ -1,2 +1,3 @@
--require should --require should
--reporter dot --reporter dot
--timeout 11000

View File

@ -1,5 +1,5 @@
var es = require('../../src/elasticsearch'), var es = require('../../src/elasticsearch'),
api = require('../../src/lib/utils').requireDir(module, '../../src/api'), api = require('../../src/lib/api'),
expect = require('expect.js'); expect = require('expect.js');
describe('Client instances creation', function () { describe('Client instances creation', function () {
@ -10,7 +10,7 @@ describe('Client instances creation', function () {
}); });
it('inherits the api', function () { it('inherits the api', function () {
client.bulk.should.be.exactly(api.bulk); client.bulk.should.eql(api.bulk);
client.cluster.nodeStats.should.be.exactly(api.cluster.node_stats); client.cluster.nodeStats.should.eql(api.cluster.prototype.nodeStats);
}); });
}); });

View File

@ -1,45 +0,0 @@
var es = require('../../src/elasticsearch'),
sinon = require('sinon'),
expect = require('expect.js');
describe('transport', function () {
describe('#sniff', function () {
it('does a head request to "/"', function (done) {
var c = new es.Client();
// stub the tranports request method, arg 1 is a callback
sinon.stub(c.transport, 'request').callsArgAsync(1);
c.transport.sniff(function (err, resp) {
var spy = c.transport.request.getCall(0),
params = spy.args[0];
params.should.have.type('object');
params.should.have.property('path', '/_cluster/nodes');
if (params.method) {
params.should.be('GET');
}
done();
});
});
describe('when sniffOnStart === true', function () {
describe('and the cluster is down', function () {
before(function (done) {
var c = new es.Client({
sniffOnStart: true,
hosts: [
'intentionally-not-a-real-cluster.com:9200'
]
});
c.on('sniff complete', done);
});
it('should not have any connections in the connection pool', function () {
});
});
});
});
});

View File

@ -114,25 +114,6 @@ describe('Utils', function () {
}); });
describe('Lodash Modifications', function () {
describe('#map', function () {
it('returns an object when passed an object', function () {
var out = _.map({a: 1, b: 2}, function (val) { return val * 2; });
expect(out).to.eql({a: 2, b: 4});
});
it('returns an array for anything else', function () {
var std = _.map([1, 2, 3], function (val) { return val * 2; });
expect(std)
.to.be.a('array')
.and.to.eql(_.map('123', function (val) { return val * 2; }));
});
});
});
describe('String Transformers', function () { describe('String Transformers', function () {
describe('#camelCase', function () { describe('#camelCase', function () {