Summary of changes:

- updated copyright
 - several tempalate changes for the docs
 - added a config for grunt-contrib-watch
 - updated nock commit number
 - fixed the coverage script
 - removed the export_docs script
 - added error message for legacy "es" users who don't have a version locked and have not upgraded
 - host will now add auth to urls created with `#makeUrl()`
 - Log class no longer looks for `config.loggers`
 - The log class now properly escapes single quotes in trace logs
 - Removed compiled yaml_tests.js from the repo
 - Yaml suite will only log error and warning messages unless the VERBOSE env var is set
 - createDefer is now a global setting, changed by modifying Transport.createDefer fubction
 - wrote tests for Content-Type checking
 - callbacks will now return the body and status of the request (if the request has completed) when an error occurs
 - Stdio logger now adds "Elasticsearch " to the front of log messages to distinguish it from other output to stdout.
This commit is contained in:
Spencer Alger
2013-12-15 14:08:29 -07:00
parent 0c8bd328fe
commit 37cd2f4f6c
20 changed files with 229 additions and 34803 deletions

View File

@ -12,9 +12,8 @@ module.exports = function (grunt) {
banner: '/*! <%= package.name %> - v<%= package.version %> - ' + banner: '/*! <%= package.name %> - v<%= package.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n' + '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
'<%= package.homepage ? " * " + package.homepage + "\\n" : "" %>' + '<%= package.homepage ? " * " + package.homepage + "\\n" : "" %>' +
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= package.author.name %>;' + ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= package.author.company %>;' +
' Licensed <%= package.license %> */\n' + ' Licensed <%= package.license %> */\n'
' // built using browserify\n\n'
} }
} }
}); });

View File

