diff --git a/lib/cartodb/api/map/anonymous-map-controller.js b/lib/cartodb/api/map/anonymous-map-controller.js index 055bd6f7..1a1f6eea 100644 --- a/lib/cartodb/api/map/anonymous-map-controller.js +++ b/lib/cartodb/api/map/anonymous-map-controller.js @@ -152,8 +152,17 @@ function prepareAdapterMapConfig (mapConfigAdapter) { } }; - mapConfigAdapter.getMapConfig(user, requestMapConfig, params, context, (err, requestMapConfig) => { + mapConfigAdapter.getMapConfig(user, + requestMapConfig, + params, + context, + (err, requestMapConfig, stats = { overviewsUsed : false }) => { req.profiler.done('anonymous.getMapConfig'); + + stats.mapType = 'anonymous'; + req.profiler.add(stats); + + if (err) { return next(err); } diff --git a/lib/cartodb/api/template/named-template-controller.js b/lib/cartodb/api/template/named-template-controller.js index 5cdf5401..0408ed3a 100644 --- a/lib/cartodb/api/template/named-template-controller.js +++ b/lib/cartodb/api/template/named-template-controller.js @@ -165,8 +165,12 @@ function getTemplate ( params ); - mapConfigProvider.getMapConfig((err, mapConfig, rendererParams) => { + mapConfigProvider.getMapConfig((err, mapConfig, rendererParams, context, stats = {}) => { req.profiler.done('named.getMapConfig'); + + stats.mapType = 'named'; + req.profiler.add(stats); + if (err) { return next(err); } diff --git a/lib/cartodb/models/mapconfig/adapter/index.js b/lib/cartodb/models/mapconfig/adapter/index.js index 70704bea..dd82df32 100644 --- a/lib/cartodb/models/mapconfig/adapter/index.js +++ b/lib/cartodb/models/mapconfig/adapter/index.js @@ -11,16 +11,21 @@ MapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, param var i = 0; var tasksLeft = this.adapters.length; - function next(err, _requestMapConfig) { + let mapConfigStats = {}; + + function next(err, _requestMapConfig, adapterStats = {}) { if (err) { return callback(err); } + + mapConfigStats = Object.assign(mapConfigStats, adapterStats); + if (tasksLeft-- === 0) { - return callback(null, _requestMapConfig); + return callback(null, _requestMapConfig, mapConfigStats); } var nextAdapter = self.adapters[i++]; nextAdapter.getMapConfig(user, _requestMapConfig, params, context, next); } - next(null, requestMapConfig); + next(null, requestMapConfig, mapConfigStats); }; diff --git a/lib/cartodb/models/mapconfig/adapter/mapconfig-overviews-adapter.js b/lib/cartodb/models/mapconfig/adapter/mapconfig-overviews-adapter.js index e67a2513..47179028 100644 --- a/lib/cartodb/models/mapconfig/adapter/mapconfig-overviews-adapter.js +++ b/lib/cartodb/models/mapconfig/adapter/mapconfig-overviews-adapter.js @@ -20,50 +20,58 @@ MapConfigOverviewsAdapter.prototype.getMapConfig = function (user, requestMapCon layers.forEach(layer => augmentLayersQueue.defer(this._augmentLayer.bind(this), user, layer, analysesResults)); - augmentLayersQueue.awaitAll(function layersAugmentQueueFinish (err, layers) { + augmentLayersQueue.awaitAll(function layersAugmentQueueFinish (err, results) { if (err) { return callback(err); } + const layers = results.map(result => result.layer); + const overviewsAddedToMapconfig = results.some(result => result.overviewsAddedToMapconfig); + if (!layers || layers.length === 0) { return callback(new Error('Missing layers array from layergroup config')); } requestMapConfig.layers = layers; - return callback(null, requestMapConfig); + const stats = { overviewsAddedToMapconfig }; + + return callback(null, requestMapConfig, stats); }); }; MapConfigOverviewsAdapter.prototype._augmentLayer = function (user, layer, analysesResults, callback) { + let overviewsAddedToMapconfig = false; if (layer.type !== 'mapnik' && layer.type !== 'cartodb') { - return callback(null, layer); + return callback(null, { layer, overviewsAddedToMapconfig }); } this.overviewsMetadataBackend.getOverviewsMetadata(user, layer.options.sql, (err, metadata) => { if (err) { - return callback(err, layer); + return callback(err, { layer, overviewsAddedToMapconfig }); } if (_.isEmpty(metadata)) { - return callback(null, layer); + return callback(null, { layer, overviewsAddedToMapconfig }); } var filters = getFilters(analysesResults, layer); + overviewsAddedToMapconfig = true; + if (!filters) { layer.options = Object.assign({}, layer.options, getQueryRewriteData(layer, analysesResults, { overviews: metadata })); - return callback(null, layer); + return callback(null, { layer, overviewsAddedToMapconfig }); } var unfilteredQuery = getUnfilteredQuery(analysesResults, layer); this.filterStatsBackend.getFilterStats(user, unfilteredQuery, filters, function (err, stats) { if (err) { - return callback(null, layer); + return callback(null, { layer, overviewsAddedToMapconfig }); } layer.options = Object.assign({}, layer.options, getQueryRewriteData(layer, analysesResults, { @@ -71,7 +79,7 @@ MapConfigOverviewsAdapter.prototype._augmentLayer = function (user, layer, analy filter_stats: stats })); - return callback(null, layer); + return callback(null, { layer, overviewsAddedToMapconfig }); }); }); }; diff --git a/lib/cartodb/models/mapconfig/provider/named-map-provider.js b/lib/cartodb/models/mapconfig/provider/named-map-provider.js index e3889aff..12a41f43 100644 --- a/lib/cartodb/models/mapconfig/provider/named-map-provider.js +++ b/lib/cartodb/models/mapconfig/provider/named-map-provider.js @@ -99,7 +99,7 @@ module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider { const { user, rendererParams } = this; this.mapConfigAdapter.getMapConfig( - user, requestMapConfig, rendererParams, context, (err, mapConfig) => { + user, requestMapConfig, rendererParams, context, (err, mapConfig, stats = {}) => { if (err) { this.err = err; return callback(err); @@ -108,7 +108,7 @@ module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider { this.mapConfig = (mapConfig === null) ? null : new MapConfig(mapConfig, context.datasource); this.analysesResults = context.analysesResults || []; - return callback(null, this.mapConfig, this.rendererParams, this.context); + return callback(null, this.mapConfig, this.rendererParams, this.context, stats); }); }); }); diff --git a/test/acceptance/overviews_metadata.js b/test/acceptance/overviews_metadata.js index 08cf37a9..a280e683 100644 --- a/test/acceptance/overviews_metadata.js +++ b/test/acceptance/overviews_metadata.js @@ -72,6 +72,7 @@ describe('overviews metadata', function() { data: JSON.stringify(layergroup) }, {}, function(res) { assert.equal(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); assert.equal(res.headers['x-layergroup-id'], parsedBody.layergroupid); expected_token = parsedBody.layergroupid; @@ -113,6 +114,83 @@ describe('overviews metadata', function() { } ); }); + + describe('Overviews Flags', function () { + it("Overviews used", function (done) { + var layergroup = { + version: '1.0.0', + layers: [overviews_layer, non_overviews_layer] + }; + + var layergroup_url = '/api/v1/map'; + + var expected_token; + step( + function do_post() { + var next = this; + assert.response(server, { + url: layergroup_url, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.equal(res.statusCode, 200, res.body); + + const headers = JSON.parse(res.headers['x-tiler-profiler']); + + assert.ok(headers.overviewsAddedToMapconfig); + assert.equal(headers.mapType, 'anonymous'); + + const parsedBody = JSON.parse(res.body); + expected_token = parsedBody.layergroupid; + next(); + }); + }, + function finish(err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + done(err); + } + ); + }); + it("Overviews NOT used", function (done) { + var layergroup = { + version: '1.0.0', + layers: [non_overviews_layer] + }; + + var layergroup_url = '/api/v1/map'; + + var expected_token; + step( + function do_post() { + var next = this; + assert.response(server, { + url: layergroup_url, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.equal(res.statusCode, 200, res.body); + + const headers = JSON.parse(res.headers['x-tiler-profiler']); + + assert.equal(headers.overviewsAddedToMapconfig, false); + assert.equal(headers.mapType, 'anonymous'); + + const parsedBody = JSON.parse(res.body); + expected_token = parsedBody.layergroupid; + next(); + }); + }, + function finish(err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + done(err); + } + ); + }); + }); }); describe('overviews metadata with filters', function() { diff --git a/test/acceptance/overviews_metadata_named_maps.js b/test/acceptance/overviews_metadata_named_maps.js index 80451222..dd72f240 100644 --- a/test/acceptance/overviews_metadata_named_maps.js +++ b/test/acceptance/overviews_metadata_named_maps.js @@ -176,4 +176,129 @@ describe('overviews metadata for named maps', function() { } ); }); + + describe('Overviews Flags', function() { + it("Overviews used", function (done) { + step( + function postTemplate() { + var next = this; + + assert.response(server, { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(template) + }, {}, function (res, err) { + next(err, res); + }); + }, + function instantiateTemplate(err) { + assert.ifError(err); + + var next = this; + assert.response(server, { + url: '/api/v1/map/named/' + templateId, + method: 'POST', + headers: { + host: 'localhost', + 'Content-Type': 'application/json' + } + }, {}, + function (res, err) { + return next(err, res); + }); + + }, + function checkFlags(err, res) { + assert.ifError(err); + + var next = this; + + var parsedBody = JSON.parse(res.body); + + keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + const headers = JSON.parse(res.headers['x-tiler-profiler']); + + assert.ok(headers.overviewsAddedToMapconfig); + assert.equal(headers.mapType, 'named'); + + next(); + }, + + function finish(err) { + done(err); + } + ); + }); + + it("Overviews NOT used", function (done) { + + const nonOverviewsTemplateId = 'non-overviews-template'; + + var nonOverviewsTemplate = { + version: '0.0.1', + name: nonOverviewsTemplateId, + auth: { method: 'open' }, + layergroup: { + version: '1.0.0', + layers: [non_overviews_layer] + } + }; + + step( + function postTemplate() { + var next = this; + + assert.response(server, { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(nonOverviewsTemplate) + }, {}, function (res, err) { + next(err, res); + }); + }, + function instantiateTemplate(err) { + assert.ifError(err); + + var next = this; + assert.response(server, { + url: '/api/v1/map/named/' + nonOverviewsTemplateId, + method: 'POST', + headers: { + host: 'localhost', + 'Content-Type': 'application/json' + } + }, {}, + function (res, err) { + return next(err, res); + }); + + }, + function checkFlags(err, res) { + assert.ifError(err); + + var next = this; + + var parsedBody = JSON.parse(res.body); + + keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + const headers = JSON.parse(res.headers['x-tiler-profiler']); + + assert.equal(headers.overviewsAddedToMapconfig, false); + assert.equal(headers.mapType, 'named'); + + next(); + }, + + function finish(err) { + done(err); + } + ); + }); + }); });