Browse Source

Merge pull request #952 from pelias/staging

Merge staging into production
pull/1005/head
Diana Shkolnikov 7 years ago committed by GitHub
parent
commit
09d455ffcf
  1. 7
      README.md
  2. 3
      app.js
  3. 10
      middleware/changeLanguage.js
  4. 9
      package.json
  5. 17
      query/reverse.js
  6. 34
      routes/legacy.js
  7. 6
      routes/v1.js
  8. 32
      sanitizer/_details.js
  9. 5
      sanitizer/_geo_reverse.js
  10. 31
      sanitizer/_location_bias.js
  11. 15
      sanitizer/autocomplete.js
  12. 13
      sanitizer/search.js
  13. 12
      sanitizer/structured_geocoding.js
  14. 8
      schema.js
  15. 51
      test/unit/controller/placeholder.js
  16. 7
      test/unit/fixture/search_boundary_country.js
  17. 10
      test/unit/fixture/search_fallback.js
  18. 10
      test/unit/fixture/search_fallback_postalcode_only.js
  19. 7
      test/unit/fixture/search_linguistic_bbox.js
  20. 7
      test/unit/fixture/search_linguistic_focus.js
  21. 7
      test/unit/fixture/search_linguistic_focus_bbox.js
  22. 7
      test/unit/fixture/search_linguistic_focus_null_island.js
  23. 7
      test/unit/fixture/search_linguistic_only.js
  24. 7
      test/unit/fixture/search_linguistic_viewport.js
  25. 7
      test/unit/fixture/search_linguistic_viewport_min_diagonal.js
  26. 7
      test/unit/fixture/search_with_category_filtering.js
  27. 7
      test/unit/fixture/search_with_source_filtering.js
  28. 7
      test/unit/fixture/structured_geocoding/boundary_country.json
  29. 10
      test/unit/fixture/structured_geocoding/fallback.json
  30. 7
      test/unit/fixture/structured_geocoding/linguistic_bbox.json
  31. 7
      test/unit/fixture/structured_geocoding/linguistic_focus.json
  32. 7
      test/unit/fixture/structured_geocoding/linguistic_focus_bbox.json
  33. 7
      test/unit/fixture/structured_geocoding/linguistic_focus_null_island.json
  34. 7
      test/unit/fixture/structured_geocoding/linguistic_only.json
  35. 7
      test/unit/fixture/structured_geocoding/linguistic_viewport.json
  36. 7
      test/unit/fixture/structured_geocoding/linguistic_viewport_min_diagonal.json
  37. 10
      test/unit/fixture/structured_geocoding/postalcode_only.js
  38. 8
      test/unit/fixture/structured_geocoding/with_source_filtering.json
  39. 84
      test/unit/middleware/changeLanguage.js
  40. 17
      test/unit/query/reverse.js
  41. 1
      test/unit/run.js
  42. 22
      test/unit/sanitizer/_geo_reverse.js
  43. 109
      test/unit/sanitizer/_location_bias.js
  44. 119
      test/unit/sanitizer/autocomplete.js
  45. 1
      test/unit/sanitizer/nearby.js
  46. 1
      test/unit/sanitizer/reverse.js
  47. 23
      test/unit/sanitizer/search.js
  48. 22
      test/unit/sanitizer/structured_geocoding.js
  49. 102
      test/unit/schema.js

7
README.md