@ -27,7 +27,7 @@ We also provide builds of the elasticsearch.js client for use in the browser. If
- [Quick Start](http://spenceralger.github.io/elasticsearch-js/index.html#quick-start) - [Quick Start](http://spenceralger.github.io/elasticsearch-js/index.html#quick-start)
- [API](http://spenceralger.github.io/elasticsearch-js/api.html) - [API](http://spenceralger.github.io/elasticsearch-js/api.html)
- [Configuration](http://spenceralger.github.io/elasticsearch-js/index.html#configuration) - [Configuration](http://spenceralger.github.io/elasticsearch-js/index.html#configuration)
- [Development/Contributions](http://spenceralger.github.io/elasticsearch-js/index.html#dev) - [Development/Contributing](http://spenceralger.github.io/elasticsearch-js/index.html#dev)
- [Extending Core Components](http://spenceralger.github.io/elasticsearch-js/index.html#extending) - [Extending Core Components](http://spenceralger.github.io/elasticsearch-js/index.html#extending)
- [Logging](http://spenceralger.github.io/elasticsearch-js/index.html#logging) - [Logging](http://spenceralger.github.io/elasticsearch-js/index.html#logging)

View File

@ -1,8 +0,0 @@
module.exports = {
unit: {
src: ['test/unit/test_*.js'],
reporter: 'XUnit',
dest: './test-output-phantom-unit.xml',
run: true
}
};

15
grunt/config/watch.js Normal file
View File

@ -0,0 +1,15 @@
module.exports = {
source: {
files: [
'src/**/*.js',
'test/unit/**/*.js',
'grunt/**/*.js',
'Gruntfile.js'
],
interrupt: true,
tasks: [
// 'jshint',
'run:unit_tests'
]
}
};

View File

@ -37,7 +37,7 @@
"mocha-lcov-reporter": "0.0.1", "mocha-lcov-reporter": "0.0.1",
"blanket": "~1.1.5", "blanket": "~1.1.5",
"sinon": "~1.7.3", "sinon": "~1.7.3",
"nock": "git://github.com/spenceralger/nock.git#f28dc3c973651830b930793932b4006577260dc1", "nock": "git://github.com/spenceralger/nock.git#5218548233983c594da5535bc07e7db36841987e",
"open": "0.0.4", "open": "0.0.4",
"testling": "git://github.com/spenceralger/testling.git", "testling": "git://github.com/spenceralger/testling.git",
"load-grunt-tasks": "~0.2.0", "load-grunt-tasks": "~0.2.0",
@ -64,7 +64,7 @@
}, },
"scripts": { "scripts": {
"test": "grunt test", "test": "grunt test",
"coverage": "mocha test/unit/test_*.js --require blanket -R html-cov > coverage.html && open -a \"Google Chrome\"./coverage.html", "coverage": "mocha test/unit/test_*.js --require blanket -R html-cov > coverage.html && open -a \"Google Chrome\" ./coverage.html",
"blanket": { "blanket": {
"pattern": "src" "pattern": "src"
} }

View File

@ -1,74 +0,0 @@
var path = require('path');
var argv = require('optimist')
.default({
outputDir: '.',
verbose: false
})
.alias({
o: 'outputDir',
v: 'verbose'
})
.argv;
require('./_steps')(argv, [
['runInModule', {
cmd: 'node',
args: ['scripts/generate', '--force']
}],
['copy', {
from: path.join(__dirname, '../docs/_methods.jade'),
to: path.join(argv.outputDir, '_methods.jade')
}],
['copy', {
from: path.join(__dirname, '../docs/_method_list.jade'),
to: path.join(argv.outputDir, '_method_list.jade')
}]
]);
// function runInModule(cmd, args, exitCb) {
// log('running', cmd, args.join(' '));
// var proc = cp.spawn(cmd, args, {
// stdio: argv.verbose ? 'inherit' : 'ignore'
// });
// proc.on('error', function (err) {
// console.error('Error! --', err.message);
// process.exit(1);
// });
// proc.on('exit', function (status) {
// if (status) {
// console.error('Error! --', cmd, 'exit status was', status);
// process.exit(1);
// } else {
// exitCb();
// }
// });
// }
// function copy(from, to, done) {
// log('copying', from, 'to', to);
// var read = fs.createReadStream(from);
// var write = fs.createWriteStream(to);
// read.pipe(write);
// read.on('error', function (err) {
// console.error('unable to read: ' + from);
// console.error(err.message);
// process.exit(1);
// });
// write.on('error', function (err) {
// console.error('unable to write to: ' + to);
// console.error(err.message);
// process.exit(1);
// });
// write.on('finish', function () {
// done();
// });
// }

View File

@ -7,14 +7,12 @@ var actionId = action.name.toLowerCase().replace(/[^\w]+/g, '-');
h2#<%= actionId %>.fn h2#<%= actionId %>.fn
span.name <%= action.name %> span.name <%= action.name %>
span.args (params, [callback]) span.args (params, [callback])
a.perma(href="api.html#<%= actionId %>", title="Permalink") include _descriptions/<%= action.name %>.jade
a.esdoc(href="<%= action.docUrl %>", title="Endpoint Docs") a.esdoc(href="<%= action.docUrl %>", title="<%= action.name %> at elasticsearch.org").
//- <%= action.docUrl %>
h4 Spec: p.tight.
pre The default method is <code><%= action.spec.method || 'GET' %></code> and
code <%= JSON.stringify(action, null, ' ').split('\n').map(function (line, i) { the usual <a href="#api-conventions">params and return values</a> apply.
return (i > 0 ? ' | ' : '') + line;
}).join('\n') %>
<% if (_.size(action.allParams)) { %> <% if (_.size(action.allParams)) { %>
h3 Params: h3 Params:
@ -26,10 +24,6 @@ dl.params.api
<%= indent(param.description || '', 4) %><% <%= indent(param.description || '', 4) %><%
}); %> }); %>
<% } %> <% } %>
p.
Default method: <%= action.spec.method || 'GET' %><br>
Includes <a href="#api-conventions-return">the usual</a>
include _examples/<%= action.name %>.jade<% include _examples/<%= action.name %>.jade<%
}); });
%> %>

View File

