Skip to content

Commit

Permalink
Validate plugin deps on every connection. Closes #3324
Browse files Browse the repository at this point in the history
  • Loading branch information
hueniverse committed Aug 28, 2016
1 parent 55a1958 commit 43a810f
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 25 deletions.
71 changes: 46 additions & 25 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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'));
}
Expand All @@ -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';
Expand Down Expand Up @@ -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) {
Expand Down
43 changes: 43 additions & 0 deletions test/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()', () => {
Expand Down

0 comments on commit 43a810f

Please sign in to comment.