diff --git a/lib/cartodb/controllers/layergroup.js b/lib/cartodb/controllers/layergroup.js index 4119655f..79268d6e 100644 --- a/lib/cartodb/controllers/layergroup.js +++ b/lib/cartodb/controllers/layergroup.js @@ -391,13 +391,15 @@ LayergroupController.prototype.getAffectedTables = function(user, dbName, layerg function getSQL(err, mapConfig) { assert.ifError(err); - var queries = mapConfig.getLayers() - .map(function(lyr) { - return lyr.options.sql; - }) - .filter(function(sql) { - return !!sql; - }); + var queries = []; + mapConfig.getLayers().forEach(function(layer) { + queries.push(layer.options.sql); + if (layer.options.affected_tables) { + layer.options.affected_tables.map(function(table) { + queries.push('SELECT * FROM ' + table + ' LIMIT 0'); + }); + } + }); return queries.length ? queries.join(';') : null; }, diff --git a/lib/cartodb/controllers/map.js b/lib/cartodb/controllers/map.js index 417cf266..01b42965 100644 --- a/lib/cartodb/controllers/map.js +++ b/lib/cartodb/controllers/map.js @@ -312,9 +312,15 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, la done(); }); - var sql = mapconfig.getLayers().map(function(layer) { - return layer.options.sql; - }).join(';'); + var sql = []; + mapconfig.getLayers().forEach(function(layer) { + sql.push(layer.options.sql); + if (layer.options.affected_tables) { + layer.options.affected_tables.map(function(table) { + sql.push('SELECT * FROM ' + table + ' LIMIT 0'); + }); + } + }); var dbName = req.params.dbname; var layergroupId = layergroup.layergroupid; @@ -325,7 +331,7 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, la }, function getAffectedTablesAndLastUpdatedTime(err, connection) { assert.ifError(err); - QueryTables.getAffectedTablesFromQuery(connection, sql, this); + QueryTables.getAffectedTablesFromQuery(connection, sql.join(';'), this); }, function handleAffectedTablesAndLastUpdatedTime(err, result) { if (req.profiler) { diff --git a/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js b/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js index b59684c7..8cb63f48 100644 --- a/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js +++ b/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js @@ -115,6 +115,7 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi } layer.options.sql = analysisSql; layer.options.columns = getDataviewsColumns(getLayerDataviews(layer, dataviews)); + layer.options.affected_tables = getAllAffectedTablesFromSourceNodes(layerNode); } else { missingNodesErrors.push( new Error('Missing analysis node.id="' + layerSourceId +'" for layer='+layerIndex) @@ -330,4 +331,13 @@ function AnalysisError(message) { this.message = message; } +function getAllAffectedTablesFromSourceNodes(node) { + var affectedTables = node.getAllInputNodes(function (node) { + return node.getType() === 'source'; + }).reduce(function(list, node) { + return list.concat(node.getAffectedTables()); + },[]); + return affectedTables; +} + require('util').inherits(AnalysisError, Error); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 13ab1331..76a043be 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -105,9 +105,9 @@ } }, "camshaft": { - "version": "0.52.0", - "from": "camshaft@0.52.0", - "resolved": "https://registry.npmjs.org/camshaft/-/camshaft-0.52.0.tgz", + "version": "0.53.0", + "from": "camshaft@0.53.0", + "resolved": "https://registry.npmjs.org/camshaft/-/camshaft-0.53.0.tgz", "dependencies": { "async": { "version": "1.5.2", @@ -206,7 +206,7 @@ }, "once": { "version": "1.4.0", - "from": "once@>=1.3.3 <2.0.0", + "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "dependencies": { "wrappy": { @@ -609,7 +609,7 @@ }, "type-is": { "version": "1.6.15", - "from": "type-is@>=1.6.10 <1.7.0", + "from": "type-is@>=1.6.6 <1.7.0", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", "dependencies": { "media-typer": { @@ -794,9 +794,9 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" }, "form-data": { - "version": "2.1.2", + "version": "2.1.4", "from": "form-data@>=2.1.1 <2.2.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "dependencies": { "asynckit": { "version": "0.4.0", @@ -1051,7 +1051,7 @@ }, "mime-types": { "version": "2.1.15", - "from": "mime-types@>=2.1.15 <2.2.0", + "from": "mime-types@>=2.1.7 <2.2.0", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", "dependencies": { "mime-db": { @@ -1693,9 +1693,9 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" }, "readable-stream": { - "version": "2.2.7", + "version": "2.2.9", "from": "readable-stream@>=2.0.0 <3.0.0||>=1.1.13 <2.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "dependencies": { "buffer-shims": { "version": "1.0.0", @@ -1886,9 +1886,9 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" }, "form-data": { - "version": "2.1.2", + "version": "2.1.4", "from": "form-data@>=2.1.1 <2.2.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "dependencies": { "asynckit": { "version": "0.4.0", @@ -1903,9 +1903,9 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", "dependencies": { "ajv": { - "version": "4.11.5", + "version": "4.11.6", "from": "ajv@>=4.9.1 <5.0.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.5.tgz", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.6.tgz", "dependencies": { "co": { "version": "4.6.0", @@ -2161,7 +2161,7 @@ }, "minimatch": { "version": "3.0.3", - "from": "minimatch@>=3.0.0 <4.0.0", + "from": "minimatch@>=3.0.2 <4.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", "dependencies": { "brace-expansion": { @@ -2233,7 +2233,7 @@ }, "inherits": { "version": "2.0.3", - "from": "inherits@>=2.0.0 <3.0.0", + "from": "inherits@>=2.0.1 <2.1.0", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" } } @@ -2257,7 +2257,7 @@ }, "fstream": { "version": "1.0.11", - "from": "fstream@>=1.0.2 <2.0.0", + "from": "fstream@>=1.0.10 <2.0.0", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", "dependencies": { "graceful-fs": { @@ -2321,9 +2321,9 @@ } }, "readable-stream": { - "version": "2.2.7", + "version": "2.2.9", "from": "readable-stream@>=2.1.4 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "dependencies": { "buffer-shims": { "version": "1.0.0", @@ -3814,7 +3814,7 @@ "dependencies": { "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.1 <4.0.0", + "from": "strip-ansi@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "dependencies": { "ansi-regex": { @@ -4084,7 +4084,7 @@ }, "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.1 <4.0.0", + "from": "strip-ansi@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "dependencies": { "ansi-regex": { @@ -4197,9 +4197,9 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" }, "readable-stream": { - "version": "2.2.7", + "version": "2.2.9", "from": "readable-stream@>=2.0.0 <3.0.0||>=1.1.13 <2.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "dependencies": { "buffer-shims": { "version": "1.0.0", @@ -4218,7 +4218,7 @@ }, "inherits": { "version": "2.0.3", - "from": "inherits@>=2.0.0 <2.1.0", + "from": "inherits@>=2.0.1 <2.1.0", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" }, "process-nextick-args": { @@ -4390,9 +4390,9 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" }, "form-data": { - "version": "2.1.2", + "version": "2.1.4", "from": "form-data@>=2.1.1 <2.2.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "dependencies": { "asynckit": { "version": "0.4.0", @@ -4407,9 +4407,9 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", "dependencies": { "ajv": { - "version": "4.11.5", + "version": "4.11.6", "from": "ajv@>=4.9.1 <5.0.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.5.tgz", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.6.tgz", "dependencies": { "co": { "version": "4.6.0", @@ -4665,7 +4665,7 @@ }, "minimatch": { "version": "3.0.3", - "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", + "from": "minimatch@>=3.0.2 <4.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", "dependencies": { "brace-expansion": { @@ -4689,7 +4689,7 @@ }, "once": { "version": "1.4.0", - "from": "once@>=1.3.3 <2.0.0", + "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "dependencies": { "wrappy": { @@ -4725,7 +4725,7 @@ }, "fstream": { "version": "1.0.11", - "from": "fstream@>=1.0.10 <2.0.0", + "from": "fstream@>=1.0.2 <2.0.0", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", "dependencies": { "graceful-fs": { @@ -4737,7 +4737,7 @@ }, "inherits": { "version": "2.0.3", - "from": "inherits@>=2.0.0 <3.0.0", + "from": "inherits@>=2.0.1 <2.1.0", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" } } @@ -4813,9 +4813,9 @@ } }, "readable-stream": { - "version": "2.2.7", + "version": "2.2.9", "from": "readable-stream@>=2.1.4 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "dependencies": { "buffer-shims": { "version": "1.0.0", @@ -4834,7 +4834,7 @@ }, "inherits": { "version": "2.0.3", - "from": "inherits@>=2.0.0 <2.1.0", + "from": "inherits@>=2.0.1 <2.1.0", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" }, "process-nextick-args": { diff --git a/package.json b/package.json index 7a5d7a1a..b419b982 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ ], "dependencies": { "body-parser": "~1.14.0", - "camshaft": "0.52.0", + "camshaft": "0.53.0", "cartodb-psql": "~0.7.1", "cartodb-query-tables": "~0.1.0", "cartodb-redis": "0.13.1", diff --git a/test/acceptance/cache/cache_headers.js b/test/acceptance/cache/cache_headers.js new file mode 100644 index 00000000..2cd916af --- /dev/null +++ b/test/acceptance/cache/cache_headers.js @@ -0,0 +1,393 @@ +var testHelper = require('../../support/test_helper'); + +var assert = require('../../support/assert'); +var qs = require('querystring'); + +var CartodbWindshaft = require('../../../lib/cartodb/server'); +var serverOptions = require('../../../lib/cartodb/server_options'); +var server = new CartodbWindshaft(serverOptions); +server.setMaxListeners(0); + +var LayergroupToken = require('../../support/layergroup-token'); + +describe('get requests with cache headers', function() { + + var keysToDelete; + beforeEach(function() { + keysToDelete = {}; + }); + + afterEach(function(done) { + testHelper.deleteRedisKeys(keysToDelete, done); + }); + + var statusOkResponse = { + status: 200 + }; + + var mapConfigs = [ + { + "description": "cache headers should be present", + "cache_headers": { + "x_cache_channel": { + "db_name": "test_windshaft_cartodb_user_1_db", + "tables": ["public.test_table"] + }, + "surrogate_keys": "t:77pJnX" + }, + "data": + { + version: '1.5.0', + layers: [ + { + options: { + source: { + id: "2570e105-7b37-40d2-bdf4-1af889598745" + }, + sql: 'select * from test_table limit 2', + cartocss: '#layer { marker-fill:red; }', + cartocss_version: '2.3.0', + attributes: { + id:'cartodb_id', + columns: [ + 'name', + 'address' + ] + } + } + } + ], + analyses: [ + { + "id": "2570e105-7b37-40d2-bdf4-1af889598745", + "type": "source", + "params": { + "query": "select * from test_table limit 2" + } + } + ] + }, + }, + { + "description": "cache headers should be present and be composed with source table name", + "cache_headers": { + "x_cache_channel": { + "db_name": "test_windshaft_cartodb_user_1_db", + "tables": ["public.analysis_2f13a3dbd7_9eb239903a1afd8a69130d1ece0fc8b38de8592d", + "public.test_table"] + }, + "surrogate_keys": "t:77pJnX t:iL4eth" + }, + "data": + { + version: '1.5.0', + layers: [ + { + options: { + source: { + id: "2570e105-7b37-40d2-bdf4-1af889598745" + }, + sql: 'select * from test_table limit 2', + cartocss: '#layer { marker-fill:red; }', + cartocss_version: '2.3.0', + attributes: { + id:'cartodb_id', + columns: [ + 'name', + 'address' + ] + } + } + } + ], + analyses: [ + { + "id": "2570e105-7b37-40d2-bdf4-1af889598745", + "type": "buffer", + "params": { + "source": { + "type": "source", + "params": { + "query": "select * from test_table limit 2" + } + }, + "radius": 50000 + } + } + ] + } + }]; + + var layergroupRequest = function(mapConfig) { + return { + url: '/api/v1/map?api_key=1234&config=' + encodeURIComponent(JSON.stringify(mapConfig)), + method: 'GET', + headers: { + host: 'localhost' + } + }; + }; + + function getRequest(url, addApiKey, callbackName) { + var params = {}; + if (!!addApiKey) { + params.api_key = '1234'; + } + if (!!callbackName) { + params.callback = callbackName; + } + + return { + url: url + '?' + qs.stringify(params), + method: 'GET', + headers: { + host: 'localhost', + 'Content-Type': 'application/json' + } + }; + } + + function validateCacheHeaders(done, expectedCacheHeaders) { + return function(res, err) { + if (err) { + return done(err); + } + + assert.ok(res.headers['x-cache-channel']); + assert.ok(res.headers['surrogate-key']); + if (expectedCacheHeaders) { + validateXChannelHeaders(res.headers, expectedCacheHeaders); + assert.equal(res.headers['surrogate-key'], expectedCacheHeaders.surrogate_keys); + } + + done(); + }; + } + + function validateXChannelHeaders(headers, expectedCacheHeaders) { + var dbName = headers['x-cache-channel'].split(':')[0]; + var tables = headers['x-cache-channel'].split(':')[1].split(',').sort(); + assert.equal(dbName, expectedCacheHeaders.x_cache_channel.db_name); + assert.deepEqual(tables, expectedCacheHeaders.x_cache_channel.tables.sort()); + } + + function noCacheHeaders(done) { + return function(res, err) { + if (err) { + return done(err); + } + + assert.ok( + !res.headers['x-cache-channel'], + 'did not expect x-cache-channel header, got: `' + res.headers['x-cache-channel'] + '`' + ); + assert.ok( + !res.headers['surrogate-key'], + 'did not expect surrogate-key header, got: `' + res.headers['surrogate-key'] + '`' + ); + done(); + }; + } + + function withLayergroupId(mapConfig, callback) { + assert.response( + server, + layergroupRequest(mapConfig), + statusOkResponse, + function(res, err) { + if (err) { + return callback(err); + } + var layergroupId = JSON.parse(res.body).layergroupid; + keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + callback(null, layergroupId, res); + } + ); + } + + mapConfigs.forEach(function(mapConfigData) { + describe(mapConfigData.description, function() { + var mapConfig = mapConfigData.data; + var expectedCacheHeaders = mapConfigData.cache_headers; + it('/api/v1/map Map instantiation', function(done) { + var testFn = validateCacheHeaders(done, expectedCacheHeaders); + withLayergroupId(mapConfig, function(err, layergroupId, res) { + testFn(res); + }); + }); + + it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik retina tiles', function(done) { + withLayergroupId(mapConfig, function(err, layergroupId) { + assert.response( + server, + getRequest('/api/v1/map/' + layergroupId + '/0/0/0@2x.png', true), + validateCacheHeaders(done, expectedCacheHeaders) + ); + }); + }); + + it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik tiles', function(done) { + withLayergroupId(mapConfig, function(err, layergroupId) { + assert.response( + server, + getRequest('/api/v1/map/' + layergroupId + '/0/0/0.png', true), + validateCacheHeaders(done, expectedCacheHeaders) + ); + }); + }); + + it ('/api/v1/map/:token/:layer/:z/:x/:y.(:format) Per :layer rendering', function(done) { + withLayergroupId(mapConfig, function(err, layergroupId) { + assert.response( + server, + getRequest('/api/v1/map/' + layergroupId + '/0/0/0/0.png', true), + validateCacheHeaders(done, expectedCacheHeaders) + ); + }); + }); + + it ('/api/v1/map/:token/:layer/attributes/:fid endpoint for info windows', function(done) { + withLayergroupId(mapConfig, function(err, layergroupId) { + assert.response( + server, + getRequest('/api/v1/map/' + layergroupId + '/0/attributes/1', true), + validateCacheHeaders(done, expectedCacheHeaders) + ); + }); + }); + + it ('/api/v1/map/static/center/:token/:z/:lat/:lng/:width/:height.:format static maps', function(done) { + withLayergroupId(mapConfig, function(err, layergroupId) { + assert.response( + server, + getRequest('/api/v1/map/static/center/' + layergroupId + '/0/0/0/400/300.png', true), + validateCacheHeaders(done, expectedCacheHeaders) + ); + }); + }); + + it ('/api/v1/map/static/bbox/:token/:bbox/:width/:height.:format static maps', function(done) { + withLayergroupId(mapConfig, function(err, layergroupId) { + assert.response( + server, + getRequest('/api/v1/map/static/bbox/' + layergroupId + '/-45,-45,45,45/400/300.png', true), + validateCacheHeaders(done, expectedCacheHeaders) + ); + }); + }); + }); + }); + + describe('cache headers should NOT be present', function() { + + it('/', function(done) { + assert.response( + server, + getRequest('/'), + statusOkResponse, + noCacheHeaders(done) + ); + }); + + it('/version', function(done) { + assert.response( + server, + getRequest('/version'), + statusOkResponse, + noCacheHeaders(done) + ); + }); + + it('/health', function(done) { + assert.response( + server, + getRequest('/health'), + statusOkResponse, + noCacheHeaders(done) + ); + }); + + it('/api/v1/map/named list named maps', function(done) { + assert.response( + server, + getRequest('/api/v1/map/named', true), + statusOkResponse, + noCacheHeaders(done) + ); + }); + + describe('with named maps', function() { + + var templateName = 'x_cache'; + + beforeEach(function(done) { + var template = { + version: '0.0.1', + name: templateName, + auth: { + method: 'open' + }, + layergroup: mapConfigs[0].data + }; + + var namedMapRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { + host: 'localhost', + 'Content-Type': 'application/json' + }, + data: JSON.stringify(template) + }; + + assert.response( + server, + namedMapRequest, + statusOkResponse, + function(res, err) { + done(err); + } + ); + }); + + afterEach(function(done) { + assert.response( + server, + { + url: '/api/v1/map/named/' + templateName + '?api_key=1234', + method: 'DELETE', + headers: { + host: 'localhost' + } + }, + { + status: 204 + }, + function(res, err) { + done(err); + } + ); + }); + + + it('/api/v1/map/named/:template_id Named map retrieval', function(done) { + assert.response( + server, + getRequest('/api/v1/map/named/' + templateName, true), + statusOkResponse, + noCacheHeaders(done) + ); + }); + + it('/api/v1/map/named/:template_id/jsonp Named map retrieval', function(done) { + assert.response( + server, + getRequest('/api/v1/map/named/' + templateName, true, 'cb'), + statusOkResponse, + noCacheHeaders(done) + ); + }); + }); + }); +}); diff --git a/test/acceptance/templates.js b/test/acceptance/templates.js index 7201b7fb..74d34d82 100644 --- a/test/acceptance/templates.js +++ b/test/acceptance/templates.js @@ -1052,8 +1052,9 @@ describe('template_api', function() { 'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body); assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); var cc = res.headers['x-cache-channel']; + var expectedCC = 'test_windshaft_cartodb_user_1_db:public.test_table_private_1'; assert.ok(cc); - assert.ok(cc.match, /ciao/, cc); + assert.equal(cc, expectedCC); // hack simulating restart... server.layergroupAffectedTablesCache.cache.reset(); // need to clean channel cache var get_request = { @@ -1072,8 +1073,9 @@ describe('template_api', function() { 'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body); assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); var cc = res.headers['x-cache-channel']; + var expectedCC = 'test_windshaft_cartodb_user_1_db:public.test_table_private_1'; assert.ok(cc, "Missing X-Cache-Channel on fetch-after-restart"); - assert.ok(cc.match, /ciao/, cc); + assert.equal(cc, expectedCC); return null; }, function deleteTemplate(err) diff --git a/test/acceptance/x_cache_channel.js b/test/acceptance/x_cache_channel.js deleted file mode 100644 index 4ebb45e8..00000000 --- a/test/acceptance/x_cache_channel.js +++ /dev/null @@ -1,307 +0,0 @@ -var testHelper = require('../support/test_helper'); - -var assert = require('../support/assert'); -var qs = require('querystring'); - -var CartodbWindshaft = require('../../lib/cartodb/server'); -var serverOptions = require('../../lib/cartodb/server_options'); -var server = new CartodbWindshaft(serverOptions); -server.setMaxListeners(0); - -var LayergroupToken = require('../support/layergroup-token'); - -describe('get requests x-cache-channel', function() { - - var keysToDelete; - beforeEach(function() { - keysToDelete = {}; - }); - - afterEach(function(done) { - testHelper.deleteRedisKeys(keysToDelete, done); - }); - - var statusOkResponse = { - status: 200 - }; - - var mapConfig = { - version: '1.3.0', - layers: [ - { - options: { - sql: 'select * from test_table limit 2', - cartocss: '#layer { marker-fill:red; }', - cartocss_version: '2.3.0', - attributes: { - id:'cartodb_id', - columns: [ - 'name', - 'address' - ] - } - } - } - ] - }; - - var layergroupRequest = { - url: '/api/v1/map?config=' + encodeURIComponent(JSON.stringify(mapConfig)), - method: 'GET', - headers: { - host: 'localhost' - } - }; - - function getRequest(url, addApiKey, callbackName) { - var params = {}; - if (!!addApiKey) { - params.api_key = '1234'; - } - if (!!callbackName) { - params.callback = callbackName; - } - - return { - url: url + '?' + qs.stringify(params), - method: 'GET', - headers: { - host: 'localhost', - 'Content-Type': 'application/json' - } - }; - } - - function validateXCacheChannel(done, expectedCacheChannel) { - return function(res, err) { - if (err) { - return done(err); - } - - assert.ok(res.headers['x-cache-channel']); - if (expectedCacheChannel) { - assert.equal(res.headers['x-cache-channel'], expectedCacheChannel); - } - - done(); - }; - } - - function noXCacheChannelHeader(done) { - return function(res, err) { - if (err) { - return done(err); - } - - assert.ok( - !res.headers['x-cache-channel'], - 'did not expect x-cache-channel header, got: `' + res.headers['x-cache-channel'] + '`' - ); - done(); - }; - } - - function withLayergroupId(callback) { - assert.response( - server, - layergroupRequest, - statusOkResponse, - function(res, err) { - if (err) { - return callback(err); - } - var layergroupId = JSON.parse(res.body).layergroupid; - keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - callback(null, layergroupId, res); - } - ); - } - - describe('header should be present', function() { - - it('/api/v1/map Map instantiation', function(done) { - var testFn = validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table'); - withLayergroupId(function(err, layergroupId, res) { - testFn(res); - }); - }); - - it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik retina tiles', function(done) { - withLayergroupId(function(err, layergroupId) { - assert.response( - server, - getRequest('/api/v1/map/' + layergroupId + '/0/0/0@2x.png'), - validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table') - ); - }); - }); - - it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik tiles', function(done) { - withLayergroupId(function(err, layergroupId) { - assert.response( - server, - getRequest('/api/v1/map/' + layergroupId + '/0/0/0.png'), - validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table') - ); - }); - }); - - it ('/api/v1/map/:token/:layer/:z/:x/:y.(:format) Per :layer rendering', function(done) { - withLayergroupId(function(err, layergroupId) { - assert.response( - server, - getRequest('/api/v1/map/' + layergroupId + '/0/0/0/0.png'), - validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table') - ); - }); - }); - - it ('/api/v1/map/:token/:layer/attributes/:fid endpoint for info windows', function(done) { - withLayergroupId(function(err, layergroupId) { - assert.response( - server, - getRequest('/api/v1/map/' + layergroupId + '/0/attributes/1'), - validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table') - ); - }); - }); - - it ('/api/v1/map/static/center/:token/:z/:lat/:lng/:width/:height.:format static maps', function(done) { - withLayergroupId(function(err, layergroupId) { - assert.response( - server, - getRequest('/api/v1/map/static/center/' + layergroupId + '/0/0/0/400/300.png'), - validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table') - ); - }); - }); - - it ('/api/v1/map/static/bbox/:token/:bbox/:width/:height.:format static maps', function(done) { - withLayergroupId(function(err, layergroupId) { - assert.response( - server, - getRequest('/api/v1/map/static/bbox/' + layergroupId + '/-45,-45,45,45/400/300.png'), - validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table') - ); - }); - }); - - }); - - describe('header should NOT be present', function() { - - it('/', function(done) { - assert.response( - server, - getRequest('/'), - statusOkResponse, - noXCacheChannelHeader(done) - ); - }); - - it('/version', function(done) { - assert.response( - server, - getRequest('/version'), - statusOkResponse, - noXCacheChannelHeader(done) - ); - }); - - it('/health', function(done) { - assert.response( - server, - getRequest('/health'), - statusOkResponse, - noXCacheChannelHeader(done) - ); - }); - - it('/api/v1/map/named list named maps', function(done) { - assert.response( - server, - getRequest('/api/v1/map/named', true), - statusOkResponse, - noXCacheChannelHeader(done) - ); - }); - - describe('with named maps', function() { - - var templateName = 'x_cache'; - - beforeEach(function(done) { - var template = { - version: '0.0.1', - name: templateName, - auth: { - method: 'open' - }, - layergroup: mapConfig - }; - - var namedMapRequest = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: { - host: 'localhost', - 'Content-Type': 'application/json' - }, - data: JSON.stringify(template) - }; - - assert.response( - server, - namedMapRequest, - statusOkResponse, - function(res, err) { - done(err); - } - ); - }); - - afterEach(function(done) { - assert.response( - server, - { - url: '/api/v1/map/named/' + templateName + '?api_key=1234', - method: 'DELETE', - headers: { - host: 'localhost' - } - }, - { - status: 204 - }, - function(res, err) { - done(err); - } - ); - }); - - - it('/api/v1/map/named/:template_id Named map retrieval', function(done) { - assert.response( - server, - getRequest('/api/v1/map/named/' + templateName, true), - statusOkResponse, - noXCacheChannelHeader(done) - ); - }); - - it('/api/v1/map/named/:template_id/jsonp Named map retrieval', function(done) { - assert.response( - server, - getRequest('/api/v1/map/named/' + templateName, true, 'cb'), - statusOkResponse, - noXCacheChannelHeader(done) - ); - }); - - }); - - }); - - -}); diff --git a/test/support/prepare_db.sh b/test/support/prepare_db.sh index 1a6d929c..4fbf4b7a 100755 --- a/test/support/prepare_db.sh +++ b/test/support/prepare_db.sh @@ -75,7 +75,7 @@ if test x"$PREPARE_PGSQL" = xyes; then dropdb "${TEST_DB}" createdb -Ttemplate_postgis -EUTF8 "${TEST_DB}" || die "Could not create test database" - LOCAL_SQL_SCRIPTS='analysis_catalog windshaft.test gadm4 ported/populated_places_simple_reduced cdb_analysis_check' + LOCAL_SQL_SCRIPTS='analysis_catalog windshaft.test gadm4 ported/populated_places_simple_reduced cdb_analysis_check cdb_invalidate_varnish' REMOTE_SQL_SCRIPTS='CDB_QueryStatements CDB_QueryTables CDB_CartodbfyTable CDB_TableMetadata CDB_ForeignTable CDB_UserTables CDB_ColumnNames CDB_ZoomFromScale CDB_OverviewsSupport CDB_Overviews CDB_QuantileBins CDB_JenksBins CDB_HeadsTailsBins CDB_EqualIntervalBins CDB_Hexagon CDB_XYZ' CURL_ARGS="" diff --git a/test/support/sql/cdb_invalidate_varnish.sql b/test/support/sql/cdb_invalidate_varnish.sql new file mode 100644 index 00000000..7cd2d8f1 --- /dev/null +++ b/test/support/sql/cdb_invalidate_varnish.sql @@ -0,0 +1,6 @@ +CREATE OR REPLACE FUNCTION CDB_Invalidate_Varnish(table_name TEXT) +RETURNS void AS +$$ +BEGIN +END; +$$ LANGUAGE PLPGSQL; \ No newline at end of file