@ -1,7 +1,13 @@
#!/bin/bash #!/bin/bash
# let the dust settle and ensure that es is ready for us.
sleep 15s
# generate the latest version of the yaml-tests # generate the latest version of the yaml-tests
node scripts/generate/ --no-api 2>&1 > /dev/null node scripts/generate/ --no-api 2>&1 > /dev/null
export VERBOSE="true"
# unit tests # unit tests
./node_modules/.bin/mocha test/unit/test_*.js \ ./node_modules/.bin/mocha test/unit/test_*.js \
--require should \ --require should \

View File

@ -5,6 +5,7 @@
* It will also instruct the client to use Angular's $http service for it's ajax requests * It will also instruct the client to use Angular's $http service for it's ajax requests
*/ */
var AngularConnector = require('./lib/connectors/angular'); var AngularConnector = require('./lib/connectors/angular');
var Transport = require('./lib/transport');
var Client = require('./lib/client'); var Client = require('./lib/client');
process.angular_build = true; process.angular_build = true;
@ -16,12 +17,14 @@ angular.module('elasticsearch.client', [])
AngularConnector.prototype.$http = $http; AngularConnector.prototype.$http = $http;
AngularConnector.prototype.$q = $q; AngularConnector.prototype.$q = $q;
// make the Transport return $q promisses instead
Transport.createDefer = function () {
return $q.defer();
};
var factory = function (config) { var factory = function (config) {
config = config || {}; config = config || {};
config.connectionClass = AngularConnector; config.connectionClass = AngularConnector;
config.createDefer = function () {
return $q.defer();
};
return new Client(config); return new Client(config);
}; };

View File

@ -1,9 +1,15 @@
var es = { // In order to help people who were accidentally upgraded to this ES client,
Client: require('./lib/client'), // throw an error when they try to instanciate the exported function.
ConnectionPool: require('./lib/connection_pool'), // previous "elasticsearch" module -> https://github.com/ncb000gt/node-es
Transport: require('./lib/transport'), function es() {
throw new Error('Looks like you are expecting the previous "elasticsearch" module. ' +
'It is now the "es" module. To create a client with this module use ' +
'`new es.Client(params)`.');
}
errors: require('./lib/errors') es.Client = require('./lib/client');
}; es.ConnectionPool = require('./lib/connection_pool');
es.Transport = require('./lib/transport');
es.errors = require('./lib/errors');
module.exports = es; module.exports = es;

View File