@ -42,10 +42,10 @@ The API recognizes the following properties under the top-level `api` key in you
|`host`|*yes*||specifies the url under which the http service is to run|
|`textAnalyzer`|*no*|*addressit*|can be either `libpostal` or `addressit` however will soon be **deprecated** and only `libpostal` will be supported going forward|
|`indexName`|*no*|*pelias*|name of the Elasticsearch index to be used when building queries|
|`legacyUrl`|*no*||the url to redirect to in case the user does not specify a version such as `v1`
|`relativeScores`|*no*|true|if set to true, confidence scores will be normalized, realistically at this point setting this to false is not tested or desirable
|`accessLog`|*no*||name of the format to use for access logs; may be any one of the [predefined values](https://github.com/expressjs/morgan#predefined-formats) in the `morgan` package. Defaults to `"common"`; if set to `false`, or an otherwise falsy value, disables access-logging entirely.|
|`services`|*no*||service definitions for [point-in-polygon](https://github.com/pelias/pip-service) and [placholder](https://github.com/pelias/placeholder) services. If missing (which is not recommended), the point-in-polygon and placeholder services will not be called.|
|`defaultParameters.focus.point.lon` <br> `defaultParameters.focus.point.lat`|no | |default coordinates for focus point
Example configuration file would look something like this:
@ -65,7 +65,6 @@ Example configuration file would look something like this:
"api": {
"host": "localhost:3100/v1/",
"indexName": "foobar",
"legacyUrl": "pelias.mapzen.com",
"relativeScores": true,
"textAnalyzer": "libpostal",
"services": {
@ -76,6 +75,10 @@ Example configuration file would look something like this:
"url": "http://myplaceholderservice.com:5000"
}
}
"defaultParameters": {
"focus.point.lat": 12.121212,
"focus.point.lon": 21.212121
}
},
"interpolation": {
"client": {

3
app.js

@ -16,9 +16,6 @@ app.use( require('./middleware/jsonp') );
/** ----------------------- routes ----------------------- **/
var legacy = require('./routes/legacy');
legacy.addRoutes(app, peliasConfig.api);
var v1 = require('./routes/v1');
v1.addRoutes(app, peliasConfig);

10
middleware/changeLanguage.js

@ -1,6 +1,7 @@
var logger = require( 'pelias-logger' ).get( 'api' );
var service = require('../service/language');
const _ = require('lodash');
/**
example response from language web service:
@ -28,7 +29,6 @@ example response from language web service:
**/
function setup() {
var transport = service.findById();
var middleware = function(req, res, next) {
@ -145,18 +145,18 @@ function updateDocs( req, res, translations ){
if( !translations[id].hasOwnProperty( 'names' ) ){ continue; }
// requested language is not available
if( !translations[id].names.hasOwnProperty( requestLanguage ) ){
logger.info( '[language] [info]', 'missing translation', requestLanguage, id );
if (_.isEmpty(_.get(translations[id].names, requestLanguage, [] ))) {
logger.debug( '[language] [debug]', 'missing translation', requestLanguage, id );
continue;
}
// translate 'parent.*' property
adminValues[i] = translations[id].names[ requestLanguage ];
adminValues[i] = translations[id].names[ requestLanguage ][0];
// if the record is an admin record we also translate
// the 'name.default' property.
if( adminKey === doc.layer ){
doc.name.default = translations[id].names[ requestLanguage ];
doc.name.default = translations[id].names[ requestLanguage ][0];
}
}
}

9
package.json

@ -43,7 +43,6 @@
"elasticsearch": "^12.0.1",
"elasticsearch-exceptions": "0.0.4",
"express": "^4.8.8",
"express-http-proxy": "^0.11.0",
"extend": "^3.0.1",
"geojson": "^0.4.0",
"@mapbox/geojson-extent": "^0.3.1",
@ -59,9 +58,9 @@
"pelias-config": "2.11.0",
"pelias-labels": "1.6.0",
"pelias-logger": "0.2.0",
"pelias-microservice-wrapper": "1.1.2",
"pelias-model": "4.8.1",
"pelias-query": "8.15.0",
"pelias-microservice-wrapper": "1.1.3",
"pelias-model": "5.0.0",
"pelias-query": "8.16.1",
"pelias-sorting": "1.0.1",
"pelias-text-analyzer": "1.8.3",
"predicates": "^1.0.1",
@ -77,7 +76,7 @@
"jshint": "^2.5.6",
"npm-check": "git://github.com/orangejulius/npm-check.git#disable-update-check",
"nsp": "^2.2.0",
"pelias-mock-logger": "1.1.0",
"pelias-mock-logger": "1.1.1",
"precommit-hook": "^3.0.0",
"proxyquire": "^1.7.10",
"semantic-release": "^6.3.2",

17
query/reverse.js

@ -65,13 +65,24 @@ function generateQuery( clean ){
// where point.lan/point.lon are provided in the
// absense of boundary.circle.lat/boundary.circle.lon
if( check.number(clean['boundary.circle.lat']) &&
check.number(clean['boundary.circle.lon']) &&
check.number(clean['boundary.circle.radius']) ){
check.number(clean['boundary.circle.lon']) ){
vs.set({
'boundary:circle:lat': clean['boundary.circle.lat'],
'boundary:circle:lon': clean['boundary.circle.lon'],
'boundary:circle:lon': clean['boundary.circle.lon']
});
if (check.undefined(clean['boundary.circle.radius'])){
// for coarse reverse when boundary circle radius is undefined
vs.set({
'boundary:circle:radius': defaults['boundary:circle:radius']
});
} else if (check.number(clean['boundary.circle.radius'])){
// plain reverse where boundary circle is a valid number
vs.set({
'boundary:circle:radius': clean['boundary.circle.radius'] + 'km'
});
}
logStr += '[param:boundary_circle] ';
}

34
routes/legacy.js

@ -1,34 +0,0 @@
var proxy = require('express-http-proxy');
function addRoutes(app, peliasConfig) {
var sendToLegacy;
if (!peliasConfig.hasOwnProperty('legacyUrl')) {
sendToLegacy = function redirectToV1(req, res, next) {
res.redirect(301, '/v1');
};
}
else {
sendToLegacy = proxy(peliasConfig.legacyUrl);
}
// api root
app.get( '/', sendToLegacy );
// place API
app.get( '/place', sendToLegacy);
// suggest APIs
app.get( '/suggest', sendToLegacy );
app.get( '/suggest/nearby', sendToLegacy );
app.get( '/suggest/coarse',sendToLegacy );
// search APIs
app.get( '/search', sendToLegacy);
app.get( '/search/coarse', sendToLegacy);
// reverse API
app.get( '/reverse', sendToLegacy );
}
module.exports.addRoutes = addRoutes;

6
routes/v1.js

@ -129,7 +129,7 @@ function addRoutes(app, peliasConfig) {
controllers.mdToHTML(peliasConfig.api, './public/attribution.md')
]),
search: createRouter([
sanitizers.search.middleware,
sanitizers.search.middleware(peliasConfig.api),
middleware.requestLanguage,
middleware.calcSize(),
controllers.placeholder(placeholderService, placeholderShouldExecute),
@ -156,7 +156,7 @@ function addRoutes(app, peliasConfig) {
postProc.sendJSON
]),
structured: createRouter([
sanitizers.structured_geocoding.middleware,
sanitizers.structured_geocoding.middleware(peliasConfig.api),
middleware.requestLanguage,
middleware.calcSize(),
controllers.search(peliasConfig.api, esclient, queries.structured_geocoding, not(hasResponseDataOrRequestErrors)),
@ -177,7 +177,7 @@ function addRoutes(app, peliasConfig) {
postProc.sendJSON
]),
autocomplete: createRouter([
sanitizers.autocomplete.middleware,
sanitizers.autocomplete.middleware(peliasConfig.api),
middleware.requestLanguage,
controllers.search(peliasConfig.api, esclient, queries.autocomplete, not(hasResponseDataOrRequestErrors)),
postProc.distances('focus.point.'),

32
sanitizer/_details.js

@ -1,32 +0,0 @@
var _ = require('lodash'),
check = require('check-types');
var DEFAULT_DETAILS_BOOL = true;
// validate inputs, convert types and apply defaults
function sanitize( raw, clean ){
// error & warning messages
var messages = { errors: [], warnings: [] };
if( !check.undefined( raw.details ) ){
clean.details = isTruthy( raw.details );
} else {
clean.details = DEFAULT_DETAILS_BOOL;
}
return messages;
}
// be lenient with 'truthy' values
function isTruthy(val) {
if( check.string( val ) ){
return _.includes( ['true', '1'], val );
}
return val === 1 || val === true;
}
// export function
module.exports = sanitize;

5
sanitizer/_geo_reverse.js

@ -29,11 +29,6 @@ module.exports = function sanitize( raw, clean ){
raw['boundary.circle.lat'] = clean['point.lat'];
raw['boundary.circle.lon'] = clean['point.lon'];
// if no radius was passed, set the default
if ( _.isUndefined( raw['boundary.circle.radius'] ) ) {
raw['boundary.circle.radius'] = defaults['boundary:circle:radius'];
}
// santize the boundary.circle
geo_common.sanitize_circle( 'boundary.circle', clean, raw, CIRCLE_IS_REQUIRED );

31
sanitizer/_location_bias.js

@ -0,0 +1,31 @@
const _ = require('lodash');
/**
Set a focus.lat and focus.lon if specified in pelias config
* @param {object} defaultParameters property of pelias config
*/
function setup(defaultParameters){
return function setLocationBias(raw, clean){
/*
check that:
1. {object} raw exists
2. pelias-config included the properties focus.point.lat and focus.point.lon
3. raw.focus.point.lon and raw.focus.point.lat have not been set
*/
if (!_.isUndefined(raw) &&
!_.isUndefined(defaultParameters['focus.point.lat']) &&
!_.isUndefined(defaultParameters['focus.point.lon']) &&
!_.has(raw, 'focus.point.lon') &&
!_.has(raw, 'focus.point.lat') ) {
raw['focus.point.lat'] = defaultParameters['focus.point.lat'];
raw['focus.point.lon'] = defaultParameters['focus.point.lon'];
}
return { errors: [], warnings: [] };
};
}
// if focus.point.lat and focus.point.lon already exists, don't change
module.exports = setup;

15
sanitizer/autocomplete.js

@ -1,7 +1,9 @@
var type_mapping = require('../helper/type_mapping');
var sanitizeAll = require('../sanitizer/sanitizeAll');
var sanitizeAll = require('../sanitizer/sanitizeAll'),
sanitizers = {
// middleware
module.exports.middleware = (_api_pelias_config) => {
var sanitizers = {
singleScalarParameters: require('../sanitizer/_single_scalar_parameters'),
text: require('../sanitizer/_text_addressit'),
tokenizer: require('../sanitizer/_tokenizer'),
@ -11,6 +13,7 @@ var sanitizeAll = require('../sanitizer/sanitizeAll'),
// depends on the layers and sources sanitizers, must be run after them
sources_and_layers: require('../sanitizer/_sources_and_layers'),
private: require('../sanitizer/_flag_bool')('private', false),
location_bias: require('../sanitizer/_location_bias')(_api_pelias_config.defaultParameters),
geo_autocomplete: require('../sanitizer/_geo_autocomplete'),
boundary_country: require('../sanitizer/_boundary_country'),
categories: require('../sanitizer/_categories')
@ -18,12 +21,7 @@ var sanitizeAll = require('../sanitizer/sanitizeAll'),
var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); };
// export sanitize for testing
module.exports.sanitize = sanitize;
module.exports.sanitizer_list = sanitizers;
// middleware
module.exports.middleware = function( req, res, next ){
return function( req, res, next ){
sanitize( req, function( err, clean ){
if( err ){
res.status(400); // 400 Bad Request
@ -32,3 +30,4 @@ module.exports.middleware = function( req, res, next ){
next();
});
};
};

13
sanitizer/search.js

@ -1,7 +1,8 @@
var type_mapping = require('../helper/type_mapping');
var sanitizeAll = require('../sanitizer/sanitizeAll'),
sanitizers = {
var sanitizeAll = require('../sanitizer/sanitizeAll');
// middleware
module.exports.middleware = (_api_pelias_config) => {
var sanitizers = {
singleScalarParameters: require('../sanitizer/_single_scalar_parameters'),
quattroshapes_deprecation: require('../sanitizer/_deprecate_quattroshapes'),
text: require('../sanitizer/_text'),
@ -13,6 +14,7 @@ var sanitizeAll = require('../sanitizer/sanitizeAll'),
// depends on the layers and sources sanitizers, must be run after them
sources_and_layers: require('../sanitizer/_sources_and_layers'),
private: require('../sanitizer/_flag_bool')('private', false),
location_bias: require('../sanitizer/_location_bias')(_api_pelias_config.defaultParameters),
geo_search: require('../sanitizer/_geo_search'),
boundary_country: require('../sanitizer/_boundary_country'),
categories: require('../sanitizer/_categories'),
@ -22,9 +24,10 @@ var sanitizeAll = require('../sanitizer/sanitizeAll'),
var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); };
// middleware
module.exports.middleware = function( req, res, next ){
return function( req, res, next ){
sanitize( req, function( err, clean ){
next();
});
};
};

12
sanitizer/structured_geocoding.js

@ -1,7 +1,9 @@
var type_mapping = require('../helper/type_mapping');
var sanitizeAll = require('../sanitizer/sanitizeAll');
var sanitizeAll = require('../sanitizer/sanitizeAll'),
sanitizers = {
// middleware
module.exports.middleware = (_api_pelias_config) => {
var sanitizers = {
singleScalarParameters: require('../sanitizer/_single_scalar_parameters'),
quattroshapes_deprecation: require('../sanitizer/_deprecate_quattroshapes'),
synthesize_analysis: require('../sanitizer/_synthesize_analysis'),
@ -13,16 +15,16 @@ var sanitizeAll = require('../sanitizer/sanitizeAll'),
// depends on the layers and sources sanitizers, must be run after them
sources_and_layers: require('../sanitizer/_sources_and_layers'),
private: require('../sanitizer/_flag_bool')('private', false),
location_bias: require('../sanitizer/_location_bias')(_api_pelias_config.defaultParameters),
geo_search: require('../sanitizer/_geo_search'),
boundary_country: require('../sanitizer/_boundary_country'),
categories: require('../sanitizer/_categories')
};
var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); };
// middleware
module.exports.middleware = function( req, res, next ){
return function( req, res, next ){
sanitize( req, function( err, clean ){
next();
});
};
};

8
schema.js

@ -12,14 +12,12 @@ const Joi = require('joi');
// optional:
// * api.accessLog (string)
// * api.relativeScores (boolean)
// * api.legacyUrl (string)
// * api.localization (flipNumberAndStreetCountries is array of 3 character strings)
module.exports = 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(),
requestRetries: Joi.number().integer().min(0),
@ -39,7 +37,11 @@ module.exports = Joi.object().keys({
timeout: Joi.number().integer().optional().default(250).min(0),
retries: Joi.number().integer().optional().default(3).min(0),
}).unknown(false).requiredKeys('url')
}).unknown(false).default({}) // default api.services to an empty object
}).unknown(false).default({}), // default api.services to an empty object
defaultParameters: Joi.object().keys({
'focus.point.lat': Joi.number(),
'focus.point.lon': Joi.number(),
}).unknown(true).default({})
}).requiredKeys('version', 'indexName', 'host').unknown(true),
esclient: Joi.object().keys({

51
test/unit/controller/placeholder.js

@ -287,8 +287,7 @@ module.exports.tests.success = (test, common) => {
'default': 'name 3'
},
population: 4321,
popularity: 8765,
parent: { }
popularity: 8765
}
]
};
@ -352,8 +351,7 @@ module.exports.tests.success = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
}
]
};
@ -413,8 +411,7 @@ module.exports.tests.success = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
}
]
};
@ -472,8 +469,7 @@ module.exports.tests.success = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
}
]
};
@ -538,8 +534,7 @@ module.exports.tests.success = (test, common) => {
},
phrase: {
'default': 'name 2'
},
parent: { }
}
}
]
};
@ -608,8 +603,7 @@ module.exports.tests.success = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
}
]
};
@ -782,8 +776,7 @@ module.exports.tests.result_filtering = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
},
{
_id: '10',
@ -800,8 +793,7 @@ module.exports.tests.result_filtering = (test, common) => {
},
phrase: {
'default': 'name 10'
},
parent: { }
}
}
]
};
@ -968,8 +960,7 @@ module.exports.tests.result_filtering = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
},
{
_id: '10',
@ -986,8 +977,7 @@ module.exports.tests.result_filtering = (test, common) => {
},
phrase: {
'default': 'name 10'
},
parent: { }
}
}
]
};
@ -1107,8 +1097,7 @@ module.exports.tests.result_filtering = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
},
{
_id: '3',
@ -1125,8 +1114,7 @@ module.exports.tests.result_filtering = (test, common) => {
},
phrase: {
'default': 'name 3'
},
parent: { }
}
},
{
_id: '5',
@ -1143,8 +1131,7 @@ module.exports.tests.result_filtering = (test, common) => {
},
phrase: {
'default': 'name 5'
},
parent: { }
}
}
]
};
@ -1567,8 +1554,7 @@ module.exports.tests.geometry_errors = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: {}
}
}
]
};
@ -1628,8 +1614,7 @@ module.exports.tests.centroid_errors = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
}
]
};
@ -1689,8 +1674,7 @@ module.exports.tests.centroid_errors = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
}
]
};
@ -1763,8 +1747,7 @@ module.exports.tests.boundingbox_errors = (test, common) => {
},
phrase: {
'default': 'name 1'
},
parent: { }
}
}
]
};

