[connector/angular] don't modify global header deaults, fixed #146

This commit is contained in:
Spencer Alger
2014-09-23 09:39:46 -07:00
parent 8053e20d7e
commit c197a42777
4 changed files with 142 additions and 102 deletions

View File

@ -10,25 +10,37 @@ var _ = require('../utils');
var ConnectionAbstract = require('../connection'); var ConnectionAbstract = require('../connection');
var ConnectionFault = require('../errors').ConnectionFault; var ConnectionFault = require('../errors').ConnectionFault;
function makeAuthHeader(auth) {
return 'Basic ' + (new Buffer(auth, 'utf8')).toString('base64');
}
function AngularConnector(host, config) { function AngularConnector(host, config) {
ConnectionAbstract.call(this, host, config); ConnectionAbstract.call(this, host, config);
var connector = this; var self = this;
self.headerDefaults = {};
if (self.host.auth) {
self.headerDefaults.Authorization = makeAuthHeader(self.host.auth);
}
config.$injector.invoke(['$http', '$q', function ($http, $q) { config.$injector.invoke(['$http', '$q', function ($http, $q) {
connector.$q = $q; self.$q = $q;
connector.$http = $http; self.$http = $http;
if (connector.host.auth) {
connector.$http.defaults.headers.common.Authorization = 'Basic ' + (new Buffer(connector.host.auth, 'utf8')).toString('base64');
}
}]); }]);
} }
_.inherits(AngularConnector, ConnectionAbstract); _.inherits(AngularConnector, ConnectionAbstract);
AngularConnector.prototype.request = function (params, cb) { AngularConnector.prototype.request = function (userParams, cb) {
var abort = this.$q.defer(); var abort = this.$q.defer();
var params = _.cloneDeep(userParams);
params.headers = _.defaults(params.headers || {}, this.headerDefaults);
if (params.auth) {
params.headers.Authorization = makeAuthHeader(params.auth);
}
// inform the host not to use the auth, by overriding it in the params
params.auth = false;
this.$http({ this.$http({
method: params.method, method: params.method,

View File

@ -125,7 +125,7 @@ Host.prototype.makeUrl = function (params) {
var auth = ''; var auth = '';
if (params.auth) { if (params.auth) {
auth = params.auth + '@'; auth = params.auth + '@';
} else if (this.auth) { } else if (this.auth && params.auth !== false) {
auth = this.auth + '@'; auth = this.auth + '@';
} }

View File

@ -18,6 +18,7 @@
<!-- libs --> <!-- libs -->
<script src="jquery.js"></script> <script src="jquery.js"></script>
<script src="angular.js"></script> <script src="angular.js"></script>
<script src="angular-mocks.js"></script>
<!-- builds --> <!-- builds -->
<script src="elasticsearch.js"></script> <script src="elasticsearch.js"></script>

View File

@ -1,7 +1,7 @@
/* jshint browser:true */ var _ = require('lodash-node');
/* global angular */
var expect = require('expect.js'); var expect = require('expect.js');
var Promise = require('bluebird');
var sinon = require('sinon');
describe('Angular esFactory', function () { describe('Angular esFactory', function () {
before(function () { before(function () {
@ -9,64 +9,55 @@ describe('Angular esFactory', function () {
}); });
var uuid = (function () { var i = 0; return function () { return ++i; }; }()); var uuid = (function () { var i = 0; return function () { return ++i; }; }());
var esFactory;
var $http;
var $rootScope;
var $httpBackend;
/** function bootstrap(env) {
* Perform promise based async code in a way that mocha will understand beforeEach(function () {
* @param {Function} cb - node style callback var promiseProvider = _.noop;
* @param {Function} body - function that executes async and returns a promise/value if (env.bluebirdPromises) {
*/ promiseProvider = function ($provide) {
var prom = function (cb, body) { $provide.service('$q', function () {
expect(cb).to.be.a('function'); return {
expect(body).to.be.a('function'); defer: function () {
return _.bindAll(Promise.defer(), ['resolve', 'reject']);
var promise = body(); },
expect(promise.then).to.be.a('function'); reject: Promise.reject,
promise.then(function () { cb(); }, cb); when: Promise.resolve,
all: Promise.all
}; };
function directive(makeDirective) {
var root = document.createElement('div');
root.setAttribute('ng-controller', 'empty-controller');
var id = uuid();
root.setAttribute('test-directive-' + id, 'test-directive');
document.body.appendChild(root);
after(function () {
document.body.removeChild(root);
root = null;
}); });
};
angular
.module('mod' + id, ['elasticsearch'])
.controller('empty-controller', function () {})
.directive('testDirective' + id, makeDirective);
angular.bootstrap(root, ['mod' + id]);
} }
it('is available in the elasticsearch module', function (done) { angular.mock.module(promiseProvider, 'elasticsearch');
directive(function (esFactory) {
return function () {
expect(esFactory).to.be.a('function');
done();
};
});
}); });
it('has Transport and ConnectionPool properties', function (done) { beforeEach(angular.mock.inject(function ($injector) {
directive(function (esFactory) { $http = $injector.get('$http');
return function () { esFactory = $injector.get('esFactory');
$rootScope = $injector.get('$rootScope');
$httpBackend = $injector.get('$httpBackend');
}));
}
describe('basic', function () {
bootstrap({
bluebirdPromises: true
});
it('is available in the elasticsearch module', function () {
expect(esFactory).to.be.a('function');
});
it('has Transport and ConnectionPool properties', function () {
expect(esFactory).to.have.property('Transport'); expect(esFactory).to.have.property('Transport');
expect(esFactory).to.have.property('ConnectionPool'); expect(esFactory).to.have.property('ConnectionPool');
done();
};
});
}); });
it('returns a new client when it is called', function (done) { it('returns a new client when it is called', function () {
directive(function (esFactory) {
return function () {
try {
var client = esFactory({ var client = esFactory({
hosts: null hosts: null
}); });
@ -74,45 +65,81 @@ describe('Angular esFactory', function () {
expect(client).to.have.keys('transport'); expect(client).to.have.keys('transport');
expect(client.transport).to.be.a(esFactory.Transport); expect(client.transport).to.be.a(esFactory.Transport);
client.close(); client.close();
} catch (e) {
return done(e);
}
done();
};
});
}); });
it('returns an error created by calling a method incorrectly', function (done) { it('returns an error created by calling a method incorrectly', function () {
directive(function (esFactory) {
return function () {
prom(done, function () {
var client = esFactory({ hosts: null }); var client = esFactory({ hosts: null });
return client.get().then(function () { var err;
expect.fail('promise should have been rejected');
var prom = client.get().then(function () {
throw new Error('expected request to fail');
}, function (err) { }, function (err) {
expect(err).to.have.property('message');
expect(err.message).to.match(/unable/i); expect(err.message).to.match(/unable/i);
}); });
});
}; $rootScope.$apply();
return prom;
}); });
}); });
it('ping\'s properly', function (done) { describe('ping', function () {
directive(function (esFactory) { bootstrap({
return function () { bluebirdPromises: true
prom(done, function () { });
it('works', function () {
$httpBackend.expect('HEAD', 'http://some-es-host.com/').respond(200);
var client = esFactory({ var client = esFactory({
hosts: 'not-a-valid-es-host.es' host: 'http://some-es-host.com/'
}); });
return client.ping().then(function () { var connection = client.transport.connectionPool.getConnections().pop();
expect.fail('promise should have been rejected'); var stub = sinon.stub(connection, '$http', function (config) {
}, function (err) { process.nextTick($httpBackend.flush);
// this error should be "NoConnections", but in some browsers it will be a Timeout due to testing proxy or because it's IE return $http(config);
expect(err).to.be.ok(); });
return client.ping();
}); });
}); });
};
describe('$http', function () {
bootstrap({
bluebirdPromises: true
});
it('uses the auth header provided', function () {
var authString = 'user:password';
var authHeader = 'Basic ' + (new Buffer(authString, 'utf8')).toString('base64');
var $httpParams = null;
var client = esFactory({
host: {
host: 'some-other-es-host.com',
auth: authString
}
});
// once the client calls the $http method, flush the requests and trigger an
// error if the expected request was not made
var connection = client.transport.connectionPool.getConnections().pop();
var stub = sinon.stub(connection, '$http', function (params) {
$httpParams = params;
return Promise.resolve({
data: null,
status: 200,
headers: function () {
return {};
}
});
});
var prom = client.ping();
return prom.then(function () {
expect($httpParams).to.have.property('headers');
expect($httpParams.headers).to.have.property('Authorization', authHeader);
});
}); });
}); });
}); });