hapi
Version:
HTTP Server framework
581 lines (416 loc) • 18.7 kB
JavaScript
// Load modules
var Lab = require('lab');
var Https = require('https');
var Hapi = require('../..');
// Declare internals
var internals = {};
// Test shortcuts
var expect = Lab.expect;
var before = Lab.before;
var after = Lab.after;
var describe = Lab.experiment;
var it = Lab.test;
describe('Server', function () {
var tlsOptions = {
key: '-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBANysie374iGH54SVcmM4vb+CjN4nVVCmL6af9XOUxTqq/50CBn+Z\nZol0XDG+OK55HTOht4CsQrAXey69ZTxgUMcCAwEAAQJAX5t5XtxkiraA/hZpqsdo\nnlKHibBs7DY0KvLeuybXlKS3ar/0Uz0OSJ1oLx3d0KDSmcdAIrfnyFuBNuBzb3/J\nEQIhAPX/dh9azhztRppR+9j8CxDg4ixJ4iZbHdK0pfnY9oIFAiEA5aV8edK31dkF\nfBXoqlOvIeuNc6WBZrYjUNspH8M+BVsCIQDZF3U6/nve81bXYXqMZwGtB4kR5LH7\nf3W2OU4wS9RfsQIhAJkNB76xX3AYqX0fpOcPyuLSeH2gynNH5JWY2vmeSBGNAiAm\nLon4E3M/IrVVvpxGRFOazKlgIsQFGAaoylDrRFYgBA==\n-----END RSA PRIVATE KEY-----\n',
cert: '-----BEGIN CERTIFICATE-----\nMIIB0TCCAXugAwIBAgIJANGtTMK5HBUIMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UECgwJaGFwaSB0ZXN0MRQwEgYDVQQD\nDAtleGFtcGxlLmNvbTAeFw0xMzA0MDQxNDQ4MDJaFw0yMzA0MDIxNDQ4MDJaMEQx\nCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UECgwJaGFwaSB0ZXN0MRQw\nEgYDVQQDDAtleGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDcrInt\n++Ihh+eElXJjOL2/gozeJ1VQpi+mn/VzlMU6qv+dAgZ/mWaJdFwxvjiueR0zobeA\nrEKwF3suvWU8YFDHAgMBAAGjUDBOMB0GA1UdDgQWBBQBOiF6iL2PI4E6PBj071Dh\nAiQOGjAfBgNVHSMEGDAWgBQBOiF6iL2PI4E6PBj071DhAiQOGjAMBgNVHRMEBTAD\nAQH/MA0GCSqGSIb3DQEBBQUAA0EAw8Y2rpM8SUQXjgaJJmFXrfEvnl/he7q83K9W\n9Sr/QLHpCFxunWVd8c0wz+b8P/F9uW2V4wUf5NWj1UdHMCd6wQ==\n-----END CERTIFICATE-----\n'
};
it('throws an error constructed without new', function (done) {
var fn = function () {
Hapi.Server('0.0.0.0', 0, {});
};
expect(fn).throws(Error, 'Server must be instantiated using new');
done();
});
it('defaults to port 80 when no port is provided', function (done) {
var server = new Hapi.Server();
expect(server.info.port).to.be.equal(80);
done();
});
it('defaults to port 443 when no port is provided with tls', function (done) {
var server = new Hapi.Server({ tls: tlsOptions });
expect(server.info.port).to.be.equal(443);
done();
});
it('defaults to port 80 when a null port is provided', function (done) {
var server = new Hapi.Server('0.0.0.0', null);
expect(server.info.port).to.be.equal(80);
done();
});
it('allows a ephemeral port to be set', function (done) {
var server = new Hapi.Server('0.0.0.0', 0);
expect(server.info.port).to.be.equal(0);
done();
});
it('defaults to 0.0.0.0 when no host is provided', function (done) {
var server = new Hapi.Server(0);
server.start(function () {
expect(server.info.host).to.equal('0.0.0.0');
done();
});
});
it('doesn\'t throw an error when host and port are provided', function (done) {
var fn = function () {
var server = new Hapi.Server('0.0.0.0', 0);
};
expect(fn).to.not.throw(Error);
done();
});
it('throws an error when double port config is provided', function (done) {
var fn = function () {
var server = new Hapi.Server(8080, 8084);
};
expect(fn).throws(Error);
done();
});
it('throws an error when invalid config properties are provided', function (done) {
var fn = function () {
var server = new Hapi.Server({ cache: 'memory', something: false });
};
expect(fn).throws(Error);
done();
});
it('throws an error when double host config is provided', function (done) {
var fn = function () {
var server = new Hapi.Server('0.0.0.0', 'localhost');
};
expect(fn).throws(Error);
done();
});
it('throws an error when unknown arg type is provided', function (done) {
var fn = function () {
var server = new Hapi.Server(true);
};
expect(fn).throws(Error);
done();
});
it('assigns this.views when config enables views', function (done) {
var server = new Hapi.Server('0.0.0.0', 0, {
views: {
engines: { 'html': 'handlebars' }
}
});
expect(server._views).to.exist;
done();
});
it('creates an https server when passed tls options', function (done) {
var server = new Hapi.Server('0.0.0.0', 0, { tls: tlsOptions });
expect(server.listener instanceof Https.Server).to.equal(true);
done();
});
it('doesn\'t throw an error when enabling auth', function (done) {
var fn = function () {
var server = new Hapi.Server('0.0.0.0', 0, { auth: { scheme: 'basic', validateFunc: function () { } } });
};
expect(fn).to.not.throw(Error);
done();
});
describe('#start', function () {
it('doesn\'t throw an error', function (done) {
var fn = function () {
var server = new Hapi.Server('0.0.0.0', 0);
server.start();
};
expect(fn).to.not.throw(Error);
done();
});
it('calls the callback when one is used', function (done) {
var server = new Hapi.Server('0.0.0.0', 0);
server.start(function () {
expect(server.info.host).to.equal('0.0.0.0');
expect(server.info.port).to.not.equal(0);
done();
});
});
it('calls the callback when one is used with tls', function (done) {
var server = new Hapi.Server('0.0.0.0', 0, { tls: tlsOptions });
server.start(function () {
expect(server.info.host).to.equal('0.0.0.0');
expect(server.info.port).to.not.equal(0);
done();
});
});
});
describe('#stop', function () {
it('doesn\'t throw an error when the server is started', function (done) {
var fn = function () {
var server = new Hapi.Server(0);
server.start(function () {
server.stop();
done();
});
};
expect(fn).to.not.throw(Error);
});
it('ignores repeated calls when the server isn\'t started', function (done) {
var fn = function () {
var server = new Hapi.Server(0);
server.stop();
};
expect(fn).to.not.throw(Error);
done();
});
it('calls the callback when provided with one', function (done) {
var fn = function () {
var server = new Hapi.Server(0);
server.start(function () {
server.stop(function () {
done();
});
});
};
expect(fn).to.not.throw(Error);
});
});
describe('#route', function () {
it('throws an error when a route is passed in that is missing a path', function (done) {
var fn = function () {
var route = {};
var server = new Hapi.Server('0.0.0.0', 0);
server.route(route);
};
expect(fn).to.throw(Error);
done();
});
it('throws an error when a route is passed in that is missing a method', function (done) {
var fn = function () {
var route = {
path: '/test'
};
var server = new Hapi.Server('0.0.0.0', 0);
server.route(route);
};
expect(fn).to.throw(Error);
done();
});
it('throws an error when a route is passed in that is missing a handler', function (done) {
var fn = function () {
var route = {
path: '/test',
method: 'put'
};
var server = new Hapi.Server('0.0.0.0', 0);
server.route(route);
};
expect(fn).to.throw(Error);
done();
});
it('adds route to correct _router method property', function (done) {
var route = {
path: '/test',
method: 'put',
handler: function () { }
};
var server = new Hapi.Server('0.0.0.0', 0);
server.route(route);
expect(server._router.table.put[0].path).to.equal('/test');
done();
});
it('throws an error when a new route conflicts with an existing route', function (done) {
var fn = function () {
var server = new Hapi.Server();
server.route({ path: '/test/{p}/{p}/end', method: 'put', handler: function () { } });
server.route({ path: '/test/{p*2}/end', method: 'put', handler: function () { } });
};
expect(fn).to.throw(Error);
done();
});
it('doesn\'t throw an error when routes differ in case and case is sensitive', function (done) {
var fn = function () {
var server = new Hapi.Server({ router: { isCaseSensitive: true } });
server.route({ path: '/test/{p}/End', method: 'put', handler: function () { } });
server.route({ path: '/test/{p}/end', method: 'put', handler: function () { } });
};
expect(fn).to.not.throw(Error);
done();
});
it('throws an error when routes differ in case and case is insensitive', function (done) {
var fn = function () {
var server = new Hapi.Server({ router: { isCaseSensitive: false } });
server.route({ path: '/test/{p}/End', method: 'put', handler: function () { } });
server.route({ path: '/test/{p}/end', method: 'put', handler: function () { } });
};
expect(fn).to.throw(Error);
done();
});
it('adds to routes object with the passed in routes values', function (done) {
var routes = [{
path: '/test',
method: 'put',
handler: function () { }
}, {
path: '/test',
method: 'post',
handler: function () { }
}];
var server = new Hapi.Server('0.0.0.0', 0);
server.route(routes);
expect(server._router.table.put[0].path).to.equal('/test');
done();
});
});
describe('#helper', function () {
it('throws an error when name is not a string', function (done) {
var fn = function () {
var server = new Hapi.Server('0.0.0.0', 0);
server.helper(0, function () { });
};
expect(fn).to.throw(Error);
done();
});
it('throws an error when method is not a function', function (done) {
var fn = function () {
var server = new Hapi.Server('0.0.0.0', 0);
server.helper('user', 'function');
};
expect(fn).to.throw(Error);
done();
});
it('throws an error when options is not an object', function (done) {
var fn = function () {
var server = new Hapi.Server('0.0.0.0', 0);
server.helper('user', function () { }, 'options');
};
expect(fn).to.throw(Error);
done();
});
it('throws an error when options.generateKey is not a function', function (done) {
var fn = function () {
var server = new Hapi.Server('0.0.0.0', 0);
server.helper('user', function () { }, { generateKey: 'function' });
};
expect(fn).to.throw(Error);
done();
});
it('throws an error when options.cache is not valid', function (done) {
var fn = function () {
var server = new Hapi.Server('0.0.0.0', 0, { cache: 'memory' });
server.helper('user', function () { }, { cache: { mode: 'server' } });
};
expect(fn).to.throw(Error);
done();
});
it('returns a valid result when calling a helper without using the cache', function (done) {
var server = new Hapi.Server('0.0.0.0', 0);
server.helper('user', function (id, next) { return next({ id: id }); });
server.helpers.user(4, function (result) {
expect(result.id).to.equal(4);
done();
});
});
it('returns a valid result when calling a helper when using the cache', function (done) {
var server = new Hapi.Server('0.0.0.0', 0);
server.start(function () {
server.helper('user', function (id, str, next) { return next({ id: id, str: str }); }, { cache: { expiresIn: 1000 } });
server.helpers.user(4, 'something', function (result) {
expect(result.id).to.equal(4);
expect(result.str).to.equal('something');
done();
});
});
});
it('returns an error result when calling a helper that returns an error', function (done) {
var server = new Hapi.Server('0.0.0.0', 0);
server.helper('user', function (id, next) { return next(new Error()); });
server.helpers.user(4, function (result) {
expect(result instanceof Error).to.equal(true);
done();
});
});
it('returns a different result when calling a helper without using the cache', function (done) {
var server = new Hapi.Server('0.0.0.0', 0);
var gen = 0;
server.helper('user', function (id, next) { return next({ id: id, gen: ++gen }); });
server.helpers.user(4, function (result1) {
expect(result1.id).to.equal(4);
expect(result1.gen).to.equal(1);
server.helpers.user(4, function (result2) {
expect(result2.id).to.equal(4);
expect(result2.gen).to.equal(2);
done();
});
});
});
describe('with cache', function () {
it('returns a valid result when calling a helper using the cache', function (done) {
var server = new Hapi.Server('0.0.0.0', 0, { cache: 'memory' });
server.start(function () {
var gen = 0;
server.helper('user', function (id, next) { return next({ id: id, gen: ++gen }); }, { cache: { expiresIn: 2000 } });
var id = Math.random();
server.helpers.user(id, function (result1) {
expect(result1.id).to.equal(id);
expect(result1.gen).to.equal(1);
server.helpers.user(id, function (result2) {
expect(result2.id).to.equal(id);
expect(result2.gen).to.equal(1);
done();
});
});
});
});
it('returns valid results when calling a helper (with different keys) using the cache', function (done) {
var server = new Hapi.Server('0.0.0.0', 0, { cache: 'memory' });
var gen = 0;
server.helper('user', function (id, next) { return next({ id: id, gen: ++gen }); }, { cache: { expiresIn: 2000 } });
var id1 = Math.random();
server.helpers.user(id1, function (result1) {
expect(result1.id).to.equal(id1);
expect(result1.gen).to.equal(1);
var id2 = Math.random();
server.helpers.user(id2, function (result2) {
expect(result2.id).to.equal(id2);
expect(result2.gen).to.equal(2);
done();
});
});
});
it('returns new object (not cached) when second key generation fails when using the cache', function (done) {
var server = new Hapi.Server('0.0.0.0', 0, { cache: 'memory' });
var id1 = Math.random();
var gen = 0;
var helper = function (id, next) {
if (typeof id === 'function') {
id = id1;
}
return next({ id: id, gen: ++gen });
};
server.helper('user', helper, { cache: { expiresIn: 2000 } });
server.helpers.user(id1, function (result1) {
expect(result1.id).to.equal(id1);
expect(result1.gen).to.equal(1);
server.helpers.user(function () { }, function (result2) {
expect(result2.id).to.equal(id1);
expect(result2.gen).to.equal(2);
done();
});
});
});
});
});
describe('#routingTable', function () {
it('returns an array of the current routes', function (done) {
var server = new Hapi.Server('0.0.0.0', 0);
server.route({ path: '/test/', method: 'get', handler: function () { } });
server.route({ path: '/test/{p}/end', method: 'get', handler: function () { } });
var routes = server.routingTable();
expect(routes.length).to.equal(2);
expect(routes[0].path).to.equal('/test/');
done();
});
});
describe('#log', function () {
it('emits a log event', function (done) {
var server = new Hapi.Server();
server.once('log', function (event) {
expect(event.data).to.equal('log event 1');
});
server.log('1', 'log event 1', Date.now());
server.once('log', function (event) {
expect(event.data).to.equal('log event 2');
});
server.log(['2'], 'log event 2', new Date(Date.now()));
done();
});
});
});