7
test/unit/fixture/search_boundary_country.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

10
test/unit/fixture/search_fallback.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -828,13 +827,6 @@ module.exports = {
]
}
},
'filter': {
'bool': {
'must': []
}
}
}
},
'max_boost': 20,
'functions': [
{

10
test/unit/fixture/search_fallback_postalcode_only.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -30,13 +29,6 @@ module.exports = {
]
}
},
'filter': {
'bool': {
'must': []
}
}
}
},
'max_boost': 20,
'functions': [
{

7
test/unit/fixture/search_linguistic_bbox.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

7
test/unit/fixture/search_linguistic_focus.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

7
test/unit/fixture/search_linguistic_focus_bbox.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

7
test/unit/fixture/search_linguistic_focus_null_island.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

7
test/unit/fixture/search_linguistic_only.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

7
test/unit/fixture/search_linguistic_viewport.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

7
test/unit/fixture/search_linguistic_viewport_min_diagonal.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

7
test/unit/fixture/search_with_category_filtering.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

7
test/unit/fixture/search_with_source_filtering.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -25,9 +24,7 @@ module.exports = {
}
}
}
]
}
},
],
'filter': {
'bool': {
'must': [

7
test/unit/fixture/structured_geocoding/boundary_country.json

@ -1,13 +1,10 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"should": []
}
},
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [

10
test/unit/fixture/structured_geocoding/fallback.json

@ -1,10 +1,9 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [
{
"bool": {
@ -829,13 +828,6 @@
]
}
},
"filter": {
"bool": {
"must": []
}
}
}
},
"max_boost": 20,
"functions": [
{

7
test/unit/fixture/structured_geocoding/linguistic_bbox.json

@ -1,13 +1,10 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"should": []
}
},
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [

7
test/unit/fixture/structured_geocoding/linguistic_focus.json

@ -1,13 +1,10 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"should": []
}
},
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [

7
test/unit/fixture/structured_geocoding/linguistic_focus_bbox.json

@ -1,13 +1,10 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"should": []
}
},
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [

7
test/unit/fixture/structured_geocoding/linguistic_focus_null_island.json

@ -1,13 +1,10 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"should": []
}
},
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [

7
test/unit/fixture/structured_geocoding/linguistic_only.json

@ -1,13 +1,10 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"should": []
}
},
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [

7
test/unit/fixture/structured_geocoding/linguistic_viewport.json

@ -1,13 +1,10 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"should": []
}
},
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [

7
test/unit/fixture/structured_geocoding/linguistic_viewport_min_diagonal.json

@ -1,13 +1,10 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"should": []
}
},
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [

10
test/unit/fixture/structured_geocoding/postalcode_only.js

@ -1,10 +1,9 @@
module.exports = {
'query': {
'function_score': {
'query': {
'filtered': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
@ -30,13 +29,6 @@ module.exports = {
]
}
},
'filter': {
'bool': {
'must': []
}
}
}
},
'max_boost': 20,
'functions': [
{

8
test/unit/fixture/structured_geocoding/with_source_filtering.json

@ -1,13 +1,11 @@
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"should": []
}
},
"minimum_should_match": 1,
"should": [
],
"filter": {
"bool": {
"must": [

84
test/unit/middleware/changeLanguage.js

@ -2,6 +2,7 @@
var fs = require('fs'),
tmp = require('tmp'),
setup = require('../../../middleware/changeLanguage');
const proxyquire = require('proxyquire').noCallThru();
// load middleware using the default pelias config
var load = function(){
@ -144,7 +145,7 @@ module.exports.tests.hit = function(test, common) {
name: { default: 'London' },
parent: {
locality_id: [ 101735809 ],
locaity: [ 'London' ]
locality: [ 'London' ]
}
}
]};
@ -158,23 +159,23 @@ module.exports.tests.hit = function(test, common) {
cb( null, {
'101750367': {
'names': {
'default':'London',
'chi':'倫敦',
'spa':'Londres',
'eng':'London',
'hin':'लदन',
'ara':'لندن',
'por':'Londres',
'ben':'লনডন',
'rus':'Лондон',
'jpn':'ロンドン',
'kor':'런던'
'default':['London'],
'chi':['倫敦'],
'spa':['Londres'],
'eng':['London'],
'hin':['लदन'],
'ara':['لندن'],
'por':['Londres'],
'ben':['লনডন'],
'rus':['Лондон'],
'jpn':['ロンドン'],
'kor':['런던']
}
},
'101735809': {
'names':{
'default':'London',
'eng':'London'
'default':['London'],
'eng':['London']
}
}
});
@ -195,13 +196,66 @@ module.exports.tests.hit = function(test, common) {
name: { default: 'London' },
parent: {
locality_id: [ 101735809 ],
locaity: [ 'London' ]
locality: [ 'London' ]
}
}
]});
t.end();
});
});
test('empty array name translation should not change the value', t => {
t.plan(2);
const req = { language: { iso6393: 'ISO3 value' } };
const res = {
data: [
{
layer: 'locality',
name: { default: 'original name' },
parent: {
locality_id: [ 123 ],
locality: [ 'original name' ]
}
}
]
};
const changeLanguage = proxyquire('../../../middleware/changeLanguage', {
'../service/language': {
findById: () => ({
query: (ids, callback) => {
t.deepEquals(ids, ['123']);
callback(null, {
'123': {
'names': {
'ISO3 value':[]
}
}
});
}
})
}
})();
changeLanguage(req, res, () => {
t.deepEqual( res, { data: [
{
layer: 'locality',
name: {
default: 'original name'
},
parent: {
locality_id: [ 123 ],
locality: [ 'original name' ]
}
}
]});
});
});
};
module.exports.all = function (tape, common) {

17
test/unit/query/reverse.js

@ -61,6 +61,23 @@ module.exports.tests.query = function(test, common) {
t.end();
});
// for coarse reverse cases where boundary circle radius isn't used
test('undefined radius set to default radius', function(t) {
var query = generate({
'point.lat': 12.12121,
'point.lon': 21.21212,
'boundary.circle.lat': 12.12121,
'boundary.circle.lon': 21.21212
});
var compiled = JSON.parse( JSON.stringify( query ) );
var expected = '1km';
t.deepEqual(compiled.type, 'reverse', 'query type set');
t.deepEqual(compiled.body.query.bool.filter[0].geo_distance.distance, expected, 'distance set to default boundary circle radius');
t.end();
});
test('boundary.circle lat/lon/radius - overrides point.lat/lon when set', function(t) {
var clean = {
'point.lat': 29.49136,

1
test/unit/run.js

@ -64,6 +64,7 @@ var tests = [
require('./sanitizer/_ids'),
require('./sanitizer/_iso2_to_iso3'),
require('./sanitizer/_layers'),
require('./sanitizer/_location_bias'),
require('./sanitizer/_city_name_standardizer'),
require('./sanitizer/_single_scalar_parameters'),
require('./sanitizer/_size'),

22
test/unit/sanitizer/_geo_reverse.js

@ -84,31 +84,11 @@ module.exports.tests.success_conditions = (test, common) => {
});
test('boundary.circle.radius not specified should use default', (t) => {
const raw = {
'point.lat': '12.121212',
'point.lon': '21.212121'
};
const clean = {};
const errorsAndWarnings = sanitize(raw, clean);
t.equals(raw['boundary.circle.lat'], 12.121212);
t.equals(raw['boundary.circle.lon'], 21.212121);
t.equals(raw['boundary.circle.radius'], defaults['boundary:circle:radius'], 'should be from defaults');
t.equals(clean['boundary.circle.lat'], 12.121212);
t.equals(clean['boundary.circle.lon'], 21.212121);
t.equals(clean['boundary.circle.radius'], parseFloat(defaults['boundary:circle:radius']), 'should be same as raw');
t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] });
t.end();
});
};
module.exports.all = (tape, common) => {
function test(name, testFunction) {
return tape(`SANTIZE _geo_reverse ${name}`, testFunction);
return tape(`SANITIZE _geo_reverse ${name}`, testFunction);
}
for( const testCase in module.exports.tests ){

109
test/unit/sanitizer/_location_bias.js

@ -0,0 +1,109 @@
const setup = require('../../../sanitizer/_location_bias');
module.exports.tests = {};
module.exports.tests.setLocationBias = function(test, common) {
test('set focus point', t => {
const defaultParameters = { // specify focus point latitude and longitude
'focus.point.lat': 12.12121212,
'focus.point.lon': 21.21212121
};
const locationBias = setup(defaultParameters);
const raw = {};
const expected = {
'focus.point.lat': 12.12121212,
'focus.point.lon': 21.21212121
};
locationBias(raw, undefined);
t.deepEqual(raw, expected, 'focus point should be set');
t.end();
});
test('undefined raw', t => {
const defaultParameters = {
'focus.point.lat': 12.12121212,
'focus.point.lon': 21.21212121
};
const locationBias = setup(defaultParameters);
locationBias(undefined, undefined);
t.deepEqual(undefined, undefined, 'should be unmodified' );
t.end();
});
test('focusPointLat is undefined', t => {
const defaultParameters = {
'focus.point.lon': 12.2121212
};
const locationBias = setup(defaultParameters);
const raw = {};
const expected = {};
locationBias(raw, undefined);
t.deepEqual(raw, expected, 'should be unmodified' );
t.end();
});
test('focusPointLon is undefined', t => {
const defaultParameters = {
'focus.point.lat': 12.2121212
};
const locationBias = setup(defaultParameters);
const raw = {};
const expected = {};
locationBias(raw, undefined);
t.deepEqual(raw, expected, 'should be unmodified' );
t.end();
});
test('raw has focus.point.lon already', t => {
const defaultParameters = {
'focus.point.lon': 12.2121212,
'focus.point.lat': 12.2121212
};
const locationBias = setup(defaultParameters);
const raw = {
'focus.point.lon': 43.4343434
};
const expected = {
'focus.point.lon': 43.4343434
};
locationBias(raw, undefined);
t.deepEqual(raw, expected, 'should be unmodified' );
t.end();
});
test('raw has focus.point.lat already', t => {
const defaultParameters = {
'focus.point.lon': 12.2121212,
'focus.point.lat': 12.2121212
};
const locationBias = setup(defaultParameters);
const raw = {
'focus.point.lat': 34.3434343
};
const expected = {
'focus.point.lat': 34.3434343
};
locationBias(raw, undefined);
t.deepEqual(raw, expected, 'should be unmodified' );
t.end();
});
};
module.exports.all = (tape, common) => {
function test(name, testFunction) {
return tape(`SANITIZE _location_bias: ${name}`, testFunction);
}
for( var testCase in module.exports.tests ){
module.exports.tests[testCase](test, common);
}
};

119
test/unit/sanitizer/autocomplete.js

@ -1,21 +1,126 @@
var autocomplete = require('../../../sanitizer/autocomplete');
const proxyquire = require('proxyquire').noCallThru();
const _ = require('lodash');
module.exports.tests = {};
module.exports.tests.sanitizers = function(test, common) {
test('check sanitizer list', function (t) {
var expected = [
'singleScalarParameters', 'text', 'tokenizer', 'size', 'layers', 'sources',
'sources_and_layers', 'private', 'geo_autocomplete', 'boundary_country', 'categories'
test('verify that all sanitizers were called as expected', function(t) {
var called_sanitizers = [];
var autocomplete = proxyquire('../../../sanitizer/autocomplete', {
'../sanitizer/_single_scalar_parameters': () => {
called_sanitizers.push('_single_scalar_parameters');
return { errors: [], warnings: [] };
},
'../sanitizer/_text_addressit': () => {
called_sanitizers.push('_text_addressit');
return { errors: [], warnings: [] };
},
'../sanitizer/_tokenizer': () => {
called_sanitizers.push('_tokenizer');
return { errors: [], warnings: [] };
},
'../sanitizer/_size': function() {
if (_.isEqual(_.values(arguments), [10, 10, 10])) {
return () => {
called_sanitizers.push('_size');
return { errors: [], warnings: [] };
};
} else {
throw new Error('incorrect parameters passed to _size');
}
},
'../sanitizer/_targets': (type) => {
if (['layers', 'sources'].indexOf(type) !== -1) {
return () => {
called_sanitizers.push(`_targets/${type}`);
return { errors: [], warnings: [] };
};
}
else {
throw new Error('incorrect parameters passed to _targets');
}
},
'../sanitizer/_sources_and_layers': () => {
called_sanitizers.push('_sources_and_layers');
return { errors: [], warnings: [] };
},
'../sanitizer/_flag_bool': function() {
if (arguments[0] === 'private' && arguments[1] === false) {
return () => {
called_sanitizers.push('_flag_bool');
return { errors: [], warnings: [] };
};
}
else {
throw new Error('incorrect parameters passed to _flag_bool');
}
},
'../sanitizer/_location_bias': (defaultParameters) => {
if (defaultParameters.key === 'value'){
return () => {
called_sanitizers.push('_location_bias');
return { errors: [], warnings: [] };
};
} else {
throw new Error('incorrect parameter passed to _location_bias');
}
},
'../sanitizer/_geo_autocomplete': () => {
called_sanitizers.push('_geo_autocomplete');
return { errors: [], warnings: [] };
},
'../sanitizer/_boundary_country': () => {
called_sanitizers.push('_boundary_country');
return { errors: [], warnings: [] };
},
'../sanitizer/_categories': () => {
called_sanitizers.push('_categories');
return { errors: [], warnings: [] };
},
});
const expected_sanitizers = [
'_single_scalar_parameters',
'_text_addressit',
'_tokenizer',
'_size',
'_targets/layers',
'_targets/sources',
'_sources_and_layers',
'_flag_bool',
'_location_bias',
'_geo_autocomplete',
'_boundary_country',
'_categories'
];
t.deepEqual(Object.keys(autocomplete.sanitizer_list), expected);
const req = {};
const res = {};
const middleware = autocomplete.middleware({
defaultParameters: {
key: 'value'
}
});
middleware(req, res, () => {
t.deepEquals(called_sanitizers, expected_sanitizers);
t.end();
});
});
};
module.exports.all = function (tape, common) {
function test(name, testFunction) {
return tape('SANTIZE /autocomplete ' + name, testFunction);
return tape('SANITIZE /autocomplete ' + name, testFunction);
}
for( var testCase in module.exports.tests ){

1
test/unit/sanitizer/nearby.js

@ -8,7 +8,6 @@ var defaultClean = { 'point.lat': 0,
'point.lon': 0,
'boundary.circle.lat': 0,
'boundary.circle.lon': 0,
'boundary.circle.radius': parseFloat(defaults['boundary:circle:radius']),
size: 10,
private: false
};

1
test/unit/sanitizer/reverse.js

@ -10,7 +10,6 @@ var reverse = require('../../../sanitizer/reverse'),
'point.lon': 0,
'boundary.circle.lat': 0,
'boundary.circle.lon': 0,
'boundary.circle.radius': parseFloat(defaults['boundary:circle:radius']),
size: 10,
private: false
};

23
test/unit/sanitizer/search.js

@ -87,7 +87,18 @@ module.exports.tests.sanitize = (test, common) => {
'../sanitizer/_geonames_warnings': () => {
called_sanitizers.push('_geonames_warnings');
return { errors: [], warnings: [] };
},
'../sanitizer/_location_bias': (defaultParameters) => {
if (defaultParameters.key === 'value'){
return () => {
called_sanitizers.push('_location_bias');
return { errors: [], warnings: [] };
};
} else {
throw new Error('incorrect parameter passed to _location_bias');
}
}
});
const expected_sanitizers = [
@ -101,6 +112,7 @@ module.exports.tests.sanitize = (test, common) => {
'_targets/sources',
'_sources_and_layers',
'_flag_bool',
'_location_bias',
'_geo_search',
'_boundary_country',
'_categories',
@ -110,17 +122,24 @@ module.exports.tests.sanitize = (test, common) => {
const req = {};
const res = {};
search.middleware(req, res, () => {
const middleware = search.middleware({
defaultParameters: {
key: 'value'
}
});
middleware(req, res, () => {
t.deepEquals(called_sanitizers, expected_sanitizers);
t.end();
});
});
};
module.exports.all = (tape, common) => {
function test(name, testFunction) {
return tape(`SANTIZE /search ${name}`, testFunction);
return tape(`SANITIZE /search ${name}`, testFunction);
}
for( const testCase in module.exports.tests ){

22
test/unit/sanitizer/structured_geocoding.js

@ -83,6 +83,16 @@ module.exports.tests.sanitize = function(test, common) {
called_sanitizers.push('_categories');
return { errors: [], warnings: [] };
},
'../sanitizer/_location_bias': function (defaultParameters) {
if (defaultParameters.key === 'value'){
return () => {
called_sanitizers.push('_location_bias');
return { errors: [], warnings: [] };
};
} else {
throw new Error('incorrect parameter passed to _location_bias');
}
}
});
var expected_sanitizers = [
@ -96,6 +106,7 @@ module.exports.tests.sanitize = function(test, common) {
'_targets/sources',
'_sources_and_layers',
'_flag_bool',
'_location_bias',
'_geo_search',
'_boundary_country',
'_categories'
@ -104,17 +115,24 @@ module.exports.tests.sanitize = function(test, common) {
var req = {};
var res = {};
search.middleware(req, res, function(){
const middleware = search.middleware({
defaultParameters: {
key: 'value'
}
});
middleware(req, res, function(){
t.deepEquals(called_sanitizers, expected_sanitizers);
t.end();
});
});
};
module.exports.all = function (tape, common) {
function test(name, testFunction) {
return tape('SANTIZE /structured ' + name, testFunction);
return tape('SANITIZE /structured ' + name, testFunction);
}
for( var testCase in module.exports.tests ){

102
test/unit/schema.js

@ -12,7 +12,6 @@ module.exports.tests.completely_valid = (test, common) => {
version: 'version value',
indexName: 'index name value',
host: 'host value',
legacyUrl: 'legacyUrl value',
accessLog: 'accessLog value',
relativeScores: true,
localization: {
@ -26,6 +25,10 @@ module.exports.tests.completely_valid = (test, common) => {
placeholder: {
url: 'http://locahost'
}
},
defaultParameters: {
'focus.point.lat': 19,
'focus.point.lon': 91
}
},
esclient: {
@ -160,29 +163,6 @@ module.exports.tests.api_validation = (test, common) => {
});
test('non-string api.legacyUrl should throw error', (t) => {
[null, 17, {}, [], true].forEach((value) => {
var config = {
api: {
version: 'version value',
indexName: 'index name value',
host: 'host value',
legacyUrl: value
},
esclient: {}
};
const result = Joi.validate(config, schema);
t.equals(result.error.details.length, 1);
t.equals(result.error.details[0].message, '"legacyUrl" must be a string');
});
t.end();
});
test('non-string api.accessLog should throw error', (t) => {
[null, 17, {}, [], true].forEach((value) => {
var config = {
@ -457,6 +437,80 @@ module.exports.tests.api_validation = (test, common) => {
});
test('non-number defaultParameters.focus.point.lat should throw error', (t) => {
[null, 'string', {}, [], false].forEach((value) => {
const config = {
api: {
version: 'version value',
indexName: 'index name value',
host: 'host value',
defaultParameters: {
'focus.point.lat': value
}
},
esclient: {}
};
const result = Joi.validate(config, schema);
t.equals(result.error.details.length, 1);
t.equals(result.error.details[0].message, '"focus.point.lat" must be a number');
});
t.end();
});
test('non-number defaultParameters.focus.point.lon should throw error', (t) => {
[null, 'string', {}, [], false].forEach((value) => {
const config = {
api: {
version: 'version value',
indexName: 'index name value',
host: 'host value',
defaultParameters: {
'focus.point.lon': value
}
},
esclient: {}
};
const result = Joi.validate(config, schema);
t.equals(result.error.details.length, 1);
t.equals(result.error.details[0].message, '"focus.point.lon" must be a number');
});
t.end();
});
test('non-object api.defaultParameters should throw error', (t) => {
[null, 17, false, [], 'string'].forEach((value) => {
var config = {
api: {
version: 'version value',
indexName: 'index name value',
host: 'host value',
defaultParameters: value
},
esclient: {}
};
const result = Joi.validate(config, schema);
t.equals(result.error.details.length, 1);
t.equals(result.error.details[0].message, '"defaultParameters" must be an object');
});
t.end();
});
};
module.exports.tests.api_services_validation = (test, common) => {

Loading…
Cancel
Save