diff --git a/controller/placeholder.js b/controller/placeholder.js index 0d00b1b8..8e97765b 100644 --- a/controller/placeholder.js +++ b/controller/placeholder.js @@ -86,19 +86,19 @@ function atLeastOneLineageMatchesBoundaryCountry(boundaryCountry, result) { // return a function that detects if a result has at least one lineage in boundary.country // if there's no boundary.country, return a function that always returns true -function getBoundaryCountryFilter(clean) { - if (_.has(clean, 'boundary.country')) { +function getBoundaryCountryFilter(clean, geometric_filters_apply) { + if (_.has(clean, 'boundary.country') && geometric_filters_apply) { return _.partial(atLeastOneLineageMatchesBoundaryCountry, clean['boundary.country']); } - return _.constant(true); + return () => true; } // return a function that detects if a result is inside a bbox if a bbox is available // if there's no bbox, return a function that always returns true -function getBoundaryRectangleFilter(clean) { - if (['min_lat', 'min_lon', 'max_lat', 'max_lon'].every((f) => { +function getBoundaryRectangleFilter(clean, geometric_filters_apply) { + if (geometric_filters_apply && ['min_lat', 'min_lon', 'max_lat', 'max_lon'].every((f) => { return _.has(clean, `boundary.rect.${f}`); })) { const polygon = [ @@ -113,14 +113,14 @@ function getBoundaryRectangleFilter(clean) { } - return _.constant(true); + return () => true; } // return a function that detects if a result is inside a circle if a circle is available // if there's no circle, return a function that always returns true -function getBoundaryCircleFilter(clean) { - if (['lat', 'lon', 'radius'].every((f) => { +function getBoundaryCircleFilter(clean, geometric_filters_apply) { + if (geometric_filters_apply && ['lat', 'lon', 'radius'].every((f) => { return _.has(clean, `boundary.circle.${f}`); })) { const center = { @@ -134,7 +134,7 @@ function getBoundaryCircleFilter(clean) { } - return _.constant(true); + return () => true; } @@ -213,7 +213,7 @@ function buildESDoc(doc) { return _.extend(esDoc.data, { _id: esDoc._id, _type: esDoc._type }); } -function setup(placeholderService, should_execute) { +function setup(placeholderService, geometric_filters_apply, should_execute) { function controller( req, res, next ){ // bail early if req/res don't pass conditions for execution if (!should_execute(req, res)) { @@ -226,7 +226,7 @@ function setup(placeholderService, should_execute) { req.errors.push( _.get(err, 'message', err)); } else { - const boundaryCountry = _.get(req, ['clean', 'boundary.country']); + const boundaryCountry = geometric_filters_apply ? _.get(req, ['clean', 'boundary.country']) : undefined; // convert results to ES docs // boundary.country filter must happen after synthesis since multiple @@ -241,13 +241,13 @@ function setup(placeholderService, should_execute) { // filter out results that don't match on requested layer(s) .filter(getLayersFilter(req.clean)) // filter out results that don't match on any lineage country - .filter(getBoundaryCountryFilter(req.clean)) + .filter(getBoundaryCountryFilter(req.clean, geometric_filters_apply)) // clean up geom.lat/lon for boundary rect/circle checks .map(numberifyGeomLatLon) // filter out results that aren't in the boundary.rect - .filter(getBoundaryRectangleFilter(req.clean)) + .filter(getBoundaryRectangleFilter(req.clean, geometric_filters_apply)) // filter out results that aren't in the boundary.circle - .filter(getBoundaryCircleFilter(req.clean)) + .filter(getBoundaryCircleFilter(req.clean, geometric_filters_apply)) // convert results to ES docs .map(_.partial(synthesizeDocs, boundaryCountry)); diff --git a/controller/predicates/is_single_field_analysis.js b/controller/predicates/is_single_field_analysis.js new file mode 100644 index 00000000..7e5f3c66 --- /dev/null +++ b/controller/predicates/is_single_field_analysis.js @@ -0,0 +1,5 @@ +const _ = require('lodash'); + +// predicate that determines if parsed_text contains only the supplied property +module.exports = property => (req, res) => + _.isEqual(_.keys(_.get(req, ['clean', 'parsed_text'])), [property]); diff --git a/routes/v1.js b/routes/v1.js index 18cc39b7..a232c92c 100644 --- a/routes/v1.js +++ b/routes/v1.js @@ -36,8 +36,8 @@ var controllers = { }; var queries = { - libpostal: require('../query/search'), - fallback_to_old_prod: require('../query/search_original'), + cascading_fallback: require('../query/search'), + very_old_prod: require('../query/search_original'), structured_geocoding: require('../query/structured_geocoding'), reverse: require('../query/reverse'), autocomplete: require('../query/autocomplete'), @@ -74,6 +74,7 @@ const hasRequestErrors = require('../controller/predicates/has_request_errors'); const isCoarseReverse = require('../controller/predicates/is_coarse_reverse'); const isAdminOnlyAnalysis = require('../controller/predicates/is_admin_only_analysis'); const hasResultsAtLayers = require('../controller/predicates/has_results_at_layers'); +const isSingleFieldAnalysis = require('../controller/predicates/is_single_field_analysis'); // shorthand for standard early-exit conditions const hasResponseDataOrRequestErrors = any(hasResponseData, hasRequestErrors); @@ -110,13 +111,33 @@ function addRoutes(app, peliasConfig) { isPipServiceEnabled, not(hasRequestErrors), not(hasResponseData) ); - const placeholderShouldExecute = all( + // execute placeholder if libpostal only parsed as admin-only and needs to + // be geodisambiguated + const placeholderGeodisambiguationShouldExecute = all( + not(hasResponseDataOrRequestErrors), + isPlaceholderServiceEnabled, + isAdminOnlyAnalysis, + not(isSingleFieldAnalysis('postalcode')) + ); + + // execute placeholder if libpostal identified address parts but ids need to + // be looked up for admin parts + const placeholderIdsLookupShouldExecute = all( not(hasResponseDataOrRequestErrors), isPlaceholderServiceEnabled, // don't run placeholder if there's a number but no street not(hasNumberButNotStreet), // don't run placeholder if there's a query or category - not(hasAnyParsedTextProperty('query', 'category')) + not(hasAnyParsedTextProperty('query', 'category')), + not(isSingleFieldAnalysis('postalcode')) + ); + + // placeholder should have executed, useful for determining whether to actually + // fallback or not (don't fallback to old search if the placeholder response + // should be honored as is) + const placeholderShouldHaveExecuted = any( + placeholderGeodisambiguationShouldExecute, + placeholderIdsLookupShouldExecute ); const searchWithIdsShouldExecute = all( @@ -127,6 +148,14 @@ function addRoutes(app, peliasConfig) { hasAnyParsedTextProperty('street') ); + // don't execute the cascading fallback query IF placeholder should have executed + // that way, if placeholder didn't return anything, don't try to find more things the old way + const fallbackQueryShouldExecute = all( + not(hasRequestErrors), + not(hasResponseData), + not(placeholderShouldHaveExecuted) + ); + // execute under the following conditions: // - there are no errors or data // - request is not coarse OR pip service is disabled @@ -138,6 +167,10 @@ function addRoutes(app, peliasConfig) { ) ); + // helpers to replace vague booleans + const geometricFiltersApply = true; + const geometricFiltersDontApply = false; + var base = '/v1/'; /** ------------------------- routers ------------------------- **/ @@ -153,13 +186,14 @@ function addRoutes(app, peliasConfig) { sanitizers.search.middleware(peliasConfig.api), middleware.requestLanguage, middleware.calcSize(), - controllers.placeholder(placeholderService, placeholderShouldExecute), + controllers.placeholder(placeholderService, geometricFiltersApply, placeholderGeodisambiguationShouldExecute), + controllers.placeholder(placeholderService, geometricFiltersDontApply, placeholderIdsLookupShouldExecute), controllers.search_with_ids(peliasConfig.api, esclient, queries.address_using_ids, searchWithIdsShouldExecute), - // 3rd parameter is which query module to use, use fallback/geodisambiguation + // 3rd parameter is which query module to use, use fallback // first, then use original search strategy if first query didn't return anything - controllers.search(peliasConfig.api, esclient, queries.libpostal, not(hasResponseDataOrRequestErrors)), + controllers.search(peliasConfig.api, esclient, queries.cascading_fallback, fallbackQueryShouldExecute), sanitizers.search_fallback.middleware, - controllers.search(peliasConfig.api, esclient, queries.fallback_to_old_prod, not(hasResponseDataOrRequestErrors)), + controllers.search(peliasConfig.api, esclient, queries.very_old_prod, fallbackQueryShouldExecute), postProc.trimByGranularity(), postProc.distances('focus.point.'), postProc.confidenceScores(peliasConfig.api), diff --git a/test/unit/controller/placeholder.js b/test/unit/controller/placeholder.js index bbe30464..efb0fc2a 100644 --- a/test/unit/controller/placeholder.js +++ b/test/unit/controller/placeholder.js @@ -30,7 +30,7 @@ module.exports.tests.should_execute = (test, common) => { return false; }; - const controller = placeholder(placeholder_service, should_execute); + const controller = placeholder(placeholder_service, true, should_execute); const req = { a: 1 }; const res = { b: 2 }; @@ -52,7 +52,7 @@ module.exports.tests.should_execute = (test, common) => { callback(null, []); }; - const controller = placeholder(placeholder_service, _.constant(true)); + const controller = placeholder(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { b: 2 }; @@ -206,7 +206,7 @@ module.exports.tests.success = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -324,7 +324,7 @@ module.exports.tests.success = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -387,7 +387,7 @@ module.exports.tests.success = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -447,7 +447,7 @@ module.exports.tests.success = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -512,7 +512,7 @@ module.exports.tests.success = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -577,7 +577,7 @@ module.exports.tests.success = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -742,7 +742,7 @@ module.exports.tests.result_filtering = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value', @@ -804,6 +804,141 @@ module.exports.tests.result_filtering = (test, common) => { }); + test('when geometric_filters_apply is false, boundary.rect should not apply', (t) => { + const logger = require('pelias-mock-logger')(); + + const placeholder_service = (req, callback) => { + t.deepEqual(req, { + param1: 'param1 value', + clean: { + 'boundary.rect.min_lat': -1, + 'boundary.rect.max_lat': 1, + 'boundary.rect.min_lon': -1, + 'boundary.rect.max_lon': 1 + } + }); + + const response = [ + { + // inside bbox + id: 1, + name: 'name 1', + placetype: 'neighbourhood', + geom: { + lat: 0, + lon: 0 + } + }, + { + // outside bbox + id: 2, + name: 'name 2', + placetype: 'neighbourhood', + geom: { + lat: -2, + lon: 2 + } + }, + { + // outside bbox + id: 3, + name: 'name 3', + placetype: 'neighbourhood', + geom: { + lat: 2, + lon: -2 + } + } + ]; + + callback(null, response); + }; + + const should_execute = (req, res) => { + return true; + }; + + const controller = proxyquire('../../../controller/placeholder', { + 'pelias-logger': logger + })(placeholder_service, false, () => true); + + const req = { + param1: 'param1 value', + clean: { + 'boundary.rect.min_lat': -1, + 'boundary.rect.max_lat': 1, + 'boundary.rect.min_lon': -1, + 'boundary.rect.max_lon': 1 + } + }; + const res = { }; + + controller(req, res, () => { + const expected_res = { + meta: { + query_type: 'fallback' + }, + data: [ + { + _id: '1', + _type: 'neighbourhood', + layer: 'neighbourhood', + source: 'whosonfirst', + source_id: '1', + center_point: { + lat: 0, + lon: 0 + }, + name: { + 'default': 'name 1' + }, + phrase: { + 'default': 'name 1' + } + }, + { + _id: '2', + _type: 'neighbourhood', + layer: 'neighbourhood', + source: 'whosonfirst', + source_id: '2', + center_point: { + lat: -2, + lon: 2 + }, + name: { + 'default': 'name 2' + }, + phrase: { + 'default': 'name 2' + } + }, + { + _id: '3', + _type: 'neighbourhood', + layer: 'neighbourhood', + source: 'whosonfirst', + source_id: '3', + center_point: { + lat: 2, + lon: -2 + }, + name: { + 'default': 'name 3' + }, + phrase: { + 'default': 'name 3' + } + } + ] + }; + + t.deepEquals(res, expected_res); + t.end(); + }); + + }); + test('when boundary.circle is available, results outside of it should be removed', (t) => { const logger = require('pelias-mock-logger')(); @@ -927,7 +1062,7 @@ module.exports.tests.result_filtering = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value', @@ -988,6 +1123,139 @@ module.exports.tests.result_filtering = (test, common) => { }); + test('when geometric_filters_apply is false, boundary.circle should not apply', (t) => { + const logger = require('pelias-mock-logger')(); + + const placeholder_service = (req, callback) => { + t.deepEqual(req, { + param1: 'param1 value', + clean: { + 'boundary.circle.lat': 0, + 'boundary.circle.lon': 0, + 'boundary.circle.radius': 500 + } + }); + + const response = [ + { + // inside circle + id: 1, + name: 'name 1', + placetype: 'neighbourhood', + geom: { + lat: 1, + lon: 1 + } + }, + { + // outside circle on +lon + id: 2, + name: 'name 2', + placetype: 'neighbourhood', + geom: { + lat: -45, + lon: 45 + } + }, + { + // outside bbox on +lat + id: 3, + name: 'name 3', + placetype: 'neighbourhood', + geom: { + lat: 45, + lon: -45 + } + } + ]; + + callback(null, response); + }; + + const should_execute = (req, res) => { + return true; + }; + + const controller = proxyquire('../../../controller/placeholder', { + 'pelias-logger': logger + })(placeholder_service, false, () => true); + + const req = { + param1: 'param1 value', + clean: { + 'boundary.circle.lat': 0, + 'boundary.circle.lon': 0, + 'boundary.circle.radius': 500 + } + }; + const res = { }; + + controller(req, res, () => { + const expected_res = { + meta: { + query_type: 'fallback' + }, + data: [ + { + _id: '1', + _type: 'neighbourhood', + layer: 'neighbourhood', + source: 'whosonfirst', + source_id: '1', + center_point: { + lat: 1, + lon: 1 + }, + name: { + 'default': 'name 1' + }, + phrase: { + 'default': 'name 1' + } + }, + { + _id: '2', + _type: 'neighbourhood', + layer: 'neighbourhood', + source: 'whosonfirst', + source_id: '2', + center_point: { + lat: -45, + lon: 45 + }, + name: { + 'default': 'name 2' + }, + phrase: { + 'default': 'name 2' + } + }, + { + _id: '3', + _type: 'neighbourhood', + layer: 'neighbourhood', + source: 'whosonfirst', + source_id: '3', + center_point: { + lat: 45, + lon: -45 + }, + name: { + 'default': 'name 3' + }, + phrase: { + 'default': 'name 3' + } + } + ] + }; + + t.deepEquals(res, expected_res); + t.end(); + }); + + }); + test('only results matching explicit layers should be returned', (t) => { const logger = mock_logger(); @@ -1062,7 +1330,7 @@ module.exports.tests.result_filtering = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value', @@ -1198,7 +1466,7 @@ module.exports.tests.result_filtering = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value', @@ -1350,7 +1618,7 @@ module.exports.tests.result_filtering = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value', @@ -1420,6 +1688,178 @@ module.exports.tests.result_filtering = (test, common) => { }); + test('when geometric_filters_apply is false, boundary.country should not apply', (t) => { + const logger = require('pelias-mock-logger')(); + + const placeholder_service = (req, callback) => { + t.deepEqual(req, { + param1: 'param1 value', + clean: { + 'boundary.country': 'ABC' + } + }); + + const response = [ + { + id: 1, + name: 'name 1', + placetype: 'locality', + lineage: [ + { + country: { + id: 1, + name: 'country name 1', + abbr: 'ABC' + } + }, + { + country: { + id: 2, + name: 'country name 2', + abbr: 'DEF' + } + } + ], + geom: { + lat: 14.141414, + lon: 41.414141 + } + }, + { + id: 3, + name: 'name 3', + placetype: 'locality', + lineage: [ + { + country: { + id: 3, + name: 'country name 3', + abbr: 'ABC' + } + } + ], + geom: { + lat: 15.151515, + lon: 51.515151 + } + }, + { + id: 4, + name: 'name 4', + placetype: 'locality', + lineage: [ + { + country: { + id: 4, + name: 'country name 4', + abbr: 'GHI' + } + } + ], + geom: { + lat: 16.161616, + lon: 61.616161 + } + } + ]; + + callback(null, response); + }; + + const controller = proxyquire('../../../controller/placeholder', { + 'pelias-logger': logger + })(placeholder_service, false, () => true); + + const req = { + param1: 'param1 value', + clean: { + 'boundary.country': 'ABC' + } + }; + const res = { }; + + controller(req, res, () => { + const expected_res = { + meta: { + query_type: 'fallback' + }, + data: [ + { + _id: '1', + _type: 'locality', + layer: 'locality', + source: 'whosonfirst', + source_id: '1', + center_point: { + lat: 14.141414, + lon: 41.414141 + }, + name: { + 'default': 'name 1' + }, + phrase: { + 'default': 'name 1' + }, + parent: { + country: ['country name 1', 'country name 2'], + country_id: ['1', '2'], + country_a: ['ABC', 'DEF'] + } + }, + { + _id: '3', + _type: 'locality', + layer: 'locality', + source: 'whosonfirst', + source_id: '3', + center_point: { + lat: 15.151515, + lon: 51.515151 + }, + name: { + 'default': 'name 3' + }, + phrase: { + 'default': 'name 3' + }, + parent: { + country: ['country name 3'], + country_id: ['3'], + country_a: ['ABC'] + } + }, + { + _id: '4', + _type: 'locality', + layer: 'locality', + source: 'whosonfirst', + source_id: '4', + center_point: { + lat: 16.161616, + lon: 61.616161 + }, + name: { + 'default': 'name 4' + }, + phrase: { + 'default': 'name 4' + }, + parent: { + country: ['country name 4'], + country_id: ['4'], + country_a: ['GHI'] + } + } + ] + }; + + t.deepEquals(res, expected_res); + t.ok(logger.isInfoMessage('[controller:placeholder] [result_count:3]')); + t.end(); + }); + + }); + }; module.exports.tests.lineage_errors = (test, common) => { @@ -1460,7 +1900,7 @@ module.exports.tests.lineage_errors = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -1534,7 +1974,7 @@ module.exports.tests.lineage_errors = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -1607,7 +2047,7 @@ module.exports.tests.lineage_errors = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -1667,7 +2107,7 @@ module.exports.tests.geometry_errors = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -1726,7 +2166,7 @@ module.exports.tests.centroid_errors = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -1786,7 +2226,7 @@ module.exports.tests.centroid_errors = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -1856,7 +2296,7 @@ module.exports.tests.boundingbox_errors = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { param1: 'param1 value' }; const res = { }; @@ -1908,7 +2348,7 @@ module.exports.tests.error_conditions = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { errors: [] @@ -1937,7 +2377,7 @@ module.exports.tests.error_conditions = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { errors: [] @@ -1962,7 +2402,7 @@ module.exports.tests.error_conditions = (test, common) => { const controller = proxyquire('../../../controller/placeholder', { 'pelias-logger': logger - })(placeholder_service, _.constant(true)); + })(placeholder_service, true, () => true); const req = { errors: [] diff --git a/test/unit/controller/predicates/is_single_field_analysis.js b/test/unit/controller/predicates/is_single_field_analysis.js new file mode 100644 index 00000000..06328fa0 --- /dev/null +++ b/test/unit/controller/predicates/is_single_field_analysis.js @@ -0,0 +1,94 @@ +'use strict'; + +const _ = require('lodash'); +const is_single_field_analysis = require('../../../../controller/predicates/is_single_field_analysis'); + +module.exports.tests = {}; + +module.exports.tests.interface = (test, common) => { + test('valid interface', (t) => { + t.ok(_.isFunction(is_single_field_analysis), 'is_single_field_analysis is a function'); + t.end(); + }); +}; + +module.exports.tests.true_conditions = (test, common) => { + test('defined request.clean.parsed_text.property should return true', (t) => { + const req = { + clean: { + parsed_text: { + property: 'value' + } + } + }; + + t.ok(is_single_field_analysis('property')(req)); + t.end(); + + }); + +}; + +module.exports.tests.false_conditions = (test, common) => { + test('undefined request should return false', (t) => { + t.notOk(is_single_field_analysis('property')()); + t.end(); + + }); + + test('undefined request.clean should return false', (t) => { + const req = {}; + + t.notOk(is_single_field_analysis('property')(req)); + t.end(); + + }); + + test('undefined request.clean.parsed_text should return false', (t) => { + const req = { + clean: {} + }; + + t.notOk(is_single_field_analysis('property')(req)); + t.end(); + + }); + + test('request.clean.parsed_text with none of the supplied properties should return false', (t) => { + const req = { + clean: { + parsed_text: {} + } + }; + + t.notOk(is_single_field_analysis('property')(req)); + t.end(); + + }); + + test('request.clean.parsed_text with none of the supplied properties should return false', (t) => { + const req = { + clean: { + parsed_text: { + property: 'value', + another_property: 'value' + } + } + }; + + t.notOk(is_single_field_analysis('property')(req)); + t.end(); + + }); + +}; + +module.exports.all = (tape, common) => { + function test(name, testFunction) { + return tape(`GET /is_single_field_analysis ${name}`, testFunction); + } + + for( const testCase in module.exports.tests ){ + module.exports.tests[testCase](test, common); + } +}; diff --git a/test/unit/run.js b/test/unit/run.js index 66ed53d8..62924347 100644 --- a/test/unit/run.js +++ b/test/unit/run.js @@ -24,6 +24,7 @@ var tests = [ require('./controller/predicates/is_admin_only_analysis'), require('./controller/predicates/is_coarse_reverse'), require('./controller/predicates/is_service_enabled'), + require('./controller/predicates/is_single_field_analysis'), require('./helper/diffPlaces'), require('./helper/geojsonify'), require('./helper/logging'),