mirror of https://github.com/pelias/api.git
Browse Source
Adds a controller, service (which could probably be made more generic and share with pointinpolygon), and predicates for determining when placeholder should be called. This also renames `is_pip_service_enabled.js` to `is_service_enabled.js` since it's generic. If placeholder returns a non-empty response then `res.data` is populated, otherwise `res.data` is not populated, allowing fallback to existing production behavior.pull/850/head
Stephen Hess
8 years ago
12 changed files with 826 additions and 17 deletions
@ -0,0 +1,73 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const _ = require('lodash'); |
||||||
|
|
||||||
|
const logger = require('pelias-logger').get('api'); |
||||||
|
const logging = require( '../helper/logging' ); |
||||||
|
const Document = require('pelias-model').Document; |
||||||
|
|
||||||
|
function synthesizeDocs(result) { |
||||||
|
return result.lineage.map((hierarchy) => { |
||||||
|
const doc = new Document('whosonfirst', result.placetype, result.id.toString()); |
||||||
|
doc.setName('default', result.name); |
||||||
|
doc.setCentroid( { lat: result.geom.lat, lon: result.geom.lon } ); |
||||||
|
|
||||||
|
const parsedBoundingBox = result.geom.bbox.split(',').map(parseFloat); |
||||||
|
doc.setBoundingBox({ |
||||||
|
upperLeft: { |
||||||
|
lat: parsedBoundingBox[3], |
||||||
|
lon: parsedBoundingBox[0] |
||||||
|
}, |
||||||
|
lowerRight: { |
||||||
|
lat: parsedBoundingBox[1], |
||||||
|
lon: parsedBoundingBox[2] |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
Object.keys(hierarchy) |
||||||
|
.filter(doc.isSupportedParent) |
||||||
|
.filter((placetype) => { return !_.isEmpty(_.trim(hierarchy[placetype].name)); } ) |
||||||
|
.forEach((placetype) => { |
||||||
|
if (hierarchy[placetype].hasOwnProperty('abbr') && placetype === 'country') { |
||||||
|
doc.setAlpha3(hierarchy[placetype].abbr); |
||||||
|
} |
||||||
|
|
||||||
|
doc.addParent( |
||||||
|
placetype, |
||||||
|
hierarchy[placetype].name, |
||||||
|
hierarchy[placetype].id.toString(), |
||||||
|
hierarchy[placetype].abbr); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
const esDoc = doc.toESDocument(); |
||||||
|
esDoc.data._id = esDoc._id; |
||||||
|
esDoc.data._type = esDoc._type; |
||||||
|
|
||||||
|
return esDoc.data; |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
function setup(placeholderService, should_execute) { |
||||||
|
function controller( req, res, next ){ |
||||||
|
if (!should_execute(req, res)) { |
||||||
|
return next(); |
||||||
|
} |
||||||
|
|
||||||
|
placeholderService.search(req.clean.text, req.clean.lang.iso6393, (err, results) => { |
||||||
|
res.meta = {}; |
||||||
|
res.data = _.flatten(results.map((result) => { |
||||||
|
return synthesizeDocs(result); |
||||||
|
})); |
||||||
|
|
||||||
|
return next(); |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
return controller; |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = setup; |
@ -0,0 +1,13 @@ |
|||||||
|
const _ = require('lodash'); |
||||||
|
|
||||||
|
module.exports = (request, response) => { |
||||||
|
if (!request.clean.hasOwnProperty('parsed_text')) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// return true only if all non-admin properties of parsed_text are empty
|
||||||
|
return ['number', 'street', 'query', 'category'].every((prop) => { |
||||||
|
return _.isEmpty(request.clean.parsed_text[prop]); |
||||||
|
}); |
||||||
|
|
||||||
|
}; |
@ -1,7 +0,0 @@ |
|||||||
module.exports = (uri) => { |
|
||||||
// this predicate relies upon the fact that the schema has already validated
|
|
||||||
// that api.pipService is a URI-formatted string
|
|
||||||
return (request, response) => { |
|
||||||
return uri !== undefined; |
|
||||||
}; |
|
||||||
}; |
|
@ -0,0 +1,5 @@ |
|||||||
|
module.exports = (uri) => { |
||||||
|
return (request, response) => { |
||||||
|
return uri !== undefined; |
||||||
|
}; |
||||||
|
}; |
@ -0,0 +1,62 @@ |
|||||||
|
const request = require('request'); |
||||||
|
const bl = require('bl'); |
||||||
|
const _ = require('lodash'); |
||||||
|
|
||||||
|
const logger = require( 'pelias-logger' ).get( 'placeholder' ); |
||||||
|
|
||||||
|
module.exports = function setup(url) { |
||||||
|
if (_.isEmpty(url)) { |
||||||
|
logger.warn('placeholder service disabled'); |
||||||
|
|
||||||
|
return { |
||||||
|
search: (text, lang, callback) => { |
||||||
|
callback(`placeholder service disabled`); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
logger.info(`using placeholder service at ${url}`); |
||||||
|
return { |
||||||
|
search: (text, lang, callback) => { |
||||||
|
const requestUrl = `${url}/search?text=${text}&lang=${lang}`; |
||||||
|
|
||||||
|
request |
||||||
|
.get(requestUrl) |
||||||
|
.on('response', (response) => { |
||||||
|
// pipe the response thru bl which will accumulate the entire body
|
||||||
|
response.pipe(bl((err, data) => { |
||||||
|
if (response.statusCode === 200) { |
||||||
|
// parse and return w/o error unless response wasn't JSON
|
||||||
|
try { |
||||||
|
const parsed = JSON.parse(data); |
||||||
|
return callback(null, parsed); |
||||||
|
} |
||||||
|
catch (err) { |
||||||
|
logger.error(`${encodeURI(requestUrl)} could not parse response: ${data}`); |
||||||
|
return callback(`${encodeURI(requestUrl)} could not parse response: ${data}`); |
||||||
|
} |
||||||
|
} |
||||||
|
else if (response.statusCode === 404) { |
||||||
|
// placeholder returns a 404 when no results are found which
|
||||||
|
// should be handled differently since it's technically not an error
|
||||||
|
logger.debug(`returned 0 results for '${text}'`); |
||||||
|
return callback(null, []); |
||||||
|
} |
||||||
|
else { |
||||||
|
// otherwise there was a non-200/404 status so handle generically
|
||||||
|
logger.error(`${encodeURI(requestUrl)} returned status ${response.statusCode}: ${data}`); |
||||||
|
return callback(`${encodeURI(requestUrl)} returned status ${response.statusCode}: ${data}`); |
||||||
|
} |
||||||
|
})); |
||||||
|
|
||||||
|
}) |
||||||
|
.on('error', (err) => { |
||||||
|
logger.error(JSON.stringify(err)); |
||||||
|
callback(err); |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
}; |
@ -0,0 +1,378 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const placeholder = require('../../../controller/placeholder'); |
||||||
|
const proxyquire = require('proxyquire').noCallThru(); |
||||||
|
|
||||||
|
module.exports.tests = {}; |
||||||
|
|
||||||
|
module.exports.tests.interface = (test, common) => { |
||||||
|
test('valid interface', (t) => { |
||||||
|
t.equal(typeof placeholder, 'function', 'placeholder is a function'); |
||||||
|
t.equal(typeof placeholder(), 'function', 'placeholder returns a controller'); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.should_execute_failure = function(test, common) { |
||||||
|
test('should_execute returning false should return without calling service', (t) => { |
||||||
|
let placeholderService_was_called = false; |
||||||
|
|
||||||
|
const placeholderService = { |
||||||
|
search: () => { |
||||||
|
placeholderService_was_called = true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const should_execute = (req, res) => { |
||||||
|
// req and res should be passed to should_execute
|
||||||
|
t.deepEquals(req, { a: 1 }); |
||||||
|
t.deepEquals(res, { b: 2 }); |
||||||
|
return false; |
||||||
|
}; |
||||||
|
|
||||||
|
const controller = placeholder(placeholderService, should_execute); |
||||||
|
|
||||||
|
const req = { a: 1 }; |
||||||
|
const res = { b: 2 }; |
||||||
|
|
||||||
|
controller(req, res, () => { |
||||||
|
t.notOk(placeholderService_was_called); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.success = function(test, common) { |
||||||
|
test('should_execute returning true should call service', (t) => { |
||||||
|
let placeholderService_was_called = false; |
||||||
|
|
||||||
|
const placeholderService = { |
||||||
|
search: (text, language, callback) => { |
||||||
|
t.equals(text, 'query value'); |
||||||
|
t.equals(language, 'language value'); |
||||||
|
placeholderService_was_called = true; |
||||||
|
callback(null, []); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const should_execute = (req, res) => { |
||||||
|
return true; |
||||||
|
}; |
||||||
|
|
||||||
|
const controller = placeholder(placeholderService, should_execute); |
||||||
|
|
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
text: 'query value', |
||||||
|
lang: { |
||||||
|
iso6393: 'language value' |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
const res = { b: 2 }; |
||||||
|
|
||||||
|
controller(req, res, () => { |
||||||
|
t.ok(placeholderService_was_called); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('response from service should be converted', (t) => { |
||||||
|
let placeholderService_was_called = false; |
||||||
|
|
||||||
|
const placeholder_response = [ |
||||||
|
{ |
||||||
|
id: 123, |
||||||
|
name: 'name 1', |
||||||
|
placetype: 'neighbourhood', |
||||||
|
lineage: [ |
||||||
|
{ |
||||||
|
country: { |
||||||
|
id: 1, |
||||||
|
name: 'country name 1' |
||||||
|
}, |
||||||
|
dependency: { |
||||||
|
id: 2, |
||||||
|
name: 'dependency name 1' |
||||||
|
}, |
||||||
|
macroregion: { |
||||||
|
id: 3, |
||||||
|
name: 'macroregion name 1' |
||||||
|
}, |
||||||
|
region: { |
||||||
|
id: 4, |
||||||
|
name: 'region name 1' |
||||||
|
}, |
||||||
|
macrocounty: { |
||||||
|
id: 5, |
||||||
|
name: 'macrocounty name 1' |
||||||
|
}, |
||||||
|
county: { |
||||||
|
id: 6, |
||||||
|
name: 'county name 1' |
||||||
|
}, |
||||||
|
localadmin: { |
||||||
|
id: 7, |
||||||
|
name: 'localadmin name 1' |
||||||
|
}, |
||||||
|
locality: { |
||||||
|
id: 8, |
||||||
|
name: 'locality name 1' |
||||||
|
}, |
||||||
|
borough: { |
||||||
|
id: 9, |
||||||
|
name: 'borough name 1' |
||||||
|
}, |
||||||
|
neighbourhood: { |
||||||
|
id: 10, |
||||||
|
name: 'neighbourhood name 1' |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
country: { |
||||||
|
id: 11, |
||||||
|
name: 'country name 2', |
||||||
|
abbr: 'XYZ' |
||||||
|
}, |
||||||
|
dependency: { |
||||||
|
id: 12, |
||||||
|
name: 'dependency name 2', |
||||||
|
abbr: 'dependency abbr 2' |
||||||
|
}, |
||||||
|
macroregion: { |
||||||
|
id: 13, |
||||||
|
name: 'macroregion name 2', |
||||||
|
abbr: 'macroregion abbr 2' |
||||||
|
}, |
||||||
|
region: { |
||||||
|
id: 14, |
||||||
|
name: 'region name 2', |
||||||
|
abbr: 'region abbr 2' |
||||||
|
}, |
||||||
|
macrocounty: { |
||||||
|
id: 15, |
||||||
|
name: 'macrocounty name 2', |
||||||
|
abbr: 'macrocounty abbr 2' |
||||||
|
}, |
||||||
|
county: { |
||||||
|
id: 16, |
||||||
|
name: 'county name 2', |
||||||
|
abbr: 'county abbr 2' |
||||||
|
}, |
||||||
|
localadmin: { |
||||||
|
id: 17, |
||||||
|
name: 'localadmin name 2', |
||||||
|
abbr: 'localadmin abbr 2' |
||||||
|
}, |
||||||
|
locality: { |
||||||
|
id: 18, |
||||||
|
name: 'locality name 2', |
||||||
|
abbr: 'locality abbr 2' |
||||||
|
}, |
||||||
|
borough: { |
||||||
|
id: 19, |
||||||
|
name: 'borough name 2', |
||||||
|
abbr: 'borough abbr 2' |
||||||
|
}, |
||||||
|
neighbourhood: { |
||||||
|
id: 20, |
||||||
|
name: 'neighbourhood name 2', |
||||||
|
abbr: 'neighbourhood abbr 2' |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
geom: { |
||||||
|
area: 12.34, |
||||||
|
bbox: '21.212121,12.121212,31.313131,13.131313', |
||||||
|
lat: 14.141414, |
||||||
|
lon: 41.414141 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 456, |
||||||
|
name: 'name 3', |
||||||
|
placetype: 'locality', |
||||||
|
lineage: [ {} ], |
||||||
|
geom: { |
||||||
|
area: 23.45, |
||||||
|
bbox: '51.515151,15.151515,61.616161,16.161616', |
||||||
|
lat: 17.171717, |
||||||
|
lon: 71.717171 |
||||||
|
} |
||||||
|
} |
||||||
|
]; |
||||||
|
|
||||||
|
const placeholderService = { |
||||||
|
search: (text, language, callback) => { |
||||||
|
t.equals(text, 'query value'); |
||||||
|
t.equals(language, 'language value'); |
||||||
|
placeholderService_was_called = true; |
||||||
|
callback(null, placeholder_response); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const should_execute = (req, res) => { |
||||||
|
return true; |
||||||
|
}; |
||||||
|
|
||||||
|
const controller = placeholder(placeholderService, should_execute); |
||||||
|
|
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
text: 'query value', |
||||||
|
lang: { |
||||||
|
iso6393: 'language value' |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
const res = { }; |
||||||
|
|
||||||
|
const expected_res = { |
||||||
|
meta: {}, |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
_id: '123', |
||||||
|
_type: 'neighbourhood', |
||||||
|
layer: 'neighbourhood', |
||||||
|
source: 'whosonfirst', |
||||||
|
source_id: '123', |
||||||
|
center_point: { |
||||||
|
lat: 14.141414, |
||||||
|
lon: 41.414141 |
||||||
|
}, |
||||||
|
bounding_box: '{"min_lat":12.121212,"max_lat":13.131313,"min_lon":21.212121,"max_lon":31.313131}', |
||||||
|
name: { |
||||||
|
'default': 'name 1' |
||||||
|
}, |
||||||
|
phrase: { |
||||||
|
'default': 'name 1' |
||||||
|
}, |
||||||
|
parent: { |
||||||
|
neighbourhood: ['neighbourhood name 1'], |
||||||
|
neighbourhood_id: ['10'], |
||||||
|
neighbourhood_a: [null], |
||||||
|
borough: ['borough name 1'], |
||||||
|
borough_id: ['9'], |
||||||
|
borough_a: [null], |
||||||
|
locality: ['locality name 1'], |
||||||
|
locality_id: ['8'], |
||||||
|
locality_a: [null], |
||||||
|
localadmin: ['localadmin name 1'], |
||||||
|
localadmin_id: ['7'], |
||||||
|
localadmin_a: [null], |
||||||
|
county: ['county name 1'], |
||||||
|
county_id: ['6'], |
||||||
|
county_a: [null], |
||||||
|
macrocounty: ['macrocounty name 1'], |
||||||
|
macrocounty_id: ['5'], |
||||||
|
macrocounty_a: [null], |
||||||
|
region: ['region name 1'], |
||||||
|
region_id: ['4'], |
||||||
|
region_a: [null], |
||||||
|
macroregion: ['macroregion name 1'], |
||||||
|
macroregion_id: ['3'], |
||||||
|
macroregion_a: [null], |
||||||
|
dependency: ['dependency name 1'], |
||||||
|
dependency_id: ['2'], |
||||||
|
dependency_a: [null], |
||||||
|
country: ['country name 1'], |
||||||
|
country_id: ['1'], |
||||||
|
country_a: [null] |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
_id: '123', |
||||||
|
_type: 'neighbourhood', |
||||||
|
layer: 'neighbourhood', |
||||||
|
source: 'whosonfirst', |
||||||
|
source_id: '123', |
||||||
|
center_point: { |
||||||
|
lat: 14.141414, |
||||||
|
lon: 41.414141 |
||||||
|
}, |
||||||
|
bounding_box: '{"min_lat":12.121212,"max_lat":13.131313,"min_lon":21.212121,"max_lon":31.313131}', |
||||||
|
name: { |
||||||
|
'default': 'name 1' |
||||||
|
}, |
||||||
|
phrase: { |
||||||
|
'default': 'name 1' |
||||||
|
}, |
||||||
|
alpha3: 'XYZ', |
||||||
|
parent: { |
||||||
|
neighbourhood: ['neighbourhood name 2'], |
||||||
|
neighbourhood_id: ['20'], |
||||||
|
neighbourhood_a: ['neighbourhood abbr 2'], |
||||||
|
borough: ['borough name 2'], |
||||||
|
borough_id: ['19'], |
||||||
|
borough_a: ['borough abbr 2'], |
||||||
|
locality: ['locality name 2'], |
||||||
|
locality_id: ['18'], |
||||||
|
locality_a: ['locality abbr 2'], |
||||||
|
localadmin: ['localadmin name 2'], |
||||||
|
localadmin_id: ['17'], |
||||||
|
localadmin_a: ['localadmin abbr 2'], |
||||||
|
county: ['county name 2'], |
||||||
|
county_id: ['16'], |
||||||
|
county_a: ['county abbr 2'], |
||||||
|
macrocounty: ['macrocounty name 2'], |
||||||
|
macrocounty_id: ['15'], |
||||||
|
macrocounty_a: ['macrocounty abbr 2'], |
||||||
|
region: ['region name 2'], |
||||||
|
region_id: ['14'], |
||||||
|
region_a: ['region abbr 2'], |
||||||
|
macroregion: ['macroregion name 2'], |
||||||
|
macroregion_id: ['13'], |
||||||
|
macroregion_a: ['macroregion abbr 2'], |
||||||
|
dependency: ['dependency name 2'], |
||||||
|
dependency_id: ['12'], |
||||||
|
dependency_a: ['dependency abbr 2'], |
||||||
|
country: ['country name 2'], |
||||||
|
country_id: ['11'], |
||||||
|
country_a: ['XYZ'] |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
_id: '456', |
||||||
|
_type: 'locality', |
||||||
|
layer: 'locality', |
||||||
|
source: 'whosonfirst', |
||||||
|
source_id: '456', |
||||||
|
center_point: { |
||||||
|
lat: 17.171717, |
||||||
|
lon: 71.717171 |
||||||
|
}, |
||||||
|
bounding_box: '{"min_lat":15.151515,"max_lat":16.161616,"min_lon":51.515151,"max_lon":61.616161}', |
||||||
|
name: { |
||||||
|
'default': 'name 3' |
||||||
|
}, |
||||||
|
phrase: { |
||||||
|
'default': 'name 3' |
||||||
|
}, |
||||||
|
parent: { } |
||||||
|
} |
||||||
|
] |
||||||
|
}; |
||||||
|
|
||||||
|
controller(req, res, () => { |
||||||
|
t.ok(placeholderService_was_called); |
||||||
|
t.deepEquals(res, expected_res); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.all = function (tape, common) { |
||||||
|
|
||||||
|
function test(name, testFunction) { |
||||||
|
return tape('GET /placeholder ' + name, testFunction); |
||||||
|
} |
||||||
|
|
||||||
|
for( const testCase in module.exports.tests ){ |
||||||
|
module.exports.tests[testCase](test, common); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,77 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const _ = require('lodash'); |
||||||
|
const is_admin_only_analysis = require('../../../../controller/predicates/is_admin_only_analysis'); |
||||||
|
|
||||||
|
module.exports.tests = {}; |
||||||
|
|
||||||
|
module.exports.tests.interface = (test, common) => { |
||||||
|
test('valid interface', (t) => { |
||||||
|
t.equal(typeof is_admin_only_analysis, 'function', 'is_admin_only_analysis is a function'); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.true_conditions = (test, common) => { |
||||||
|
test('parsed_text with admin-only properties should return true', (t) => { |
||||||
|
['neighbourhood', 'borough', 'city', 'county', 'state', 'postalcode', 'country'].forEach((property) => { |
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
parsed_text: {} |
||||||
|
} |
||||||
|
}; |
||||||
|
const res = {}; |
||||||
|
|
||||||
|
req.clean.parsed_text[property] = `${property} value`; |
||||||
|
|
||||||
|
t.ok(is_admin_only_analysis(req, res)); |
||||||
|
|
||||||
|
}); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.false_conditions = (test, common) => { |
||||||
|
test('req.clean with no parsed_text should return false', (t) => { |
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
} |
||||||
|
}; |
||||||
|
const res = {}; |
||||||
|
|
||||||
|
t.notOk(is_admin_only_analysis(req, res)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('parsed_text with non-admin properties should return false', (t) => { |
||||||
|
['number', 'street', 'query', 'category'].forEach((property) => { |
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
parsed_text: {} |
||||||
|
} |
||||||
|
}; |
||||||
|
const res = {}; |
||||||
|
|
||||||
|
req.clean.parsed_text[property] = `${property} value`; |
||||||
|
|
||||||
|
t.notOk(is_admin_only_analysis(req, res)); |
||||||
|
|
||||||
|
}); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.all = (tape, common) => { |
||||||
|
function test(name, testFunction) { |
||||||
|
return tape(`GET /is_admin_only_analysis ${name}`, testFunction); |
||||||
|
} |
||||||
|
|
||||||
|
for( const testCase in module.exports.tests ){ |
||||||
|
module.exports.tests[testCase](test, common); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,193 @@ |
|||||||
|
const proxyquire = require('proxyquire').noCallThru(); |
||||||
|
const express = require('express'); |
||||||
|
|
||||||
|
const setup = require('../../../service/placeholder'); |
||||||
|
|
||||||
|
module.exports.tests = {}; |
||||||
|
|
||||||
|
module.exports.tests.interface = (test, common) => { |
||||||
|
test('valid interface', (t) => { |
||||||
|
const logger = require('pelias-mock-logger')(); |
||||||
|
|
||||||
|
var service = proxyquire('../../../service/placeholder', { |
||||||
|
'pelias-logger': logger |
||||||
|
}); |
||||||
|
|
||||||
|
t.equal(typeof service, 'function', 'service is a function'); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.do_nothing_service = (test, common) => { |
||||||
|
test('undefined url should return service that logs fact that placeholder service is not available', (t) => { |
||||||
|
const logger = require('pelias-mock-logger')(); |
||||||
|
|
||||||
|
const service = proxyquire('../../../service/placeholder', { |
||||||
|
'pelias-logger': logger |
||||||
|
})(); |
||||||
|
|
||||||
|
service.search('search text', 'search lang', (err) => { |
||||||
|
t.deepEquals(logger.getWarnMessages(), [ |
||||||
|
'placeholder service disabled' |
||||||
|
]); |
||||||
|
t.equals(err, 'placeholder service disabled'); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.failure_conditions = (test, common) => { |
||||||
|
test('server returning error should log it and return no results', (t) => { |
||||||
|
const server = express().listen(); |
||||||
|
const port = server.address().port; |
||||||
|
|
||||||
|
// immediately close the server so to ensure an error response
|
||||||
|
server.close(); |
||||||
|
|
||||||
|
const logger = require('pelias-mock-logger')(); |
||||||
|
|
||||||
|
const service = proxyquire('../../../service/placeholder', { |
||||||
|
'pelias-logger': logger |
||||||
|
})(`http://localhost:${port}`); |
||||||
|
|
||||||
|
service.search('search text', 'search lang', (err, results) => { |
||||||
|
t.equals(err.code, 'ECONNREFUSED'); |
||||||
|
t.notOk(results); |
||||||
|
t.ok(logger.isErrorMessage(/ECONNREFUSED/), 'there should be a connection refused error message'); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
server.close(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('server returning non-200/404 response should log error and return no results', (t) => { |
||||||
|
const placeholderServer = express(); |
||||||
|
placeholderServer.get('/search', (req, res, next) => { |
||||||
|
res.status(400).send('a bad request was made'); |
||||||
|
}); |
||||||
|
|
||||||
|
const server = placeholderServer.listen(); |
||||||
|
const port = server.address().port; |
||||||
|
|
||||||
|
const logger = require('pelias-mock-logger')(); |
||||||
|
|
||||||
|
const service = proxyquire('../../../service/placeholder', { |
||||||
|
'pelias-logger': logger |
||||||
|
})(`http://localhost:${port}`); |
||||||
|
|
||||||
|
service.search('search text', 'search lang', (err, results) => { |
||||||
|
t.equals(err, `http://localhost:${port}/search?text=search%20text&lang=search%20lang returned status 400: a bad request was made`); |
||||||
|
t.notOk(results); |
||||||
|
t.ok(logger.isErrorMessage(`http://localhost:${port}/search?text=search%20text&lang=search%20lang ` + |
||||||
|
`returned status 400: a bad request was made`)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
server.close(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('server returning 404 statusCode should log debug message and return no error or results', (t) => { |
||||||
|
const placeholderServer = express(); |
||||||
|
placeholderServer.get('/search', (req, res, next) => { |
||||||
|
res.status(404).send('no results found'); |
||||||
|
}); |
||||||
|
|
||||||
|
const server = placeholderServer.listen(); |
||||||
|
const port = server.address().port; |
||||||
|
|
||||||
|
const logger = require('pelias-mock-logger')(); |
||||||
|
|
||||||
|
const service = proxyquire('../../../service/placeholder', { |
||||||
|
'pelias-logger': logger |
||||||
|
})(`http://localhost:${port}`); |
||||||
|
|
||||||
|
service.search('search text', 'search lang', (err, results) => { |
||||||
|
t.notOk(err); |
||||||
|
t.deepEquals(results, [], 'should return an empty array'); |
||||||
|
t.ok(logger.isDebugMessage('returned 0 results for \'search text\'')); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
server.close(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('server returning 200 statusCode but with non-JSON response should log error and return undefined', (t) => { |
||||||
|
const placeholderServer = express(); |
||||||
|
placeholderServer.get('/search', (req, res, next) => { |
||||||
|
res.status(200).send('this is not parseable as JSON'); |
||||||
|
}); |
||||||
|
|
||||||
|
const server = placeholderServer.listen(); |
||||||
|
const port = server.address().port; |
||||||
|
|
||||||
|
const logger = require('pelias-mock-logger')(); |
||||||
|
|
||||||
|
const service = proxyquire('../../../service/placeholder', { |
||||||
|
'pelias-logger': logger |
||||||
|
})(`http://localhost:${port}`); |
||||||
|
|
||||||
|
service.search('search text', 'search lang', (err, results) => { |
||||||
|
t.equals(err, `http://localhost:${port}/search?text=search%20text&lang=search%20lang ` + |
||||||
|
`could not parse response: this is not parseable as JSON`); |
||||||
|
t.notOk(results, 'should return undefined'); |
||||||
|
t.ok(logger.isErrorMessage(`http://localhost:${port}/search?text=search%20text&lang=search%20lang ` + |
||||||
|
`could not parse response: this is not parseable as JSON`)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
server.close(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.success_conditions = (test, common) => { |
||||||
|
test('server returning statusCode 200 should return no error and parsed output', (t) => { |
||||||
|
const placeholderServer = express(); |
||||||
|
placeholderServer.get('/search', (req, res, next) => { |
||||||
|
if (req.query.text === 'search text' && req.query.lang === 'search lang') { |
||||||
|
res.status(200).send('[1, 2, 3]'); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
const server = placeholderServer.listen(); |
||||||
|
const port = server.address().port; |
||||||
|
|
||||||
|
const logger = require('pelias-mock-logger')(); |
||||||
|
|
||||||
|
const service = proxyquire('../../../service/placeholder', { |
||||||
|
'pelias-logger': logger |
||||||
|
})(`http://localhost:${port}`); |
||||||
|
|
||||||
|
service.search('search text', 'search lang', (err, results) => { |
||||||
|
t.notOk(err, 'should be no error'); |
||||||
|
t.deepEquals(results, [1, 2, 3]); |
||||||
|
t.notOk(logger.hasErrorMessages()); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
server.close(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.all = (tape, common) => { |
||||||
|
function test(name, testFunction) { |
||||||
|
return tape(`SERVICE /placeholder ${name}`, testFunction); |
||||||
|
} |
||||||
|
|
||||||
|
for( var testCase in module.exports.tests ){ |
||||||
|
module.exports.tests[testCase](test, common); |
||||||
|
} |
||||||
|
}; |
Loading…
Reference in new issue