@ -36,4 +36,5 @@ AngularConnector.prototype.request = function (params, cb) {
// must be overwritten before this connection can be used // must be overwritten before this connection can be used
AngularConnector.prototype.$http = null; AngularConnector.prototype.$http = null;
// required in order to provide abort functionality
AngularConnector.prototype.$q = null; AngularConnector.prototype.$q = null;

View File

@ -128,7 +128,14 @@ Host.prototype.makeUrl = function (params) {
query = qs.stringify(this.query); query = qs.stringify(this.query);
} }
return this.protocol + '://' + this.host + port + path + (query ? '?' + query : ''); var auth = '';
if (params.auth) {
auth = params.auth + '@';
} else if (this.auth) {
auth = this.auth + '@';
}
return this.protocol + '://' + auth + this.host + port + path + (query ? '?' + query : '');
}; };
Host.prototype.toString = function () { Host.prototype.toString = function () {

View File

@ -22,10 +22,6 @@ function Log(config) {
var i; var i;
var outputs; var outputs;
if (config.loggers) {
config.log = config.loggers;
}
if (config.log) { if (config.log) {
if (_.isArrayOfStrings(config.log)) { if (_.isArrayOfStrings(config.log)) {
outputs = [{ outputs = [{
@ -305,8 +301,7 @@ Log.prototype.trace = function (method, requestUrl, body, responseBody, response
function prettyJSON(body) { function prettyJSON(body) {
try { try {
// TESTME return JSON.stringify(JSON.parse(body), null, ' ').replace(/'/g, '\\u0027');
return JSON.stringify(JSON.parse(body), null, ' ').replace(/'/g, '\\\'');
} catch (e) { } catch (e) {
return body || ''; return body || '';
} }

File diff suppressed because one or more lines are too long

View File

@ -68,8 +68,7 @@ module.exports = {
], ],
log: { log: {
type: process.browser ? 'console' : 'stdio', type: process.browser ? 'console' : 'stdio',
level: 'trace', level: process.env.VERBOSE ? 'trace' : 'warning'
color: false
} }
}); });

View File

@ -122,8 +122,9 @@ describe('Host class', function () {
path: '/this and that', path: '/this and that',
query: { query: {
param: 1 param: 1
} },
}).should.eql('http://localhost:9200/prefix/this and that?param=1&user_id=123'); auth: 'user:pass'
}).should.eql('http://user:pass@localhost:9200/prefix/this and that?param=1&user_id=123');
}); });
it('ensures that path starts with a forward-slash', function () { it('ensures that path starts with a forward-slash', function () {
@ -148,8 +149,8 @@ describe('Host class', function () {
host = new Host({ host: 'john', port: 80 }); host = new Host({ host: 'john', port: 80 });
host.makeUrl().should.eql('http://john/'); host.makeUrl().should.eql('http://john/');
host = new Host({ host: 'italy', path: '/pie' }); host = new Host({ host: 'italy', path: '/pie', auth: 'user:pass'});
host.makeUrl().should.eql('http://italy:9200/pie'); host.makeUrl().should.eql('http://user:pass@italy:9200/pie');
}); });
}); });

View File

@ -188,7 +188,7 @@ describe('Http Connector', function () {
}); });
}); });
it('logs error events when an error occurs', function (done) { it('does not log error events', function (done) {
var con = new HttpConnection(new Host('http://google.com')); var con = new HttpConnection(new Host('http://google.com'));
stub(con.log, 'error'); stub(con.log, 'error');
@ -205,8 +205,8 @@ describe('Http Connector', function () {
err.message.should.eql('actual error'); err.message.should.eql('actual error');
// logged the error and the trace log // logged the error and the trace log
con.log.error.callCount.should.eql(1);
con.log.trace.callCount.should.eql(1); con.log.trace.callCount.should.eql(1);
con.log.error.callCount.should.eql(0);
con.log.info.callCount.should.eql(0); con.log.info.callCount.should.eql(0);
con.log.warning.callCount.should.eql(0); con.log.warning.callCount.should.eql(0);
con.log.debug.callCount.should.eql(0); con.log.debug.callCount.should.eql(0);
@ -227,9 +227,7 @@ describe('Http Connector', function () {
err.message.should.eql('actual error'); err.message.should.eql('actual error');
// logged the error // logged the error
con.log.error.callCount.should.eql(1); con.log.error.callCount.should.eql(0);
con.log.error.lastCall.args[0].message.should.eql('actual error');
done(); done();
}); });
}); });
@ -250,13 +248,13 @@ describe('Http Connector', function () {
}); });
} }
it('logs error event', function (done) { it('does not log errors', function (done) {
var con = new HttpConnection(new Host('https://google.com')); var con = new HttpConnection(new Host('https://google.com'));
stub(con.log, 'error'); stub(con.log, 'error');
stub(https, 'request', makeStubReqWithMsgWhichErrorsMidBody()); stub(https, 'request', makeStubReqWithMsgWhichErrorsMidBody());
con.request({}, function (err, resp, status) { con.request({}, function (err, resp, status) {
con.log.error.callCount.should.eql(1); con.log.error.callCount.should.eql(0);
done(); done();
}); });
}); });

View File

