mirror of https://github.com/pelias/api.git
Stephen K Hess
8 years ago
committed by
GitHub
12 changed files with 426 additions and 541 deletions
@ -0,0 +1,21 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const url = require('url'); |
||||||
|
|
||||||
|
const _ = require('lodash'); |
||||||
|
|
||||||
|
const ServiceConfiguration = require('pelias-microservice-wrapper').ServiceConfiguration; |
||||||
|
|
||||||
|
class PointInPolygon extends ServiceConfiguration { |
||||||
|
constructor(o) { |
||||||
|
super('pip', o); |
||||||
|
} |
||||||
|
|
||||||
|
getUrl(req) { |
||||||
|
// use resolve to eliminate possibility of duplicate /'s in URL
|
||||||
|
return url.resolve(this.baseUrl, `${req.clean['point.lon']}/${req.clean['point.lat']}`); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
module.exports = PointInPolygon; |
@ -1,86 +0,0 @@ |
|||||||
const logger = require( 'pelias-logger' ).get( 'pointinpolygon' ); |
|
||||||
const request = require('request'); |
|
||||||
const _ = require('lodash'); |
|
||||||
|
|
||||||
function sanitizeUrl(requestUrl) { |
|
||||||
return requestUrl.replace(/^(.+)\/.+\/.+$/, (match, base) => { |
|
||||||
return `${base}/[removed]/[removed]`; |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
function parseErrorMessage(requestUrl, body, do_not_track) { |
|
||||||
if (do_not_track) { |
|
||||||
return `${sanitizeUrl(requestUrl)} returned status 200 but with non-JSON response: ${body}`; |
|
||||||
} |
|
||||||
|
|
||||||
return `${requestUrl} returned status 200 but with non-JSON response: ${body}`; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
function serviceErrorMessage(requestUrl, statusCode, body, do_not_track) { |
|
||||||
if (do_not_track) { |
|
||||||
return `${sanitizeUrl(requestUrl)} returned status ${statusCode}: ${body}`; |
|
||||||
|
|
||||||
} else { |
|
||||||
return `${requestUrl} returned status ${statusCode}: ${body}`; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
module.exports = (url) => { |
|
||||||
if (!_.isEmpty(url)) { |
|
||||||
logger.info(`using point-in-polygon service at ${url}`); |
|
||||||
|
|
||||||
return function pointinpolygon( centroid, do_not_track, callback ) { |
|
||||||
const requestUrl = `${url}/${centroid.lon}/${centroid.lat}`; |
|
||||||
|
|
||||||
const options = { |
|
||||||
method: 'GET', |
|
||||||
url: requestUrl |
|
||||||
}; |
|
||||||
|
|
||||||
if (do_not_track) { |
|
||||||
options.headers = { |
|
||||||
dnt: '1' |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
request(options, (err, response, body) => { |
|
||||||
if (err) { |
|
||||||
logger.error(JSON.stringify(err)); |
|
||||||
callback(err); |
|
||||||
} |
|
||||||
else if (response.statusCode === 200) { |
|
||||||
try { |
|
||||||
const parsed = JSON.parse(body); |
|
||||||
callback(err, parsed); |
|
||||||
} |
|
||||||
catch (err) { |
|
||||||
const parseMsg = parseErrorMessage(requestUrl, body, do_not_track); |
|
||||||
|
|
||||||
logger.error(parseMsg); |
|
||||||
callback(parseMsg); |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
const errorMsg = serviceErrorMessage(requestUrl, response.statusCode, body, do_not_track); |
|
||||||
|
|
||||||
logger.error(errorMsg); |
|
||||||
callback(errorMsg); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
} else { |
|
||||||
logger.warn('point-in-polygon service disabled'); |
|
||||||
|
|
||||||
return (centroid, do_not_track, callback) => { |
|
||||||
callback(`point-in-polygon service disabled, unable to resolve ` + |
|
||||||
(do_not_track ? 'centroid' : JSON.stringify(centroid))); |
|
||||||
}; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
}; |
|
@ -0,0 +1,101 @@ |
|||||||
|
module.exports.tests = {}; |
||||||
|
|
||||||
|
const PointInPolygon = require('../../../../service/configurations/PointInPolygon'); |
||||||
|
|
||||||
|
module.exports.tests.all = (test, common) => { |
||||||
|
test('getName should return \'pip\'', (t) => { |
||||||
|
const configBlob = { |
||||||
|
url: 'http://localhost:1234', |
||||||
|
timeout: 17, |
||||||
|
retries: 19 |
||||||
|
}; |
||||||
|
|
||||||
|
const pointInPolygon = new PointInPolygon(configBlob); |
||||||
|
|
||||||
|
t.equals(pointInPolygon.getName(), 'pip'); |
||||||
|
t.equals(pointInPolygon.getBaseUrl(), 'http://localhost:1234/'); |
||||||
|
t.equals(pointInPolygon.getTimeout(), 17); |
||||||
|
t.equals(pointInPolygon.getRetries(), 19); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('getUrl should return value formatted with point.lon/lat passed to constructor', (t) => { |
||||||
|
const configBlob = { |
||||||
|
url: 'http://localhost:1234' |
||||||
|
}; |
||||||
|
|
||||||
|
const pointInPolygon = new PointInPolygon(configBlob); |
||||||
|
|
||||||
|
const req = { |
||||||
|
clean: { } |
||||||
|
}; |
||||||
|
|
||||||
|
req.clean['point.lon'] = 21.212121; |
||||||
|
req.clean['point.lat'] = 12.121212; |
||||||
|
|
||||||
|
t.equals(pointInPolygon.getUrl(req), 'http://localhost:1234/21.212121/12.121212'); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('getHeaders should return an empty object', (t) => { |
||||||
|
const configBlob = { |
||||||
|
url: 'http://localhost:1234', |
||||||
|
timeout: 17, |
||||||
|
retries: 19 |
||||||
|
}; |
||||||
|
|
||||||
|
const pointInPolygon = new PointInPolygon(configBlob); |
||||||
|
|
||||||
|
t.deepEquals(pointInPolygon.getHeaders(), {}); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('getParameters should return an empty object', (t) => { |
||||||
|
const configBlob = { |
||||||
|
url: 'http://localhost:1234', |
||||||
|
timeout: 17, |
||||||
|
retries: 19 |
||||||
|
}; |
||||||
|
|
||||||
|
const pointInPolygon = new PointInPolygon(configBlob); |
||||||
|
|
||||||
|
t.deepEquals(pointInPolygon.getParameters(), {}); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('baseUrl ending in / should not have double /\'s return by getUrl', (t) => { |
||||||
|
const configBlob = { |
||||||
|
url: 'http://localhost:1234/', |
||||||
|
timeout: 17, |
||||||
|
retries: 19 |
||||||
|
}; |
||||||
|
|
||||||
|
const pointInPolygon = new PointInPolygon(configBlob); |
||||||
|
|
||||||
|
const req = { |
||||||
|
clean: { } |
||||||
|
}; |
||||||
|
|
||||||
|
req.clean['point.lon'] = 21.212121; |
||||||
|
req.clean['point.lat'] = 12.121212; |
||||||
|
|
||||||
|
t.equals(pointInPolygon.getUrl(req), 'http://localhost:1234/21.212121/12.121212'); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.all = (tape, common) => { |
||||||
|
function test(name, testFunction) { |
||||||
|
return tape(`SERVICE CONFIGURATION /PointInPolygon ${name}`, testFunction); |
||||||
|
} |
||||||
|
|
||||||
|
for( var testCase in module.exports.tests ){ |
||||||
|
module.exports.tests[testCase](test, common); |
||||||
|
} |
||||||
|
}; |
@ -1,323 +0,0 @@ |
|||||||
const proxyquire = require('proxyquire').noCallThru(); |
|
||||||
|
|
||||||
const setup = require('../../../service/pointinpolygon'); |
|
||||||
|
|
||||||
module.exports.tests = {}; |
|
||||||
|
|
||||||
module.exports.tests.interface = (test, common) => { |
|
||||||
test('valid interface', (t) => { |
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
var service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
}); |
|
||||||
|
|
||||||
t.equal(typeof service, 'function', 'service is a function'); |
|
||||||
t.end(); |
|
||||||
}); |
|
||||||
}; |
|
||||||
|
|
||||||
module.exports.tests.do_nothing_service = (test, common) => { |
|
||||||
test('undefined PiP uri should return service that logs fact that PiP service is not available', (t) => { |
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
const service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(); |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121 }, false, (err) => { |
|
||||||
t.deepEquals(logger.getWarnMessages(), [ |
|
||||||
'point-in-polygon service disabled' |
|
||||||
]); |
|
||||||
t.equals(err, 'point-in-polygon service disabled, unable to resolve {"lat":12.121212,"lon":21.212121}'); |
|
||||||
t.end(); |
|
||||||
}); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
test('service unavailable message should not output centroid when do_not_track is true', (t) => { |
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
const service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(); |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121 }, true, (err) => { |
|
||||||
t.deepEquals(logger.getWarnMessages(), [ |
|
||||||
'point-in-polygon service disabled' |
|
||||||
]); |
|
||||||
t.equals(err, 'point-in-polygon service disabled, unable to resolve centroid'); |
|
||||||
t.end(); |
|
||||||
}); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
module.exports.tests.success = (test, common) => { |
|
||||||
test('lat and lon should be passed to server', (t) => { |
|
||||||
const pipServer = require('express')(); |
|
||||||
pipServer.get('/:lon/:lat', (req, res, next) => { |
|
||||||
t.equals(req.params.lat, '12.121212'); |
|
||||||
t.equals(req.params.lon, '21.212121'); |
|
||||||
|
|
||||||
res.send('{ "field": "value" }'); |
|
||||||
}); |
|
||||||
|
|
||||||
const server = pipServer.listen(); |
|
||||||
const port = server.address().port; |
|
||||||
|
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
const service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(`http://localhost:${port}`); |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121}, false, (err, results) => { |
|
||||||
t.notOk(err); |
|
||||||
t.deepEquals(results, { field: 'value' }); |
|
||||||
|
|
||||||
t.ok(logger.isInfoMessage(`using point-in-polygon service at http://localhost:${port}`)); |
|
||||||
t.notOk(logger.hasErrorMessages()); |
|
||||||
|
|
||||||
t.end(); |
|
||||||
|
|
||||||
server.close(); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
test('do_not_track=true should pass DNT header', (t) => { |
|
||||||
const pipServer = require('express')(); |
|
||||||
pipServer.get('/:lon/:lat', (req, res, next) => { |
|
||||||
t.ok(req.headers.hasOwnProperty('dnt')); |
|
||||||
t.equals(req.params.lat, '12.121212'); |
|
||||||
t.equals(req.params.lon, '21.212121'); |
|
||||||
|
|
||||||
res.send('{ "field": "value" }'); |
|
||||||
}); |
|
||||||
|
|
||||||
const server = pipServer.listen(); |
|
||||||
const port = server.address().port; |
|
||||||
|
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
const service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(`http://localhost:${port}`); |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121}, true, (err, results) => { |
|
||||||
t.notOk(err); |
|
||||||
t.deepEquals(results, { field: 'value' }); |
|
||||||
|
|
||||||
t.ok(logger.isInfoMessage(`using point-in-polygon service at http://localhost:${port}`)); |
|
||||||
t.notOk(logger.hasErrorMessages()); |
|
||||||
|
|
||||||
t.end(); |
|
||||||
|
|
||||||
server.close(); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
test('do_not_track=false should not pass DNT header', (t) => { |
|
||||||
const pipServer = require('express')(); |
|
||||||
pipServer.get('/:lon/:lat', (req, res, next) => { |
|
||||||
t.notOk(req.headers.hasOwnProperty('dnt')); |
|
||||||
t.equals(req.params.lat, '12.121212'); |
|
||||||
t.equals(req.params.lon, '21.212121'); |
|
||||||
|
|
||||||
res.send('{ "field": "value" }'); |
|
||||||
}); |
|
||||||
|
|
||||||
const server = pipServer.listen(); |
|
||||||
const port = server.address().port; |
|
||||||
|
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
const service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(`http://localhost:${port}`); |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121}, false, (err, results) => { |
|
||||||
t.notOk(err); |
|
||||||
t.deepEquals(results, { field: 'value' }); |
|
||||||
|
|
||||||
t.ok(logger.isInfoMessage(`using point-in-polygon service at http://localhost:${port}`)); |
|
||||||
t.notOk(logger.hasErrorMessages()); |
|
||||||
|
|
||||||
t.end(); |
|
||||||
|
|
||||||
server.close(); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
module.exports.tests.failure = (test, common) => { |
|
||||||
test('server returning success but non-JSON body should log error and return no results', (t) => { |
|
||||||
const pipServer = require('express')(); |
|
||||||
pipServer.get('/:lon/:lat', (req, res, next) => { |
|
||||||
t.equals(req.params.lat, '12.121212'); |
|
||||||
t.equals(req.params.lon, '21.212121'); |
|
||||||
|
|
||||||
res.send('this is not JSON'); |
|
||||||
}); |
|
||||||
|
|
||||||
const server = pipServer.listen(); |
|
||||||
const port = server.address().port; |
|
||||||
|
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
const service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(`http://localhost:${port}`); |
|
||||||
|
|
||||||
const expectedErrorMsg = `http://localhost:${port}/21.212121/12.121212 returned ` + |
|
||||||
`status 200 but with non-JSON response: this is not JSON`; |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121}, false, (err, results) => { |
|
||||||
t.equals(err, expectedErrorMsg); |
|
||||||
t.notOk(results); |
|
||||||
t.ok(logger.isErrorMessage(expectedErrorMsg)); |
|
||||||
t.end(); |
|
||||||
|
|
||||||
server.close(); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
test('server returning 200 & non-JSON body should log sanitized error and return no results when do_not_track', (t) => { |
|
||||||
const pipServer = require('express')(); |
|
||||||
pipServer.get('/:lon/:lat', (req, res, next) => { |
|
||||||
t.equals(req.params.lat, '12.121212'); |
|
||||||
t.equals(req.params.lon, '21.212121'); |
|
||||||
|
|
||||||
res.send('this is not JSON'); |
|
||||||
}); |
|
||||||
|
|
||||||
const server = pipServer.listen(); |
|
||||||
const port = server.address().port; |
|
||||||
|
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
const service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(`http://localhost:${port}`); |
|
||||||
|
|
||||||
const expectedErrorMsg = `http://localhost:${port}/[removed]/[removed] returned ` + |
|
||||||
`status 200 but with non-JSON response: this is not JSON`; |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121}, true, (err, results) => { |
|
||||||
t.equals(err, expectedErrorMsg); |
|
||||||
t.notOk(results); |
|
||||||
t.ok(logger.isErrorMessage(expectedErrorMsg)); |
|
||||||
t.end(); |
|
||||||
|
|
||||||
server.close(); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
test('server returning error should log it and return no results', (t) => { |
|
||||||
const server = require('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/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(`http://localhost:${port}`); |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121}, false, (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('non-OK status should log error and return no results', (t) => { |
|
||||||
const pipServer = require('express')(); |
|
||||||
pipServer.get('/:lat/:lon', (req, res, next) => { |
|
||||||
res.status(400).send('a bad request was made'); |
|
||||||
}); |
|
||||||
|
|
||||||
const server = pipServer.listen(); |
|
||||||
const port = server.address().port; |
|
||||||
|
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
const service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(`http://localhost:${port}`); |
|
||||||
|
|
||||||
const expectedErrorMsg = `http://localhost:${port}/21.212121/12.121212 returned ` + |
|
||||||
`status 400: a bad request was made`; |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121}, false, (err, results) => { |
|
||||||
t.equals(err, expectedErrorMsg); |
|
||||||
t.notOk(results); |
|
||||||
t.ok(logger.isErrorMessage(expectedErrorMsg)); |
|
||||||
t.end(); |
|
||||||
|
|
||||||
server.close(); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
test('non-OK status should log sanitized error and return no results when do_not_track=true', (t) => { |
|
||||||
const pipServer = require('express')(); |
|
||||||
pipServer.get('/:lat/:lon', (req, res, next) => { |
|
||||||
res.status(400).send('a bad request was made'); |
|
||||||
}); |
|
||||||
|
|
||||||
const server = pipServer.listen(); |
|
||||||
const port = server.address().port; |
|
||||||
|
|
||||||
const logger = require('pelias-mock-logger')(); |
|
||||||
|
|
||||||
const service = proxyquire('../../../service/pointinpolygon', { |
|
||||||
'pelias-logger': logger |
|
||||||
})(`http://localhost:${port}`); |
|
||||||
|
|
||||||
const expectedErrorMsg = `http://localhost:${port}/[removed]/[removed] returned ` + |
|
||||||
`status 400: a bad request was made`; |
|
||||||
|
|
||||||
service({ lat: 12.121212, lon: 21.212121}, true, (err, results) => { |
|
||||||
t.equals(err, expectedErrorMsg); |
|
||||||
t.notOk(results); |
|
||||||
t.ok(logger.isErrorMessage(expectedErrorMsg)); |
|
||||||
t.end(); |
|
||||||
|
|
||||||
server.close(); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
module.exports.all = (tape, common) => { |
|
||||||
function test(name, testFunction) { |
|
||||||
return tape(`SERVICE /pointinpolygon ${name}`, testFunction); |
|
||||||
} |
|
||||||
|
|
||||||
for( var testCase in module.exports.tests ){ |
|
||||||
module.exports.tests[testCase](test, common); |
|
||||||
} |
|
||||||
}; |
|
Loading…
Reference in new issue