You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

799 lines
20 KiB

'use strict';
const setup = require('../../../controller/coarse_reverse');
const proxyquire = require('proxyquire').noCallThru();
const _ = require('lodash');
module.exports.tests = {};
module.exports.tests.interface = (test, common) => {
test('valid interface', (t) => {
t.equal(typeof setup, 'function', 'setup is a function');
t.equal(typeof setup(), 'function', 'setup returns a controller');
t.end();
});
};
module.exports.tests.early_exit_conditions = (test, common) => {
test('should_execute returning false should not call service', (t) => {
t.plan(2);
const service = () => {
throw Error('service should not have been called');
};
const controller = setup(service, _.constant(false));
const req = {
clean: {
layers: ['locality']
},
errors: ['error']
};
// verify that next was called
const next = () => {
t.pass('next() was called');
};
// passing res=undefined verifies that it wasn't interacted with
t.doesNotThrow(controller.bind(null, req, undefined, next));
t.end();
});
};
module.exports.tests.error_conditions = (test, common) => {
test('service error should log and call next', (t) => {
t.plan(3);
const service = (req, callback) => {
t.deepEquals(req, { clean: { layers: ['locality'] } } );
callback('this is an error');
};
const logger = require('pelias-mock-logger')();
const controller = proxyquire('../../../controller/coarse_reverse', {
'pelias-logger': logger
})(service, _.constant(true));
const req = {
clean: {
layers: ['locality']
}
};
// verify that next was called
const next = () => {
t.pass('next() was called');
};
// passing res=undefined verifies that it wasn't interacted with
controller(req, undefined, next);
t.ok(logger.isErrorMessage('this is an error'));
t.end();
});
};
module.exports.tests.success_conditions = (test, common) => {
test('service returning results should use first entry for each layer', (t) => {
t.plan(4);
const service = (req, callback) => {
t.deepEquals(req, { clean: { layers: ['neighbourhood'] } } );
const results = {
neighbourhood: [
{
id: 10,
name: 'neighbourhood name',
abbr: 'neighbourhood abbr',
centroid: {
lat: 12.121212,
lon: 21.212121
},
bounding_box: '-76.345902,40.006751,-76.254038,40.072939'
},
{ id: 11, name: 'neighbourhood name 2'}
],
borough: [
{ id: 20, name: 'borough name', abbr: 'borough abbr'},
{ id: 21, name: 'borough name 2'}
],
locality: [
{ id: 30, name: 'locality name', abbr: 'locality abbr'},
{ id: 31, name: 'locality name 2'}
],
localadmin: [
{ id: 40, name: 'localadmin name', abbr: 'localadmin abbr'},
{ id: 41, name: 'localadmin name 2'}
],
county: [
{ id: 50, name: 'county name', abbr: 'county abbr'},
{ id: 51, name: 'county name 2'}
],
macrocounty: [
{ id: 60, name: 'macrocounty name', abbr: 'macrocounty abbr'},
{ id: 61, name: 'macrocounty name 2'}
],
region: [
{ id: 70, name: 'region name', abbr: 'region abbr'},
{ id: 71, name: 'region name 2'}
],
macroregion: [
{ id: 80, name: 'macroregion name', abbr: 'macroregion abbr'},
{ id: 81, name: 'macroregion name 2'}
],
dependency: [
{ id: 90, name: 'dependency name', abbr: 'dependency abbr'},
{ id: 91, name: 'dependency name 2'}
],
country: [
{ id: 100, name: 'country name', abbr: 'xyz'},
{ id: 101, name: 'country name 2'}
]
};
callback(undefined, results);
};
const logger = require('pelias-mock-logger')();
const controller = proxyquire('../../../controller/coarse_reverse', {
'pelias-logger': logger
})(service, _.constant(true));
const req = {
clean: {
layers: ['neighbourhood']
}
};
const res = { };
// verify that next was called
const next = () => {
t.pass('next() was called');
};
controller(req, res, next);
const expected = {
meta: {},
data: [
{
_id: '10',
_type: 'neighbourhood',
layer: 'neighbourhood',
source: 'whosonfirst',
source_id: '10',
name: {
'default': 'neighbourhood name'
},
phrase: {
'default': 'neighbourhood name'
},
parent: {
neighbourhood: ['neighbourhood name'],
neighbourhood_id: ['10'],
neighbourhood_a: ['neighbourhood abbr'],
borough: ['borough name'],
borough_id: ['20'],
borough_a: ['borough abbr'],
locality: ['locality name'],
locality_id: ['30'],
locality_a: ['locality abbr'],
localadmin: ['localadmin name'],
localadmin_id: ['40'],
localadmin_a: ['localadmin abbr'],
county: ['county name'],
county_id: ['50'],
county_a: ['county abbr'],
macrocounty: ['macrocounty name'],
macrocounty_id: ['60'],
macrocounty_a: ['macrocounty abbr'],
region: ['region name'],
region_id: ['70'],
region_a: ['region abbr'],
macroregion: ['macroregion name'],
macroregion_id: ['80'],
macroregion_a: ['macroregion abbr'],
dependency: ['dependency name'],
dependency_id: ['90'],
dependency_a: ['dependency abbr'],
country: ['country name'],
country_id: ['100'],
country_a: ['xyz']
},
center_point: {
lat: 12.121212,
lon: 21.212121
},
bounding_box: '{"min_lat":40.006751,"max_lat":40.072939,"min_lon":-76.345902,"max_lon":-76.254038}'
}
]
};
t.deepEquals(res, expected);
t.notOk(logger.hasErrorMessages());
t.end();
});
test('layers missing from results should be ignored', (t) => {
t.plan(4);
const service = (req, callback) => {
t.deepEquals(req, { clean: { layers: ['neighbourhood'] } } );
const results = {
neighbourhood: [
{
id: 10,
name: 'neighbourhood name',
centroid: {
lat: 12.121212,
lon: 21.212121
},
bounding_box: '-76.345902,40.006751,-76.254038,40.072939'
}
]
};
callback(undefined, results);
};
const logger = require('pelias-mock-logger')();
const controller = proxyquire('../../../controller/coarse_reverse', {
'pelias-logger': logger
})(service, _.constant(true));
const req = {
clean: {
layers: ['neighbourhood']
}
};
const res = { };
// verify that next was called
const next = () => {
t.pass('next() was called');
};
controller(req, res, next);
const expected = {
meta: {},
data: [
{
_id: '10',
_type: 'neighbourhood',
layer: 'neighbourhood',
source: 'whosonfirst',
source_id: '10',
name: {
'default': 'neighbourhood name'
},
phrase: {
'default': 'neighbourhood name'
},
parent: {
neighbourhood: ['neighbourhood name'],
neighbourhood_id: ['10'],
neighbourhood_a: [null]
},
center_point: {
lat: 12.121212,
lon: 21.212121
},
bounding_box: '{"min_lat":40.006751,"max_lat":40.072939,"min_lon":-76.345902,"max_lon":-76.254038}'
}
]
};
t.deepEquals(res, expected);
t.notOk(logger.hasErrorMessages());
t.end();
});
test('most granular layer missing centroid should not set', (t) => {
t.plan(4);
const service = (req, callback) => {
t.deepEquals(req, { clean: { layers: ['neighbourhood'] } } );
const results = {
neighbourhood: [
{
id: 10,
name: 'neighbourhood name',
abbr: 'neighbourhood abbr',
bounding_box: '-76.345902,40.006751,-76.254038,40.072939'
}
]
};
callback(undefined, results);
};
const logger = require('pelias-mock-logger')();
const controller = proxyquire('../../../controller/coarse_reverse', {
'pelias-logger': logger
})(service, _.constant(true));
const req = {
clean: {
layers: ['neighbourhood']
}
};
const res = { };
// verify that next was called
const next = () => {
t.pass('next() was called');
};
controller(req, res, next);
const expected = {
meta: {},
data: [
{
_id: '10',
_type: 'neighbourhood',
layer: 'neighbourhood',
source: 'whosonfirst',
source_id: '10',
name: {
'default': 'neighbourhood name'
},
phrase: {
'default': 'neighbourhood name'
},
parent: {
neighbourhood: ['neighbourhood name'],
neighbourhood_id: ['10'],
neighbourhood_a: ['neighbourhood abbr']
},
bounding_box: '{"min_lat":40.006751,"max_lat":40.072939,"min_lon":-76.345902,"max_lon":-76.254038}'
}
]
};
t.deepEquals(res, expected);
t.notOk(logger.hasErrorMessages());
t.end();
});
test('most granular layer missing bounding_box should not set', (t) => {
t.plan(4);
const service = (req, callback) => {
t.deepEquals(req, { clean: { layers: ['neighbourhood'] } } );
const results = {
neighbourhood: [
{
id: 10,
name: 'neighbourhood name',
abbr: 'neighbourhood abbr',
centroid: {
lat: 12.121212,
lon: 21.212121
}
}
]
};
callback(undefined, results);
};
const logger = require('pelias-mock-logger')();
const controller = proxyquire('../../../controller/coarse_reverse', {
'pelias-logger': logger
})(service, _.constant(true));
const req = {
clean: {
layers: ['neighbourhood']
}
};
const res = { };
// verify that next was called
const next = () => {
t.pass('next() was called');
};
controller(req, res, next);
const expected = {
meta: {},
data: [
{
_id: '10',
_type: 'neighbourhood',
layer: 'neighbourhood',
source: 'whosonfirst',
source_id: '10',
name: {
'default': 'neighbourhood name'
},
phrase: {
'default': 'neighbourhood name'
},
parent: {
neighbourhood: ['neighbourhood name'],
neighbourhood_id: ['10'],
neighbourhood_a: ['neighbourhood abbr']
},
center_point: {
lat: 12.121212,
lon: 21.212121
}
}
]
};
t.deepEquals(res, expected);
t.notOk(logger.hasErrorMessages());
t.end();
});
test('no requested layers should use everything', (t) => {
// this test is used to test coarse reverse fallback for when non-coarse reverse
// was requested but no non-coarse results were found
// by plan'ing the number of tests, we can verify that next() was called w/o
// additional bookkeeping
t.plan(4);
const service = (req, callback) => {
const results = {
neighbourhood: [
{
id: 10,
name: 'neighbourhood name',
abbr: 'neighbourhood abbr'
}
]
};
callback(undefined, results);
};
const logger = require('pelias-mock-logger')();
const controller = proxyquire('../../../controller/coarse_reverse', {
'pelias-logger': logger
})(service, _.constant(true));
const req = {
clean: {
layers: [],
point: {
lat: 12.121212,
lon: 21.212121
}
}
};
const res = { };
// verify that next was called
const next = () => {
t.pass('next() should have been called');
};
controller(req, res, next);
const expected = {
meta: {},
data: [
{
_id: '10',
_type: 'neighbourhood',
layer: 'neighbourhood',
source: 'whosonfirst',
source_id: '10',
name: {
'default': 'neighbourhood name'
},
phrase: {
'default': 'neighbourhood name'
},
parent: {
neighbourhood: ['neighbourhood name'],
neighbourhood_id: ['10'],
neighbourhood_a: ['neighbourhood abbr']
}
}
]
};
t.deepEquals(req.clean.layers, [], 'req.clean.layers should be unmodified');
t.deepEquals(res, expected);
t.notOk(logger.hasErrorMessages());
t.end();
});
test('layers specifying only venue, address, or street should not exclude coarse results', (t) => {
// this test is used to test coarse reverse fallback for when non-coarse reverse
// was requested but no non-coarse results were found
const non_coarse_layers = ['venue', 'address', 'street'];
const tests_per_non_coarse_layer = 4;
// by plan'ing the number of tests, we can verify that next() was called w/o
// additional bookkeeping
t.plan(non_coarse_layers.length * tests_per_non_coarse_layer);
non_coarse_layers.forEach((non_coarse_layer) => {
const service = (req, callback) => {
const results = {
neighbourhood: [
{
id: 10,
name: 'neighbourhood name',
abbr: 'neighbourhood abbr'
}
]
};
callback(undefined, results);
};
const logger = require('pelias-mock-logger')();
const controller = proxyquire('../../../controller/coarse_reverse', {
'pelias-logger': logger
})(service, _.constant(true));
const req = {
clean: {
layers: [non_coarse_layer],
point: {
lat: 12.121212,
lon: 21.212121
}
}
};
const res = { };
// verify that next was called
const next = () => {
t.pass('next() should have been called');
};
controller(req, res, next);
const expected = {
meta: {},
data: [
{
_id: '10',
_type: 'neighbourhood',
layer: 'neighbourhood',
source: 'whosonfirst',
source_id: '10',
name: {
'default': 'neighbourhood name'
},
phrase: {
'default': 'neighbourhood name'
},
parent: {
neighbourhood: ['neighbourhood name'],
neighbourhood_id: ['10'],
neighbourhood_a: ['neighbourhood abbr']
}
}
]
};
t.deepEquals(req.clean.layers, [non_coarse_layer], 'req.clean.layers should be unmodified');
t.deepEquals(res, expected);
t.notOk(logger.hasErrorMessages());
});
t.end();
});
test('layers specifying venue, address, or street AND coarse layer should not exclude coarse results', (t) => {
// this test is used to test coarse reverse fallback for when non-coarse reverse
// was requested but no non-coarse results were found
const non_coarse_layers = ['venue', 'address', 'street'];
const tests_per_non_coarse_layer = 4;
// by plan'ing the number of tests, we can verify that next() was called w/o
// additional bookkeeping
t.plan(non_coarse_layers.length * tests_per_non_coarse_layer);
non_coarse_layers.forEach((non_coarse_layer) => {
const service = (req, callback) => {
const results = {
neighbourhood: [
{
id: 10,
name: 'neighbourhood name',
abbr: 'neighbourhood abbr'
}
]
};
callback(undefined, results);
};
const logger = require('pelias-mock-logger')();
const controller = proxyquire('../../../controller/coarse_reverse', {
'pelias-logger': logger
})(service, _.constant(true));
const req = {
clean: {
layers: [non_coarse_layer, 'neighbourhood'],
point: {
lat: 12.121212,
lon: 21.212121
}
}
};
const res = { };
// verify that next was called
const next = () => {
t.pass('next() should have been called');
};
controller(req, res, next);
const expected = {
meta: {},
data: [
{
_id: '10',
_type: 'neighbourhood',
layer: 'neighbourhood',
source: 'whosonfirst',
source_id: '10',
name: {
'default': 'neighbourhood name'
},
phrase: {
'default': 'neighbourhood name'
},
parent: {
neighbourhood: ['neighbourhood name'],
neighbourhood_id: ['10'],
neighbourhood_a: ['neighbourhood abbr']
}
}
]
};
t.deepEquals(req.clean.layers, [non_coarse_layer, 'neighbourhood'], 'req.clean.layers should be unmodified');
t.deepEquals(res, expected);
t.notOk(logger.hasErrorMessages());
});
t.end();
});
};
module.exports.tests.failure_conditions = (test, common) => {
test('service returning 0 results at the requested layer should return nothing', (t) => {
t.plan(4);
const service = (req, callback) => {
t.deepEquals(req, { clean: { layers: ['neighbourhood'] } } );
// response without neighbourhood results
const results = {
borough: [
{ id: 20, name: 'borough name', abbr: 'borough abbr'},
{ id: 21, name: 'borough name 2'}
],
locality: [
{ id: 30, name: 'locality name', abbr: 'locality abbr'},
{ id: 31, name: 'locality name 2'}
],
localadmin: [
{ id: 40, name: 'localadmin name', abbr: 'localadmin abbr'},
{ id: 41, name: 'localadmin name 2'}
],
county: [
{ id: 50, name: 'county name', abbr: 'county abbr'},
{ id: 51, name: 'county name 2'}
],
macrocounty: [
{ id: 60, name: 'macrocounty name', abbr: 'macrocounty abbr'},
{ id: 61, name: 'macrocounty name 2'}
],
region: [
{ id: 70, name: 'region name', abbr: 'region abbr'},
{ id: 71, name: 'region name 2'}
],
macroregion: [
{ id: 80, name: 'macroregion name', abbr: 'macroregion abbr'},
{ id: 81, name: 'macroregion name 2'}
],
dependency: [
{ id: 90, name: 'dependency name', abbr: 'dependency abbr'},
{ id: 91, name: 'dependency name 2'}
],
country: [
{ id: 100, name: 'country name', abbr: 'xyz'},
{ id: 101, name: 'country name 2'}
]
};
callback(undefined, results);
};
const logger = require('pelias-mock-logger')();
const controller = proxyquire('../../../controller/coarse_reverse', {
'pelias-logger': logger
})(service, _.constant(true));
const req = {
clean: {
layers: ['neighbourhood']
}
};
const res = { };
// verify that next was called
const next = () => {
t.pass('next() was called');
};
controller(req, res, next);
const expected = {
meta: {},
data: []
};
t.deepEquals(res, expected);
t.notOk(logger.hasErrorMessages());
t.end();
});
};
module.exports.all = (tape, common) => {
function test(name, testFunction) {
return tape(`GET /coarse_reverse ${name}`, testFunction);
}
for( const testCase in module.exports.tests ){
module.exports.tests[testCase](test, common);
}
};