diff --git a/lib/server.js b/lib/server.js index 6ea5a593f..ae86f42e0 100755 --- a/lib/server.js +++ b/lib/server.js @@ -180,13 +180,23 @@ internals.Server.prototype.start = function (callback) { } Hoek.assert(typeof callback === 'function', 'Missing required start callback function'); + const nextTickCallback = Hoek.nextTick(callback); + + if (this._state === 'initialized' || + this._state === 'started') { + + const error = this._validateDeps(); + if (error) { + return nextTickCallback(error); + } + } if (this._state === 'initialized') { return this._start(callback); } if (this._state === 'started') { - const each = (connectionItem, next) => connectionItem._start(next); + const each = (connection, next) => connection._start(next); return Items.parallel(this.connections, each, callback); } @@ -211,7 +221,9 @@ internals.Server.prototype.initialize = function (callback) { return Promises.wrap(this, this.initialize); } + Hoek.assert(typeof callback === 'function', 'Missing required start callback function'); const nextTickCallback = Hoek.nextTick(callback); + if (!this.connections.length) { return nextTickCallback(new Error('No connections to start')); } @@ -228,29 +240,9 @@ internals.Server.prototype.initialize = function (callback) { return nextTickCallback(new Error('Cannot initialize server while it is in ' + this._state + ' state')); } - // Assert dependencies - - for (let i = 0; i < this._dependencies.length; ++i) { - const dependency = this._dependencies[i]; - if (dependency.connections) { - for (let j = 0; j < dependency.connections.length; ++j) { - const connection = dependency.connections[j]; - for (let k = 0; k < dependency.deps.length; ++k) { - const dep = dependency.deps[k]; - if (!connection.registrations[dep]) { - return nextTickCallback(new Error('Plugin ' + dependency.plugin + ' missing dependency ' + dep + ' in connection: ' + connection.info.uri)); - } - } - } - } - else { - for (let j = 0; j < dependency.deps.length; ++j) { - const dep = dependency.deps[j]; - if (!this._registrations[dep]) { - return nextTickCallback(new Error('Plugin ' + dependency.plugin + ' missing dependency ' + dep)); - } - } - } + const error = this._validateDeps(); + if (error) { + return nextTickCallback(error); } this._state = 'initializing'; @@ -292,11 +284,40 @@ internals.Server.prototype.initialize = function (callback) { }; +internals.Server.prototype._validateDeps = function () { + + for (let i = 0; i < this._dependencies.length; ++i) { + const dependency = this._dependencies[i]; + if (dependency.connections) { + for (let j = 0; j < dependency.connections.length; ++j) { + const connection = dependency.connections[j]; + for (let k = 0; k < dependency.deps.length; ++k) { + const dep = dependency.deps[k]; + if (!connection.registrations[dep]) { + return new Error('Plugin ' + dependency.plugin + ' missing dependency ' + dep + ' in connection: ' + connection.info.uri); + } + } + } + } + else { + for (let j = 0; j < dependency.deps.length; ++j) { + const dep = dependency.deps[j]; + if (!this._registrations[dep]) { + return new Error('Plugin ' + dependency.plugin + ' missing dependency ' + dep); + } + } + } + } + + return null; +}; + + internals.Server.prototype._start = function (callback) { this._state = 'starting'; - const each = (connectionItem, next) => connectionItem._start(next); + const each = (connection, next) => connection._start(next); Items.parallel(this.connections, each, (err) => { if (err) { diff --git a/test/plugin.js b/test/plugin.js index 8d46f190d..5dee6ad05 100755 --- a/test/plugin.js +++ b/test/plugin.js @@ -2827,6 +2827,49 @@ describe('Plugin', () => { }); }); }); + + it('errors when missing dependencies on connection added after initialize', (done) => { + + const a = function (srv, options, next) { + + return next(); + }; + + a.attributes = { + name: 'a' + }; + + const b = function (srv, options, next) { + + srv.dependency('a'); + return next(); + }; + + b.attributes = { + name: 'b' + }; + + const server = new Hapi.Server(); + server.connection(); + server.register([a, b], (err) => { + + expect(err).to.not.exist(); + server.initialize((err) => { + + expect(err).to.not.exist(); + const select = server.connection(); + select.register(b, (err) => { + + expect(err).to.not.exist(); + server.start((err) => { + + expect(err).to.be.an.error(`Plugin b missing dependency a in connection: ${select.info.uri}`); + server.stop(done); + }); + }); + }); + }); + }); }); describe('encoder()', () => {