From c10e8225bb1e50a7540b037e17e62246a37c857f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Fri, 22 Mar 2019 13:54:38 +0100 Subject: [PATCH] fix: set `app.booting` flag immediately Before this change, `app.booting` was set by Application plugin as part of regular phase invocation, which executes individual plugins in subsequent turns of the event loop. As a result, `app.booting` was initially `undefined` despite the fact that the booting process was already in progress. This patch moves manipulation of `app.booting` flag directly to `Bootstrapper#run` method, to ensure it's set early enough and always properly cleared at the end. --- lib/bootstrapper.js | 9 +++++++ lib/plugins/application.js | 2 -- test/acceptance.test.js | 40 +++++++++++++++++++++++++++++ test/fixtures/empty-app/config.json | 2 ++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 test/acceptance.test.js create mode 100644 test/fixtures/empty-app/config.json diff --git a/lib/bootstrapper.js b/lib/bootstrapper.js index 4aaef57..dd8cc43 100644 --- a/lib/bootstrapper.js +++ b/lib/bootstrapper.js @@ -202,11 +202,20 @@ Bootstrapper.prototype.run = function(context, done) { context = context || {}; var phases = context.phases || this.phases; + + if (phases.includes('starting') || phases.includes('start')) { + context.app.booting = true; + } + var bootPlugins = this.getExtensions('/boot'); async.eachSeries(phases, function(phase, done) { debug('Phase %s', phase); async.eachSeries(bootPlugins, pluginIteratorFactory(context, phase), done); }, function(err) { + if (phases.includes('started')) { + context.app.booting = false; + } + return done(err, context); }); return done.promise; diff --git a/lib/plugins/application.js b/lib/plugins/application.js index 72684da..d04ce82 100644 --- a/lib/plugins/application.js +++ b/lib/plugins/application.js @@ -116,7 +116,6 @@ function applyAppConfig(app, appConfig) { Application.prototype.starting = function(context) { var app = context.app; - app.booting = true; assertLoopBackVersion(app); var appConfig = context.instructions.application; @@ -129,7 +128,6 @@ Application.prototype.starting = function(context) { Application.prototype.started = function(context, done) { var app = context.app; - app.booting = false; process.nextTick(function() { app.emit('booted'); done(); diff --git a/test/acceptance.test.js b/test/acceptance.test.js new file mode 100644 index 0000000..7f53747 --- /dev/null +++ b/test/acceptance.test.js @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2015,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +var path = require('path'); +var loopback = require('loopback'); + +var chai = require('chai'); +var dirtyChai = require('dirty-chai'); +var expect = chai.expect; +chai.use(dirtyChai); + +const bootLoopBackApp = require('..'); + +describe('bootLoopBackApp', function() { + var app; + beforeEach(function() { + app = loopback(); + }); + + it('sets app.booting immediately', function() { + const appDir = path.join(__dirname, './fixtures/empty-app'); + + // Start the bootstrapper + const promise = bootLoopBackApp(app, appDir); + + // Still in the original turn of the event loop, + // verify that the app is signalling "boot in progress" + expect(app.booting).to.equal(true); + + // Wait for bootstrapper to finish + return promise.then(() => { + // Verify that app is signalling "boot has finished" + expect(app.booting).to.equal(false); + }); + }); +}); diff --git a/test/fixtures/empty-app/config.json b/test/fixtures/empty-app/config.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/test/fixtures/empty-app/config.json @@ -0,0 +1,2 @@ +{ +}