@ -45,7 +45,7 @@ describe('Stdio Logger', function () {
it('obeys the logger.color === false', function () { it('obeys the logger.color === false', function () {
var logger = makeLogger(); var logger = makeLogger();
stub(process.stdout, 'write'); stub(process.stdout, 'write');
var withoutColor = 'INFO: ' + now + '\n something\n\n'; var withoutColor = 'Elasticsearch INFO: ' + now + '\n something\n\n';
logger.color = false; logger.color = false;
logger.onInfo('something'); logger.onInfo('something');
@ -56,7 +56,7 @@ describe('Stdio Logger', function () {
var logger = makeLogger(); var logger = makeLogger();
stub(process.stdout, 'write'); stub(process.stdout, 'write');
var withoutColor = 'TRACE: ' + now + '\n curl\n msg\n\n'; var withoutColor = 'Elasticsearch TRACE: ' + now + '\n curl\n msg\n\n';
logger.color = true; logger.color = true;
logger.onTrace('msg', 'curl'); logger.onTrace('msg', 'curl');

View File

@ -33,20 +33,6 @@ describe('Transport Class', function () {
trans.log.should.be.an.instanceOf(CustomLogClass); trans.log.should.be.an.instanceOf(CustomLogClass);
}); });
it('Accepts a "createDefer" function, which can be used to tie into other promise libs.', function () {
function CustomPromise() {
this.then = function () {};
}
var trans = new Transport({
createDefer: function () {
return new CustomPromise();
}
});
trans.createDefer().should.be.an.instanceOf(CustomPromise);
});
it('Accepts a connection pool class and intanciates it at this.connectionPool', function () { it('Accepts a connection pool class and intanciates it at this.connectionPool', function () {
function CustomConnectionPool() {} function CustomConnectionPool() {}
var trans = new Transport({ var trans = new Transport({
@ -75,6 +61,33 @@ describe('Transport Class', function () {
}).should.throw(/invalid connectionpool/i); }).should.throw(/invalid connectionpool/i);
}); });
it('calls sniff immediately if sniffOnStart is true', function () {
stub(Transport.prototype, 'sniff');
var trans = new Transport({
sniffOnStart: true
});
trans.sniff.callCount.should.eql(1);
});
it('schedules a sniff when sniffInterval is set', function () {
var clock = sinon.useFakeTimers('setTimeout');
stub(Transport.prototype, 'sniff');
var trans = new Transport({
sniffInterval: 25000
});
_.size(clock.timeouts).should.eql(1);
var id = _.keys(clock.timeouts).pop();
clock.tick(25000);
trans.sniff.callCount.should.eql(1);
_.size(clock.timeouts).should.eql(1);
_.keys(clock.timeouts).pop().should.not.eql(id);
clock.restore();
});
describe('host config', function () { describe('host config', function () {
it('rejects non-strings/objects', function () { it('rejects non-strings/objects', function () {
(function () { (function () {
@ -195,6 +208,14 @@ describe('Transport Class', function () {
}); });
}); });
describe('::createDefer', function () {
it('returns a when.js promise by default', function () {
Transport.createDefer().constructor.should.be.exactly(when.defer().constructor);
});
});
describe('#sniff', function () { describe('#sniff', function () {
var trans; var trans;
@ -275,27 +296,6 @@ describe('Transport Class', function () {
}); });
}); });
describe('#createDefer', function () {
it('returns a when.js promise by default', function () {
var trans = new Transport({
hosts: 'localhost'
});
trans.createDefer().constructor.should.be.exactly(when.defer().constructor);
});
it('is overridden by the createDefer option', function () {
var when = require('when');
var trans = new Transport({
hosts: 'localhost',
createDefer: function () {
return 'pasta';
}
});
trans.createDefer().should.be.exactly('pasta');
});
});
describe('#request', function () { describe('#request', function () {
it('logs when it begins', function (done) { it('logs when it begins', function (done) {
var trans = new Transport(); var trans = new Transport();
@ -445,48 +445,47 @@ describe('Transport Class', function () {
}); });
describe('gets a connection err', function () { describe('gets a connection err', function () {
function testRetries(retries, done) { // create a test that checks N retries
var randomSelector = require('../../src/lib/selectors/random'); function testRetries(retries) {
var connections; return function (done) {
var attempts = 0; var randomSelector = require('../../src/lib/selectors/random');
function failRequest(params, cb) { var connections;
attempts++; var attempts = 0;
process.nextTick(function () { function failRequest(params, cb) {
cb(new Error('Unable to do that thing you wanted')); attempts++;
}); process.nextTick(function () {
} cb(new Error('Unable to do that thing you wanted'));
});
var trans = new Transport({
hosts: _.map(new Array(retries + 1), function (i) {
return 'localhost/' + i;
}),
maxRetries: retries,
selector: function (_conns) {
connections = _conns;
return randomSelector(_conns);
} }
});
// trigger a select so that we can harvest the connection list var trans = new Transport({
trans.connectionPool.select(_.noop); hosts: _.map(new Array(retries + 1), function (i) {
_.each(connections, function (conn) { return 'localhost/' + i;
stub(conn, 'request', failRequest); }),
}); maxRetries: retries,
selector: function (_conns) {
connections = _conns;
return randomSelector(_conns);
}
});
trans.request({}, function (err, resp, body) { // trigger a select so that we can harvest the connection list
attempts.should.eql(retries + 1); trans.connectionPool.select(_.noop);
err.should.be.an.instanceOf(errors.ConnectionFault); _.each(connections, function (conn) {
should.not.exist(resp); stub(conn, 'request', failRequest);
should.not.exist(body); });
done();
}); trans.request({}, function (err, resp, body) {
attempts.should.eql(retries + 1);
err.should.be.an.instanceOf(errors.ConnectionFault);
should.not.exist(resp);
should.not.exist(body);
done();
});
};
} }
it('retries when there are retries remaining', function (done) { it('retries when there are retries remaining', testRetries(_.random(25, 40)));
testRetries(30, done); it('responds when there are no retries', testRetries(0));
});
it('responds when there are no retries', function (done) {
testRetries(0, done);
});
}); });
describe('server responds', function () { describe('server responds', function () {
@ -505,16 +504,34 @@ describe('Transport Class', function () {
.reply(500, 'ah shit') .reply(500, 'ah shit')
.get('/exists?') .get('/exists?')
.reply(200, '{"status":200}') .reply(200, {
status: 200
})
.get('/give-me-someth') .get('/give-me-someth')
.reply(200, '{"not":"valid') .reply(200, '{"not":"valid', {
'Content-Type': 'application/json'
})
.get('/') .get('/')
.reply(200, '{"the answer":42}') .reply(200, {
'the answer': 42
})
.get('/huh?') .get('/huh?')
.reply(530, 'boo'); .reply(530, 'boo')
.get('/hottie-threads')
.reply(200, [
'he said',
'she said',
'he said',
'she said',
'he said',
'she said'
].join('\n'), {
'Content-Type': 'text/plain'
});
}); });
after(function () { after(function () {
@ -532,8 +549,8 @@ describe('Transport Class', function () {
}, function (err, body, status) { }, function (err, body, status) {
err.should.be.an.instanceOf(errors[400]); err.should.be.an.instanceOf(errors[400]);
err.should.be.an.instanceOf(errors.BadRequest); err.should.be.an.instanceOf(errors.BadRequest);
should.not.exist(body); body.should.eql('sorry bub');
should.not.exist(status); status.should.eql(400);
done(); done();
}); });
}); });
@ -568,8 +585,8 @@ describe('Transport Class', function () {
}, function (err, body, status) { }, function (err, body, status) {
err.should.be.an.instanceOf(errors[404]); err.should.be.an.instanceOf(errors[404]);
err.should.be.an.instanceOf(errors.NotFound); err.should.be.an.instanceOf(errors.NotFound);
should.not.exist(body); body.should.eql('nothing here');
should.not.exist(status); status.should.eql(404);
done(); done();
}); });
}); });
@ -587,14 +604,14 @@ describe('Transport Class', function () {
}, function (err, body, status) { }, function (err, body, status) {
err.should.be.an.instanceOf(errors[500]); err.should.be.an.instanceOf(errors[500]);
err.should.be.an.instanceOf(errors.InternalServerError); err.should.be.an.instanceOf(errors.InternalServerError);
should.not.exist(body); body.should.eql('ah shit');
should.not.exist(status); status.should.eql(500);
done(); done();
}); });
}); });
}); });
describe('with a 500 status code', function () { describe('with a 530 status code', function () {
it('passes back a Generic error', function (done) { it('passes back a Generic error', function (done) {
var trans = new Transport({ var trans = new Transport({
hosts: 'localhost' hosts: 'localhost'
@ -604,8 +621,8 @@ describe('Transport Class', function () {
path: '/huh?' path: '/huh?'
}, function (err, body, status) { }, function (err, body, status) {
err.should.be.an.instanceOf(errors.Generic); err.should.be.an.instanceOf(errors.Generic);
should.not.exist(body); body.should.eql('boo');
should.not.exist(status); status.should.eql(530);
done(); done();
}); });
}); });
@ -639,8 +656,8 @@ describe('Transport Class', function () {
path: '/give-me-someth', path: '/give-me-someth',
}, function (err, body, status) { }, function (err, body, status) {
err.should.be.an.instanceOf(errors.Serialization); err.should.be.an.instanceOf(errors.Serialization);
should.not.exist(body); body.should.eql('{"not":"valid');
should.not.exist(status); status.should.eql(200);
done(); done();
}); });
}); });
@ -663,6 +680,22 @@ describe('Transport Class', function () {
}); });
}); });
}); });
describe('with plain text', function () {
it('notices the content-type header and returns the text', function (done) {
var trans = new Transport({
hosts: 'localhost'
});
trans.request({
path: '/hottie-threads',
}, function (err, body, status) {
should.not.exist(err);
body.should.match(/s?he said/g);
done();
});
});
});
}); });
describe('return value', function () { describe('return value', function () {
@ -680,22 +713,44 @@ describe('Transport Class', function () {
when.isPromise(ret).should.be.ok; when.isPromise(ret).should.be.ok;
ret.abort.should.have.type('function'); ret.abort.should.have.type('function');
}); });
it('the promise is always pulled from the defer created by this.createDefer()', function () { it('promise is always pulled from the defer created by this.createDefer()', function () {
var fakePromise = {}; var fakePromise = {};
var tran = new Transport({ var origCreate = Transport.createDefer;
createDefer: function () { Transport.createDefer = function () {
return { return {
resolve: _.noop, resolve: _.noop,
reject: _.noop, reject: _.noop,
promise: fakePromise promise: fakePromise
}; };
} };
}); var tran = new Transport({});
shortCircuitRequest(tran); shortCircuitRequest(tran);
var ret = tran.request({}); var ret = tran.request({});
Transport.createDefer = origCreate;
ret.should.be.exactly(fakePromise); ret.should.be.exactly(fakePromise);
ret.abort.should.have.type('function'); ret.abort.should.have.type('function');
}); });
it('resolves the promise it returns with an object containing status and body keys', function (done) {
var serverMock = nock('http://esbox.1.com')
.get('/')
.reply(200, {
good: 'day'
});
var tran = new Transport({
hosts: 'http://esbox.1.com'
});
tran.request({}).then(function (resp) {
resp.should.eql({
body: {
good: 'day'
},
status: 200
});
done();
});
});
}); });
describe('aborting', function () { describe('aborting', function () {

View File

@ -29,6 +29,7 @@ var suites = testXml.create('testsuites');
var suiteCount = 0; var suiteCount = 0;
var moment = require('moment'); var moment = require('moment');
var _ = require('lodash'); var _ = require('lodash');
var chalk = require('chalk');
function makeJUnitXml(runnerName, testDetails) { function makeJUnitXml(runnerName, testDetails) {
_.each(testDetails.suites, function serializeSuite(suiteInfo) { _.each(testDetails.suites, function serializeSuite(suiteInfo) {
@ -78,10 +79,10 @@ function makeJUnitXml(runnerName, testDetails) {
} }
if (suiteInfo.stdout.trim()) { if (suiteInfo.stdout.trim()) {
suite.ele('system-out', {}).cdata(suiteInfo.stdout); suite.ele('system-out', {}).cdata(chalk.stripColor(suiteInfo.stdout));
} }
if (suiteInfo.stderr.trim()) { if (suiteInfo.stderr.trim()) {
suite.ele('system-err', {}).cdata(suiteInfo.stderr); suite.ele('system-err', {}).cdata(chalk.stripColor(suiteInfo.stderr));
} }
}); });