diff --git a/index.js b/index.js index 31c8f0a..959e1ca 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,6 @@ +const peliasConfig = require('pelias-config').generate(); +require('./src/configValidation').validate(peliasConfig); + var createLookupStream = require('./src/lookupStream'); var createWofPipResolver = require('./src/resolversFactory'); diff --git a/package.json b/package.json index d1b0dd4..9365933 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,13 @@ "who's on first" ], "dependencies": { + "joi": "^10.1.0", "lodash": "^4.6.0", "pelias-config": "2.4.0", "pelias-logger": "0.1.0", "pelias-parallel-stream": "0.0.2", "pelias-wof-pip-service": "1.12.0", + "proxyquire": "^1.7.10", "request": "^2.67.0", "through2": "^2.0.0" }, @@ -33,11 +35,12 @@ "event-stream": "^3.3.2", "intercept-stdout": "^0.1.2", "jshint": "^2.8.0", - "precommit-hook": "^3.0.0", "pelias-model": "4.4.0", + "precommit-hook": "^3.0.0", + "proxyquire": "^1.7.10", + "semantic-release": "^6.3.2", "tap-dot": "^1.0.1", - "tape": "^4.2.2", - "semantic-release": "^6.3.2" + "tape": "^4.2.2" }, "pre-commit": [ "lint", diff --git a/src/configValidation.js b/src/configValidation.js new file mode 100644 index 0000000..9466857 --- /dev/null +++ b/src/configValidation.js @@ -0,0 +1,23 @@ +'use strict'; + +const Joi = require('joi'); + +// requires just `maxConcurrentReqs` +const schema = Joi.object().keys({ + imports: { + adminLookup: { + maxConcurrentReqs: Joi.number().integer() + } + } +}).unknown(true); + +module.exports = { + validate: function validate(config) { + Joi.validate(config, schema, { allowUnknown: true }, (err, value) => { + if (err) { + throw new Error(err.details[0].message); + } + }); + } + +}; diff --git a/test/configValidationTest.js b/test/configValidationTest.js new file mode 100644 index 0000000..0cc7442 --- /dev/null +++ b/test/configValidationTest.js @@ -0,0 +1,170 @@ +'use strict'; + +const tape = require('tape'); + +const configValidation = require('../src/configValidation'); +const proxyquire = require('proxyquire').noCallThru(); + +tape('tests configuration scenarios', function(test) { + test.test('missing imports should not throw error', function(t) { + const config = {}; + + t.doesNotThrow(function() { + configValidation.validate(config); + }); + t.end(); + + }); + + test.test('non-object imports should throw error', function(t) { + [null, 17, 'string', [], true].forEach((value) => { + const config = { imports: value }; + + t.throws(function() { + configValidation.validate(config); + }, /"imports" must be an object/); + }); + + t.end(); + + }); + + test.test('missing imports.adminLookup should not throw error', function(t) { + const config = { + imports: { + } + }; + + t.doesNotThrow(function() { + configValidation.validate(config); + }); + t.end(); + + }); + + test.test('non-object imports.adminLookup should throw error', function(t) { + [null, 17, 'string', [], true].forEach((value) => { + const config = { + imports: { + adminLookup: value + } + }; + + t.throws(function() { + configValidation.validate(config); + }, /"adminLookup" must be an object/); + }); + + t.end(); + + }); + + test.test('non-number imports.adminLookup.maxConcurrentReqs should throw error', function(t) { + [null, 'string', {}, [], true].forEach((value) => { + const config = { + imports: { + adminLookup: { + maxConcurrentReqs: value + } + } + }; + + t.throws(function() { + configValidation.validate(config); + }, /"maxConcurrentReqs" must be a number/); + + }); + + t.end(); + + }); + + test.test('non-integer imports.adminLookup.maxConcurrentReqs should throw error', function(t) { + const config = { + imports: { + adminLookup: { + maxConcurrentReqs: 17.3 + } + } + }; + + t.throws(function() { + configValidation.validate(config); + }, /"maxConcurrentReqs" must be an integer/); + + t.end(); + + }); + + test.test('missing imports.adminLookup.maxConcurrentReqs should not throw error', function(t) { + const config = { + imports: { + adminLookup: { + } + } + }; + + t.doesNotThrow(function() { + configValidation.validate(config); + }); + + t.end(); + + }); + + test.test('integer imports.adminLookup.maxConcurrentReqs should not throw error', function(t) { + const config = { + imports: { + adminLookup: { + maxConcurrentReqs: 17 + } + } + }; + + t.doesNotThrow(function() { + configValidation.validate(config); + }); + + t.end(); + + }); + + test.test('unknown properties should not throw errors', function(t) { + const config = { + imports: { + adminLookup: { + maxConcurrentReqs: 17, + unknown_property: 'property value' + } + } + }; + + t.doesNotThrow(function() { + configValidation.validate(config); + }); + + t.end(); + + }); + +}); + +tape('tests for main entry point', function(test) { + test.test('configValidation throwing error should rethrow', function(t) { + const config = {}; + + t.throws(function() { + proxyquire('../index', { + './src/configValidation': { + validate: () => { + throw Error('config is not valid'); + } + } + }); + + configValidation.validate(config); + }, /config is not valid/); + t.end(); + + }); +}); diff --git a/test/test.js b/test/test.js index 61159de..f5f1087 100644 --- a/test/test.js +++ b/test/test.js @@ -1,3 +1,4 @@ +require ('./configValidationTest.js'); require ('./lookupStreamTest.js'); require ('./resolversFactoryTest.js'); require ('./resolversFactoryLocalTest.js');