From 47dd485282871446a4c91aff8d16683ec96df494 Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Fri, 10 Mar 2017 11:40:48 +0100 Subject: [PATCH 1/9] Get affected tables and add it to the layergroup --- .../adapter/analysis-mapconfig-adapter.js | 9 ++++++ test/acceptance/analysis/analysis-layers.js | 30 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js b/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js index b59684c7..09467ea9 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,12 @@ function AnalysisError(message) { this.message = message; } +function getAllAffectedTablesFromSourceNodes(node) { + var affectedTables = []; + 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/test/acceptance/analysis/analysis-layers.js b/test/acceptance/analysis/analysis-layers.js index a745fb97..3a54ea2c 100644 --- a/test/acceptance/analysis/analysis-layers.js +++ b/test/acceptance/analysis/analysis-layers.js @@ -146,6 +146,36 @@ describe('analysis-layers', function() { }); }); + it('should have empty affected tables if it has only "source" node', function(done) { + var useCase = useCases[0]; + + var testClient = new TestClient(useCase.mapConfig, 1234); + + testClient.getLayergroup(function(err, layergroupResult) { + assert.ok(!err, err); + + var affected_tables = layergroupResult.metadata.layers[0].meta.affected_tables; + assert.equal(affected_tables.length, 0); + + testClient.drain(done); + }); + }); + + it('should have empty affected tables if it has a node other than "source"', function(done) { + var useCase = useCases[1]; + + var testClient = new TestClient(useCase.mapConfig, 1234); + + testClient.getLayergroup(function(err, layergroupResult) { + assert.ok(!err, err); + + var affected_tables = layergroupResult.metadata.layers[0].meta.affected_tables; + assert.equal(affected_tables[0], 'public.populated_places_simple_reduced'); + + testClient.drain(done); + }); + }); + it('should NOT fail for non-authenticated requests when it is just source', function(done) { var useCase = useCases[0]; From 1ba42e37e90f1bea9c3870c681b669fad5c280cf Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Fri, 10 Mar 2017 17:22:07 +0100 Subject: [PATCH 2/9] Add more tests for x-cache-channel but with analysis --- test/acceptance/x_cache_channel.js | 247 ++++++++++++++++++----------- 1 file changed, 152 insertions(+), 95 deletions(-) diff --git a/test/acceptance/x_cache_channel.js b/test/acceptance/x_cache_channel.js index 4ebb45e8..cd12e6ce 100644 --- a/test/acceptance/x_cache_channel.js +++ b/test/acceptance/x_cache_channel.js @@ -25,32 +25,92 @@ describe('get requests x-cache-channel', function() { status: 200 }; - var mapConfig = { - version: '1.3.0', - layers: [ + var mapConfigs = [ + { + "description": "header should be present", + "data": + { + version: '1.4.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": "header should be present and be composed with source table name", + "data": { - 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' - ] + 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 = { - url: '/api/v1/map?config=' + encodeURIComponent(JSON.stringify(mapConfig)), - method: 'GET', - headers: { - host: 'localhost' - } + 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) { @@ -101,10 +161,10 @@ describe('get requests x-cache-channel', function() { }; } - function withLayergroupId(callback) { + function withLayergroupId(mapConfig, callback) { assert.response( server, - layergroupRequest, + layergroupRequest(mapConfig), statusOkResponse, function(res, err) { if (err) { @@ -118,75 +178,76 @@ describe('get requests x-cache-channel', function() { ); } - describe('header should be present', function() { + mapConfigs.forEach(function(mapConfigData) { + describe(mapConfigData.description, function() { + var mapConfig = mapConfigData.data; + it('/api/v1/map Map instantiation', function(done) { + var testFn = validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table'); + withLayergroupId(mapConfig, function(err, layergroupId, res) { + testFn(res); + }); + }); - 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(mapConfig, 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(mapConfig, 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(mapConfig, 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(mapConfig, 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(mapConfig, 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(mapConfig, 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') + ); + }); }); }); - - 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() { @@ -238,7 +299,7 @@ describe('get requests x-cache-channel', function() { auth: { method: 'open' }, - layergroup: mapConfig + layergroup: mapConfigs[0].data }; var namedMapRequest = { @@ -298,10 +359,6 @@ describe('get requests x-cache-channel', function() { noXCacheChannelHeader(done) ); }); - }); - }); - - }); From 7631edb3dbd03b346d9e6e96aec0c84409905123 Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Mon, 13 Mar 2017 17:28:29 +0100 Subject: [PATCH 3/9] Affected tables are now included in X-Cache-Channel --- lib/cartodb/controllers/layergroup.js | 16 +++++----- lib/cartodb/controllers/map.js | 14 ++++++--- .../adapter/analysis-mapconfig-adapter.js | 1 - test/acceptance/analysis/analysis-layers.js | 30 ------------------ test/acceptance/templates.js | 6 ++-- test/acceptance/x_cache_channel.js | 31 +++++++++++-------- 6 files changed, 41 insertions(+), 57 deletions(-) diff --git a/lib/cartodb/controllers/layergroup.js b/lib/cartodb/controllers/layergroup.js index 4119655f..10b5324b 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().map(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..f32ef06a 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().map(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 09467ea9..c6467488 100644 --- a/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js +++ b/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js @@ -332,7 +332,6 @@ function AnalysisError(message) { } function getAllAffectedTablesFromSourceNodes(node) { - var affectedTables = []; var affectedTables = node.getAllInputNodes(function (node) { return node.getType() === 'source'; }).reduce(function(list, node) { return list.concat(node.getAffectedTables()); },[]); diff --git a/test/acceptance/analysis/analysis-layers.js b/test/acceptance/analysis/analysis-layers.js index 3a54ea2c..a745fb97 100644 --- a/test/acceptance/analysis/analysis-layers.js +++ b/test/acceptance/analysis/analysis-layers.js @@ -146,36 +146,6 @@ describe('analysis-layers', function() { }); }); - it('should have empty affected tables if it has only "source" node', function(done) { - var useCase = useCases[0]; - - var testClient = new TestClient(useCase.mapConfig, 1234); - - testClient.getLayergroup(function(err, layergroupResult) { - assert.ok(!err, err); - - var affected_tables = layergroupResult.metadata.layers[0].meta.affected_tables; - assert.equal(affected_tables.length, 0); - - testClient.drain(done); - }); - }); - - it('should have empty affected tables if it has a node other than "source"', function(done) { - var useCase = useCases[1]; - - var testClient = new TestClient(useCase.mapConfig, 1234); - - testClient.getLayergroup(function(err, layergroupResult) { - assert.ok(!err, err); - - var affected_tables = layergroupResult.metadata.layers[0].meta.affected_tables; - assert.equal(affected_tables[0], 'public.populated_places_simple_reduced'); - - testClient.drain(done); - }); - }); - it('should NOT fail for non-authenticated requests when it is just source', function(done) { var useCase = useCases[0]; 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 index cd12e6ce..298c0ef0 100644 --- a/test/acceptance/x_cache_channel.js +++ b/test/acceptance/x_cache_channel.js @@ -28,6 +28,7 @@ describe('get requests x-cache-channel', function() { var mapConfigs = [ { "description": "header should be present", + "x_cache_channel": "test_windshaft_cartodb_user_1_db:public.test_table", "data": { version: '1.4.0', @@ -63,6 +64,9 @@ describe('get requests x-cache-channel', function() { }, { "description": "header should be present and be composed with source table name", + "x_cache_channel": "test_windshaft_cartodb_user_1_db:" + + "public.analysis_2f13a3dbd7_9eb239903a1afd8a69130d1ece0fc8b38de8592d" + + ",public.test_table", "data": { version: '1.5.0', @@ -181,8 +185,9 @@ describe('get requests x-cache-channel', function() { mapConfigs.forEach(function(mapConfigData) { describe(mapConfigData.description, function() { var mapConfig = mapConfigData.data; + var expectedCacheChannel = mapConfigData.x_cache_channel; it('/api/v1/map Map instantiation', function(done) { - var testFn = validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table'); + var testFn = validateXCacheChannel(done, expectedCacheChannel); withLayergroupId(mapConfig, function(err, layergroupId, res) { testFn(res); }); @@ -192,8 +197,8 @@ describe('get requests x-cache-channel', function() { withLayergroupId(mapConfig, 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') + getRequest('/api/v1/map/' + layergroupId + '/0/0/0@2x.png', true), + validateXCacheChannel(done, expectedCacheChannel) ); }); }); @@ -202,8 +207,8 @@ describe('get requests x-cache-channel', function() { withLayergroupId(mapConfig, 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') + getRequest('/api/v1/map/' + layergroupId + '/0/0/0.png', true), + validateXCacheChannel(done, expectedCacheChannel) ); }); }); @@ -212,8 +217,8 @@ describe('get requests x-cache-channel', function() { withLayergroupId(mapConfig, 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') + getRequest('/api/v1/map/' + layergroupId + '/0/0/0/0.png', true), + validateXCacheChannel(done, expectedCacheChannel) ); }); }); @@ -222,8 +227,8 @@ describe('get requests x-cache-channel', function() { withLayergroupId(mapConfig, 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') + getRequest('/api/v1/map/' + layergroupId + '/0/attributes/1', true), + validateXCacheChannel(done, expectedCacheChannel) ); }); }); @@ -232,8 +237,8 @@ describe('get requests x-cache-channel', function() { withLayergroupId(mapConfig, 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') + getRequest('/api/v1/map/static/center/' + layergroupId + '/0/0/0/400/300.png', true), + validateXCacheChannel(done, expectedCacheChannel) ); }); }); @@ -242,8 +247,8 @@ describe('get requests x-cache-channel', function() { withLayergroupId(mapConfig, 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') + getRequest('/api/v1/map/static/bbox/' + layergroupId + '/-45,-45,45,45/400/300.png', true), + validateXCacheChannel(done, expectedCacheChannel) ); }); }); From 07880928e890e9c445aa2c050afe4f64cc90ac94 Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Mon, 13 Mar 2017 18:36:13 +0100 Subject: [PATCH 4/9] Include check for surrogate-key header and renamed the test file --- lib/cartodb/controllers/layergroup.js | 2 +- lib/cartodb/controllers/map.js | 2 +- .../adapter/analysis-mapconfig-adapter.js | 4 +- .../cache_headers.js} | 76 +++++++++++-------- 4 files changed, 49 insertions(+), 35 deletions(-) rename test/acceptance/{x_cache_channel.js => cache/cache_headers.js} (81%) diff --git a/lib/cartodb/controllers/layergroup.js b/lib/cartodb/controllers/layergroup.js index 10b5324b..79268d6e 100644 --- a/lib/cartodb/controllers/layergroup.js +++ b/lib/cartodb/controllers/layergroup.js @@ -392,7 +392,7 @@ LayergroupController.prototype.getAffectedTables = function(user, dbName, layerg assert.ifError(err); var queries = []; - mapConfig.getLayers().map(function(layer) { + mapConfig.getLayers().forEach(function(layer) { queries.push(layer.options.sql); if (layer.options.affected_tables) { layer.options.affected_tables.map(function(table) { diff --git a/lib/cartodb/controllers/map.js b/lib/cartodb/controllers/map.js index f32ef06a..01b42965 100644 --- a/lib/cartodb/controllers/map.js +++ b/lib/cartodb/controllers/map.js @@ -313,7 +313,7 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, la }); var sql = []; - mapconfig.getLayers().map(function(layer) { + mapconfig.getLayers().forEach(function(layer) { sql.push(layer.options.sql); if (layer.options.affected_tables) { layer.options.affected_tables.map(function(table) { diff --git a/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js b/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js index c6467488..8cb63f48 100644 --- a/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js +++ b/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js @@ -334,7 +334,9 @@ function AnalysisError(message) { function getAllAffectedTablesFromSourceNodes(node) { var affectedTables = node.getAllInputNodes(function (node) { return node.getType() === 'source'; - }).reduce(function(list, node) { return list.concat(node.getAffectedTables()); },[]); + }).reduce(function(list, node) { + return list.concat(node.getAffectedTables()); + },[]); return affectedTables; } diff --git a/test/acceptance/x_cache_channel.js b/test/acceptance/cache/cache_headers.js similarity index 81% rename from test/acceptance/x_cache_channel.js rename to test/acceptance/cache/cache_headers.js index 298c0ef0..13ca77dc 100644 --- a/test/acceptance/x_cache_channel.js +++ b/test/acceptance/cache/cache_headers.js @@ -1,16 +1,16 @@ -var testHelper = require('../support/test_helper'); +var testHelper = require('../../support/test_helper'); -var assert = require('../support/assert'); +var assert = require('../../support/assert'); var qs = require('querystring'); -var CartodbWindshaft = require('../../lib/cartodb/server'); -var serverOptions = require('../../lib/cartodb/server_options'); +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'); +var LayergroupToken = require('../../support/layergroup-token'); -describe('get requests x-cache-channel', function() { +describe('get requests with cache headers', function() { var keysToDelete; beforeEach(function() { @@ -27,11 +27,14 @@ describe('get requests x-cache-channel', function() { var mapConfigs = [ { - "description": "header should be present", - "x_cache_channel": "test_windshaft_cartodb_user_1_db:public.test_table", + "description": "cache headers should be present", + "cache_headers": { + "x_cache_channel": "test_windshaft_cartodb_user_1_db:public.test_table", + "surrogate_keys": "t:77pJnX" + }, "data": { - version: '1.4.0', + version: '1.5.0', layers: [ { options: { @@ -63,10 +66,13 @@ describe('get requests x-cache-channel', function() { }, }, { - "description": "header should be present and be composed with source table name", - "x_cache_channel": "test_windshaft_cartodb_user_1_db:" + - "public.analysis_2f13a3dbd7_9eb239903a1afd8a69130d1ece0fc8b38de8592d" + - ",public.test_table", + "description": "cache headers should be present and be composed with source table name", + "cache_headers": { + "x_cache_channel": "test_windshaft_cartodb_user_1_db:" + + "public.analysis_2f13a3dbd7_9eb239903a1afd8a69130d1ece0fc8b38de8592d" + + ",public.test_table", + "surrogate_keys": "t:77pJnX t:iL4eth" + }, "data": { version: '1.5.0', @@ -136,22 +142,24 @@ describe('get requests x-cache-channel', function() { }; } - function validateXCacheChannel(done, expectedCacheChannel) { + function validateCacheHeaders(done, expectedCacheHeaders) { 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); + assert.ok(res.headers['surrogate-key']); + if (expectedCacheHeaders) { + assert.equal(res.headers['x-cache-channel'], expectedCacheHeaders.x_cache_channel); + assert.equal(res.headers['surrogate-key'], expectedCacheHeaders.surrogate_keys); } done(); }; } - function noXCacheChannelHeader(done) { + function noCacheHeaders(done) { return function(res, err) { if (err) { return done(err); @@ -161,6 +169,10 @@ describe('get requests x-cache-channel', function() { !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(); }; } @@ -185,9 +197,9 @@ describe('get requests x-cache-channel', function() { mapConfigs.forEach(function(mapConfigData) { describe(mapConfigData.description, function() { var mapConfig = mapConfigData.data; - var expectedCacheChannel = mapConfigData.x_cache_channel; + var expectedCacheHeaders = mapConfigData.cache_headers; it('/api/v1/map Map instantiation', function(done) { - var testFn = validateXCacheChannel(done, expectedCacheChannel); + var testFn = validateCacheHeaders(done, expectedCacheHeaders); withLayergroupId(mapConfig, function(err, layergroupId, res) { testFn(res); }); @@ -198,7 +210,7 @@ describe('get requests x-cache-channel', function() { assert.response( server, getRequest('/api/v1/map/' + layergroupId + '/0/0/0@2x.png', true), - validateXCacheChannel(done, expectedCacheChannel) + validateCacheHeaders(done, expectedCacheHeaders) ); }); }); @@ -208,7 +220,7 @@ describe('get requests x-cache-channel', function() { assert.response( server, getRequest('/api/v1/map/' + layergroupId + '/0/0/0.png', true), - validateXCacheChannel(done, expectedCacheChannel) + validateCacheHeaders(done, expectedCacheHeaders) ); }); }); @@ -218,7 +230,7 @@ describe('get requests x-cache-channel', function() { assert.response( server, getRequest('/api/v1/map/' + layergroupId + '/0/0/0/0.png', true), - validateXCacheChannel(done, expectedCacheChannel) + validateCacheHeaders(done, expectedCacheHeaders) ); }); }); @@ -228,7 +240,7 @@ describe('get requests x-cache-channel', function() { assert.response( server, getRequest('/api/v1/map/' + layergroupId + '/0/attributes/1', true), - validateXCacheChannel(done, expectedCacheChannel) + validateCacheHeaders(done, expectedCacheHeaders) ); }); }); @@ -238,7 +250,7 @@ describe('get requests x-cache-channel', function() { assert.response( server, getRequest('/api/v1/map/static/center/' + layergroupId + '/0/0/0/400/300.png', true), - validateXCacheChannel(done, expectedCacheChannel) + validateCacheHeaders(done, expectedCacheHeaders) ); }); }); @@ -248,21 +260,21 @@ describe('get requests x-cache-channel', function() { assert.response( server, getRequest('/api/v1/map/static/bbox/' + layergroupId + '/-45,-45,45,45/400/300.png', true), - validateXCacheChannel(done, expectedCacheChannel) + validateCacheHeaders(done, expectedCacheHeaders) ); }); }); }); }); - describe('header should NOT be present', function() { + describe('cache headers should NOT be present', function() { it('/', function(done) { assert.response( server, getRequest('/'), statusOkResponse, - noXCacheChannelHeader(done) + noCacheHeaders(done) ); }); @@ -271,7 +283,7 @@ describe('get requests x-cache-channel', function() { server, getRequest('/version'), statusOkResponse, - noXCacheChannelHeader(done) + noCacheHeaders(done) ); }); @@ -280,7 +292,7 @@ describe('get requests x-cache-channel', function() { server, getRequest('/health'), statusOkResponse, - noXCacheChannelHeader(done) + noCacheHeaders(done) ); }); @@ -289,7 +301,7 @@ describe('get requests x-cache-channel', function() { server, getRequest('/api/v1/map/named', true), statusOkResponse, - noXCacheChannelHeader(done) + noCacheHeaders(done) ); }); @@ -352,7 +364,7 @@ describe('get requests x-cache-channel', function() { server, getRequest('/api/v1/map/named/' + templateName, true), statusOkResponse, - noXCacheChannelHeader(done) + noCacheHeaders(done) ); }); @@ -361,7 +373,7 @@ describe('get requests x-cache-channel', function() { server, getRequest('/api/v1/map/named/' + templateName, true, 'cb'), statusOkResponse, - noXCacheChannelHeader(done) + noCacheHeaders(done) ); }); }); From 1fc49b5ad57f0a698451939bc13937b72a575d5f Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Tue, 14 Mar 2017 14:06:50 +0100 Subject: [PATCH 5/9] Add cdb_invalidate_varnish function fixture to tests --- test/support/prepare_db.sh | 2 +- test/support/sql/cdb_invalidate_varnish.sql | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 test/support/sql/cdb_invalidate_varnish.sql 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 From fff2c33100b4d36cc0f5215d71e9e7650998d210 Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Tue, 14 Mar 2017 14:32:36 +0100 Subject: [PATCH 6/9] Make the cache headers tests idempotent --- test/acceptance/cache/cache_headers.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/test/acceptance/cache/cache_headers.js b/test/acceptance/cache/cache_headers.js index 13ca77dc..2cd916af 100644 --- a/test/acceptance/cache/cache_headers.js +++ b/test/acceptance/cache/cache_headers.js @@ -29,7 +29,10 @@ describe('get requests with cache headers', function() { { "description": "cache headers should be present", "cache_headers": { - "x_cache_channel": "test_windshaft_cartodb_user_1_db:public.test_table", + "x_cache_channel": { + "db_name": "test_windshaft_cartodb_user_1_db", + "tables": ["public.test_table"] + }, "surrogate_keys": "t:77pJnX" }, "data": @@ -68,9 +71,11 @@ describe('get requests with cache headers', function() { { "description": "cache headers should be present and be composed with source table name", "cache_headers": { - "x_cache_channel": "test_windshaft_cartodb_user_1_db:" + - "public.analysis_2f13a3dbd7_9eb239903a1afd8a69130d1ece0fc8b38de8592d" + - ",public.test_table", + "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": @@ -151,7 +156,7 @@ describe('get requests with cache headers', function() { assert.ok(res.headers['x-cache-channel']); assert.ok(res.headers['surrogate-key']); if (expectedCacheHeaders) { - assert.equal(res.headers['x-cache-channel'], expectedCacheHeaders.x_cache_channel); + validateXChannelHeaders(res.headers, expectedCacheHeaders); assert.equal(res.headers['surrogate-key'], expectedCacheHeaders.surrogate_keys); } @@ -159,6 +164,13 @@ describe('get requests with cache headers', function() { }; } + 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) { From 5c22a7439f1caa14417ab73ac118ad3597b15c35 Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Tue, 14 Mar 2017 12:57:46 +0100 Subject: [PATCH 7/9] Point to camshaft branch to test properly --- npm-shrinkwrap.json | 48 ++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 13ab1331..5d51b776 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.52.1", + "from": "cartodb/camshaft#add_affected_tables", + "resolved": "git://github.com/cartodb/camshaft.git#cb5ebc468ceb33e18a908ff80980228742140b73", "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": { @@ -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.8", "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.8.tgz", "dependencies": { "buffer-shims": { "version": "1.0.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": { @@ -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.8", "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.8.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.8", "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.8.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": { @@ -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.8", "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.8.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..79d0b19e 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ ], "dependencies": { "body-parser": "~1.14.0", - "camshaft": "0.52.0", + "camshaft": "cartodb/camshaft#add_affected_tables", "cartodb-psql": "~0.7.1", "cartodb-query-tables": "~0.1.0", "cartodb-redis": "0.13.1", From 8fa7f7d779c7e74a574a9e3dd5b060c8902be2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Aubert?= Date: Mon, 10 Apr 2017 11:54:06 +0200 Subject: [PATCH 8/9] Upgrade camshaft to 0.53.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 79d0b19e..b419b982 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ ], "dependencies": { "body-parser": "~1.14.0", - "camshaft": "cartodb/camshaft#add_affected_tables", + "camshaft": "0.53.0", "cartodb-psql": "~0.7.1", "cartodb-query-tables": "~0.1.0", "cartodb-redis": "0.13.1", From 8cba537ac60017d03444be1bd6d92f14ad3c945d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Aubert?= Date: Mon, 10 Apr 2017 12:05:24 +0200 Subject: [PATCH 9/9] Update shrinkwrap --- npm-shrinkwrap.json | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 5d51b776..76a043be 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -105,9 +105,9 @@ } }, "camshaft": { - "version": "0.52.1", - "from": "cartodb/camshaft#add_affected_tables", - "resolved": "git://github.com/cartodb/camshaft.git#cb5ebc468ceb33e18a908ff80980228742140b73", + "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", @@ -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", @@ -1693,9 +1693,9 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" }, "readable-stream": { - "version": "2.2.8", + "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.8.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", @@ -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" } } @@ -2321,9 +2321,9 @@ } }, "readable-stream": { - "version": "2.2.8", + "version": "2.2.9", "from": "readable-stream@>=2.1.4 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.8.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "dependencies": { "buffer-shims": { "version": "1.0.0", @@ -4197,9 +4197,9 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" }, "readable-stream": { - "version": "2.2.8", + "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.8.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "dependencies": { "buffer-shims": { "version": "1.0.0", @@ -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", @@ -4813,9 +4813,9 @@ } }, "readable-stream": { - "version": "2.2.8", + "version": "2.2.9", "from": "readable-stream@>=2.1.4 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.8.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "dependencies": { "buffer-shims": { "version": "1.0.0",