mirror of https://github.com/pelias/api.git
Stephen Hess
8 years ago
6 changed files with 523 additions and 5 deletions
@ -0,0 +1,44 @@
|
||||
'use strict'; |
||||
|
||||
const Joi = require('joi'); |
||||
|
||||
// Schema Configuration
|
||||
// required:
|
||||
// * api.version (string)
|
||||
// * api.indexName (string)
|
||||
// * api.host (string)
|
||||
// * esclient (object - positive integer requestTimeout)
|
||||
//
|
||||
// optional:
|
||||
// * api.accessLog (string)
|
||||
// * api.relativeScores (boolean)
|
||||
// * api.legacyUrl (string)
|
||||
// * api.localization (flipNumberAndStreetCountries is array of 3 character strings)
|
||||
const schema = Joi.object().keys({ |
||||
api: Joi.object().keys({ |
||||
version: Joi.string(), |
||||
indexName: Joi.string(), |
||||
host: Joi.string(), |
||||
legacyUrl: Joi.string(), |
||||
accessLog: Joi.string(), |
||||
relativeScores: Joi.boolean(), |
||||
localization: Joi.object().keys({ |
||||
flipNumberAndStreetCountries: Joi.array().items(Joi.string().regex(/^[A-Z]{3}$/)) |
||||
}).unknown(false) |
||||
|
||||
}).requiredKeys('version', 'indexName', 'host').unknown(true), |
||||
esclient: Joi.object().keys({ |
||||
requestTimeout: Joi.number().integer().min(0) |
||||
}).unknown(true) |
||||
}).requiredKeys('api', 'esclient').unknown(true); |
||||
|
||||
module.exports = { |
||||
validate: function validate(config) { |
||||
Joi.validate(config, schema, (err) => { |
||||
if (err) { |
||||
throw new Error(err.details[0].message); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
}; |
@ -0,0 +1,35 @@
|
||||
'use strict'; |
||||
|
||||
const proxyquire = require('proxyquire').noCallThru(); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.invalid_configuration = function(test, common) { |
||||
test('configuration validation throwing error should rethrow', function(t) { |
||||
t.throws(function() { |
||||
proxyquire('../../app', { |
||||
'./src/configValidation': { |
||||
validate: () => { |
||||
throw Error('config is not valid'); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
}, /config is not valid/); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
|
||||
function test(name, testFunction) { |
||||
return tape('app: ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,434 @@
|
||||
'use strict'; |
||||
|
||||
const configValidation = require('../../../src/configValidation'); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.completely_valid = function(test, common) { |
||||
test('all valid configuration elements should not throw error', function(t) { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
legacyUrl: 'legacyUrl value', |
||||
accessLog: 'accessLog value', |
||||
relativeScores: true, |
||||
localization: { |
||||
flipNumberAndStreetCountries: ['ABC', 'DEF'] |
||||
} |
||||
}, |
||||
esclient: { |
||||
requestTimeout: 17 |
||||
} |
||||
}; |
||||
|
||||
t.doesNotThrow(function() { |
||||
configValidation.validate(config); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('basic valid configurtaion should not throw error', function(t) { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value' |
||||
}, |
||||
esclient: { |
||||
requestTimeout: 17 |
||||
} |
||||
}; |
||||
|
||||
t.doesNotThrow(function() { |
||||
configValidation.validate(config); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.tests.api_validation = function(test, common) { |
||||
test('config without api should throw error', function(t) { |
||||
var config = { |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"api" is required/, 'api should exist'); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('config without unknown field in api should not throw error', function(t) { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
unknown: 'unknown value' |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.doesNotThrow(function() { |
||||
configValidation.validate(config); |
||||
}, 'unknown properties should be allowed'); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-string api.version should throw error', function(t) { |
||||
[null, 17, {}, [], true].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: value, |
||||
indexName: 'index name value', |
||||
host: 'host value' |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"version" must be a string/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-string api.indexName should throw error', function(t) { |
||||
[null, 17, {}, [], true].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: value, |
||||
host: 'host value' |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"indexName" must be a string/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-string api.host should throw error', function(t) { |
||||
[null, 17, {}, [], true].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: value |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"host" must be a string/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-string api.legacyUrl should throw error', function(t) { |
||||
[null, 17, {}, [], true].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
legacyUrl: value |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"legacyUrl" must be a string/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-string api.accessLog should throw error', function(t) { |
||||
[null, 17, {}, [], true].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
accessLog: value |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"accessLog" must be a string/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-boolean api.relativeScores should throw error', function(t) { |
||||
[null, 17, {}, [], 'string'].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
relativeScores: value |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"relativeScores" must be a boolean/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-object api.localization should throw error', function(t) { |
||||
[null, 17, false, [], 'string'].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
localization: value |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"localization" must be an object/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('unknown properties in api.localization should throw error', function(t) { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
localization: { |
||||
unknown_property: 'value' |
||||
} |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"unknown_property" is not allowed/); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-array api.localization.flipNumberAndStreetCountries should throw error', function(t) { |
||||
[null, 17, {}, false, 'string'].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
localization: { |
||||
flipNumberAndStreetCountries: value |
||||
} |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"flipNumberAndStreetCountries" must be an array/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-string api.localization.flipNumberAndStreetCountries elements should throw error', function(t) { |
||||
[null, 17, {}, false, []].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
localization: { |
||||
flipNumberAndStreetCountries: [value] |
||||
} |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"0" must be a string/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-3-char api.localization.flipNumberAndStreetCountries elements should throw error', function(t) { |
||||
['AB', 'ABCD'].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value', |
||||
localization: { |
||||
flipNumberAndStreetCountries: [value] |
||||
} |
||||
}, |
||||
esclient: {} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /fails to match the required pattern/); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.tests.esclient_validation = function(test, common) { |
||||
test('config without esclient should throw error', function(t) { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value' |
||||
} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"esclient" is required/, 'esclient should exist'); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('config with non-object esclient should throw error', function(t) { |
||||
[null, 17, [], 'string', true].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value' |
||||
}, |
||||
esclient: value |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"esclient" must be an object/, 'esclient should be an object'); |
||||
|
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('config with non-integer esclient.requestTimeout should throw error', function(t) { |
||||
[null, 'string', {}, [], false].forEach((value) => { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value' |
||||
}, |
||||
esclient: { |
||||
requestTimeout: value |
||||
} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"requestTimeout" must be a number/, 'esclient.requestTimeout should be a number'); |
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('config with non-integer esclient.requestTimeout should throw error', function(t) { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value' |
||||
}, |
||||
esclient: { |
||||
requestTimeout: 17.3 |
||||
} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"requestTimeout" must be an integer/, 'esclient.requestTimeout should be an integer'); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('config with negative esclient.requestTimeout should throw error', function(t) { |
||||
var config = { |
||||
api: { |
||||
version: 'version value', |
||||
indexName: 'index name value', |
||||
host: 'host value' |
||||
}, |
||||
esclient: { |
||||
requestTimeout: -1 |
||||
} |
||||
}; |
||||
|
||||
t.throws(function() { |
||||
configValidation.validate(config); |
||||
}, /"requestTimeout" must be larger than or equal to 0/, 'esclient.requestTimeout must be positive'); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
|
||||
function test(name, testFunction) { |
||||
return tape('configValidation: ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
Loading…
Reference in new issue