diff --git a/lib/core/params.js b/lib/core/params.js index 675076fa..39c271d9 100644 --- a/lib/core/params.js +++ b/lib/core/params.js @@ -47,6 +47,8 @@ module.exports = function(Ravel) { Object.assign(defaults, this[symbols.params]); // now defaults contains what we want, so make it this[symbols.params] this[symbols.params] = defaults; + // done! + this[symbols.parametersLoaded] = true; }; /** @@ -91,7 +93,9 @@ module.exports = function(Ravel) { * @return {Object} the parameter value, or undefined if it is not required and not set */ Ravel.prototype.get = function(key) { - if (!this[symbols.knownParameters][key]) { + if (!this[symbols.parametersLoaded]) { + throw new this.ApplicationError.General('Cannot get() parameters until after app.init()'); + } else if (!this[symbols.knownParameters][key]) { throw new this.ApplicationError.NotFound(`Parameter ${key} was requested, but is unknown.`); } else if (this[symbols.knownParameters][key].required && this[symbols.params][key] === undefined) { throw new this.ApplicationError.NotFound( diff --git a/lib/core/symbols.js b/lib/core/symbols.js index 1b003d04..47bc5d94 100644 --- a/lib/core/symbols.js +++ b/lib/core/symbols.js @@ -16,6 +16,7 @@ module.exports = { // methods loadParameters: Symbol.for('_loadParameters()'), + parametersLoaded: Symbol.for('_parametersLoaded()'), moduleInit: Symbol.for('_moduleInit'), resourceInit: Symbol.for('_resourceInit'), routesInit: Symbol.for('_routesInit'), diff --git a/lib/ravel.js b/lib/ravel.js index 2838f7c0..278a765d 100644 --- a/lib/ravel.js +++ b/lib/ravel.js @@ -157,7 +157,9 @@ class Ravel extends EventEmitter { }); // load parameters from .ravelrc file, if any + this.emit('pre load parameters'); this[coreSymbols.loadParameters](); + this.emit('post load parameters'); this[sInitialized] = true; diff --git a/lib/util/log.js b/lib/util/log.js index ae86030c..bdc9ef0a 100644 --- a/lib/util/log.js +++ b/lib/util/log.js @@ -91,7 +91,7 @@ class Log extends Logger { ravelInstance.registerParameter('log level', true); ravelInstance.set('log level', this.DEBUG); //default log level - ravelInstance.once('pre init', function() { + ravelInstance.once('post load parameters', function() { intel.setLevel(logLevels[ravelInstance.get('log level')]); }); } diff --git a/package.json b/package.json index 00176111..733bbeea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ravel", - "version": "0.17.12", + "version": "0.17.13", "author": "Sean McIntyre ", "description": "Ravel Rapid Application Development Framework", "engines": { diff --git a/test/auth/test-authenticate-request.js b/test/auth/test-authenticate-request.js index 20f200e2..5226bf3e 100644 --- a/test/auth/test-authenticate-request.js +++ b/test/auth/test-authenticate-request.js @@ -51,6 +51,7 @@ describe('util/authenticate_request', function() { Ravel.log.setLevel('NONE'); app = koa(); Ravel.kvstore = {}; // mock Ravel.kvstore, since we're not actually starting Ravel. + Ravel[coreSymbols.parametersLoaded] = true; done(); }); diff --git a/test/auth/test-authenticate-token.js b/test/auth/test-authenticate-token.js index 1da3cd64..6a1a1c8a 100644 --- a/test/auth/test-authenticate-token.js +++ b/test/auth/test-authenticate-token.js @@ -8,7 +8,7 @@ chai.use(require('sinon-chai')); const mockery = require('mockery'); const sinon = require('sinon'); -let Ravel, tokenAuth, profile, testProvider; +let Ravel, tokenAuth, profile, testProvider, coreSymbols; describe('auth/authenticate_token', function() { beforeEach((done) => { @@ -31,10 +31,12 @@ describe('auth/authenticate_token', function() { mockery.registerMock('redis', redisMock); Ravel = new (require('../../lib/ravel'))(); + coreSymbols = require('../../lib/core/symbols'); Ravel.log.setLevel(Ravel.log.NONE); Ravel.set('redis port', 0); Ravel.set('redis host', 'localhost'); Ravel.set('redis password', 'password'); + Ravel[coreSymbols.parametersLoaded] = true; Ravel.kvstore = require('../../lib/util/kvstore')(Ravel); tokenAuth = new (require('../../lib/auth/authenticate_token'))(Ravel); @@ -67,6 +69,7 @@ describe('auth/authenticate_token', function() { afterEach((done) => { Ravel = undefined; + coreSymbols = undefined; tokenAuth = undefined; mockery.deregisterAll(); mockery.disable(); diff --git a/test/core/test-params.js b/test/core/test-params.js index 6fecea1e..23c321f0 100644 --- a/test/core/test-params.js +++ b/test/core/test-params.js @@ -40,6 +40,7 @@ describe('Ravel', function() { it('should allow clients to set the value of a parameter', (done) => { Ravel.registerParameter('test param', false); Ravel.set('test param', 'test value'); + Ravel[coreSymbols.parametersLoaded] = true; expect(Ravel.get('test param')).to.equal('test value'); done(); }); @@ -59,12 +60,14 @@ describe('Ravel', function() { it('should allow clients to retrieve the value of a set optional parameter', (done) => { Ravel.registerParameter('test param', false); Ravel.set('test param', 'test value'); + Ravel[coreSymbols.parametersLoaded] = true; expect(Ravel.get('test param')).to.equal('test value'); done(); }); it('should return undefined when clients attempt to retrieve the value of an unset optional parameter', (done) => { Ravel.registerParameter('test param', false); + Ravel[coreSymbols.parametersLoaded] = true; expect(Ravel.get('test param')).to.equal(undefined); done(); }); @@ -72,12 +75,25 @@ describe('Ravel', function() { it('should allow clients to retrieve the value of a set required parameter', (done) => { Ravel.registerParameter('test param', true); Ravel.set('test param', 'test value'); + Ravel[coreSymbols.parametersLoaded] = true; expect(Ravel.get('test param')).to.equal('test value'); done(); }); + it('should throw a Ravel.ApplicationError.General error when clients attempt to retrieve a parameter before loading', (done) => { + try { + Ravel[coreSymbols.parametersLoaded] = false; + Ravel.get('test param'); + done(new Error('Should never reach this line.')); + } catch (err) { + expect(err).to.be.instanceof(Ravel.ApplicationError.General); + done(); + } + }); + it('should throw a Ravel.ApplicationError.NotFound error when clients attempt to retrieve an unregistered parameter', (done) => { try { + Ravel[coreSymbols.parametersLoaded] = true; Ravel.get('test param'); done(new Error('Should never reach this line.')); } catch (err) { @@ -89,6 +105,7 @@ describe('Ravel', function() { it('should throw a Ravel.ApplicationError.NotFound error when clients attempt to retrieve the value of an unset required parameter', (done) => { try { Ravel.registerParameter('test param', true); + Ravel[coreSymbols.parametersLoaded] = true; Ravel.get('test param'); done(new Error('Should never reach this line.')); } catch (err) { diff --git a/test/util/test-kvstore.js b/test/util/test-kvstore.js index 6c6dc809..54310922 100644 --- a/test/util/test-kvstore.js +++ b/test/util/test-kvstore.js @@ -5,7 +5,7 @@ const expect = chai.expect; chai.use(require('chai-things')); const mockery = require('mockery'); -let Ravel, redisClientStub, redisMock; +let Ravel, redisClientStub, redisMock, coreSymbols; describe('Ravel', function() { @@ -26,6 +26,7 @@ describe('Ravel', function() { }; mockery.registerMock('redis', redisMock); Ravel = new (require('../../lib/ravel'))(); + coreSymbols = require('../../lib/core/symbols'); Ravel.log.setLevel(Ravel.log.NONE); Ravel.set('redis port', 0); Ravel.set('redis host', 'localhost'); @@ -35,6 +36,7 @@ describe('Ravel', function() { afterEach((done) => { Ravel = undefined; + coreSymbols = undefined; mockery.deregisterAll();mockery.disable(); done(); }); @@ -52,6 +54,7 @@ describe('Ravel', function() { const retryStrategy = require('../../lib/util/kvstore').retryStrategy(Ravel); expect(retryStrategy).to.be.a('function'); Ravel.set('redis max retries', 10); + Ravel[coreSymbols.parametersLoaded] = true; const options = { error:{code:'something'}, attempt: Ravel.get('redis max retries') + 1 @@ -64,6 +67,7 @@ describe('Ravel', function() { const retryStrategy = require('../../lib/util/kvstore').retryStrategy(Ravel); expect(retryStrategy).to.be.a('function'); Ravel.set('redis max retries', 10); + Ravel[coreSymbols.parametersLoaded] = true; const options = { error:{code:'something'}, attempt: 1 diff --git a/test/util/test-log.js b/test/util/test-log.js index af92fc8f..3309d102 100644 --- a/test/util/test-log.js +++ b/test/util/test-log.js @@ -7,7 +7,7 @@ chai.use(require('sinon-chai')); const sinon = require('sinon'); const mockery = require('mockery'); -let Ravel, intel, intelLogger; +let Ravel, intel, intelLogger, coreSymbols; describe('Ravel.Log', function() { beforeEach((done) => { @@ -55,11 +55,13 @@ describe('Ravel.Log', function() { }; mockery.registerMock('intel', intel); Ravel = new (require('../../lib/ravel'))(); + coreSymbols = require('../../lib/core/symbols'); done(); }); afterEach((done) => { Ravel = undefined; + coreSymbols = undefined; mockery.deregisterAll();mockery.disable(); done(); }); @@ -210,6 +212,9 @@ describe('Ravel.Log', function() { it('should set the default log level on \'start\' if none was specified via Ravel.set(\'log level\')', (done) => { const stub = sinon.stub(intel, 'setLevel'); Ravel.emit('pre init'); + Ravel.emit('pre load parameters'); + Ravel[coreSymbols.parametersLoaded] = true; + Ravel.emit('post load parameters'); expect(stub).to.have.been.calledOnce; expect(stub).to.have.been.calledWith(intel.DEBUG); done(); @@ -219,6 +224,9 @@ describe('Ravel.Log', function() { const stub = sinon.stub(intel, 'setLevel'); Ravel.set('log level', Ravel.log.ERROR); Ravel.emit('pre init'); + Ravel.emit('pre load parameters'); + Ravel[coreSymbols.parametersLoaded] = true; + Ravel.emit('post load parameters'); expect(stub).to.have.been.calledOnce; expect(stub).to.have.been.calledWith(intel.ERROR); done();