diff --git a/.jshintignore b/.eslintignore similarity index 100% rename from .jshintignore rename to .eslintignore diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..609a2aea --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,22 @@ +module.exports = { + env: { + commonjs: true, + es6: true, + node: true, + mocha: true + }, + extends: [ + 'standard' + ], + globals: { + Atomics: 'readonly', + SharedArrayBuffer: 'readonly' + }, + parserOptions: { + ecmaVersion: 2018 + }, + rules: { + "indent": ["error", 4], + "semi": ["error", "always"] + } +} diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index fbc4c96e..00000000 --- a/.jshintrc +++ /dev/null @@ -1,95 +0,0 @@ -{ -// // JSHint Default Configuration File (as on JSHint website) -// // See http://jshint.com/docs/ for more details -// -// "maxerr" : 50, // {int} Maximum error before stopping -// -// // Enforcing -// "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) -// "camelcase" : false, // true: Identifiers must be in camelCase - "curly" : true, // true: Require {} for every new block or scope - "eqeqeq" : true, // true: Require triple equals (===) for comparison - "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() - "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc. - "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` -// "indent" : 4, // {int} Number of spaces to use for indentation -// "latedef" : false, // true: Require variables/functions to be defined before being used - "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` - "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` -// "noempty" : true, // true: Prohibit use of empty blocks - "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters. - "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment) -// "plusplus" : false, // true: Prohibit use of `++` & `--` -// "quotmark" : false, // Quotation mark consistency: -// // false : do nothing (default) -// // true : ensure whatever is used is consistent -// // "single" : require single quotes -// // "double" : require double quotes - "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) - "unused" : true, // true: Require all defined variables be used -// "strict" : true, // true: Requires all functions run in ES5 Strict Mode -// "maxparams" : false, // {int} Max number of formal params allowed per function -// "maxdepth" : false, // {int} Max depth of nested blocks (within functions) -// "maxstatements" : false, // {int} Max number statements per function - "maxcomplexity" : 6, // {int} Max cyclomatic complexity per function - "maxlen" : 120, // {int} Max number of characters per line -// -// // Relaxing -// "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) -// "boss" : false, // true: Tolerate assignments where comparisons would be expected - "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. -// "eqnull" : false, // true: Tolerate use of `== null` -// "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) - "esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`) -// "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) -// // (ex: `for each`, multiple try/catch, function expression…) -// "evil" : false, // true: Tolerate use of `eval` and `new Function()` -// "expr" : false, // true: Tolerate `ExpressionStatement` as Programs -// "funcscope" : false, // true: Tolerate defining variables inside control statements -// "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') -// "iterator" : false, // true: Tolerate using the `__iterator__` property -// "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block -// "laxbreak" : false, // true: Tolerate possibly unsafe line breakings -// "laxcomma" : false, // true: Tolerate comma-first style coding -// "loopfunc" : false, // true: Tolerate functions being defined in loops -// "multistr" : false, // true: Tolerate multi-line strings -// "noyield" : false, // true: Tolerate generator functions with no yield statement in them. -// "notypeof" : false, // true: Tolerate invalid typeof operator values -// "proto" : false, // true: Tolerate using the `__proto__` property -// "scripturl" : false, // true: Tolerate script-targeted URLs -// "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` -// "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation -// "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` -// "validthis" : false, // true: Tolerate using this in a non-constructor function -// -// // Environments -// "browser" : true, // Web Browser (window, document, etc) -// "browserify" : false, // Browserify (node.js code in the browser) -// "couch" : false, // CouchDB -// "devel" : true, // Development/debugging (alert, confirm, etc) -// "dojo" : false, // Dojo Toolkit -// "jasmine" : false, // Jasmine -// "jquery" : false, // jQuery -// "mocha" : true, // Mocha -// "mootools" : false, // MooTools - "node" : true, // Node.js -// "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) -// "prototypejs" : false, // Prototype and Scriptaculous -// "qunit" : false, // QUnit -// "rhino" : false, // Rhino -// "shelljs" : false, // ShellJS -// "worker" : false, // Web Workers -// "wsh" : false, // Windows Scripting Host -// "yui" : false, // Yahoo User Interface - - // Custom predefined global variables - "predef": [ - "-console", // disallows console, use debug - "beforeEach", - "afterEach", - "before", - "after", - "describe", - "it" - ] -} diff --git a/Makefile b/Makefile index f523adda..23554888 100644 --- a/Makefile +++ b/Makefile @@ -39,15 +39,15 @@ test-acceptance: config/environments/test.js @echo "***tests***" @$(SHELL) ./run_tests.sh ${RUNTESTFLAGS} $(TEST_SUITE_ACCEPTANCE) -jshint: - @echo "***jshint***" - @./node_modules/.bin/jshint lib/ test/ app.js +lint: + @echo "***eslint***" + @./node_modules/.bin/eslint app.js "lib/**/*.js" "test/**/*.js" -test-all: test jshint +test-all: test lint coverage: @RUNTESTFLAGS=--with-coverage make test check: test -.PHONY: pre-install test jshint coverage +.PHONY: pre-install test lint coverage diff --git a/NEWS.md b/NEWS.md index 830b7de4..480f1957 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,9 @@ ## 8.0.1 Released 2019-mm-dd +Announcements: +- Removed `jshint` as linter in favour of `eslint` to check syntax, find problems, and enforce code style. + ## 8.0.0 Released 2019-11-13 diff --git a/app.js b/app.js index e8cd445b..445e5389 100755 --- a/app.js +++ b/app.js @@ -54,7 +54,7 @@ var availableEnvironments = { }; // sanity check -if (!availableEnvironments[ENVIRONMENT]){ +if (!availableEnvironments[ENVIRONMENT]) { logError('node app.js [environment]'); logError('environments: %s', Object.keys(availableEnvironments).join(', ')); process.exit(1); @@ -76,27 +76,26 @@ var agentOptions = _.defaults(global.environment.httpAgent || {}, { http.globalAgent = new http.Agent(agentOptions); https.globalAgent = new https.Agent(agentOptions); - global.log4js = require('log4js'); var log4jsConfig = { appenders: [], replaceConsole: true }; -if ( global.environment.log_filename ) { +if (global.environment.log_filename) { var logFilename = path.resolve(global.environment.log_filename); var logDirectory = path.dirname(logFilename); if (!fs.existsSync(logDirectory)) { - logError("Log filename directory does not exist: " + logDirectory); + logError('Log filename directory does not exist: ' + logDirectory); process.exit(1); } - log("Logs will be written to " + logFilename); + log('Logs will be written to ' + logFilename); log4jsConfig.appenders.push( - { type: "file", absolute: true, filename: logFilename } + { type: 'file', absolute: true, filename: logFilename } ); } else { log4jsConfig.appenders.push( - { type: "console", layout: { type:'basic' } } + { type: 'console', layout: { type: 'basic' } } ); } @@ -118,13 +117,13 @@ var backlog = global.environment.maxConnections || 128; var listener = server.listen(serverOptions.bind.port, serverOptions.bind.host, backlog); -var version = require("./package").version; +var version = require('./package').version; -listener.on('listening', function() { - log("Using Node.js %s", process.version); +listener.on('listening', function () { + log('Using Node.js %s', process.version); log('Using configuration file "%s"', configurationFile); log( - "Windshaft tileserver %s started on %s:%s PID=%d (%s)", + 'Windshaft tileserver %s started on %s:%s PID=%d (%s)', version, serverOptions.bind.host, serverOptions.bind.port, process.pid, ENVIRONMENT ); }); @@ -163,15 +162,15 @@ setInterval(function cpuUsageMetrics () { previousCPUUsage = CPUUsage; }, 5000); -setInterval(function() { +setInterval(function () { var memoryUsage = process.memoryUsage(); - Object.keys(memoryUsage).forEach(function(k) { + Object.keys(memoryUsage).forEach(function (k) { global.statsClient.gauge('windshaft.memory.' + k, memoryUsage[k]); }); }, 5000); -process.on('SIGHUP', function() { - global.log4js.clearAndShutdownAppenders(function() { +process.on('SIGHUP', function () { + global.log4js.clearAndShutdownAppenders(function () { global.log4js.configure(log4jsConfig); global.logger = global.log4js.getLogger(); log('Log files reloaded'); @@ -179,12 +178,12 @@ process.on('SIGHUP', function() { }); if (global.gc) { - var gcInterval = Number.isFinite(global.environment.gc_interval) ? - global.environment.gc_interval : - 10000; + var gcInterval = Number.isFinite(global.environment.gc_interval) + ? global.environment.gc_interval + : 10000; if (gcInterval > 0) { - setInterval(function gcForcedCycle() { + setInterval(function gcForcedCycle () { global.gc(); }, gcInterval); } @@ -206,24 +205,24 @@ function getGCTypeValue (type) { let value; switch (type) { - case 1: - value = 'Scavenge'; - break; - case 2: - value = 'MarkSweepCompact'; - break; - case 4: - value = 'IncrementalMarking'; - break; - case 8: - value = 'ProcessWeakCallbacks'; - break; - case 15: - value = 'All'; - break; - default: - value = 'Unkown'; - break; + case 1: + value = 'Scavenge'; + break; + case 2: + value = 'MarkSweepCompact'; + break; + case 4: + value = 'IncrementalMarking'; + break; + case 8: + value = 'ProcessWeakCallbacks'; + break; + case 15: + value = 'All'; + break; + default: + value = 'Unkown'; + break; } return value; @@ -231,7 +230,7 @@ function getGCTypeValue (type) { addHandlers(listener, global.logger, 45000); -function addHandlers(listener, logger, killTimeout) { +function addHandlers (listener, logger, killTimeout) { process.on('uncaughtException', exitProcess(listener, logger, killTimeout)); process.on('unhandledRejection', exitProcess(listener, logger, killTimeout)); process.on('ENOMEM', exitProcess(listener, logger, killTimeout)); diff --git a/lib/api/api-router.js b/lib/api/api-router.js index b3ff84cc..ad89d0a3 100644 --- a/lib/api/api-router.js +++ b/lib/api/api-router.js @@ -1,5 +1,7 @@ 'use strict'; +const path = require('path'); + const { Router: router } = require('express'); const RedisPool = require('redis-mpool'); @@ -83,10 +85,9 @@ module.exports = class ApiRouter { const metadataBackend = cartodbRedis({ pool: redisPool }); const pgConnection = new PgConnection(metadataBackend); - const windshaftLogger = environmentOptions.log_windshaft && global.log4js ? - global.log4js.getLogger('[windshaft]') : - null; - + const windshaftLogger = environmentOptions.log_windshaft && global.log4js + ? global.log4js.getLogger('[windshaft]') + : null; const mapStore = new windshaft.storage.MapStore({ pool: redisPool, expire_time: serverOptions.grainstore.default_layergroup_ttl, @@ -237,7 +238,6 @@ module.exports = class ApiRouter { } }; - function createTemplateMaps ({ redisPool, surrogateKeysCache }) { const templateMaps = new TemplateMaps(redisPool, { max_user_templates: global.environment.maxUserTemplates @@ -245,12 +245,12 @@ function createTemplateMaps ({ redisPool, surrogateKeysCache }) { function invalidateNamedMap (owner, templateName) { var startTime = Date.now(); - surrogateKeysCache.invalidate(new NamedMapsCacheEntry(owner, templateName), function(err) { + surrogateKeysCache.invalidate(new NamedMapsCacheEntry(owner, templateName), function (err) { var logMessage = JSON.stringify({ username: owner, type: 'named_map_invalidation', elapsed: Date.now() - startTime, - error: !!err ? JSON.stringify(err.message) : undefined + error: err ? JSON.stringify(err.message) : undefined }); if (err) { global.logger.warn(logMessage); @@ -260,15 +260,14 @@ function createTemplateMaps ({ redisPool, surrogateKeysCache }) { }); } - - ['update', 'delete'].forEach(function(eventType) { + ['update', 'delete'].forEach(function (eventType) { templateMaps.on(eventType, invalidateNamedMap); }); return templateMaps; } -function createSurrogateKeysCacheBackends(serverOptions) { +function createSurrogateKeysCacheBackends (serverOptions) { var cacheBackends = []; if (serverOptions.varnish_purge_enabled) { @@ -287,14 +286,13 @@ function createSurrogateKeysCacheBackends(serverOptions) { return cacheBackends; } -const timeoutErrorTilePath = __dirname + '/../../assets/render-timeout-fallback.png'; -const timeoutErrorTile = require('fs').readFileSync(timeoutErrorTilePath, {encoding: null}); +const timeoutErrorTilePath = path.join(__dirname, '/../../assets/render-timeout-fallback.png'); +const timeoutErrorTile = require('fs').readFileSync(timeoutErrorTilePath, { encoding: null }); function createRendererFactory ({ redisPool, serverOptions, environmentOptions }) { var onTileErrorStrategy; if (environmentOptions.enabledFeatures.onTileErrorStrategy !== false) { - onTileErrorStrategy = function onTileErrorStrategy$TimeoutTile(err, tile, headers, stats, format, callback) { - + onTileErrorStrategy = function onTileErrorStrategy$TimeoutTile (err, tile, headers, stats, format, callback) { function isRenderTimeoutError (err) { return err.message === 'Render timed out'; } @@ -313,7 +311,7 @@ function createRendererFactory ({ redisPool, serverOptions, environmentOptions } if (isTimeoutError(err) && isRasterFormat(format)) { return callback(null, timeoutErrorTile, { - 'Content-Type': 'image/png', + 'Content-Type': 'image/png' }, {}); } else { return callback(err, tile, headers, stats); diff --git a/lib/api/map/analyses-catalog-controller.js b/lib/api/map/analyses-catalog-controller.js index 8c75af63..31cd2ee7 100644 --- a/lib/api/map/analyses-catalog-controller.js +++ b/lib/api/map/analyses-catalog-controller.js @@ -48,10 +48,10 @@ function createPGClient () { }; } -function getDataFromQuery({ queryTemplate, key }) { +function getDataFromQuery ({ queryTemplate, key }) { const readOnlyTransactionOn = true; - return function getCatalogMiddleware(req, res, next) { + return function getCatalogMiddleware (req, res, next) { const { pg, user } = res.locals; const sql = queryTemplate({ _username: user }); @@ -82,27 +82,27 @@ function prepareResponse () { }, {}); const analysisCatalog = catalog.map(analysis => { - if (analysisIdToTable.hasOwnProperty(analysis.node_id)) { + if (Object.prototype.hasOwnProperty.call(analysisIdToTable, analysis.node_id)) { analysis.table = analysisIdToTable[analysis.node_id]; } return analysis; }) - .sort((analysisA, analysisB) => { - if (!!analysisA.table && !!analysisB.table) { - return analysisB.table.size - analysisA.table.size; - } + .sort((analysisA, analysisB) => { + if (!!analysisA.table && !!analysisB.table) { + return analysisB.table.size - analysisA.table.size; + } + + if (analysisA.table) { + return -1; + } + + if (analysisB.table) { + return 1; + } - if (!!analysisA.table) { return -1; - } - - if (!!analysisB.table) { - return 1; - } - - return -1; - }); + }); res.statusCode = 200; res.body = { catalog: analysisCatalog }; @@ -112,7 +112,7 @@ function prepareResponse () { } function unauthorizedError () { - return function unathorizedErrorMiddleware(err, req, res, next) { + return function unathorizedErrorMiddleware (err, req, res, next) { if (err.message.match(/permission\sdenied/)) { err = new Error('Unauthorized'); err.http_status = 401; diff --git a/lib/api/map/analysis-layergroup-controller.js b/lib/api/map/analysis-layergroup-controller.js index fe51e607..188292e5 100644 --- a/lib/api/map/analysis-layergroup-controller.js +++ b/lib/api/map/analysis-layergroup-controller.js @@ -35,7 +35,7 @@ module.exports = class AnalysisLayergroupController { }; function analysisNodeStatus (analysisStatusBackend) { - return function analysisNodeStatusMiddleware(req, res, next) { + return function analysisNodeStatusMiddleware (req, res, next) { const { nodeId } = req.params; const dbParams = dbParamsFromResLocals(res.locals); diff --git a/lib/api/map/anonymous-map-controller.js b/lib/api/map/anonymous-map-controller.js index 32707b03..508e1cd8 100644 --- a/lib/api/map/anonymous-map-controller.js +++ b/lib/api/map/anonymous-map-controller.js @@ -87,7 +87,7 @@ module.exports = class AnonymousMapController { checkJsonContentType(), checkCreateLayergroup(), prepareAdapterMapConfig(this.mapConfigAdapter), - createLayergroup ( + createLayergroup( this.mapBackend, this.userLimitsBackend, this.pgConnection, @@ -130,10 +130,10 @@ function checkCreateLayergroup () { } function prepareAdapterMapConfig (mapConfigAdapter) { - return function prepareAdapterMapConfigMiddleware(req, res, next) { + return function prepareAdapterMapConfigMiddleware (req, res, next) { const requestMapConfig = req.body; - const { user, api_key } = res.locals; + const { user, api_key: apiKey } = res.locals; const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals; const params = Object.assign({ dbuser, dbname, dbpassword, dbhost, dbport }, req.query); @@ -149,31 +149,30 @@ function prepareAdapterMapConfig (mapConfigAdapter) { }, batch: { username: user, - apiKey: api_key + apiKey } } }; mapConfigAdapter.getMapConfig(user, - requestMapConfig, - params, - context, - (err, requestMapConfig, stats = { overviewsAddedToMapconfig : false }) => { - req.profiler.done('anonymous.getMapConfig'); + requestMapConfig, + params, + context, + (err, requestMapConfig, stats = { overviewsAddedToMapconfig: false }) => { + req.profiler.done('anonymous.getMapConfig'); - stats.mapType = 'anonymous'; - req.profiler.add(stats); + stats.mapType = 'anonymous'; + req.profiler.add(stats); + if (err) { + return next(err); + } - if (err) { - return next(err); - } + req.body = requestMapConfig; + res.locals.context = context; - req.body = requestMapConfig; - res.locals.context = context; - - next(); - }); + next(); + }); }; } @@ -182,12 +181,17 @@ function createLayergroup (mapBackend, userLimitsBackend, pgConnection, affected const requestMapConfig = req.body; const { context } = res.locals; - const { user, cache_buster, api_key } = res.locals; + const { user, cache_buster: cacheBuster, api_key: apiKey } = res.locals; const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals; const params = { - cache_buster, api_key, - dbuser, dbname, dbpassword, dbhost, dbport + cache_buster: cacheBuster, + api_key: apiKey, + dbuser, + dbname, + dbpassword, + dbhost, + dbport }; const datasource = context.datasource || Datasource.EmptyDatasource(); diff --git a/lib/api/map/attributes-layergroup-controller.js b/lib/api/map/attributes-layergroup-controller.js index a9a26ada..f734d3d2 100644 --- a/lib/api/map/attributes-layergroup-controller.js +++ b/lib/api/map/attributes-layergroup-controller.js @@ -70,8 +70,13 @@ function getFeatureAttributes (attributesBackend) { const params = { token, - dbuser, dbname, dbpassword, dbhost, dbport, - layer, fid + dbuser, + dbname, + dbpassword, + dbhost, + dbport, + layer, + fid }; attributesBackend.getFeatureAttributes(mapConfigProvider, params, false, (err, tile, stats = {}) => { diff --git a/lib/api/map/clustered-features-layergroup-controller.js b/lib/api/map/clustered-features-layergroup-controller.js index 573436d8..7b300ac7 100644 --- a/lib/api/map/clustered-features-layergroup-controller.js +++ b/lib/api/map/clustered-features-layergroup-controller.js @@ -44,7 +44,7 @@ module.exports = class AggregatedFeaturesLayergroupController { dbConnSetup(this.pgConnection), // TODO: create its rate limit rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ATTRIBUTES), - cleanUpQueryParams([ 'aggregation' ]), + cleanUpQueryParams(['aggregation']), createMapStoreMapConfigProvider( this.mapStore, this.userLimitsBackend, @@ -71,9 +71,16 @@ function getClusteredFeatures (clusterBackend) { const { aggregation } = req.query; const params = { - user, token, - dbuser, dbname, dbpassword, dbhost, dbport, - layer, zoom, clusterId, + user, + token, + dbuser, + dbname, + dbpassword, + dbhost, + dbport, + layer, + zoom, + clusterId, aggregation }; diff --git a/lib/api/map/dataview-layergroup-controller.js b/lib/api/map/dataview-layergroup-controller.js index 234e6106..a10fbc25 100644 --- a/lib/api/map/dataview-layergroup-controller.js +++ b/lib/api/map/dataview-layergroup-controller.js @@ -22,10 +22,10 @@ const ALLOWED_DATAVIEW_QUERY_PARAMS = [ 'end', // number 'column_type', // string 'bins', // number - 'aggregation', //string + 'aggregation', // string 'offset', // number 'q', // widgets search - 'categories', // number + 'categories' // number ]; module.exports = class DataviewLayergroupController { diff --git a/lib/api/map/preview-template-controller.js b/lib/api/map/preview-template-controller.js index e4c0beed..989bb8e1 100644 --- a/lib/api/map/preview-template-controller.js +++ b/lib/api/map/preview-template-controller.js @@ -21,7 +21,7 @@ const DEFAULT_ZOOM_CENTER = { } }; -function numMapper(n) { +function numMapper (n) { return +n; } @@ -60,7 +60,8 @@ module.exports = class PreviewTemplateController { checkStaticImageFormat(), namedMapProvider({ namedMapProviderCache: this.namedMapProviderCache, - label: 'STATIC_VIZ_MAP', forcedFormat: 'png' + label: 'STATIC_VIZ_MAP', + forcedFormat: 'png' }), getTemplate({ label: 'STATIC_VIZ_MAP' }), prepareLayerFilterFromPreviewLayers({ @@ -99,7 +100,7 @@ function getTemplate ({ label }) { function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label }) { return function prepareLayerFilterFromPreviewLayersMiddleware (req, res, next) { const { template } = res.locals; - const { config, auth_token } = req.query; + const { config, auth_token: authToken } = req.query; if (!template || !template.view || !template.view.preview_layers) { return next(); @@ -109,8 +110,8 @@ function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label }) var layerVisibilityFilter = []; template.layergroup.layers.forEach((layer, index) => { - if (previewLayers[''+index] !== false && previewLayers[layer.id] !== false) { - layerVisibilityFilter.push(''+index); + if (previewLayers['' + index] !== false && previewLayers[layer.id] !== false) { + layerVisibilityFilter.push('' + index); } }); @@ -118,21 +119,29 @@ function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label }) return next(); } - const { user, token, cache_buster, api_key } = res.locals; + const { user, token, cache_buster: cacheBuster, api_key: apiKey } = res.locals; const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals; - const { template_id, format } = req.params; + const { template_id: templateId, format } = req.params; const params = { - user, token, cache_buster, api_key, - dbuser, dbname, dbpassword, dbhost, dbport, - template_id, format + user, + token, + cache_buster: cacheBuster, + api_key: apiKey, + dbuser, + dbname, + dbpassword, + dbhost, + dbport, + template_id: templateId, + format }; // overwrites 'all' default filter params.layer = layerVisibilityFilter.join(','); // recreates the provider - namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, provider) => { + namedMapProviderCache.get(user, templateId, config, authToken, params, (err, provider) => { if (err) { err.label = label; return next(err); @@ -146,7 +155,7 @@ function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label }) } function getStaticImageOptions ({ tablesExtentBackend }) { - return function getStaticImageOptionsMiddleware(req, res, next) { + return function getStaticImageOptionsMiddleware (req, res, next) { const { user, mapConfigProvider, template } = res.locals; const { zoom, lon, lat, bbox } = req.query; const params = { zoom, lon, lat, bbox }; @@ -248,7 +257,7 @@ function getImageOptionsFromBoundingBox (bbox = '') { } } -function getImage({ previewBackend, label }) { +function getImage ({ previewBackend, label }) { return function getImageMiddleware (req, res, next) { const { imageOpts, mapConfigProvider } = res.locals; const { zoom, center, bbox } = imageOpts; @@ -298,7 +307,7 @@ function getImage({ previewBackend, label }) { } function setContentTypeHeader () { - return function setContentTypeHeaderMiddleware(req, res, next) { + return function setContentTypeHeaderMiddleware (req, res, next) { const format = req.params.format === 'jpg' ? 'jpeg' : 'png'; res.set('Content-Type', `image/${format}`); @@ -312,7 +321,7 @@ function incrementMapViewsError (ctx) { } function incrementMapViews ({ metadataBackend }) { - return function incrementMapViewsMiddleware(req, res, next) { + return function incrementMapViewsMiddleware (req, res, next) { const { user, mapConfigProvider } = res.locals; mapConfigProvider.getMapConfig((err, mapConfig) => { @@ -334,7 +343,7 @@ function incrementMapViews ({ metadataBackend }) { }; } -function templateZoomCenter(view) { +function templateZoomCenter (view) { if (view.zoom !== undefined && view.center) { return { zoom: view.zoom, @@ -344,7 +353,7 @@ function templateZoomCenter(view) { return false; } -function templateBounds(view) { +function templateBounds (view) { if (view.bounds) { var hasAllBounds = ['west', 'south', 'east', 'north'].every(prop => Number.isFinite(view.bounds[prop])); diff --git a/lib/api/map/tile-layergroup-controller.js b/lib/api/map/tile-layergroup-controller.js index 18fe23be..a067c2e6 100644 --- a/lib/api/map/tile-layergroup-controller.js +++ b/lib/api/map/tile-layergroup-controller.js @@ -45,14 +45,14 @@ module.exports = class TileLayergroupController { route (mapRouter) { // REGEXP: doesn't match with `val` - const not = (val) => `(?!${val})([^\/]+?)`; + const not = (val) => `(?!${val})([^\/]+?)`; // eslint-disable-line no-useless-escape // Sadly the path that matches 1 also matches with 2 so we need to tell to express // that performs only the middlewares of the first path that matches // for that we use one array to group all paths. mapRouter.get([ - `/:token/:z/:x/:y@:scale_factor?x.:format`, // 1 - `/:token/:z/:x/:y.:format`, // 2 + '/:token/:z/:x/:y@:scale_factor?x.:format', // 1 + '/:token/:z/:x/:y.:format', // 2 `/:token${not('static')}/:layer/:z/:x/:y.(:format)` ], this.middlewares()); } @@ -90,7 +90,7 @@ function parseFormat (format = '') { return SUPPORTED_FORMATS[prettyFormat] ? prettyFormat : 'invalid'; } -function getStatusCode(tile, format){ +function getStatusCode (tile, format) { return tile.length === 0 && format === 'mvt' ? 204 : 200; } @@ -149,9 +149,8 @@ function incrementErrorMetrics (statsClient) { function tileError () { return function tileErrorMiddleware (err, req, res, next) { - // See https://github.com/Vizzuality/Windshaft-cartodb/issues/68 - let errMsg = err.message ? ( '' + err.message ) : ( '' + err ); + let errMsg = err.message ? ('' + err.message) : ('' + err); // Rewrite mapnik parsing errors to start with layer number const matches = errMsg.match("(.*) in style 'layer([0-9]+)'"); diff --git a/lib/api/middlewares/authorize.js b/lib/api/middlewares/authorize.js index 619f1f74..506f0b77 100644 --- a/lib/api/middlewares/authorize.js +++ b/lib/api/middlewares/authorize.js @@ -9,8 +9,8 @@ module.exports = function authorize (authBackend) { return next(err); } - if(!authorized) { - err = new Error("Sorry, you are unauthorized (permission denied)"); + if (!authorized) { + err = new Error('Sorry, you are unauthorized (permission denied)'); err.http_status = 403; return next(err); } diff --git a/lib/api/middlewares/cache-control-header.js b/lib/api/middlewares/cache-control-header.js index 84b7a360..4043668a 100644 --- a/lib/api/middlewares/cache-control-header.js +++ b/lib/api/middlewares/cache-control-header.js @@ -48,7 +48,7 @@ module.exports = function setCacheControlHeader ({ return next(); } - const directives = [ 'public' ]; + const directives = ['public']; if (everyAffectedTableCanBeInvalidated(affectedTables)) { directives.push(`max-age=${ttl}`); diff --git a/lib/api/middlewares/check-json-content-type.js b/lib/api/middlewares/check-json-content-type.js index 6f02c750..57d7b5a8 100644 --- a/lib/api/middlewares/check-json-content-type.js +++ b/lib/api/middlewares/check-json-content-type.js @@ -1,7 +1,7 @@ 'use strict'; module.exports = function checkJsonContentType () { - return function checkJsonContentTypeMiddleware(req, res, next) { + return function checkJsonContentTypeMiddleware (req, res, next) { if (req.method === 'POST' && !req.is('application/json')) { return next(new Error('POST data must be of type application/json')); } diff --git a/lib/api/middlewares/check-static-image-format.js b/lib/api/middlewares/check-static-image-format.js index 411240db..d0cc89a8 100644 --- a/lib/api/middlewares/check-static-image-format.js +++ b/lib/api/middlewares/check-static-image-format.js @@ -4,7 +4,7 @@ const VALID_IMAGE_FORMATS = ['png', 'jpg']; module.exports = function checkStaticImageFormat () { return function checkStaticImageFormatMiddleware (req, res, next) { - if(!VALID_IMAGE_FORMATS.includes(req.params.format)) { + if (!VALID_IMAGE_FORMATS.includes(req.params.format)) { return next(new Error(`Unsupported image format "${req.params.format}"`)); } diff --git a/lib/api/middlewares/cors.js b/lib/api/middlewares/cors.js index 87e41dc7..5ac107af 100644 --- a/lib/api/middlewares/cors.js +++ b/lib/api/middlewares/cors.js @@ -13,8 +13,8 @@ module.exports = function cors () { headers.push('Content-Type'); } - res.set("Access-Control-Allow-Origin", "*"); - res.set("Access-Control-Allow-Headers", headers.join(', ')); + res.set('Access-Control-Allow-Origin', '*'); + res.set('Access-Control-Allow-Headers', headers.join(', ')); next(); }; diff --git a/lib/api/middlewares/credentials.js b/lib/api/middlewares/credentials.js index 71316f4b..10ceff13 100644 --- a/lib/api/middlewares/credentials.js +++ b/lib/api/middlewares/credentials.js @@ -3,24 +3,24 @@ const basicAuth = require('basic-auth'); module.exports = function credentials () { - return function credentialsMiddleware(req, res, next) { + return function credentialsMiddleware (req, res, next) { const apikeyCredentials = getApikeyCredentialsFromRequest(req); res.locals.api_key = apikeyCredentials.token; res.locals.basicAuthUsername = apikeyCredentials.username; - res.set('vary', 'Authorization'); //Honor Authorization header when caching. + res.set('vary', 'Authorization'); // Honor Authorization header when caching. return next(); }; }; -function getApikeyCredentialsFromRequest(req) { +function getApikeyCredentialsFromRequest (req) { let apikeyCredentials = { token: null, - username: null, + username: null }; - for (let getter of apikeyGetters) { + for (const getter of apikeyGetters) { apikeyCredentials = getter(req); if (apikeyTokenFound(apikeyCredentials)) { break; @@ -33,10 +33,10 @@ function getApikeyCredentialsFromRequest(req) { const apikeyGetters = [ getApikeyTokenFromHeaderAuthorization, getApikeyTokenFromRequestQueryString, - getApikeyTokenFromRequestBody, + getApikeyTokenFromRequestBody ]; -function getApikeyTokenFromHeaderAuthorization(req) { +function getApikeyTokenFromHeaderAuthorization (req) { const credentials = basicAuth(req); if (credentials) { @@ -47,12 +47,12 @@ function getApikeyTokenFromHeaderAuthorization(req) { } else { return { username: null, - token: null, + token: null }; } } -function getApikeyTokenFromRequestQueryString(req) { +function getApikeyTokenFromRequestQueryString (req) { let token = null; if (req.query && req.query.api_key) { @@ -63,11 +63,11 @@ function getApikeyTokenFromRequestQueryString(req) { return { username: null, - token: token, + token: token }; } -function getApikeyTokenFromRequestBody(req) { +function getApikeyTokenFromRequestBody (req) { let token = null; if (req.body && req.body.api_key) { @@ -78,10 +78,10 @@ function getApikeyTokenFromRequestBody(req) { return { username: null, - token: token, + token: token }; } -function apikeyTokenFound(apikey) { +function apikeyTokenFound (apikey) { return !!apikey && !!apikey.token; } diff --git a/lib/api/middlewares/db-conn-setup.js b/lib/api/middlewares/db-conn-setup.js index 0ab4d105..7a7e76a8 100644 --- a/lib/api/middlewares/db-conn-setup.js +++ b/lib/api/middlewares/db-conn-setup.js @@ -10,7 +10,7 @@ module.exports = function dbConnSetup (pgConnection) { req.profiler.done('dbConnSetup'); if (err) { - if (err.message && -1 !== err.message.indexOf('name not found')) { + if (err.message && err.message.indexOf('name not found') !== -1) { err.http_status = 404; } diff --git a/lib/api/middlewares/error-middleware.js b/lib/api/middlewares/error-middleware.js index 688b861a..cd649c90 100644 --- a/lib/api/middlewares/error-middleware.js +++ b/lib/api/middlewares/error-middleware.js @@ -52,10 +52,10 @@ function isTimeoutError (errorTypes) { return errorTypes.renderTimeoutError || errorTypes.datasourceTimeoutError; } -function getErrorTypes(error) { +function getErrorTypes (error) { return { renderTimeoutError: isRenderTimeoutError(error), - datasourceTimeoutError: isDatasourceTimeoutError(error), + datasourceTimeoutError: isDatasourceTimeoutError(error) }; } @@ -99,9 +99,9 @@ function populateLimitErrors (errors) { }); } -function findStatusCode(err) { +function findStatusCode (err) { var statusCode; - if ( err.http_status ) { + if (err.http_status) { statusCode = err.http_status; } else { statusCode = statusFromErrorMessage('' + err); @@ -111,34 +111,30 @@ function findStatusCode(err) { module.exports.findStatusCode = findStatusCode; -function statusFromErrorMessage(errMsg) { +function statusFromErrorMessage (errMsg) { // Find an appropriate statusCode based on message // jshint maxcomplexity:7 var statusCode = 400; - if ( -1 !== errMsg.indexOf('permission denied') ) { + if (errMsg.indexOf('permission denied') !== -1) { statusCode = 403; - } - else if ( -1 !== errMsg.indexOf('authentication failed') ) { + } else if (errMsg.indexOf('authentication failed') !== -1) { statusCode = 403; - } - else if (errMsg.match(/Postgis Plugin.*[\s|\n].*column.*does not exist/)) { + } else if (errMsg.match(/Postgis Plugin.*[\s|\n].*column.*does not exist/)) { statusCode = 400; - } - else if ( -1 !== errMsg.indexOf('does not exist') ) { - if ( -1 !== errMsg.indexOf(' role ') ) { + } else if (errMsg.indexOf('does not exist') !== -1) { + if (errMsg.indexOf(' role ') !== -1) { statusCode = 403; // role 'xxx' does not exist - } else if ( errMsg.match(/function .* does not exist/) ) { + } else if (errMsg.match(/function .* does not exist/)) { statusCode = 400; // invalid SQL (SQL function does not exist) } else { statusCode = 404; } } - return statusCode; } -function errorMessage(err) { +function errorMessage (err) { // See https://github.com/Vizzuality/Windshaft-cartodb/issues/68 var message = (_.isString(err) ? err : err.message) || 'Unknown error'; @@ -147,7 +143,7 @@ function errorMessage(err) { module.exports.errorMessage = errorMessage; -function stripConnectionInfo(message) { +function stripConnectionInfo (message) { // Strip connection info, if any return message // See https://github.com/CartoDB/Windshaft/issues/173 @@ -168,18 +164,18 @@ function shouldBeExposed (prop) { return !!ERROR_INFO_TO_EXPOSE[prop]; } -function errorMessageWithContext(err) { +function errorMessageWithContext (err) { // See https://github.com/Vizzuality/Windshaft-cartodb/issues/68 var message = (_.isString(err) ? err : err.message) || 'Unknown error'; var error = { type: err.type || 'unknown', - message: stripConnectionInfo(message), + message: stripConnectionInfo(message) }; for (var prop in err) { // type & message are properties from Error's prototype and will be skipped - if (err.hasOwnProperty(prop) && shouldBeExposed(prop)) { + if (Object.prototype.hasOwnProperty.call(err, prop) && shouldBeExposed(prop)) { error[prop] = err[prop]; } } @@ -187,27 +183,27 @@ function errorMessageWithContext(err) { return error; } -function setErrorHeader(errors, statusCode, res) { - let errorsCopy = errors.slice(0); +function setErrorHeader (errors, statusCode, res) { + const errorsCopy = errors.slice(0); const mainError = errorsCopy.shift(); - let errorsLog = { + const errorsLog = { mainError: { statusCode: statusCode || 200, - message: mainError.message, - name: mainError.name, - label: mainError.label, - type: mainError.type, - subtype: mainError.subtype + message: mainError.message, + name: mainError.name, + label: mainError.label, + type: mainError.type, + subtype: mainError.subtype } }; errorsLog.moreErrors = errorsCopy.map(error => { return { message: error.message, - name: error.name, - label: error.label, - type: error.type, + name: error.name, + label: error.label, + type: error.type, subtype: error.subtype }; }); @@ -221,14 +217,14 @@ function setErrorHeader(errors, statusCode, res) { * * @param {Object} object */ -function stringifyForLogs(object) { +function stringifyForLogs (object) { Object.keys(object).map(key => { - if(typeof object[key] === 'string') { + if (typeof object[key] === 'string') { object[key] = object[key].replace(/[^a-zA-Z0-9]/g, ' '); } else if (typeof object[key] === 'object') { stringifyForLogs(object[key]); } else if (object[key] instanceof Array) { - for (let element of object[key]) { + for (const element of object[key]) { stringifyForLogs(element); } } diff --git a/lib/api/middlewares/increment-map-view-count.js b/lib/api/middlewares/increment-map-view-count.js index 6afb8c76..00bb4673 100644 --- a/lib/api/middlewares/increment-map-view-count.js +++ b/lib/api/middlewares/increment-map-view-count.js @@ -1,7 +1,7 @@ 'use strict'; module.exports = function incrementMapViewCount (metadataBackend) { - return function incrementMapViewCountMiddleware(req, res, next) { + return function incrementMapViewCountMiddleware (req, res, next) { const { mapConfig, user } = res.locals; // Error won't blow up, just be logged. diff --git a/lib/api/middlewares/last-modified-header.js b/lib/api/middlewares/last-modified-header.js index e80d142a..4f00c0d2 100644 --- a/lib/api/middlewares/last-modified-header.js +++ b/lib/api/middlewares/last-modified-header.js @@ -1,18 +1,18 @@ 'use strict'; module.exports = function setLastModifiedHeader () { - return function setLastModifiedHeaderMiddleware(req, res, next) { + return function setLastModifiedHeaderMiddleware (req, res, next) { if (req.method !== 'GET') { return next(); } - const { mapConfigProvider, cache_buster } = res.locals; + const { mapConfigProvider, cache_buster: cacheBuster } = res.locals; - if (cache_buster) { - const cacheBuster = parseInt(cache_buster, 10); - const lastModifiedDate = Number.isFinite(cacheBuster) && cacheBuster !== 0 ? - new Date(cacheBuster) : - new Date(); + if (cacheBuster) { + const cacheBusterTimestamp = parseInt(cacheBuster, 10); + const lastModifiedDate = Number.isFinite(cacheBusterTimestamp) && cacheBusterTimestamp !== 0 + ? new Date(cacheBusterTimestamp) + : new Date(); res.set('Last-Modified', lastModifiedDate.toUTCString()); diff --git a/lib/api/middlewares/last-updated-time-layergroup.js b/lib/api/middlewares/last-updated-time-layergroup.js index d0520316..a1c4593a 100644 --- a/lib/api/middlewares/last-updated-time-layergroup.js +++ b/lib/api/middlewares/last-updated-time-layergroup.js @@ -27,12 +27,12 @@ module.exports = function setLastUpdatedTimeToLayergroup () { }; }; -function getLastUpdatedTime(analysesResults, lastUpdateTime) { +function getLastUpdatedTime (analysesResults, lastUpdateTime) { if (!Array.isArray(analysesResults)) { return lastUpdateTime; } - return analysesResults.reduce(function(lastUpdateTime, analysis) { - return analysis.getNodes().reduce(function(lastNodeUpdatedAtTime, node) { + return analysesResults.reduce(function (lastUpdateTime, analysis) { + return analysis.getNodes().reduce(function (lastNodeUpdatedAtTime, node) { var nodeUpdatedAtDate = node.getUpdatedAt(); var nodeUpdatedTimeAt = (nodeUpdatedAtDate && nodeUpdatedAtDate.getTime()) || 0; return nodeUpdatedTimeAt > lastNodeUpdatedAtTime ? nodeUpdatedTimeAt : lastNodeUpdatedAtTime; diff --git a/lib/api/middlewares/layer-stats.js b/lib/api/middlewares/layer-stats.js index 2df472f7..b5990a72 100644 --- a/lib/api/middlewares/layer-stats.js +++ b/lib/api/middlewares/layer-stats.js @@ -1,7 +1,7 @@ 'use strict'; module.exports = function setLayerStats (pgConnection, statsBackend) { - return function setLayerStatsMiddleware(req, res, next) { + return function setLayerStatsMiddleware (req, res, next) { const { user, mapConfig } = res.locals; const layergroup = res.body; @@ -10,7 +10,7 @@ module.exports = function setLayerStats (pgConnection, statsBackend) { return next(err); } - statsBackend.getStats(mapConfig, connection, function(err, layersStats) { + statsBackend.getStats(mapConfig, connection, function (err, layersStats) { if (err) { return next(err); } diff --git a/lib/api/middlewares/layergroup-metadata.js b/lib/api/middlewares/layergroup-metadata.js index ae1fddba..e5b54f2b 100644 --- a/lib/api/middlewares/layergroup-metadata.js +++ b/lib/api/middlewares/layergroup-metadata.js @@ -9,7 +9,7 @@ module.exports = function setMetadataToLayergroup (layergroupMetadata, includeQu layergroupMetadata.addAnalysesMetadata(user, layergroup, analysesResults, includeQuery); layergroupMetadata.addTurboCartoContextMetadata(layergroup, mapConfig.obj(), context); layergroupMetadata.addAggregationContextMetadata(layergroup, mapConfig.obj(), context); - layergroupMetadata.addDateWrappingMetadata (layergroup, mapConfig.obj()); + layergroupMetadata.addDateWrappingMetadata(layergroup, mapConfig.obj()); layergroupMetadata.addTileJsonMetadata(layergroup, user, mapConfig, userApiKey); next(); diff --git a/lib/api/middlewares/layergroup-token.js b/lib/api/middlewares/layergroup-token.js index fcc6959b..88e9295d 100644 --- a/lib/api/middlewares/layergroup-token.js +++ b/lib/api/middlewares/layergroup-token.js @@ -19,7 +19,7 @@ module.exports = function layergroupToken () { if (res.locals.signer !== user) { const err = new Error(authErrorMessageTemplate(res.locals.signer, user)); err.type = 'auth'; - err.http_status = (req.query && req.query.callback) ? 200: 403; + err.http_status = (req.query && req.query.callback) ? 200 : 403; return next(err); } diff --git a/lib/api/middlewares/lzma.js b/lib/api/middlewares/lzma.js index dee7ee61..b47c3b28 100644 --- a/lib/api/middlewares/lzma.js +++ b/lib/api/middlewares/lzma.js @@ -6,20 +6,20 @@ module.exports = function lzma () { const lzmaWorker = new LZMA(); return function lzmaMiddleware (req, res, next) { - if (!req.query.hasOwnProperty('lzma')) { + if (!Object.prototype.hasOwnProperty.call(req.query, 'lzma')) { return next(); } // Decode (from base64) - var lzma = new Buffer(req.query.lzma, 'base64') + var lzma = Buffer.from(req.query.lzma, 'base64') .toString('binary') .split('') - .map(function(c) { + .map(function (c) { return c.charCodeAt(0) - 128; }); // Decompress - lzmaWorker.decompress(lzma, function(result) { + lzmaWorker.decompress(lzma, function (result) { try { delete req.query.lzma; Object.assign(req.query, JSON.parse(result)); diff --git a/lib/api/middlewares/map-error.js b/lib/api/middlewares/map-error.js index 7c0ec278..fcc5ef2a 100644 --- a/lib/api/middlewares/map-error.js +++ b/lib/api/middlewares/map-error.js @@ -17,7 +17,7 @@ module.exports = function mapError (options) { }; }; -function populateError(err, mapConfig) { +function populateError (err, mapConfig) { var error = new Error(err.message); error.http_status = err.http_status; diff --git a/lib/api/middlewares/map-store-map-config-provider.js b/lib/api/middlewares/map-store-map-config-provider.js index 37c624c5..3d8481bd 100644 --- a/lib/api/middlewares/map-store-map-config-provider.js +++ b/lib/api/middlewares/map-store-map-config-provider.js @@ -10,15 +10,27 @@ module.exports = function createMapStoreMapConfigProvider ( forcedFormat = null ) { return function createMapStoreMapConfigProviderMiddleware (req, res, next) { - const { user, token, cache_buster, api_key } = res.locals; + const { user, token, cache_buster: cacheBuster, api_key: apiKey } = res.locals; const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals; - const { layer: layerFromParams, z, x, y, scale_factor, format } = req.params; + const { layer: layerFromParams, z, x, y, scale_factor: scaleFactor, format } = req.params; const { layer: layerFromQuery } = req.query; const params = { - user, token, cache_buster, api_key, - dbuser, dbname, dbpassword, dbhost, dbport, - layer: (layerFromQuery || layerFromParams), z, x, y, scale_factor, format + user, + token, + cache_buster: cacheBuster, + api_key: apiKey, + dbuser, + dbname, + dbpassword, + dbhost, + dbport, + layer: (layerFromQuery || layerFromParams), + z, + x, + y, + scale_factor: scaleFactor, + format }; if (forcedFormat) { diff --git a/lib/api/middlewares/named-map-provider.js b/lib/api/middlewares/named-map-provider.js index 9134dd29..bcc9b767 100644 --- a/lib/api/middlewares/named-map-provider.js +++ b/lib/api/middlewares/named-map-provider.js @@ -2,15 +2,27 @@ module.exports = function getNamedMapProvider ({ namedMapProviderCache, label, forcedFormat = null }) { return function getNamedMapProviderMiddleware (req, res, next) { - const { user, token, cache_buster, api_key } = res.locals; + const { user, token, cache_buster: cacheBuster, api_key: apiKey } = res.locals; const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals; - const { template_id, layer: layerFromParams, z, x, y, format } = req.params; + const { template_id: templateId, layer: layerFromParams, z, x, y, format } = req.params; const { layer: layerFromQuery } = req.query; const params = { - user, token, cache_buster, api_key, - dbuser, dbname, dbpassword, dbhost, dbport, - template_id, layer: (layerFromQuery || layerFromParams), z, x, y, format + user, + token, + cache_buster: cacheBuster, + api_key: apiKey, + dbuser, + dbname, + dbpassword, + dbhost, + dbport, + template_id: templateId, + layer: (layerFromQuery || layerFromParams), + z, + x, + y, + format }; if (forcedFormat) { @@ -18,9 +30,9 @@ module.exports = function getNamedMapProvider ({ namedMapProviderCache, label, f params.layer = params.layer || 'all'; } - const { config, auth_token } = req.query; + const { config, auth_token: authToken } = req.query; - namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, namedMapProvider) => { + namedMapProviderCache.get(user, templateId, config, authToken, params, (err, namedMapProvider) => { if (err) { err.label = label; return next(err); diff --git a/lib/api/middlewares/rate-limit.js b/lib/api/middlewares/rate-limit.js index 14452254..63a6479d 100644 --- a/lib/api/middlewares/rate-limit.js +++ b/lib/api/middlewares/rate-limit.js @@ -19,12 +19,12 @@ const RATE_LIMIT_ENDPOINTS_GROUPS = { NAMED_TILES: 'named_tiles' }; -function rateLimit(userLimitsBackend, endpointGroup = null) { +function rateLimit (userLimitsBackend, endpointGroup = null) { if (!isRateLimitEnabled(endpointGroup)) { - return function rateLimitDisabledMiddleware(req, res, next) { next(); }; + return function rateLimitDisabledMiddleware (req, res, next) { next(); }; } - return function rateLimitMiddleware(req, res, next) { + return function rateLimitMiddleware (req, res, next) { userLimitsBackend.getRateLimit(res.locals.user, endpointGroup, function (err, userRateLimit) { if (err) { return next(err); @@ -46,7 +46,7 @@ function rateLimit(userLimitsBackend, endpointGroup = null) { // retry is floor rounded in seconds by redis-cell res.set('Retry-After', retry + 1); - let rateLimitError = new Error( + const rateLimitError = new Error( 'You are over platform\'s limits: too many requests.' + ' Please contact us to know more details' ); @@ -61,8 +61,7 @@ function rateLimit(userLimitsBackend, endpointGroup = null) { }; } - -function isRateLimitEnabled(endpointGroup) { +function isRateLimitEnabled (endpointGroup) { return global.environment.enabledFeatures.rateLimitsEnabled && endpointGroup && global.environment.enabledFeatures.rateLimitsByEndpoint[endpointGroup]; diff --git a/lib/api/middlewares/stats.js b/lib/api/middlewares/stats.js index 24facbcf..9fe212ac 100644 --- a/lib/api/middlewares/stats.js +++ b/lib/api/middlewares/stats.js @@ -20,7 +20,7 @@ module.exports = function stats (options) { // May throw due to dns, see: http://github.com/CartoDB/Windshaft/issues/166 req.profiler.sendStats(); } catch (err) { - debug("error sending profiling stats: " + err); + debug('error sending profiling stats: ' + err); } }); diff --git a/lib/api/middlewares/surrogate-key-header.js b/lib/api/middlewares/surrogate-key-header.js index b4b6c922..d46c95f8 100644 --- a/lib/api/middlewares/surrogate-key-header.js +++ b/lib/api/middlewares/surrogate-key-header.js @@ -4,7 +4,7 @@ const NamedMapsCacheEntry = require('../../cache/model/named-maps-entry'); const NamedMapMapConfigProvider = require('../../models/mapconfig/provider/named-map-provider'); module.exports = function setSurrogateKeyHeader ({ surrogateKeysCache }) { - return function setSurrogateKeyHeaderMiddleware(req, res, next) { + return function setSurrogateKeyHeaderMiddleware (req, res, next) { const { user, mapConfigProvider } = res.locals; if (mapConfigProvider instanceof NamedMapMapConfigProvider) { diff --git a/lib/api/middlewares/user.js b/lib/api/middlewares/user.js index 17a85260..7ce3a40a 100644 --- a/lib/api/middlewares/user.js +++ b/lib/api/middlewares/user.js @@ -5,7 +5,7 @@ const CdbRequest = require('../../models/cdb-request'); module.exports = function user () { const cdbRequest = new CdbRequest(); - return function userMiddleware(req, res, next) { + return function userMiddleware (req, res, next) { res.locals.user = cdbRequest.userByReq(req); next(); diff --git a/lib/api/middlewares/vector-error.js b/lib/api/middlewares/vector-error.js index 6e69f982..b1cce3ac 100644 --- a/lib/api/middlewares/vector-error.js +++ b/lib/api/middlewares/vector-error.js @@ -1,12 +1,12 @@ 'use strict'; const fs = require('fs'); -const timeoutErrorVectorTile = fs.readFileSync(__dirname + '/../../../assets/render-timeout-fallback.mvt'); - -module.exports = function vectorError() { - return function vectorErrorMiddleware(err, req, res, next) { - if(req.params.format === 'mvt') { +const path = require('path'); +const timeoutErrorVectorTile = fs.readFileSync(path.join(__dirname, '/../../../assets/render-timeout-fallback.mvt')); +module.exports = function vectorError () { + return function vectorErrorMiddleware (err, req, res, next) { + if (req.params.format === 'mvt') { if (isTimeoutError(err) || isRateLimitError(err)) { res.set('Content-Type', 'application/x-protobuf'); return res.status(429).send(timeoutErrorVectorTile); @@ -17,7 +17,6 @@ module.exports = function vectorError() { }; }; - function isRenderTimeoutError (err) { return err.message === 'Render timed out'; } diff --git a/lib/api/template/admin-template-controller.js b/lib/api/template/admin-template-controller.js index 082d4f34..456f6bc0 100644 --- a/lib/api/template/admin-template-controller.js +++ b/lib/api/template/admin-template-controller.js @@ -19,7 +19,7 @@ module.exports = class AdminTemplateController { } route (templateRouter) { - templateRouter.options(`/:template_id`); + templateRouter.options('/:template_id'); templateRouter.post('/', this.middlewares({ action: 'create', diff --git a/lib/api/template/named-template-controller.js b/lib/api/template/named-template-controller.js index 7a7ee9d2..b7b3a865 100644 --- a/lib/api/template/named-template-controller.js +++ b/lib/api/template/named-template-controller.js @@ -106,7 +106,7 @@ module.exports = class NamedMapController { lastModifiedHeader(), lastUpdatedTimeLayergroup(), layerStats(this.pgConnection, this.statsBackend), - layergroupIdHeader(this.templateMaps ,useTemplateHash), + layergroupIdHeader(this.templateMaps, useTemplateHash), layergroupMetadata(this.layergroupMetadata, includeQuery), mapError({ label, addContext }) ]; @@ -114,7 +114,7 @@ module.exports = class NamedMapController { }; function checkInstantiteLayergroup () { - return function checkInstantiteLayergroupMiddleware(req, res, next) { + return function checkInstantiteLayergroupMiddleware (req, res, next) { if (req.method === 'GET') { const { callback, config } = req.query; @@ -125,7 +125,7 @@ function checkInstantiteLayergroup () { if (config) { try { req.body = JSON.parse(config); - } catch(e) { + } catch (e) { return next(new Error('Invalid config parameter, should be a valid JSON')); } } @@ -148,8 +148,8 @@ function getTemplate ( return function getTemplateMiddleware (req, res, next) { const templateParams = req.body; const { user, dbuser, dbname, dbpassword, dbhost, dbport } = res.locals; - const { template_id } = req.params; - const { auth_token } = req.query; + const { template_id: templateId } = req.params; + const { auth_token: authToken } = req.query; const params = Object.assign({ dbuser, dbname, dbpassword, dbhost, dbport }, req.query); @@ -161,9 +161,9 @@ function getTemplate ( mapConfigAdapter, affectedTablesCache, user, - template_id, + templateId, templateParams, - auth_token, + authToken, params ); diff --git a/lib/api/template/template-router.js b/lib/api/template/template-router.js index ecdc9802..81d7973f 100644 --- a/lib/api/template/template-router.js +++ b/lib/api/template/template-router.js @@ -21,7 +21,7 @@ module.exports = class TemplateRouter { authBackend, layergroupMetadata, namedMapProviderCache, - tileBackend, + tileBackend } = collaborators; this.namedMapController = new NamedMapController( diff --git a/lib/api/template/tile-template-controller.js b/lib/api/template/tile-template-controller.js index 90904027..1112678e 100644 --- a/lib/api/template/tile-template-controller.js +++ b/lib/api/template/tile-template-controller.js @@ -89,7 +89,7 @@ function getTile ({ tileBackend, label }) { } function setContentTypeHeader () { - return function setContentTypeHeaderMiddleware(req, res, next) { + return function setContentTypeHeaderMiddleware (req, res, next) { res.set('Content-Type', res.get('content-type') || res.get('Content-Type') || 'image/png'); next(); diff --git a/lib/backends/analysis-status.js b/lib/backends/analysis-status.js index 1c636f4e..172623c5 100644 --- a/lib/backends/analysis-status.js +++ b/lib/backends/analysis-status.js @@ -2,7 +2,7 @@ var PSQL = require('cartodb-psql'); -function AnalysisStatusBackend() { +function AnalysisStatusBackend () { } module.exports = AnalysisStatusBackend; @@ -15,7 +15,7 @@ AnalysisStatusBackend.prototype.getNodeStatus = function (nodeId, dbParams, call var pg = new PSQL(dbParams); - pg.query(statusQuery, function(err, result) { + pg.query(statusQuery, function (err, result) { if (err) { return callback(err, result); } diff --git a/lib/backends/analysis.js b/lib/backends/analysis.js index 4abaf4c7..b33f928f 100644 --- a/lib/backends/analysis.js +++ b/lib/backends/analysis.js @@ -43,7 +43,7 @@ AnalysisBackend.prototype.setLoggerConfig = function (options) { } }; -AnalysisBackend.prototype.create = function(analysisConfiguration, analysisDefinition, callback) { +AnalysisBackend.prototype.create = function (analysisConfiguration, analysisDefinition, callback) { analysisConfiguration.batch.endpoint = this.batchConfig.endpoint; analysisConfiguration.batch.inlineExecution = this.batchConfig.inlineExecution; analysisConfiguration.batch.hostHeaderTemplate = this.batchConfig.hostHeaderTemplate; @@ -52,13 +52,14 @@ AnalysisBackend.prototype.create = function(analysisConfiguration, analysisDefin stream: this.stream ? this.stream : process.stdout }; - this.getAnalysesLimits(analysisConfiguration.user, function(err, limits) { + this.getAnalysesLimits(analysisConfiguration.user, function (err, limits) { + if (err) {} analysisConfiguration.limits = limits || {}; camshaft.create(analysisConfiguration, analysisDefinition, callback); }); }; -AnalysisBackend.prototype.getAnalysesLimits = function(username, callback) { +AnalysisBackend.prototype.getAnalysesLimits = function (username, callback) { var self = this; var analysesLimits = { @@ -70,16 +71,17 @@ AnalysisBackend.prototype.getAnalysesLimits = function(username, callback) { } }; - Object.keys(self.options.limits).forEach(function(analysisTypeOrTag) { + Object.keys(self.options.limits).forEach(function (analysisTypeOrTag) { analysesLimits.analyses[analysisTypeOrTag] = _.extend({}, self.options.limits[analysisTypeOrTag]); }); var analysesLimitsKey = REDIS_LIMITS.PREFIX + username; - this.metadataBackend.redisCmd(REDIS_LIMITS.DB, 'HGETALL', [analysesLimitsKey], function(err, analysesTimeouts) { + this.metadataBackend.redisCmd(REDIS_LIMITS.DB, 'HGETALL', [analysesLimitsKey], function (err, analysesTimeouts) { + if (err) {} // analysesTimeouts wil be something like: { moran: 3000, intersection: 5000 } analysesTimeouts = analysesTimeouts || {}; - Object.keys(analysesTimeouts).forEach(function(analysisType) { + Object.keys(analysesTimeouts).forEach(function (analysisType) { analysesLimits.analyses[analysisType] = _.defaults( { timeout: Number.isFinite(+analysesTimeouts[analysisType]) ? +analysesTimeouts[analysisType] : 0 diff --git a/lib/backends/auth.js b/lib/backends/auth.js index 0a17e4a2..2c9dd3ee 100644 --- a/lib/backends/auth.js +++ b/lib/backends/auth.js @@ -9,7 +9,7 @@ * @constructor * @type {AuthBackend} */ -function AuthBackend(pgConnection, metadataBackend, mapStore, templateMaps) { +function AuthBackend (pgConnection, metadataBackend, mapStore, templateMaps) { this.pgConnection = pgConnection; this.metadataBackend = metadataBackend; this.mapStore = mapStore; @@ -25,28 +25,28 @@ module.exports = AuthBackend; // null if the request is not signed by anyone // or will be a string cartodb username otherwise. // -AuthBackend.prototype.authorizedBySigner = function(req, res, callback) { - if ( ! res.locals.token || ! res.locals.signer ) { +AuthBackend.prototype.authorizedBySigner = function (req, res, callback) { + if (!res.locals.token || !res.locals.signer) { return callback(null, false); // no signer requested } var self = this; - var layergroup_id = res.locals.token; - var auth_token = req.query.auth_token; + var layergroupId = res.locals.token; + var authToken = req.query.auth_token; - this.mapStore.load(layergroup_id, function(err, mapConfig) { + this.mapStore.load(layergroupId, function (err, mapConfig) { if (err) { return callback(err); } - var authorized = self.templateMaps.isAuthorized(mapConfig.obj().template, auth_token); + var authorized = self.templateMaps.isAuthorized(mapConfig.obj().template, authToken); return callback(null, authorized); }); }; -function isValidApiKey(apikey) { +function isValidApiKey (apikey) { return apikey.type && apikey.user && apikey.databasePassword && @@ -60,11 +60,11 @@ function isValidApiKey(apikey) { // @param callback function(err, authorized) // NOTE: authorized is expected to be 0 or 1 (integer) // -AuthBackend.prototype.authorizedByAPIKey = function(user, res, callback) { +AuthBackend.prototype.authorizedByAPIKey = function (user, res, callback) { const apikeyToken = res.locals.api_key; const basicAuthUsername = res.locals.basicAuthUsername; - if ( ! apikeyToken ) { + if (!apikeyToken) { return callback(null, false); // no api key, no authorization... } @@ -77,7 +77,7 @@ AuthBackend.prototype.authorizedByAPIKey = function(user, res, callback) { return callback(err); } - if ( !isValidApiKey(apikey)) { + if (!isValidApiKey(apikey)) { const error = new Error('Unauthorized'); error.type = 'auth'; error.subtype = 'api-key-not-found'; @@ -109,7 +109,7 @@ AuthBackend.prototype.authorizedByAPIKey = function(user, res, callback) { }; function isNameNotFoundError (err) { - return err.message && -1 !== err.message.indexOf('name not found'); + return err.message && err.message.indexOf('name not found') !== -1; } function usernameMatches (basicAuthUsername, requestUsername) { @@ -123,7 +123,7 @@ function usernameMatches (basicAuthUsername, requestUsername) { * @param res - standard res object. Contains the auth parameters in locals * @param callback function(err, allowed) is access allowed not? */ -AuthBackend.prototype.authorize = function(req, res, callback) { +AuthBackend.prototype.authorize = function (req, res, callback) { var user = res.locals.user; this.authorizedByAPIKey(user, res, (err, isAuthorizedByApikey) => { diff --git a/lib/backends/cluster.js b/lib/backends/cluster.js index 27d8d5ac..6a3429f0 100644 --- a/lib/backends/cluster.js +++ b/lib/backends/cluster.js @@ -71,8 +71,8 @@ function getFeatures (pg, layer, params, callback) { } const SKIP_COLUMNS = { - 'the_geom': true, - 'the_geom_webmercator': true + the_geom: true, + the_geom_webmercator: true }; function getColumnsName (pg, query, callback) { @@ -100,7 +100,7 @@ function getClusterFeatures (pg, zoom, clusterId, columns, query, resolution, ag zoom: zoom, id: clusterId, query: query, - res: 256/resolution, + res: 256 / resolution, columns: columns }); @@ -127,7 +127,7 @@ function getClusterFeatures (pg, zoom, clusterId, columns, query, resolution, ag } return callback(null, data); - } , true); // use read-only transaction + }, true); // use read-only transaction } const schemaQuery = ctx => `SELECT * FROM (${ctx.query}) __cdb_cluster_schema LIMIT 0`; @@ -159,8 +159,8 @@ const clusterFeaturesQuery = ctx => ` `; const gridResolution = ctx => { - const zoomResolution = webmercator.getResolution({ z : Math.min(38, ctx.zoom) }); - return `${256/ctx.res} * (${zoomResolution})::double precision`; + const zoomResolution = webmercator.getResolution({ z: Math.min(38, ctx.zoom) }); + return `${256 / ctx.res} * (${zoomResolution})::double precision`; }; const aggregationQuery = ctx => ` @@ -194,9 +194,8 @@ function parseAggregation (aggregation) { try { aggregation = JSON.parse(aggregation); } catch (err) { - throw new Error(`Invalid aggregation input, should be a a valid JSON`); + throw new Error('Invalid aggregation input, should be a a valid JSON'); } - } return aggregation; @@ -207,7 +206,7 @@ function validateAggregation (aggregation) { const { columns, expressions } = aggregation; if (!hasColumns(columns)) { - throw new Error(`Invalid aggregation input, columns should be and array of column names`); + throw new Error('Invalid aggregation input, columns should be and array of column names'); } validateExpressions(expressions); @@ -221,16 +220,16 @@ function hasColumns (columns) { function validateExpressions (expressions) { if (expressions !== undefined) { if (!isValidExpression(expressions)) { - throw new Error(`Invalid aggregation input, expressions should be and object with valid functions`); + throw new Error('Invalid aggregation input, expressions should be and object with valid functions'); } - for (const { aggregate_function, aggregated_column } of Object.values(expressions)) { - if (typeof aggregated_column !== 'string') { - throw new Error(`Invalid aggregation input, aggregated column should be an string`); + for (const { aggregate_function: aggregateFunction, aggregated_column: aggregatedColumn } of Object.values(expressions)) { + if (typeof aggregatedColumn !== 'string') { + throw new Error('Invalid aggregation input, aggregated column should be an string'); } - if (typeof aggregate_function !== 'string') { - throw new Error(`Invalid aggregation input, aggregate function should be an string`); + if (typeof aggregateFunction !== 'string') { + throw new Error('Invalid aggregation input, aggregate function should be an string'); } } } diff --git a/lib/backends/dataview.js b/lib/backends/dataview.js index d37e3d56..080718e1 100644 --- a/lib/backends/dataview.js +++ b/lib/backends/dataview.js @@ -14,7 +14,7 @@ var overviewsQueryRewriter = new OverviewsQueryRewriter({ var dot = require('dot'); dot.templateSettings.strip = false; -function DataviewBackend(analysisBackend) { +function DataviewBackend (analysisBackend) { this.analysisBackend = analysisBackend; } @@ -84,14 +84,14 @@ function getQueryWithFilters (dataviewDefinition, params) { var query = getDataviewQuery(dataviewDefinition, ownFilter, noFilters); if (params.bbox) { - var bboxFilter = new BBoxFilter({column: 'the_geom_webmercator', srid: 3857}, {bbox: params.bbox}); + var bboxFilter = new BBoxFilter({ column: 'the_geom_webmercator', srid: 3857 }, { bbox: params.bbox }); query = bboxFilter.sql(query); } return query; } -function getDataviewQuery(dataviewDefinition, ownFilter, noFilters) { +function getDataviewQuery (dataviewDefinition, ownFilter, noFilters) { if (noFilters) { return dataviewDefinition.sql.no_filters; } else if (ownFilter === 1) { @@ -101,9 +101,9 @@ function getDataviewQuery(dataviewDefinition, ownFilter, noFilters) { } } -function getQueryRewriteData(mapConfig, dataviewDefinition, params) { +function getQueryRewriteData (mapConfig, dataviewDefinition, params) { var sourceId = dataviewDefinition.source.id; // node.id - var layer = _.find(mapConfig.obj().layers, function(l) { + var layer = _.find(mapConfig.obj().layers, function (l) { return l.options.source && (l.options.source.id === sourceId); }); var queryRewriteData = layer && layer.options.query_rewrite_data; @@ -115,7 +115,7 @@ function getQueryRewriteData(mapConfig, dataviewDefinition, params) { } if (params.bbox && queryRewriteData) { - var bbox_filter_definition = { + var bboxFilterDefinition = { type: 'bbox', options: { column: 'the_geom_webmercator', @@ -125,22 +125,22 @@ function getQueryRewriteData(mapConfig, dataviewDefinition, params) { bbox: params.bbox } }; - queryRewriteData = _.extend(queryRewriteData, { bbox_filter: bbox_filter_definition }); + queryRewriteData = _.extend(queryRewriteData, { bbox_filter: bboxFilterDefinition }); } return queryRewriteData; } -function getOverrideParams(params, ownFilter) { +function getOverrideParams (params, ownFilter) { var overrideParams = _.reduce(_.pick(params, 'start', 'end', 'bins', 'offset', 'categories'), - function castNumbers(overrides, val, k) { + function castNumbers (overrides, val, k) { if (!Number.isFinite(+val)) { throw new Error('Invalid number format for parameter \'' + k + '\''); } overrides[k] = +val; return overrides; }, - {ownFilter: ownFilter} + { ownFilter: ownFilter } ); // validation will be delegated to the proper dataview @@ -202,7 +202,7 @@ function getQueryWithOwnFilters (dataviewDefinition, params) { return query; } -function getDataviewDefinition(mapConfig, dataviewName) { +function getDataviewDefinition (mapConfig, dataviewName) { var dataviews = mapConfig.dataviews || {}; return dataviews[dataviewName]; } diff --git a/lib/backends/filter-stats.js b/lib/backends/filter-stats.js index c5fb48bb..d5ac456b 100644 --- a/lib/backends/filter-stats.js +++ b/lib/backends/filter-stats.js @@ -3,32 +3,32 @@ var _ = require('underscore'); var AnalysisFilter = require('../models/filter/analysis'); -function FilterStatsBackends(pgQueryRunner) { +function FilterStatsBackends (pgQueryRunner) { this.pgQueryRunner = pgQueryRunner; } module.exports = FilterStatsBackends; -function getEstimatedRows(pgQueryRunner, username, query, callback) { - pgQueryRunner.run(username, "EXPLAIN (FORMAT JSON)"+query, function(err, result_rows) { - if (err){ +function getEstimatedRows (pgQueryRunner, username, query, callback) { + pgQueryRunner.run(username, 'EXPLAIN (FORMAT JSON)' + query, function (err, resultRows) { + if (err) { callback(err); return; } var rows; - if ( result_rows[0] && result_rows[0]['QUERY PLAN'] && - result_rows[0]['QUERY PLAN'][0] && result_rows[0]['QUERY PLAN'][0].Plan ) { - rows = result_rows[0]['QUERY PLAN'][0].Plan['Plan Rows']; + if (resultRows[0] && resultRows[0]['QUERY PLAN'] && + resultRows[0]['QUERY PLAN'][0] && resultRows[0]['QUERY PLAN'][0].Plan) { + rows = resultRows[0]['QUERY PLAN'][0].Plan['Plan Rows']; } return callback(null, rows); }); } -FilterStatsBackends.prototype.getFilterStats = function (username, unfiltered_query, filters, callback) { +FilterStatsBackends.prototype.getFilterStats = function (username, unfilteredQuery, filters, callback) { var stats = {}; - getEstimatedRows(this.pgQueryRunner, username, unfiltered_query, (err, rows) => { - if (err){ + getEstimatedRows(this.pgQueryRunner, username, unfilteredQuery, (err, rows) => { + if (err) { return callback(err); } @@ -39,10 +39,10 @@ FilterStatsBackends.prototype.getFilterStats = function (username, unfiltered_qu } var analysisFilter = new AnalysisFilter(filters); - var query = analysisFilter.sql(unfiltered_query); + var query = analysisFilter.sql(unfilteredQuery); getEstimatedRows(this.pgQueryRunner, username, query, (err, rows) => { - if (err){ + if (err) { return callback(err); } diff --git a/lib/backends/layer-stats/empty-layer-stats.js b/lib/backends/layer-stats/empty-layer-stats.js index 72c76e84..5a48eda1 100644 --- a/lib/backends/layer-stats/empty-layer-stats.js +++ b/lib/backends/layer-stats/empty-layer-stats.js @@ -1,6 +1,6 @@ 'use strict'; -function EmptyLayerStats(types) { +function EmptyLayerStats (types) { this._types = types || {}; } @@ -10,7 +10,7 @@ EmptyLayerStats.prototype.is = function (type) { EmptyLayerStats.prototype.getStats = function (layer, dbConnection, callback) { - setImmediate(function() { + setImmediate(function () { callback(null, {}); }); }; diff --git a/lib/backends/layer-stats/factory.js b/lib/backends/layer-stats/factory.js index 19eb0701..2b980c74 100644 --- a/lib/backends/layer-stats/factory.js +++ b/lib/backends/layer-stats/factory.js @@ -5,7 +5,7 @@ var EmptyLayerStats = require('./empty-layer-stats'); var MapnikLayerStats = require('./mapnik-layer-stats'); var TorqueLayerStats = require('./torque-layer-stats'); -module.exports = function LayerStatsFactory(type) { +module.exports = function LayerStatsFactory (type) { var layerStatsIterator = []; var selectedType = type || 'ALL'; diff --git a/lib/backends/layer-stats/layer-stats.js b/lib/backends/layer-stats/layer-stats.js index 38e9b461..9f04645b 100644 --- a/lib/backends/layer-stats/layer-stats.js +++ b/lib/backends/layer-stats/layer-stats.js @@ -2,7 +2,7 @@ var queue = require('queue-async'); -function LayerStats(layerStatsIterator) { +function LayerStats (layerStatsIterator) { this.layerStatsIterator = layerStatsIterator; } @@ -41,7 +41,6 @@ LayerStats.prototype.getStats = function (mapConfig, dbConnection, callback) { return callback(err, stats); }); - }; module.exports = LayerStats; diff --git a/lib/backends/layer-stats/mapnik-layer-stats.js b/lib/backends/layer-stats/mapnik-layer-stats.js index 8e281e19..6032b928 100644 --- a/lib/backends/layer-stats/mapnik-layer-stats.js +++ b/lib/backends/layer-stats/mapnik-layer-stats.js @@ -15,7 +15,7 @@ MapnikLayerStats.prototype.is = function (type) { return this._types[type] ? this._types[type] : false; }; -function columnAggregations(field) { +function columnAggregations (field) { if (field.type === 'number') { return ['min', 'max', 'avg', 'sum']; } @@ -28,25 +28,24 @@ function columnAggregations(field) { return []; } -function _getSQL(ctx, query, type='pre', zoom=0) { +function _getSQL (ctx, query, type = 'pre', zoom = 0) { let sql; if (type === 'pre') { sql = ctx.preQuery; - } - else { + } else { sql = ctx.aggrQuery; } sql = queryUtils.substituteTokensForZoom(sql, zoom || 0); return query(sql); } -function _estimatedFeatureCount(ctx) { +function _estimatedFeatureCount (ctx) { return queryUtils.queryPromise(ctx.dbConnection, _getSQL(ctx, queryUtils.getQueryRowEstimation)) .then(res => ({ estimatedFeatureCount: res.rows[0].rows })) .catch(() => ({ estimatedFeatureCount: -1 })); } -function _featureCount(ctx) { +function _featureCount (ctx) { if (ctx.metaOptions.featureCount) { // TODO: if ctx.metaOptions.columnStats we can combine this with column stats query return queryUtils.queryPromise(ctx.dbConnection, _getSQL(ctx, queryUtils.getQueryActualRowCount)) @@ -55,20 +54,20 @@ function _featureCount(ctx) { return Promise.resolve(); } -function _aggrFeatureCount(ctx) { - if (ctx.metaOptions.hasOwnProperty('aggrFeatureCount')) { +function _aggrFeatureCount (ctx) { + if (Object.prototype.hasOwnProperty.call(ctx.metaOptions, 'aggrFeatureCount')) { // We expect as zoom level as the value of aggrFeatureCount // TODO: it'd be nice to admit an array of zoom levels to // return metadata for multiple levels. return queryUtils.queryPromise( ctx.dbConnection, - _getSQL(ctx, queryUtils.getQueryActualRowCount, 'post', ctx.metaOptions.aggrFeatureCount) + _getSQL(ctx, queryUtils.getQueryActualRowCount, 'post', ctx.metaOptions.aggrFeatureCount) ).then(res => ({ aggrFeatureCount: res.rows[0].rows })); } return Promise.resolve(); } -function _geometryType(ctx) { +function _geometryType (ctx) { if (ctx.metaOptions.geometryType) { const geometryColumn = AggregationMapConfig.getAggregationGeometryColumn(); const sqlQuery = _getSQL(ctx, sql => queryUtils.getQueryGeometryType(sql, geometryColumn)); @@ -78,7 +77,7 @@ function _geometryType(ctx) { return Promise.resolve(); } -function _columns(ctx) { +function _columns (ctx) { if (ctx.metaOptions.columns || ctx.metaOptions.columnStats || ctx.metaOptions.dimensions) { // note: post-aggregation columns are in layer.options.columns when aggregation is present return queryUtils.queryPromise(ctx.dbConnection, _getSQL(ctx, sql => queryUtils.getQueryLimited(sql, 0))) @@ -89,7 +88,7 @@ function _columns(ctx) { // combine a list of results merging the properties of all the objects // undefined results are admitted and ignored -function mergeResults(results) { +function mergeResults (results) { if (results) { if (results.length === 0) { return {}; @@ -108,15 +107,15 @@ function mergeResults(results) { // deeper (1 level) combination of a list of objects: // mergeColumns([{ col1: { a: 1 }, col2: { a: 2 } }, { col1: { b: 3 } }]) => { col1: { a: 1, b: 3 }, col2: { a: 2 } } -function mergeColumns(results) { +function mergeColumns (results) { if (results) { if (results.length === 0) { return {}; } return results.reduce((a, b) => { - let c = Object.assign({}, b || {}, a || {}); + const c = Object.assign({}, b || {}, a || {}); Object.keys(c).forEach(key => { - if (b.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(b, key)) { c[key] = Object.assign(c[key], b[key]); } }); @@ -127,7 +126,7 @@ function mergeColumns(results) { const DEFAULT_SAMPLE_ROWS = 100; -function _sample(ctx) { +function _sample (ctx) { if (!ctx.metaOptions.sample) { return Promise.resolve(); } @@ -164,32 +163,32 @@ function _getSampleValuesFromRange (min, span, limit) { return Array.from(sample); } -function _columnsMetadataRequired(options) { +function _columnsMetadataRequired (options) { // We need determine the columns of a query // if either column stats or dimension stats are required, // since we'll ultimately use the same query to fetch both return options.columnStats || options.dimensions; } -function _columnStats(ctx, columns, dimensions) { +function _columnStats (ctx, columns, dimensions) { if (!columns) { return Promise.resolve(); } if (_columnsMetadataRequired(ctx.metaOptions)) { - let queries = []; + const queries = []; let aggr = []; if (ctx.metaOptions.columnStats) { queries.push(new Promise(resolve => resolve({ columns }))); // add columns as first result Object.keys(columns).forEach(name => { aggr = aggr.concat( columnAggregations(columns[name]) - .map(fn => `${fn}("${name}") AS "${name}_${fn}"`) + .map(fn => `${fn}("${name}") AS "${name}_${fn}"`) ); if (columns[name].type === 'string') { const topN = ctx.metaOptions.columnStats.topCategories || 1024; - const includeNulls = ctx.metaOptions.columnStats.hasOwnProperty('includeNulls') ? - ctx.metaOptions.columnStats.includeNulls : - true; + const includeNulls = Object.prototype.hasOwnProperty.call(ctx.metaOptions.columnStats, 'includeNulls') + ? ctx.metaOptions.columnStats.includeNulls + : true; // TODO: ctx.metaOptions.columnStats.maxCategories // => use PG stats to dismiss columns with more distinct values @@ -223,7 +222,7 @@ function _columnStats(ctx, columns, dimensions) { ctx.dbConnection, _getSQL(ctx, sql => `SELECT ${aggr.join(',')} FROM (${sql}) AS __cdb_query`) ).then(res => { - let stats = { columns: {}, dimensions: {} }; + const stats = { columns: {}, dimensions: {} }; Object.keys(columns).forEach(name => { stats.columns[name] = {}; columnAggregations(columns[name]).forEach(fn => { @@ -245,62 +244,62 @@ function _columnStats(ctx, columns, dimensions) { ); return Promise.all(queries).then(results => ({ columns: mergeColumns(results.map(r => r.columns)), - dimensions: mergeColumns(results.map( r => r.dimensions)) + dimensions: mergeColumns(results.map(r => r.dimensions)) })); } return Promise.resolve({ columns }); } // This is adapted from SQL API: -function fieldType(cname) { +function fieldType (cname) { let tname; switch (true) { - case /bool/.test(cname): - tname = 'boolean'; - break; - case /int|float|numeric/.test(cname): - tname = 'number'; - break; - case /text|char|unknown/.test(cname): - tname = 'string'; - break; - case /date|time/.test(cname): - tname = 'date'; - break; - default: - tname = cname; + case /bool/.test(cname): + tname = 'boolean'; + break; + case /int|float|numeric/.test(cname): + tname = 'number'; + break; + case /text|char|unknown/.test(cname): + tname = 'string'; + break; + case /date|time/.test(cname): + tname = 'date'; + break; + default: + tname = cname; } - if ( tname && cname.match(/^_/) ) { + if (tname && cname.match(/^_/)) { tname += '[]'; } return tname; } -function fieldTypeSafe(dbConnection, field) { +function fieldTypeSafe (dbConnection, field) { const cname = dbConnection.typeName(field.dataTypeID); return cname ? fieldType(cname) : `unknown(${field.dataTypeID})`; } // columns are returned as an object { columnName1: { type1: ...}, ..} // for consistency with SQL API -function formatResultFields(dbConnection, fields = []) { - let nfields = {}; - for (let field of fields) { - nfields[field.name] = { type: fieldTypeSafe(dbConnection, field) }; +function formatResultFields (dbConnection, fields = []) { + const nfields = {}; + for (const field of fields) { + nfields[field.name] = { type: fieldTypeSafe(dbConnection, field) }; } return nfields; } MapnikLayerStats.prototype.getStats = function (layer, dbConnection, callback) { - let aggrQuery = layer.options.sql; - let preQuery = layer.options.sql_raw || aggrQuery; + const aggrQuery = layer.options.sql; + const preQuery = layer.options.sql_raw || aggrQuery; - let ctx = { + const ctx = { dbConnection, preQuery, aggrQuery, - metaOptions: layer.options.metadata || {}, + metaOptions: layer.options.metadata || {} }; // TODO: could save some queries if queryUtils.getAggregationMetadata() has been used and kept somewhere @@ -316,7 +315,7 @@ function (layer, dbConnection, callback) { Promise.all([ _estimatedFeatureCount(ctx).then( ({ estimatedFeatureCount }) => _sample(ctx) - .then(sampleResults => mergeResults([ sampleResults, { estimatedFeatureCount }] )) + .then(sampleResults => mergeResults([sampleResults, { estimatedFeatureCount }])) ), _featureCount(ctx), _aggrFeatureCount(ctx), diff --git a/lib/backends/layer-stats/torque-layer-stats.js b/lib/backends/layer-stats/torque-layer-stats.js index af198b1e..ea293c06 100644 --- a/lib/backends/layer-stats/torque-layer-stats.js +++ b/lib/backends/layer-stats/torque-layer-stats.js @@ -1,6 +1,6 @@ 'use strict'; -function TorqueLayerStats() { +function TorqueLayerStats () { this._types = { torque: true }; diff --git a/lib/backends/overviews-metadata.js b/lib/backends/overviews-metadata.js index 8b7f0122..f82e2887 100644 --- a/lib/backends/overviews-metadata.js +++ b/lib/backends/overviews-metadata.js @@ -2,7 +2,7 @@ const queryUtils = require('../utils/query-utils'); -function OverviewsMetadataBackend(pgQueryRunner) { +function OverviewsMetadataBackend (pgQueryRunner) { this.pgQueryRunner = pgQueryRunner; } @@ -17,15 +17,15 @@ OverviewsMetadataBackend.prototype.getOverviewsMetadata = function (username, sq cartodb.CDB_QueryTablesText($windshaft$${queryUtils.substituteDummyTokens(sql)}$windshaft$) ); `; - this.pgQueryRunner.run(username, query, function handleOverviewsRows(err, rows) { - if (err){ + this.pgQueryRunner.run(username, query, function handleOverviewsRows (err, rows) { + if (err) { callback(err); return; } - var metadata = rows.reduce(function(metadata, row){ + var metadata = rows.reduce(function (metadata, row) { var table = row.base_table; var schema = row._cdb_schema_name; - if ( !metadata[table] ) { + if (!metadata[table]) { metadata[table] = {}; } metadata[table][row.z] = { table: row.overview_table }; diff --git a/lib/backends/pg-connection.js b/lib/backends/pg-connection.js index fa6fb542..5d8c9d29 100644 --- a/lib/backends/pg-connection.js +++ b/lib/backends/pg-connection.js @@ -5,13 +5,12 @@ var _ = require('underscore'); const debug = require('debug')('cachechan'); const dbParamsFromReqParams = require('../utils/database-params'); -function PgConnection(metadataBackend) { +function PgConnection (metadataBackend) { this.metadataBackend = metadataBackend; } module.exports = PgConnection; - // Set db authentication parameters to those of the given username // // @param username the cartodb username, mapped to a database username @@ -22,7 +21,7 @@ module.exports = PgConnection; // // @param callback function(err) // -PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callback) { +PgConnection.prototype.setDBAuth = function (username, params, apikeyType, callback) { if (apikeyType === 'master') { this.metadataBackend.getMasterApikey(username, (err, apikey) => { if (err) { @@ -37,7 +36,7 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba return callback(); }); - } else if (apikeyType === 'regular') { //Actually it can be any type of api key + } else if (apikeyType === 'regular') { // Actually it can be any type of api key this.metadataBackend.getApikey(username, params.api_key, (err, apikey) => { if (err) { if (isNameNotFoundError(err)) { @@ -71,10 +70,9 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba }; function isNameNotFoundError (err) { - return err.message && -1 !== err.message.indexOf('name not found'); + return err.message && err.message.indexOf('name not found') !== -1; } - // Set db connection parameters to those for the given username // // @param dbowner cartodb username of database owner, @@ -86,7 +84,7 @@ function isNameNotFoundError (err) { // // @param callback function(err) // -PgConnection.prototype.setDBConn = function(dbowner, params, callback) { +PgConnection.prototype.setDBConn = function (dbowner, params, callback) { _.defaults(params, { // dbuser: global.environment.postgres.user, // dbpassword: global.environment.postgres.password, @@ -118,8 +116,8 @@ PgConnection.prototype.setDBConn = function(dbowner, params, callback) { * @param {Function} callback function({Error}, {PSQL}) */ -PgConnection.prototype.getConnection = function(username, callback) { - debug("getConn1"); +PgConnection.prototype.getConnection = function (username, callback) { + debug('getConn1'); this.getDatabaseParams(username, (err, databaseParams) => { if (err) { @@ -129,7 +127,7 @@ PgConnection.prototype.getConnection = function(username, callback) { }); }; -PgConnection.prototype.getDatabaseParams = function(username, callback) { +PgConnection.prototype.getDatabaseParams = function (username, callback) { const databaseParams = {}; this.setDBAuth(username, databaseParams, 'master', err => { diff --git a/lib/backends/pg-query-runner.js b/lib/backends/pg-query-runner.js index c6a7d2b4..f5236f54 100644 --- a/lib/backends/pg-query-runner.js +++ b/lib/backends/pg-query-runner.js @@ -3,7 +3,7 @@ var PSQL = require('cartodb-psql'); const dbParamsFromReqParams = require('../utils/database-params'); -function PgQueryRunner(pgConnection) { +function PgQueryRunner (pgConnection) { this.pgConnection = pgConnection; } @@ -16,8 +16,7 @@ module.exports = PgQueryRunner; * @param {String} query * @param {Function} callback function({Error}, {Array}) second argument is guaranteed to be an array */ -PgQueryRunner.prototype.run = function(username, query, callback) { - +PgQueryRunner.prototype.run = function (username, query, callback) { this.pgConnection.getDatabaseParams(username, (err, databaseParams) => { if (err) { return callback(err); diff --git a/lib/backends/stats.js b/lib/backends/stats.js index c3e5303d..88f126d9 100644 --- a/lib/backends/stats.js +++ b/lib/backends/stats.js @@ -2,14 +2,14 @@ var layerStats = require('./layer-stats/factory'); -function StatsBackend() { +function StatsBackend () { } module.exports = StatsBackend; -StatsBackend.prototype.getStats = function(mapConfig, dbConnection, callback) { +StatsBackend.prototype.getStats = function (mapConfig, dbConnection, callback) { var enabledFeatures = global.environment.enabledFeatures; - var layerStatsEnabled = enabledFeatures ? enabledFeatures.layerStats: false; + var layerStatsEnabled = enabledFeatures ? enabledFeatures.layerStats : false; if (layerStatsEnabled) { layerStats().getStats(mapConfig, dbConnection, callback); } else { diff --git a/lib/backends/tables-extent.js b/lib/backends/tables-extent.js index f7499ee7..440a516e 100644 --- a/lib/backends/tables-extent.js +++ b/lib/backends/tables-extent.js @@ -1,6 +1,6 @@ 'use strict'; -function TablesExtentBackend(pgQueryRunner) { +function TablesExtentBackend (pgQueryRunner) { this.pgQueryRunner = pgQueryRunner; } @@ -16,21 +16,21 @@ module.exports = TablesExtentBackend; * @param {Function} callback function(err, result) {Object} result with `west`, `south`, `east`, `north` */ TablesExtentBackend.prototype.getBounds = function (username, tables, callback) { - var estimatedExtentSQLs = tables.map(function(table) { + var estimatedExtentSQLs = tables.map(function (table) { return "ST_EstimatedExtent('" + table.schema_name + "', '" + table.table_name + "', 'the_geom_webmercator')"; }); var query = [ - "WITH ext as (" + - "SELECT ST_Transform(ST_SetSRID(ST_Extent(ST_Union(ARRAY[", - estimatedExtentSQLs.join(','), - "])), 3857), 4326) geom)", - "SELECT", - "ST_XMin(geom) west,", - "ST_YMin(geom) south,", - "ST_XMax(geom) east,", - "ST_YMax(geom) north", - "FROM ext" + 'WITH ext as (' + + 'SELECT ST_Transform(ST_SetSRID(ST_Extent(ST_Union(ARRAY[', + estimatedExtentSQLs.join(','), + '])), 3857), 4326) geom)', + 'SELECT', + 'ST_XMin(geom) west,', + 'ST_YMin(geom) south,', + 'ST_XMax(geom) east,', + 'ST_YMax(geom) north', + 'FROM ext' ].join(' '); this.pgQueryRunner.run(username, query, function handleBoundsResult (err, rows) { diff --git a/lib/backends/template-maps.js b/lib/backends/template-maps.js index ea2d93fd..e1e45c3e 100644 --- a/lib/backends/template-maps.js +++ b/lib/backends/template-maps.js @@ -5,16 +5,14 @@ var debug = require('debug')('windshaft:templates'); var _ = require('underscore'); var dot = require('dot'); - var EventEmitter = require('events').EventEmitter; var util = require('util'); - // Class handling map templates // // See http://github.com/CartoDB/Windshaft-cartodb/wiki/Template-maps // -// @param redis_pool an instance of a "redis-mpool" +// @param redisPool an instance of a "redis-mpool" // See https://github.com/CartoDB/node-redis-mpool // Needs version 0.x.x of the API. // @@ -22,43 +20,42 @@ var util = require('util'); // 'max_user_templates' limit on the number of per-user // // -function TemplateMaps(redis_pool, opts) { - if (!(this instanceof TemplateMaps)) { - return new TemplateMaps(); - } +function TemplateMaps (redisPool, opts) { + if (!(this instanceof TemplateMaps)) { + return new TemplateMaps(); + } - EventEmitter.call(this); + EventEmitter.call(this); - this.redis_pool = redis_pool; - this.opts = opts || {}; + this.redisPool = redisPool; + this.opts = opts || {}; - // Database containing templates - // TODO: allow configuring ? - // NOTE: currently it is the same as - // the one containing layergroups - this.db_signatures = 0; + // Database containing templates + // TODO: allow configuring ? + // NOTE: currently it is the same as + // the one containing layergroups + this.db_signatures = 0; - // - // Map templates are owned by a user that specifies access permissions - // for their instances. - // - // We have the following datastores: - // - // 1. User templates: set of per-user map templates + // + // Map templates are owned by a user that specifies access permissions + // for their instances. + // + // We have the following datastores: + // + // 1. User templates: set of per-user map templates - // User templates (HASH:tpl_id->tpl_val) - this.key_usr_tpl = dot.template("map_tpl|{{=it.owner}}"); + // User templates (HASH:tplId->tpl_val) + this.key_usr_tpl = dot.template('map_tpl|{{=it.owner}}'); } util.inherits(TemplateMaps, EventEmitter); module.exports = TemplateMaps; +// --------------- PRIVATE METHODS -------------------------------- -//--------------- PRIVATE METHODS -------------------------------- - -TemplateMaps.prototype._userTemplateLimit = function() { - return this.opts.max_user_templates || 0; +TemplateMaps.prototype._userTemplateLimit = function () { + return this.opts.max_user_templates || 0; }; /** @@ -68,14 +65,14 @@ TemplateMaps.prototype._userTemplateLimit = function() { * @param redisArgs - the arguments for the redis function in an array * @param callback - function to pass results too. */ -TemplateMaps.prototype._redisCmd = function(redisFunc, redisArgs, callback) { - this.redis_pool.acquire(this.db_signatures, (err, redisClient) => { +TemplateMaps.prototype._redisCmd = function (redisFunc, redisArgs, callback) { + this.redisPool.acquire(this.db_signatures, (err, redisClient) => { if (err) { return callback(err); } redisClient[redisFunc.toUpperCase()](...redisArgs, (err, data) => { - this.redis_pool.release(this.db_signatures, redisClient); + this.redisPool.release(this.db_signatures, redisClient); if (err) { return callback(err); } @@ -84,64 +81,64 @@ TemplateMaps.prototype._redisCmd = function(redisFunc, redisArgs, callback) { }); }; -var _reValidNameIdentifier = /^[a-z0-9][0-9a-z_\-]*$/i; +var _reValidNameIdentifier = /^[a-z0-9][0-9a-z_-]*$/i; var _reValidPlaceholderIdentifier = /^[a-z][0-9a-z_]*$/i; // jshint maxcomplexity:15 -TemplateMaps.prototype._checkInvalidTemplate = function(template) { - if ( template.version !== '0.0.1' ) { - return new Error("Unsupported template version " + template.version); - } - var tplname = template.name; - if ( ! tplname ) { - return new Error("Missing template name"); - } - if ( ! tplname.match(_reValidNameIdentifier) ) { - return new Error("Invalid characters in template name '" + tplname + "'"); - } +TemplateMaps.prototype._checkInvalidTemplate = function (template) { + if (template.version !== '0.0.1') { + return new Error('Unsupported template version ' + template.version); + } + var tplname = template.name; + if (!tplname) { + return new Error('Missing template name'); + } + if (!tplname.match(_reValidNameIdentifier)) { + return new Error("Invalid characters in template name '" + tplname + "'"); + } - var invalidError = isInvalidLayergroup(template.layergroup); - if (invalidError) { - return invalidError; - } + var invalidError = isInvalidLayergroup(template.layergroup); + if (invalidError) { + return invalidError; + } - var placeholders = template.placeholders || {}; + var placeholders = template.placeholders || {}; - var placeholderKeys = Object.keys(placeholders); - for (var i = 0, len = placeholderKeys.length; i < len; i++) { - var placeholderKey = placeholderKeys[i]; + var placeholderKeys = Object.keys(placeholders); + for (var i = 0, len = placeholderKeys.length; i < len; i++) { + var placeholderKey = placeholderKeys[i]; - if (!placeholderKey.match(_reValidPlaceholderIdentifier)) { - return new Error("Invalid characters in placeholder name '" + placeholderKey + "'"); - } - if ( ! placeholders[placeholderKey].hasOwnProperty('default') ) { - return new Error("Missing default for placeholder '" + placeholderKey + "'"); - } - if ( ! placeholders[placeholderKey].hasOwnProperty('type') ) { - return new Error("Missing type for placeholder '" + placeholderKey + "'"); - } - } + if (!placeholderKey.match(_reValidPlaceholderIdentifier)) { + return new Error("Invalid characters in placeholder name '" + placeholderKey + "'"); + } + if (!Object.prototype.hasOwnProperty.call(placeholders[placeholderKey], 'default')) { + return new Error("Missing default for placeholder '" + placeholderKey + "'"); + } + if (!Object.prototype.hasOwnProperty.call(placeholders[placeholderKey], 'type')) { + return new Error("Missing type for placeholder '" + placeholderKey + "'"); + } + } var auth = template.auth || {}; - switch ( auth.method ) { - case 'open': - break; - case 'token': - if ( ! _.isArray(auth.valid_tokens) ) { - return new Error("Invalid 'token' authentication: missing valid_tokens"); - } - if ( ! auth.valid_tokens.length ) { - return new Error("Invalid 'token' authentication: no valid_tokens"); - } - break; - default: - return new Error("Unsupported authentication method: " + auth.method); + switch (auth.method) { + case 'open': + break; + case 'token': + if (!_.isArray(auth.valid_tokens)) { + return new Error("Invalid 'token' authentication: missing valid_tokens"); + } + if (!auth.valid_tokens.length) { + return new Error("Invalid 'token' authentication: no valid_tokens"); + } + break; + default: + return new Error('Unsupported authentication method: ' + auth.method); } return false; }; -function isInvalidLayergroup(layergroup) { +function isInvalidLayergroup (layergroup) { if (!layergroup) { return new Error('Missing layergroup'); } @@ -153,10 +150,10 @@ function isInvalidLayergroup(layergroup) { } var invalidLayers = layers - .map(function(layer, layerIndex) { + .map(function (layer, layerIndex) { return layer.options ? null : layerIndex; }) - .filter(function(layerIndex) { + .filter(function (layerIndex) { return layerIndex !== null; }); @@ -167,7 +164,7 @@ function isInvalidLayergroup(layergroup) { return false; } -function templateDefaults(template) { +function templateDefaults (template) { var templateAuth = _.defaults({}, template.auth || {}, { method: 'open' }); @@ -183,10 +180,10 @@ function templateDefaults(template) { * @param owner cartodb username of the template owner * @param callback returns error if the user reaches the limit */ -TemplateMaps.prototype._checkUserTemplatesLimit = function(userTemplatesKey, owner, callback) { +TemplateMaps.prototype._checkUserTemplatesLimit = function (userTemplatesKey, owner, callback) { const limit = this._userTemplateLimit(); - if(!limit) { + if (!limit) { return callback(); } @@ -207,7 +204,7 @@ TemplateMaps.prototype._checkUserTemplatesLimit = function(userTemplatesKey, own }); }; -//--------------- PUBLIC API ------------------------------------- +// --------------- PUBLIC API ------------------------------------- // Add a template // @@ -218,10 +215,10 @@ TemplateMaps.prototype._checkUserTemplatesLimit = function(userTemplatesKey, own // @param template layergroup template, see // http://github.com/CartoDB/Windshaft-cartodb/wiki/Template-maps#template-format // -// @param callback function(err, tpl_id) +// @param callback function(err, tplId) // Return template identifier (only valid for given user) // -TemplateMaps.prototype.addTemplate = function(owner, template, callback) { +TemplateMaps.prototype.addTemplate = function (owner, template, callback) { template = templateDefaults(template); var invalidError = this._checkInvalidTemplate(template); @@ -263,22 +260,22 @@ TemplateMaps.prototype.addTemplate = function(owner, template, callback) { // // @param owner cartodb username of the template owner // -// @param tpl_id template identifier as returned +// @param tplId template identifier as returned // by addTemplate or listTemplates // // @param callback function(err) // -TemplateMaps.prototype.delTemplate = function(owner, tpl_id, callback) { - this._redisCmd('HDEL', [ this.key_usr_tpl({ owner:owner }), tpl_id ], (err, deleted) => { +TemplateMaps.prototype.delTemplate = function (owner, tplId, callback) { + this._redisCmd('HDEL', [this.key_usr_tpl({ owner: owner }), tplId], (err, deleted) => { if (err) { return callback(err); } if (!deleted) { - return callback(new Error(`Template '${tpl_id}' of user '${owner}' does not exist`)); + return callback(new Error(`Template '${tplId}' of user '${owner}' does not exist`)); } - this.emit('delete', owner, tpl_id); + this.emit('delete', owner, tplId); return callback(); }); }; @@ -292,14 +289,14 @@ TemplateMaps.prototype.delTemplate = function(owner, tpl_id, callback) { // // @param owner cartodb username of the template owner // -// @param tpl_id template identifier as returned by addTemplate +// @param tplId template identifier as returned by addTemplate // // @param template layergroup template, see // http://github.com/CartoDB/Windshaft-cartodb/wiki/Template-maps#template-format // // @param callback function(err) // -TemplateMaps.prototype.updTemplate = function(owner, tpl_id, template, callback) { +TemplateMaps.prototype.updTemplate = function (owner, tplId, template, callback) { template = templateDefaults(template); var invalidError = this._checkInvalidTemplate(template); @@ -307,19 +304,19 @@ TemplateMaps.prototype.updTemplate = function(owner, tpl_id, template, callback) return callback(invalidError); } - if (tpl_id !== template.name) { - return callback(new Error(`Cannot update name of a map template ('${tpl_id}' != '${template.name}')`)); + if (tplId !== template.name) { + return callback(new Error(`Cannot update name of a map template ('${tplId}' != '${template.name}')`)); } var userTemplatesKey = this.key_usr_tpl({ owner }); - this._redisCmd('HGET', [userTemplatesKey, tpl_id], (err, beforeUpdateTemplate) => { + this._redisCmd('HGET', [userTemplatesKey, tplId], (err, beforeUpdateTemplate) => { if (err) { return callback(err); } if (!beforeUpdateTemplate) { - return callback(new Error(`Template '${tpl_id}' of user '${owner}' does not exist`)); + return callback(new Error(`Template '${tplId}' of user '${owner}' does not exist`)); } let templateString; @@ -358,25 +355,25 @@ TemplateMaps.prototype.updTemplate = function(owner, tpl_id, template, callback) // // @param owner cartodb username of the templates owner // -// @param callback function(err, tpl_id_list) +// @param callback function(err, tplId_list) // Returns a list of template identifiers // -TemplateMaps.prototype.listTemplates = function(owner, callback) { - this._redisCmd('HKEYS', [ this.key_usr_tpl({owner:owner}) ], callback); +TemplateMaps.prototype.listTemplates = function (owner, callback) { + this._redisCmd('HKEYS', [this.key_usr_tpl({ owner: owner })], callback); }; // Get a templates // // @param owner cartodb username of the template owner // -// @param tpl_id template identifier as returned +// @param tplId template identifier as returned // by addTemplate or listTemplates // // @param callback function(err, template) // Return full template definition // -TemplateMaps.prototype.getTemplate = function(owner, tpl_id, callback) { - this._redisCmd('HGET', [this.key_usr_tpl({owner:owner}), tpl_id], (err, template) => { +TemplateMaps.prototype.getTemplate = function (owner, tplId, callback) { + this._redisCmd('HGET', [this.key_usr_tpl({ owner: owner }), tplId], (err, template) => { if (err) { return callback(err); } @@ -392,7 +389,7 @@ TemplateMaps.prototype.getTemplate = function(owner, tpl_id, callback) { }); }; -TemplateMaps.prototype.isAuthorized = function(template, authTokens) { +TemplateMaps.prototype.isAuthorized = function (template, authTokens) { if (!template) { return false; } @@ -432,99 +429,95 @@ TemplateMaps.prototype.isAuthorized = function(template, authTokens) { // // @throws Error on malformed template or parameter // -var _reNumber = /^([-+]?[\d\.]?\d+([eE][+-]?\d+)?)$/, - _reCSSColorName = /^[a-zA-Z]+$/, - _reCSSColorVal = /^#[0-9a-fA-F]{3,6}$/; +var _reNumber = /^([-+]?[\d\.]?\d+([eE][+-]?\d+)?)$/; // eslint-disable-line no-useless-escape +var _reCSSColorName = /^[a-zA-Z]+$/; +var _reCSSColorVal = /^#[0-9a-fA-F]{3,6}$/; function _replaceVars (str, params) { // Construct regular expressions for each param - Object.keys(params).forEach(function(k) { - str = str.replace(new RegExp("<%=\\s*" + k + "\\s*%>", "g"), params[k]); + Object.keys(params).forEach(function (k) { + str = str.replace(new RegExp('<%=\\s*' + k + '\\s*%>', 'g'), params[k]); }); return str; } -function isObject(val) { - return ( _.isObject(val) && !_.isArray(val) && !_.isFunction(val)); +function isObject (val) { + return (_.isObject(val) && !_.isArray(val) && !_.isFunction(val)); } -TemplateMaps.prototype.instance = function(template, params) { - var all_params = {}; - var phold = template.placeholders || {}; - Object.keys(phold).forEach(function(k) { - var val = params.hasOwnProperty(k) ? params[k] : phold[k].default; - var type = phold[k].type; - // properly escape - if ( type === 'sql_literal' ) { - // duplicate any single-quote - val = val.replace(/'/g, "''"); - } - else if ( type === 'sql_ident' ) { - // duplicate any double-quote - val = val.replace(/"/g, '""'); - } - else if ( type === 'number' ) { - // check it's a number - if ( typeof(val) !== 'number' && ! val.match(_reNumber) ) { - throw new Error("Invalid number value for template parameter '" + k + "': " + val); - } - } - else if ( type === 'css_color' ) { - // check it only contains letters or - // starts with # and only contains hexdigits - if ( ! val.match(_reCSSColorName) && ! val.match(_reCSSColorVal) ) { - throw new Error("Invalid css_color value for template parameter '" + k + "': " + val); - } - } - else { - // NOTE: should be checked at template create/update time - throw new Error("Invalid placeholder type '" + type + "'"); - } - all_params[k] = val; - }); +TemplateMaps.prototype.instance = function (template, params) { + var allParams = {}; + var phold = template.placeholders || {}; + Object.keys(phold).forEach(function (k) { + var val = Object.prototype.hasOwnProperty.call(params, k) ? params[k] : phold[k].default; + var type = phold[k].type; + // properly escape + if (type === 'sql_literal') { + // duplicate any single-quote + val = val.replace(/'/g, "''"); + } else if (type === 'sql_ident') { + // duplicate any double-quote + val = val.replace(/"/g, '""'); + } else if (type === 'number') { + // check it's a number + if (typeof (val) !== 'number' && !val.match(_reNumber)) { + throw new Error("Invalid number value for template parameter '" + k + "': " + val); + } + } else if (type === 'css_color') { + // check it only contains letters or + // starts with # and only contains hexdigits + if (!val.match(_reCSSColorName) && !val.match(_reCSSColorVal)) { + throw new Error("Invalid css_color value for template parameter '" + k + "': " + val); + } + } else { + // NOTE: should be checked at template create/update time + throw new Error("Invalid placeholder type '" + type + "'"); + } + allParams[k] = val; + }); - // NOTE: we're deep-cloning the layergroup here - var layergroup = JSON.parse(JSON.stringify(template.layergroup)); + // NOTE: we're deep-cloning the layergroup here + var layergroup = JSON.parse(JSON.stringify(template.layergroup)); - if (layergroup.buffersize && isObject(layergroup.buffersize)) { - Object.keys(layergroup.buffersize).forEach(function(k) { - layergroup.buffersize[k] = parseInt(_replaceVars(layergroup.buffersize[k], all_params), 10); - }); - } + if (layergroup.buffersize && isObject(layergroup.buffersize)) { + Object.keys(layergroup.buffersize).forEach(function (k) { + layergroup.buffersize[k] = parseInt(_replaceVars(layergroup.buffersize[k], allParams), 10); + }); + } - for (var i=0; i String` method * @param {Function} callback */ -FastlyCacheBackend.prototype.invalidate = function(cacheObject, callback) { +FastlyCacheBackend.prototype.invalidate = function (cacheObject, callback) { this.fastlyPurge.key(this.serviceId, cacheObject.key(), callback); }; diff --git a/lib/cache/backend/varnish-http.js b/lib/cache/backend/varnish-http.js index 35fa5330..05851072 100644 --- a/lib/cache/backend/varnish-http.js +++ b/lib/cache/backend/varnish-http.js @@ -2,7 +2,7 @@ var request = require('request'); -function VarnishHttpCacheBackend(host, port) { +function VarnishHttpCacheBackend (host, port) { this.host = host; this.port = port; } @@ -13,7 +13,7 @@ module.exports = VarnishHttpCacheBackend; * @param cacheObject should respond to `key() -> String` method * @param {Function} callback */ -VarnishHttpCacheBackend.prototype.invalidate = function(cacheObject, callback) { +VarnishHttpCacheBackend.prototype.invalidate = function (cacheObject, callback) { request( { method: 'PURGE', @@ -22,7 +22,7 @@ VarnishHttpCacheBackend.prototype.invalidate = function(cacheObject, callback) { 'Invalidation-Match': '\\b' + cacheObject.key() + '\\b' } }, - function(err, response) { + function (err, response) { if (err || response.statusCode !== 204) { return callback(new Error('Unable to invalidate Varnish object')); } diff --git a/lib/cache/layergroup-affected-tables.js b/lib/cache/layergroup-affected-tables.js index fb63eb37..fd4c6d0e 100644 --- a/lib/cache/layergroup-affected-tables.js +++ b/lib/cache/layergroup-affected-tables.js @@ -2,25 +2,25 @@ var LruCache = require('lru-cache'); -function LayergroupAffectedTables() { +function LayergroupAffectedTables () { // dbname + layergroupId -> affected tables cache this.cache = new LruCache({ max: 2000 }); } module.exports = LayergroupAffectedTables; -LayergroupAffectedTables.prototype.hasAffectedTables = function(dbName, layergroupId) { +LayergroupAffectedTables.prototype.hasAffectedTables = function (dbName, layergroupId) { return this.cache.has(createKey(dbName, layergroupId)); }; -LayergroupAffectedTables.prototype.set = function(dbName, layergroupId, affectedTables) { +LayergroupAffectedTables.prototype.set = function (dbName, layergroupId, affectedTables) { this.cache.set(createKey(dbName, layergroupId), affectedTables); }; -LayergroupAffectedTables.prototype.get = function(dbName, layergroupId) { +LayergroupAffectedTables.prototype.get = function (dbName, layergroupId) { return this.cache.get(createKey(dbName, layergroupId)); }; -function createKey(dbName, layergroupId) { +function createKey (dbName, layergroupId) { return dbName + ':' + layergroupId; } diff --git a/lib/cache/model/named-maps-entry.js b/lib/cache/model/named-maps-entry.js index a4537368..42ac5e25 100644 --- a/lib/cache/model/named-maps-entry.js +++ b/lib/cache/model/named-maps-entry.js @@ -2,7 +2,7 @@ var crypto = require('crypto'); -function NamedMaps(owner, name) { +function NamedMaps (owner, name) { this.namespace = 'n'; this.owner = owner; this.name = name; @@ -10,11 +10,10 @@ function NamedMaps(owner, name) { module.exports = NamedMaps; - -NamedMaps.prototype.key = function() { +NamedMaps.prototype.key = function () { return this.namespace + ':' + shortHashKey(this.owner + ':' + this.name); }; -function shortHashKey(target) { - return crypto.createHash('sha256').update(target).digest('base64').substring(0,6); +function shortHashKey (target) { + return crypto.createHash('sha256').update(target).digest('base64').substring(0, 6); } diff --git a/lib/cache/named-map-provider-cache.js b/lib/cache/named-map-provider-cache.js index 844a2038..9d35e5ab 100644 --- a/lib/cache/named-map-provider-cache.js +++ b/lib/cache/named-map-provider-cache.js @@ -34,7 +34,7 @@ module.exports = class NamedMapProviderCache { const namedMapProviders = this.providerCache.get(namedMapKey) || {}; const providerKey = createProviderKey(config, authToken, params); - if (namedMapProviders.hasOwnProperty(providerKey)) { + if (Object.prototype.hasOwnProperty.call(namedMapProviders, providerKey)) { return callback(null, namedMapProviders[providerKey]); } diff --git a/lib/cache/surrogate-keys-cache.js b/lib/cache/surrogate-keys-cache.js index bf4bc852..e23344f2 100644 --- a/lib/cache/surrogate-keys-cache.js +++ b/lib/cache/surrogate-keys-cache.js @@ -6,28 +6,26 @@ var queue = require('queue-async'); * @param {Array|Object} cacheBackends each backend backend should respond to `invalidate(cacheObject, callback)` method * @constructor */ -function SurrogateKeysCache(cacheBackends) { +function SurrogateKeysCache (cacheBackends) { this.cacheBackends = Array.isArray(cacheBackends) ? cacheBackends : [cacheBackends]; } module.exports = SurrogateKeysCache; - /** * @param response should respond to `header(key, value)` method * @param cacheObject should respond to `key() -> String` method */ -SurrogateKeysCache.prototype.tag = function(response, cacheObject) { +SurrogateKeysCache.prototype.tag = function (response, cacheObject) { var newKey = cacheObject.key(); response.set('Surrogate-Key', appendSurrogateKey( response.get('Surrogate-Key'), Array.isArray(newKey) ? cacheObject.key().join(' ') : newKey )); - }; -function appendSurrogateKey(currentKey, newKey) { - if (!!currentKey) { +function appendSurrogateKey (currentKey, newKey) { + if (currentKey) { newKey = currentKey + ' ' + newKey; } return newKey; @@ -37,16 +35,16 @@ function appendSurrogateKey(currentKey, newKey) { * @param cacheObject should respond to `key() -> String` method * @param {Function} callback */ -SurrogateKeysCache.prototype.invalidate = function(cacheObject, callback) { +SurrogateKeysCache.prototype.invalidate = function (cacheObject, callback) { var invalidationQueue = queue(this.cacheBackends.length); - this.cacheBackends.forEach(function(cacheBackend) { - invalidationQueue.defer(function(cacheBackend, done) { + this.cacheBackends.forEach(function (cacheBackend) { + invalidationQueue.defer(function (cacheBackend, done) { cacheBackend.invalidate(cacheObject, done); }, cacheBackend); }); - invalidationQueue.awaitAll(function(err, result) { + invalidationQueue.awaitAll(function (err, result) { if (err) { return callback(err); } diff --git a/lib/models/aggregation/aggregation-mapconfig.js b/lib/models/aggregation/aggregation-mapconfig.js index 74099f1e..493a5c96 100644 --- a/lib/models/aggregation/aggregation-mapconfig.js +++ b/lib/models/aggregation/aggregation-mapconfig.js @@ -53,11 +53,11 @@ module.exports = class AggregationMapConfig extends MapConfig { return null; } - static supportsGeometryType(geometryType) { + static supportsGeometryType (geometryType) { return AggregationMapConfig.SUPPORTED_GEOMETRY_TYPES.includes(geometryType); } - static getAggregationGeometryColumn() { + static getAggregationGeometryColumn () { return aggregationQuery.GEOMETRY_COLUMN; } @@ -83,7 +83,7 @@ module.exports = class AggregationMapConfig extends MapConfig { } getAggregatedQuery (index) { - const { sql_raw, sql } = this.getLayer(index).options; + const { sql_raw: sqlRaw, sql } = this.getLayer(index).options; const { // The default aggregation has no placement, columns or dimensions; // this enables the special "full-sample" aggregation. @@ -96,7 +96,7 @@ module.exports = class AggregationMapConfig extends MapConfig { } = this.getAggregation(index); return aggregationQuery({ - query: sql_raw || sql, + query: sqlRaw || sql, resolution, threshold, placement, @@ -108,7 +108,7 @@ module.exports = class AggregationMapConfig extends MapConfig { } isAggregationLayer (index) { - let hasAggregation = this.hasLayerAggregation(index); + const hasAggregation = this.hasLayerAggregation(index); // for vector-only MapConfig are aggregated unless explicitly disabled return hasAggregation || ( this.isVectorOnlyMapConfig() && hasAggregation !== AggregationMapConfig.HAS_AGGREGATION_DISABLED @@ -176,7 +176,7 @@ module.exports = class AggregationMapConfig extends MapConfig { _getLayerAggregationRequiredColumns (index) { const { columns, dimensions } = this.getAggregation(index); - let finalColumns = ['cartodb_id', '_cdb_feature_count']; + const finalColumns = ['cartodb_id', '_cdb_feature_count']; let aggregatedColumns = []; if (columns) { @@ -191,10 +191,10 @@ module.exports = class AggregationMapConfig extends MapConfig { return removeDuplicates(finalColumns.concat(aggregatedColumns).concat(dimensionsColumns)); } - doesLayerReachThreshold(index, featureCount) { - const threshold = this.getAggregation(index) && this.getAggregation(index).threshold ? - this.getAggregation(index).threshold : - AggregationMapConfig.THRESHOLD; + doesLayerReachThreshold (index, featureCount) { + const threshold = this.getAggregation(index) && this.getAggregation(index).threshold + ? this.getAggregation(index).threshold + : AggregationMapConfig.THRESHOLD; return featureCount >= threshold; } @@ -243,7 +243,7 @@ module.exports = class AggregationMapConfig extends MapConfig { this._isEmptyParameter(aggregation.filters); } - _isEmptyParameter(parameter) { + _isEmptyParameter (parameter) { return parameter === undefined || parameter === null || this._isEmptyObject(parameter); } diff --git a/lib/models/aggregation/aggregation-query.js b/lib/models/aggregation/aggregation-query.js index 4e76fc75..775123a5 100644 --- a/lib/models/aggregation/aggregation-query.js +++ b/lib/models/aggregation/aggregation-query.js @@ -9,7 +9,7 @@ const webmercator = new WebMercatorHelper(); function optionsToParams (options) { return { sourceQuery: options.query, - res: 256/options.resolution, + res: 256 / options.resolution, columns: options.columns, dimensions: options.dimensions, filters: options.filters, @@ -50,30 +50,30 @@ module.exports.infoForOptions = (options) => { }; const SUPPORTED_AGGREGATE_FUNCTIONS = { - 'count': { - sql: (column_name, params) => `count(${params.aggregated_column || '*'})` + count: { + sql: (columnName, params) => `count(${params.aggregated_column || '*'})` }, - 'avg': { - sql: (column_name, params) => `avg(${params.aggregated_column || column_name})` + avg: { + sql: (columnName, params) => `avg(${params.aggregated_column || columnName})` }, - 'sum': { - sql: (column_name, params) => `sum(${params.aggregated_column || column_name})` + sum: { + sql: (columnName, params) => `sum(${params.aggregated_column || columnName})` }, - 'min': { - sql: (column_name, params) => `min(${params.aggregated_column || column_name})` + min: { + sql: (columnName, params) => `min(${params.aggregated_column || columnName})` }, - 'max': { - sql: (column_name, params) => `max(${params.aggregated_column || column_name})` + max: { + sql: (columnName, params) => `max(${params.aggregated_column || columnName})` }, - 'mode': { - sql: (column_name, params) => `mode() WITHIN GROUP (ORDER BY ${params.aggregated_column || column_name})` + mode: { + sql: (columnName, params) => `mode() WITHIN GROUP (ORDER BY ${params.aggregated_column || columnName})` } }; module.exports.SUPPORTED_AGGREGATE_FUNCTIONS = Object.keys(SUPPORTED_AGGREGATE_FUNCTIONS); const sep = (list) => { - let expr = list.join(', '); + const expr = list.join(', '); return expr ? ', ' + expr : expr; }; @@ -85,20 +85,20 @@ const aggregateColumns = ctx => { }, ctx.columns || {}); }; -const aggregateExpression = (column_name, column_parameters) => { - const aggregate_function = column_parameters.aggregate_function || 'count'; - const aggregate_definition = SUPPORTED_AGGREGATE_FUNCTIONS[aggregate_function]; - if (!aggregate_definition) { - throw new Error("Invalid Aggregate function: '" + aggregate_function + "'"); +const aggregateExpression = (columnName, columnParameters) => { + const aggregateFunction = columnParameters.aggregate_function || 'count'; + const aggregateDefinition = SUPPORTED_AGGREGATE_FUNCTIONS[aggregateFunction]; + if (!aggregateDefinition) { + throw new Error("Invalid Aggregate function: '" + aggregateFunction + "'"); } - return aggregate_definition.sql(column_name, column_parameters); + return aggregateDefinition.sql(columnName, columnParameters); }; const aggregateColumnDefs = ctx => { - let columns = aggregateColumns(ctx); - return sep(Object.keys(columns).map(column_name => { - const aggregate_expression = aggregateExpression(column_name, columns[column_name]); - return `${aggregate_expression} AS ${column_name}`; + const columns = aggregateColumns(ctx); + return sep(Object.keys(columns).map(columnName => { + const aggregate = aggregateExpression(columnName, columns[columnName]); + return `${aggregate} AS ${columnName}`; })); }; @@ -119,7 +119,7 @@ const timeDimensionParameters = definition => { // Adapt old-style dimension definitions for backwards compatibility const adaptDimensionDefinition = definition => { - if (typeof(definition) === 'string') { + if (typeof (definition) === 'string') { return { column: definition }; } return definition; @@ -135,7 +135,7 @@ const dimensionExpression = definition => { }; const dimensionNamesAndExpressions = (ctx) => { - let dimensions = aggregateDimensions(ctx); + const dimensions = aggregateDimensions(ctx); return Object.keys(dimensions).map(dimensionName => { const dimension = adaptDimensionDefinition(dimensions[dimensionName]); const expression = dimensionExpression(dimension); @@ -152,7 +152,7 @@ const dimensionNames = (ctx, table) => { const dimensionDefs = ctx => { return sep( dimensionNamesAndExpressions(ctx) - .map(([dimensionName, expression]) => `${expression.sql} AS "${dimensionName}"`) + .map(([dimensionName, expression]) => `${expression.sql} AS "${dimensionName}"`) ); }; @@ -192,7 +192,7 @@ const sqlQ = (value) => { const FILTERS = { between: (expr, filter) => { - const lo = filter.greater_than_or_equal_to, hi = filter.less_than_or_equal_to; + const lo = filter.greater_than_or_equal_to; const hi = filter.less_than_or_equal_to; if (lo != null && hi != null) { return `(${expr} BETWEEN ${sqlQ(lo)} AND ${sqlQ(hi)})`; } @@ -218,7 +218,7 @@ const FILTERS = { } }, range: (expr, filter) => { - let conds = []; + const conds = []; if (filter.greater_than_or_equal_to != null) { conds.push(`(${expr} >= ${sqlQ(filter.greater_than_or_equal_to)})`); } @@ -238,26 +238,25 @@ const FILTERS = { }; const filterConditions = ctx => { - let columns = aggregateColumns(ctx); - let dimensions = aggregateDimensions(ctx); - let filters = aggregateFilters(ctx); - return Object.keys(filters).map(filtered_column => { - let filtered_expr; - if (columns[filtered_column]) { - filtered_expr = aggregateExpression(filtered_column, columns[filtered_column]); + const columns = aggregateColumns(ctx); + const dimensions = aggregateDimensions(ctx); + const filters = aggregateFilters(ctx); + return Object.keys(filters).map(filteredColumn => { + let filteredExpr; + if (columns[filteredColumn]) { + filteredExpr = aggregateExpression(filteredColumn, columns[filteredColumn]); + } else if (dimensions[filteredColumn]) { + filteredExpr = dimensions[filteredColumn]; } - else if (dimensions[filtered_column]) { - filtered_expr = dimensions[filtered_column]; + if (!filteredExpr) { + throw new Error("Invalid filtered column: '" + filteredColumn + "'"); } - if (!filtered_expr) { - throw new Error("Invalid filtered column: '" + filtered_column + "'"); - } - return filterConditionSQL(filtered_expr, filters[filtered_column]); + return filterConditionSQL(filteredExpr, filters[filteredColumn]); }).join(' AND '); }; const havingClause = ctx => { - let cond = filterConditions(ctx); + const cond = filterConditions(ctx); return cond ? `HAVING ${cond}` : ''; }; @@ -274,8 +273,8 @@ const havingClause = ctx => { // NOTE 2: The 0.00028 is used in Mapnik (and replicated in pg-mvt) and comes from // OGC's Styled Layer Descriptor Implementation Specification const gridResolution = ctx => { - const minimumResolution = webmercator.getResolution({ z : 38 }); - return `${256/ctx.res} * GREATEST(!scale_denominator! * 0.00028, ${minimumResolution})::double precision`; + const minimumResolution = webmercator.getResolution({ z: 38 }); + return `${256 / ctx.res} * GREATEST(!scale_denominator! * 0.00028, ${minimumResolution})::double precision`; }; // SQL query to extract the boundaries of the area to be aggregated and the grid resolution @@ -309,55 +308,49 @@ const gridInfoQuery = ctx => { `; }; - // Function to generate the resulting point for a cell from the aggregated data const aggregatedPointWebMercator = (ctx) => { switch (ctx.placement) { - - // For centroid, we return the average of the cell - case 'centroid': - return ', ST_SetSRID(ST_MakePoint(AVG(cdb_x), AVG(cdb_y)), 3857) AS the_geom_webmercator'; + // For centroid, we return the average of the cell + case 'centroid': + return ', ST_SetSRID(ST_MakePoint(AVG(cdb_x), AVG(cdb_y)), 3857) AS the_geom_webmercator'; // Middle point of the cell - case 'point-grid': - return `, ST_SetSRID(ST_MakePoint(cdb_pos_grid_x, cdb_pos_grid_y), 3857) AS the_geom_webmercator`; + case 'point-grid': + return ', ST_SetSRID(ST_MakePoint(cdb_pos_grid_x, cdb_pos_grid_y), 3857) AS the_geom_webmercator'; // For point-sample we'll get a single point directly from the source // If it's default aggregation we'll add the extra columns to keep backwards compatibility - case 'point-sample': - return ''; + case 'point-sample': + return ''; - default: - throw new Error(`Invalid aggregation placement "${ctx.placement}"`); + default: + throw new Error(`Invalid aggregation placement "${ctx.placement}"`); } }; // Function to generate the resulting point for a cell from the a join with the source const aggregatedPointJoin = (ctx) => { switch (ctx.placement) { - - case 'centroid': - return ''; - - case 'point-grid': - return ''; - - // For point-sample we'll get a single point directly from the source - // If it's default aggregation we'll add the extra columns to keep backwards compatibility - case 'point-sample': - return ` -NATURAL JOIN -( - SELECT ${ctx.isDefaultAggregation ? `*` : `cartodb_id, the_geom_webmercator`} - FROM - ( - ${ctx.sourceQuery} - ) __cdb_src_query -) __cdb_query_columns -`; - - default: - throw new Error('Invalid aggregation placement "${ctx.placement}"'); + case 'centroid': + return ''; + case 'point-grid': + return ''; + // For point-sample we'll get a single point directly from the source + // If it's default aggregation we'll add the extra columns to keep backwards compatibility + case 'point-sample': + return ` + NATURAL JOIN + ( + SELECT ${ctx.isDefaultAggregation ? '*' : 'cartodb_id, the_geom_webmercator'} + FROM + ( + ${ctx.sourceQuery} + ) __cdb_src_query + ) __cdb_query_columns + `; + default: + throw new Error(`Invalid aggregation placement "${ctx.placement}"`); } }; @@ -367,17 +360,16 @@ NATURAL JOIN // which requires extra data in the group by clause const aggregatedPosCoordinate = (ctx, coordinate) => { switch (ctx.placement) { - // For point-grid we return the coordinate of the middle point of the grid - case `point-grid`: - return `(FLOOR(cdb_${coordinate} / __cdb_grid_params.cdb_res) + 0.5) * __cdb_grid_params.cdb_res`; + // For point-grid we return the coordinate of the middle point of the grid + case 'point-grid': + return `(FLOOR(cdb_${coordinate} / __cdb_grid_params.cdb_res) + 0.5) * __cdb_grid_params.cdb_res`; // For other, we return the cell position (relative to the world) - default: - return `FLOOR(cdb_${coordinate} / __cdb_grid_params.cdb_res)`; + default: + return `FLOOR(cdb_${coordinate} / __cdb_grid_params.cdb_res)`; } }; - const aggregationQueryTemplate = ctx => ` WITH __cdb_grid_params AS ( @@ -445,5 +437,5 @@ const clusterFeaturesQuery = ctx => ` module.exports.featuresQuery = (id, options) => clusterFeaturesQuery({ id, sourceQuery: options.query, - res: 256/options.resolution + res: 256 / options.resolution }); diff --git a/lib/models/aggregation/aggregation-validator.js b/lib/models/aggregation/aggregation-validator.js index 257e7980..99ac4839 100644 --- a/lib/models/aggregation/aggregation-validator.js +++ b/lib/models/aggregation/aggregation-validator.js @@ -76,11 +76,11 @@ module.exports.createAggregationFiltersValidator = function (mapconfig, validPar }; }; -function createAggregationColumnNamesValidator(mapconfig) { +function createAggregationColumnNamesValidator (mapconfig) { return function validateAggregationColumnNames (value, key, index) { Object.keys(value).forEach((columnName) => { if (columnName.length <= 0) { - const message = `Invalid column name, should be a non empty string`; + const message = 'Invalid column name, should be a non empty string'; throw createLayerError(message, mapconfig, index); } }); @@ -90,10 +90,10 @@ function createAggregationColumnNamesValidator(mapconfig) { function createAggregateFunctionValidator (mapconfig, validAggregatedFunctions) { return function validateAggregateFunction (value, key, index) { Object.keys(value).forEach((columnName) => { - const { aggregate_function } = value[columnName]; + const { aggregate_function: aggregateFunction } = value[columnName]; - if (!validAggregatedFunctions.includes(aggregate_function)) { - const message = `Unsupported aggregation function ${aggregate_function},` + + if (!validAggregatedFunctions.includes(aggregateFunction)) { + const message = `Unsupported aggregation function ${aggregateFunction},` + ` valid ones: ${validAggregatedFunctions.join(', ')}`; throw createLayerError(message, mapconfig, index); } @@ -104,17 +104,17 @@ function createAggregateFunctionValidator (mapconfig, validAggregatedFunctions) function createAggregatedColumnValidator (mapconfig) { return function validateAggregatedColumn (value, key, index) { Object.keys(value).forEach((columnName) => { - const { aggregated_column } = value[columnName]; + const { aggregated_column: aggregatedColumn } = value[columnName]; - if (typeof aggregated_column !== 'string' || aggregated_column <= 0) { - const message = `Invalid aggregated column, should be a non empty string`; + if (typeof aggregatedColumn !== 'string' || aggregatedColumn <= 0) { + const message = 'Invalid aggregated column, should be a non empty string'; throw createLayerError(message, mapconfig, index); } }); }; } -function createLayerError(message, mapconfig, index) { +function createLayerError (message, mapconfig, index) { const error = new Error(message); error.type = 'layer'; error.layer = { diff --git a/lib/models/aggregation/time-dimension.js b/lib/models/aggregation/time-dimension.js index bd14bbf2..c261ca75 100644 --- a/lib/models/aggregation/time-dimension.js +++ b/lib/models/aggregation/time-dimension.js @@ -4,7 +4,7 @@ // a valid (case-insensitive) tz/PG name; // they include abbreviations defined by PG (which have precedence and // are fixed offsets, not handling DST) or general names that can handle DST. -function timezone(tz) { +function timezone (tz) { if (isFinite(tz)) { return `INTERVAL '${tz} seconds'`; } @@ -19,21 +19,21 @@ function timezone(tz) { // So, for using this with aggregations, relying on dates & times // converted to UTC UNIX epoch numbers, apply `to_timestamp` to the // (converted) column. -function timeExpression(t, tz) { - if (tz !== undefined) { +function timeExpression (t, tz) { + if (tz !== undefined) { return `timezone(${timezone(tz)}, ${t})`; - } - return t; + } + return t; } -function epochWithDefaults(epoch) { +function epochWithDefaults (epoch) { /* jshint maxcomplexity:9 */ // goddammit linter, I like this as is!! - const format = /^(\d\d\d\d)(?:\-?(\d\d)(?:\-?(\d\d)(?:[T\s]?(\d\d)(?:(\d\d)(?:\:(\d\d))?)?)?)?)?$/; - const match = (epoch || '').match(format) || []; - const year = match[1] || '0001'; - const month = match[2] || '01'; - const day = match[3] || '01'; - const hour = match[4] || '00'; + const format = /^(\d\d\d\d)(?:\-?(\d\d)(?:\-?(\d\d)(?:[T\s]?(\d\d)(?:(\d\d)(?:\:(\d\d))?)?)?)?)?$/; // eslint-disable-line no-useless-escape + const match = (epoch || '').match(format) || []; + const year = match[1] || '0001'; + const month = match[2] || '01'; + const day = match[3] || '01'; + const hour = match[4] || '00'; const minute = match[5] || '00'; const second = match[6] || '00'; return `${year}-${month}-${day}T${hour}:${minute}:${second}`; @@ -44,9 +44,9 @@ function epochWithDefaults(epoch) { // It can be partial, e.g. 'YYYY', 'YYYY-MM', 'YYYY-MM-DDTHH', etc. // Defaults are applied: YYYY=0001, MM=01, DD=01, HH=00, MM=00, S=00 // It returns a timestamp without time zone -function epochExpression(epoch) { +function epochExpression (epoch) { return `TIMESTAMP '${epoch}'`; - } +} const YEARSPAN = "(date_part('year', $t)-date_part('year', $epoch))"; // Note that SECONDSPAN is not a UTC epoch, but an epoch in the specified TZ, @@ -112,10 +112,10 @@ const serialParts = { } }; -function serialSqlExpr(params) { +function serialSqlExpr (params) { const { sql, zeroBased } = serialParts[params.units]; const column = timeExpression(params.time, params.timezone); - const epoch = epochExpression(params.starting); + const epoch = epochExpression(params.starting); const serial = sql.replace(/\$t/g, column).replace(/\$epoch/g, epoch); let expr = serial; if (params.count !== 1) { @@ -131,22 +131,22 @@ function serialSqlExpr(params) { } const isoParts = { - second: `to_char($t, 'YYYY-MM-DD"T"HH24:MI:SS')`, - minute: `to_char($t, 'YYYY-MM-DD"T"HH24:MI')`, - hour: `to_char($t, 'YYYY-MM-DD"T"HH24')`, - day: `to_char($t, 'YYYY-MM-DD')`, - month: `to_char($t, 'YYYY-MM')`, - year: `to_char($t, 'YYYY')`, - week: `to_char($t, 'IYYY-"W"IW')`, - quarter: `to_char($t, 'YYYY-"Q"Q')`, - semester: `to_char($t, 'YYYY"S"') || to_char(CEIL(date_part('month', $t)/6), '9')`, - trimester: `to_char($t, 'YYYY"t"') || to_char(CEIL(date_part('month', $t)/4), '9')`, - decade: `to_char(date_part('decade', $t), '"D"999')`, - century: `to_char($t, '"C"CC')`, - millennium: `to_char(date_part('millennium', $t), '"M"999')` + second: 'to_char($t, \'YYYY-MM-DD"T"HH24:MI:SS\')', + minute: 'to_char($t, \'YYYY-MM-DD"T"HH24:MI\')', + hour: 'to_char($t, \'YYYY-MM-DD"T"HH24\')', + day: 'to_char($t, \'YYYY-MM-DD\')', + month: 'to_char($t, \'YYYY-MM\')', + year: 'to_char($t, \'YYYY\')', + week: 'to_char($t, \'IYYY-"W"IW\')', + quarter: 'to_char($t, \'YYYY-"Q"Q\')', + semester: 'to_char($t, \'YYYY"S"\') || to_char(CEIL(date_part(\'month\', $t)/6), \'9\')', + trimester: 'to_char($t, \'YYYY"t"\') || to_char(CEIL(date_part(\'month\', $t)/4), \'9\')', + decade: 'to_char(date_part(\'decade\', $t), \'"D"999\')', + century: 'to_char($t, \'"C"CC\')', + millennium: 'to_char(date_part(\'millennium\', $t), \'"M"999\')' }; -function isoSqlExpr(params) { +function isoSqlExpr (params) { const column = timeExpression(params.time, params.timezone); if (params.count > 1) { // TODO: it would be sensible to return the ISO of the first unit in the period @@ -156,19 +156,19 @@ function isoSqlExpr(params) { } const cyclicParts = { - dayOfWeek: `date_part('isodow', $t)`, // 1 = monday to 7 = sunday; - dayOfMonth: `date_part('day', $t)`, // 1 to 31 - dayOfYear: `date_part('doy', $t)`, // 1 to 366 - hourOfDay: `date_part('hour', $t)`, // 0 to 23 - monthOfYear: `date_part('month', $t)`, // 1 to 12 - quarterOfYear: `date_part('quarter', $t)`, // 1 to 4 - semesterOfYear: `FLOOR((date_part('month', $t)-1)/6.0) + 1`, // 1 to 2 - trimesterOfYear: `FLOOR((date_part('month', $t)-1)/4.0) + 1`, // 1 to 3 - weekOfYear: `date_part('week', $t)`, // 1 to 53 - minuteOfHour: `date_part('minute', $t)` // 0 to 59 + dayOfWeek: 'date_part(\'isodow\', $t)', // 1 = monday to 7 = sunday; + dayOfMonth: 'date_part(\'day\', $t)', // 1 to 31 + dayOfYear: 'date_part(\'doy\', $t)', // 1 to 366 + hourOfDay: 'date_part(\'hour\', $t)', // 0 to 23 + monthOfYear: 'date_part(\'month\', $t)', // 1 to 12 + quarterOfYear: 'date_part(\'quarter\', $t)', // 1 to 4 + semesterOfYear: 'FLOOR((date_part(\'month\', $t)-1)/6.0) + 1', // 1 to 2 + trimesterOfYear: 'FLOOR((date_part(\'month\', $t)-1)/4.0) + 1', // 1 to 3 + weekOfYear: 'date_part(\'week\', $t)', // 1 to 53 + minuteOfHour: 'date_part(\'minute\', $t)' // 0 to 59 }; -function cyclicSqlExpr(params) { +function cyclicSqlExpr (params) { const column = timeExpression(params.time, params.timezone); return cyclicParts[params.units].replace(/\$t/g, column); } @@ -176,7 +176,7 @@ function cyclicSqlExpr(params) { const ACCEPTED_PARAMETERS = ['time', 'units', 'timezone', 'count', 'starting', 'format']; const REQUIRED_PARAMETERS = ['time', 'units']; -function validateParameters(params, checker) { +function validateParameters (params, checker) { const errors = []; const presentParams = Object.keys(params); const invalidParams = presentParams.filter(param => !ACCEPTED_PARAMETERS.includes(param)); @@ -187,19 +187,19 @@ function validateParameters(params, checker) { if (missingParams.length) { errors.push(`Missing parameters: ${missingParams.join(', ')}`); } - const params_errors = checker(params); - errors.push(...params_errors.errors); + const paramsErrors = checker(params); + errors.push(...paramsErrors.errors); if (errors.length) { - throw new Error(`Invalid time dimension:\n${errors.join("\n")}`); + throw new Error(`Invalid time dimension:\n${errors.join('\n')}`); } - return params_errors.params; + return paramsErrors.params; } const VALID_CYCLIC_UNITS = Object.keys(cyclicParts); const VALID_SERIAL_UNITS = Object.keys(serialParts); const VALID_ISO_UNITS = Object.keys(isoParts); -function cyclicCheckParams(params) { +function cyclicCheckParams (params) { const errors = []; if (!VALID_CYCLIC_UNITS.includes(params.units)) { errors.push(`Invalid units "${params.units}"`); @@ -210,7 +210,7 @@ function cyclicCheckParams(params) { return { errors: errors, params: params }; } -function serialCheckParams(params) { +function serialCheckParams (params) { const errors = []; if (!VALID_SERIAL_UNITS.includes(params.units)) { errors.push(`Invalid grouping units "${params.units}"`); @@ -218,7 +218,7 @@ function serialCheckParams(params) { return { errors: errors, params: Object.assign({}, params, { starting: epochWithDefaults(params.starting) }) }; } -function isoCheckParams(params) { +function isoCheckParams (params) { const errors = []; if (!VALID_ISO_UNITS.includes(params.units)) { errors.push(`Invalid units "${params.units}"`); @@ -244,11 +244,11 @@ const CLASSIFIERS = { } }; -function isCyclic(units) { +function isCyclic (units) { return VALID_CYCLIC_UNITS.includes(units); } -function classifierFor(params) { +function classifierFor (params) { let classifier = 'serial'; if (params.units && isCyclic(params.units)) { classifier = 'cyclic'; @@ -258,7 +258,7 @@ function classifierFor(params) { return CLASSIFIERS[classifier]; } -function classificationSql(params) { +function classificationSql (params) { const classifier = classifierFor(params); params = validateParameters(params, classifier.checkParams); return { sql: classifier.sqlExpr(params), effectiveParams: params }; diff --git a/lib/models/cdb-request.js b/lib/models/cdb-request.js index 54593c17..d449db12 100644 --- a/lib/models/cdb-request.js +++ b/lib/models/cdb-request.js @@ -1,6 +1,6 @@ 'use strict'; -function CdbRequest() { +function CdbRequest () { this.RE_USER_FROM_HOST = new RegExp(global.environment.user_from_host || '^([^\\.]+)\\.' // would extract "strk" from "strk.cartodb.com" ); @@ -8,18 +8,17 @@ function CdbRequest() { module.exports = CdbRequest; - -CdbRequest.prototype.userByReq = function(req) { +CdbRequest.prototype.userByReq = function (req) { var host = req.headers.host || ''; if (req.params.user) { return req.params.user; } var mat = host.match(this.RE_USER_FROM_HOST); - if ( ! mat ) { + if (!mat) { global.logger.error("Pattern '%s' does not match hostname '%s'", this.RE_USER_FROM_HOST, host); return; } - if ( mat.length !== 2 ) { + if (mat.length !== 2) { global.logger.error("Pattern '%s' gave unexpected matches against '%s': %s", this.RE_USER_FROM_HOST, host, mat); return; } diff --git a/lib/models/dataview/aggregation.js b/lib/models/dataview/aggregation.js index 4efbbba2..757d617f 100644 --- a/lib/models/dataview/aggregation.js +++ b/lib/models/dataview/aggregation.js @@ -12,9 +12,9 @@ const filteredQueryTpl = ctx => ` AND ${ctx.aggregationColumn} != '-infinity'::float AND - ${ctx.aggregationColumn} != 'NaN'::float` : - '' - } + ${ctx.aggregationColumn} != 'NaN'::float` + : '' +} `; const summaryQueryTpl = ctx => ` @@ -30,9 +30,9 @@ const summaryQueryTpl = ctx => ` ELSE 0 END ) AS infinities_count, - sum(CASE WHEN ${ctx.aggregationColumn} = 'NaN'::float THEN 1 ELSE 0 END) AS nans_count` : - '' - } + sum(CASE WHEN ${ctx.aggregationColumn} = 'NaN'::float THEN 1 ELSE 0 END) AS nans_count` + : '' +} FROM (${ctx.query}) _cdb_aggregation_nulls ) `; @@ -44,7 +44,7 @@ const rankedCategoriesQueryTpl = ctx => ` ${ctx.aggregationFn} AS value, row_number() OVER (ORDER BY ${ctx.aggregationFn} desc) as rank FROM (${filteredQueryTpl(ctx)}) filtered_source - WHERE ${ctx.aggregation === "count" ? `${ctx.column}` : `${ctx.aggregationColumn}`} IS NOT NULL + WHERE ${ctx.aggregation === 'count' ? `${ctx.column}` : `${ctx.aggregationColumn}`} IS NOT NULL GROUP BY ${ctx.column} ORDER BY 2 DESC ) @@ -70,7 +70,7 @@ const categoriesSummaryCountQueryTpl = ctx => ` ) `; -const specialNumericValuesColumns = () => `, nans_count, infinities_count`; +const specialNumericValuesColumns = () => ', nans_count, infinities_count'; const rankedAggregationQueryTpl = ctx => ` SELECT @@ -82,7 +82,7 @@ const rankedAggregationQueryTpl = ctx => ` max_val, count, categories_count - ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' } + ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : ''} FROM categories, summary, categories_summary_min_max, categories_summary_count WHERE rank < ${ctx.limit} UNION ALL @@ -95,7 +95,7 @@ const rankedAggregationQueryTpl = ctx => ` max_val, count, categories_count - ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' } + ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : ''} FROM categories, summary, categories_summary_min_max, categories_summary_count WHERE rank >= ${ctx.limit} GROUP BY @@ -104,7 +104,7 @@ const rankedAggregationQueryTpl = ctx => ` max_val, count, categories_count - ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' } + ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : ''} `; const aggregationQueryTpl = ctx => ` @@ -117,7 +117,7 @@ const aggregationQueryTpl = ctx => ` max_val, count, categories_count - ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' } + ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : ''} FROM (${ctx.query}) _cdb_aggregation_all, summary, categories_summary_min_max, categories_summary_count GROUP BY ${ctx.column}, @@ -126,7 +126,7 @@ const aggregationQueryTpl = ctx => ` max_val, count, categories_count - ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' } + ${ctx.isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : ''} ORDER BY value DESC `; @@ -138,7 +138,7 @@ const aggregationDataviewQueryTpl = ctx => ` ${rankedCategoriesQueryTpl(ctx)}, ${categoriesSummaryMinMaxQueryTpl(ctx)}, ${categoriesSummaryCountQueryTpl(ctx)} - ${!!ctx.override.ownFilter ? `${aggregationQueryTpl(ctx)}` : `${rankedAggregationQueryTpl(ctx)}`} + ${ctx.override.ownFilter ? `${aggregationQueryTpl(ctx)}` : `${rankedAggregationQueryTpl(ctx)}`} `; const filterCategoriesQueryTpl = ctx => ` @@ -206,11 +206,11 @@ module.exports = class Aggregation extends BaseDataview { _checkOptions (options) { if (typeof options.column !== 'string') { - throw new Error(`Aggregation expects 'column' in dataview options`); + throw new Error('Aggregation expects \'column\' in dataview options'); } if (typeof options.aggregation !== 'string') { - throw new Error(`Aggregation expects 'aggregation' operation in dataview options`); + throw new Error('Aggregation expects \'aggregation\' operation in dataview options'); } if (!VALID_OPERATIONS[options.aggregation]) { @@ -218,7 +218,7 @@ module.exports = class Aggregation extends BaseDataview { } const requiredOptions = VALID_OPERATIONS[options.aggregation]; - const missingOptions = requiredOptions.filter(requiredOption => !options.hasOwnProperty(requiredOption)); + const missingOptions = requiredOptions.filter(requiredOption => !Object.prototype.hasOwnProperty.call(options, requiredOption)); if (missingOptions.length > 0) { throw new Error( @@ -244,9 +244,9 @@ module.exports = class Aggregation extends BaseDataview { return null; } - const limit = Number.isFinite(override.categories) && override.categories > 0 ? - override.categories : - CATEGORIES_LIMIT; + const limit = Number.isFinite(override.categories) && override.categories > 0 + ? override.categories + : CATEGORIES_LIMIT; const aggregationSql = aggregationDataviewQueryTpl({ override: override, @@ -280,7 +280,7 @@ module.exports = class Aggregation extends BaseDataview { min_val = 0, max_val = 0, categories_count = 0 - } = result.rows[0] || {}; + } = result.rows[0] || {}; return { aggregation: this.aggregation, @@ -303,9 +303,9 @@ module.exports = class Aggregation extends BaseDataview { search (psql, userQuery, callback) { const escapedUserQuery = psql.escapeLiteral(`%${userQuery}%`); - const value = this.aggregation !== 'count' && this.aggregationColumn ? - `${this.aggregation}(${this.aggregationColumn})` : - 'count(1)'; + const value = this.aggregation !== 'count' && this.aggregationColumn + ? `${this.aggregation}(${this.aggregationColumn})` + : 'count(1)'; // TODO unfiltered will be wrong as filters are already applied at this point const query = searchQueryTpl({ @@ -330,7 +330,7 @@ module.exports = class Aggregation extends BaseDataview { return callback(err, result); } - return callback(null, {type: this.getType(), categories: result.rows }); + return callback(null, { type: this.getType(), categories: result.rows }); }, true); // use read-only transaction } diff --git a/lib/models/dataview/base.js b/lib/models/dataview/base.js index 8525224f..0813e3b1 100644 --- a/lib/models/dataview/base.js +++ b/lib/models/dataview/base.js @@ -16,8 +16,8 @@ const columnTypeQueryTpl = ctx => `SELECT pg_typeof(${ctx.column})::oid FROM (${ function getPGTypeName (pgType) { return { - float: FLOAT_OIDS.hasOwnProperty(pgType), - date: DATE_OIDS.hasOwnProperty(pgType) + float: Object.prototype.hasOwnProperty.call(FLOAT_OIDS, pgType), + date: Object.prototype.hasOwnProperty.call(DATE_OIDS, pgType) }; } @@ -36,7 +36,7 @@ module.exports = class BaseDataview { result = this.format(result, override); result.type = this.getType(); - //Overviews logging + // Overviews logging const stats = {}; if (flags && flags.usesOverviews !== undefined) { diff --git a/lib/models/dataview/factory.js b/lib/models/dataview/factory.js index bd035270..6e1659b2 100644 --- a/lib/models/dataview/factory.js +++ b/lib/models/dataview/factory.js @@ -3,7 +3,7 @@ const dataviews = require('.'); module.exports = class DataviewFactory { - static get dataviews() { + static get dataviews () { return Object.keys(dataviews).reduce((allDataviews, dataviewClassName) => { allDataviews[dataviewClassName.toLowerCase()] = dataviews[dataviewClassName]; return allDataviews; diff --git a/lib/models/dataview/formula.js b/lib/models/dataview/formula.js index a0b3278a..cba18057 100644 --- a/lib/models/dataview/formula.js +++ b/lib/models/dataview/formula.js @@ -5,11 +5,11 @@ const debug = require('debug')('windshaft:dataview:formula'); const utils = require('../../utils/query-utils'); const formulaQueryTpl = ctx => -`SELECT + `SELECT ${ctx.operation}(${utils.handleFloatColumn(ctx)}) AS result, ${utils.countNULLs(ctx)} AS nulls_count - ${ctx.isFloatColumn ? `,${utils.countInfinites(ctx)} AS infinities_count,` : ``} - ${ctx.isFloatColumn ? `${utils.countNaNs(ctx)} AS nans_count` : ``} + ${ctx.isFloatColumn ? `,${utils.countInfinites(ctx)} AS infinities_count,` : ''} + ${ctx.isFloatColumn ? `${utils.countNaNs(ctx)} AS nans_count` : ''} FROM (${ctx.query}) __cdb_formula`; const VALID_OPERATIONS = { @@ -46,7 +46,7 @@ module.exports = class Formula extends BaseDataview { _checkOptions (options) { if (typeof options.operation !== 'string') { - throw new Error(`Formula expects 'operation' in dataview options`); + throw new Error('Formula expects \'operation\' in dataview options'); } if (!VALID_OPERATIONS[options.operation]) { @@ -54,11 +54,10 @@ module.exports = class Formula extends BaseDataview { } if (options.operation !== 'count' && typeof options.column !== 'string') { - throw new Error(`Formula expects 'column' in dataview options`); + throw new Error('Formula expects \'column\' in dataview options'); } } - sql (psql, override, callback) { if (!callback) { callback = override; @@ -92,16 +91,16 @@ module.exports = class Formula extends BaseDataview { const { result = 0, nulls_count = 0, - nans_count, - infinities_count + nans_count: nansCount, + infinities_count: infinitiesCount } = res.rows[0] || {}; return { operation: this.operation, result, nulls: nulls_count, - nans: nans_count, - infinities: infinities_count + nans: nansCount, + infinities: infinitiesCount }; } diff --git a/lib/models/dataview/histogram.js b/lib/models/dataview/histogram.js index bc51979e..55f64303 100644 --- a/lib/models/dataview/histogram.js +++ b/lib/models/dataview/histogram.js @@ -20,23 +20,23 @@ module.exports = class Histogram { let implementation = null; switch (this._getHistogramSubtype(override)) { - case DATE_HISTOGRAM: - debug('Delegating to DateHistogram with options: %j and overriding: %j', this.options, override); - implementation = new DateHistogram(this.query, this.options, this.queries); - break; - case NUMERIC_HISTOGRAM: - debug('Delegating to NumericHistogram with options: %j and overriding: %j', this.options, override); - implementation = new NumericHistogram(this.query, this.options, this.queries); - break; - default: - throw new Error('Unsupported Histogram type'); + case DATE_HISTOGRAM: + debug('Delegating to DateHistogram with options: %j and overriding: %j', this.options, override); + implementation = new DateHistogram(this.query, this.options, this.queries); + break; + case NUMERIC_HISTOGRAM: + debug('Delegating to NumericHistogram with options: %j and overriding: %j', this.options, override); + implementation = new NumericHistogram(this.query, this.options, this.queries); + break; + default: + throw new Error('Unsupported Histogram type'); } return implementation; } _getHistogramSubtype (override) { - if(this._isDateHistogram(override)) { + if (this._isDateHistogram(override)) { return DATE_HISTOGRAM; } @@ -44,7 +44,8 @@ module.exports = class Histogram { } _isDateHistogram (override = {}) { - return (this.options.hasOwnProperty('aggregation') || override.hasOwnProperty('aggregation')); + return (Object.prototype.hasOwnProperty.call(this.options, 'aggregation') || + Object.prototype.hasOwnProperty.call(override, 'aggregation')); } getResult (psql, override, callback) { diff --git a/lib/models/dataview/histograms/base-histogram.js b/lib/models/dataview/histograms/base-histogram.js index 29496632..d5d5280a 100644 --- a/lib/models/dataview/histograms/base-histogram.js +++ b/lib/models/dataview/histograms/base-histogram.js @@ -62,7 +62,7 @@ module.exports = class BaseHistogram extends BaseDataview { } _hasOverridenRange (override) { - return override && override.hasOwnProperty('start') && override.hasOwnProperty('end'); + return override && Object.prototype.hasOwnProperty.call(override, 'start') && Object.prototype.hasOwnProperty.call(override, 'end'); } _getBinStart (override = {}) { diff --git a/lib/models/dataview/histograms/date-histogram.js b/lib/models/dataview/histograms/date-histogram.js index 632c4438..61b6e974 100644 --- a/lib/models/dataview/histograms/date-histogram.js +++ b/lib/models/dataview/histograms/date-histogram.js @@ -4,7 +4,6 @@ const BaseHistogram = require('./base-histogram'); const debug = require('debug')('windshaft:dataview:date-histogram'); const utils = require('../../../utils/query-utils'); - /** * Gets the name of a timezone with the same offset as the required * using the pg_timezone_names table. We do this because it's simpler to pass @@ -32,18 +31,17 @@ WITH __wd_tz AS * the aggregation. Since the data stored is in epoch we need to adapt it to * our timezone so when calling date_trunc it falls into the correct bin */ -function dataBucketsQuery(ctx) { - var condition_str = ''; +function dataBucketsQuery (ctx) { + var conditionStr = ''; if (ctx.start !== 0) { - condition_str = `WHERE ${ctx.column} >= to_timestamp(${ctx.start})`; + conditionStr = `WHERE ${ctx.column} >= to_timestamp(${ctx.start})`; } if (ctx.end !== 0) { - if (condition_str === '') { - condition_str = `WHERE ${ctx.column} <= to_timestamp(${ctx.end})`; - } - else { - condition_str += ` and ${ctx.column} <= to_timestamp(${ctx.end})`; + if (conditionStr === '') { + conditionStr = `WHERE ${ctx.column} <= to_timestamp(${ctx.end})`; + } else { + conditionStr += ` and ${ctx.column} <= to_timestamp(${ctx.end})`; } } @@ -58,7 +56,7 @@ __wd_buckets AS ( ${ctx.query} ) __source, __wd_tz - ${condition_str} + ${conditionStr} GROUP BY 1, __wd_tz.name ),`; } @@ -68,23 +66,23 @@ __wd_buckets AS * start and end date. If not provided we use the min and max generated from * the dataBucketsQuery */ -function allBucketsArrayQuery(ctx) { - var extra_from = ``; - var series_start = ``; - var series_end = ``; +function allBucketsArrayQuery (ctx) { + var extraFrom = ''; + var seriesStart = ''; + var seriesEnd = ''; if (ctx.start === 0) { - extra_from = `, __wd_buckets GROUP BY __wd_tz.name`; - series_start = `min(__wd_buckets.timestamp)`; + extraFrom = ', __wd_buckets GROUP BY __wd_tz.name'; + seriesStart = 'min(__wd_buckets.timestamp)'; } else { - series_start = `date_trunc('${ctx.aggregation}', timezone(__wd_tz.name, to_timestamp(${ctx.start})))`; + seriesStart = `date_trunc('${ctx.aggregation}', timezone(__wd_tz.name, to_timestamp(${ctx.start})))`; } if (ctx.end === 0) { - extra_from = `, __wd_buckets GROUP BY __wd_tz.name`; - series_end = `max(__wd_buckets.timestamp)`; + extraFrom = ', __wd_buckets GROUP BY __wd_tz.name'; + seriesEnd = 'max(__wd_buckets.timestamp)'; } else { - series_end = `date_trunc('${ctx.aggregation}', timezone(__wd_tz.name, to_timestamp(${ctx.end})))`; + seriesEnd = `date_trunc('${ctx.aggregation}', timezone(__wd_tz.name, to_timestamp(${ctx.end})))`; } return ` @@ -93,10 +91,10 @@ __wd_all_buckets AS SELECT ARRAY( SELECT generate_series( - ${series_start}, - ${series_end}, + ${seriesStart}, + ${seriesEnd}, interval '${ctx.interval}') as bin_start - FROM __wd_tz${extra_from} + FROM __wd_tz${extraFrom} ) as bins )`; } @@ -148,18 +146,18 @@ const dateIntervalQueryTpl = ctx => ` const MAX_INTERVAL_VALUE = 100; const DATE_AGGREGATIONS = { - 'auto': true, - 'second' : true, - 'minute': true, - 'hour': true, - 'day': true, - 'week': true, - 'month': true, - 'quarter': true, - 'year': true, - 'decade' : true, - 'century' : true, - 'millennium' : true + auto: true, + second: true, + minute: true, + hour: true, + day: true, + week: true, + month: true, + quarter: true, + year: true, + decade: true, + century: true, + millennium: true }; /** @@ -219,8 +217,8 @@ ORDER BY bin ASC; return null; } - var interval = this._getAggregation(override) === 'quarter' ? - '3 months' : '1 ' + this._getAggregation(override); + var interval = this._getAggregation(override) === 'quarter' + ? '3 months' : '1 ' + this._getAggregation(override); const histogramSql = this._buildQueryTpl({ override: override, @@ -239,7 +237,7 @@ ORDER BY bin ASC; } _isValidAggregation (override) { - return DATE_AGGREGATIONS.hasOwnProperty(this._getAggregation(override)); + return Object.prototype.hasOwnProperty.call(DATE_AGGREGATIONS, this._getAggregation(override)); } _getAutomaticAggregation (psql, callback) { @@ -294,7 +292,7 @@ ORDER BY bin ASC; } _getBuckets (result) { - result.rows.forEach(function(row) { + result.rows.forEach(function (row) { row.min = row.max = row.avg = row.timestamp; }); diff --git a/lib/models/dataview/histograms/numeric-histogram.js b/lib/models/dataview/histograms/numeric-histogram.js index 492316ba..6f17b59b 100644 --- a/lib/models/dataview/histograms/numeric-histogram.js +++ b/lib/models/dataview/histograms/numeric-histogram.js @@ -26,7 +26,7 @@ const irqQueryTpl = ctx => ` max(${ctx.column}) AS __cdb_max_val, min(${ctx.column}) AS __cdb_min_val, count(1) AS __cdb_total_rows, - ${ctx.irq ? ctx.irq : `0`} AS __cdb_iqr + ${ctx.irq ? ctx.irq : '0'} AS __cdb_iqr FROM ( SELECT * @@ -51,10 +51,6 @@ Numeric histogram: } */ module.exports = class NumericHistogram extends BaseHistogram { - constructor (query, options, queries) { - super(query, options, queries); - } - _buildQuery (psql, override, callback) { const histogramSql = this._buildQueryTpl({ column: this._columnType === 'date' ? utils.columnCastTpl({ column: this.column }) : this.column, @@ -72,8 +68,7 @@ module.exports = class NumericHistogram extends BaseHistogram { return callback(null, histogramSql); } - -/** + /** * ctx: Object with the following values * ctx.column -- Column for the histogram * ctx.isFloatColumn - Whether the column is float or not @@ -85,35 +80,35 @@ module.exports = class NumericHistogram extends BaseHistogram { * ctx.maxBins - If !full max bins to calculate [Optional] */ _buildQueryTpl (ctx) { - var extra_tables = ``; - var extra_queries = ``; - var extra_groupby = ``; - var extra_filter = ``; + var extraTables = ''; + var extraQueries = ''; + var extraGroupBy = ''; + var extraFilter = ''; if (ctx.start < ctx.end) { - extra_filter = ` + extraFilter = ` WHERE __ctx_query.${ctx.column} >= ${ctx.start} AND __ctx_query.${ctx.column} <= ${ctx.end} `; } else { - ctx.end = `__cdb_basics.__cdb_max_val`; - ctx.start = `__cdb_basics.__cdb_min_val`; - extra_groupby = `, __cdb_basics.__cdb_max_val, __cdb_basics.__cdb_min_val`; - extra_tables = `, __cdb_basics`; - extra_queries = `WITH ${irqQueryTpl(ctx)}`; + ctx.end = '__cdb_basics.__cdb_max_val'; + ctx.start = '__cdb_basics.__cdb_min_val'; + extraGroupBy = ', __cdb_basics.__cdb_max_val, __cdb_basics.__cdb_min_val'; + extraTables = ', __cdb_basics'; + extraQueries = `WITH ${irqQueryTpl(ctx)}`; } if (ctx.bins <= 0) { - ctx.bins = `__cdb_basics.__cdb_bins_number`; + ctx.bins = '__cdb_basics.__cdb_bins_number'; ctx.irq = `percentile_disc(0.75) within group (order by ${ctx.column}) - percentile_disc(0.25) within group (order by ${ctx.column})`; - extra_groupby += `, __cdb_basics.__cdb_bins_number`; - extra_tables = `, __cdb_basics`; - extra_queries = `WITH ${irqQueryTpl(ctx)}`; + extraGroupBy += ', __cdb_basics.__cdb_bins_number'; + extraTables = ', __cdb_basics'; + extraQueries = `WITH ${irqQueryTpl(ctx)}`; } return ` -${extra_queries} +${extraQueries} SELECT (${ctx.end} - ${ctx.start}) / ${ctx.bins}::float AS bin_width, ${ctx.bins} as bins_number, @@ -132,44 +127,44 @@ SELECT END AS bin FROM ( - SELECT * FROM (${ctx.query}) __ctx_query${extra_tables} ${extra_filter} -) __cdb_filtered_source_query${extra_tables} -GROUP BY 10${extra_groupby} + SELECT * FROM (${ctx.query}) __ctx_query${extraTables} ${extraFilter} +) __cdb_filtered_source_query${extraTables} +GROUP BY 10${extraGroupBy} ORDER BY 10;`; } _hasOverridenBins (override) { - return override && override.hasOwnProperty('bins'); + return override && Object.prototype.hasOwnProperty.call(override, 'bins'); } _getSummary (result, override) { const firstRow = result.rows[0] || {}; - var total_nulls = 0; - var total_infinities = 0; - var total_nans = 0; - var total_avg = 0; - var total_count = 0; + var totalNulls = 0; + var totalInfinities = 0; + var totalNans = 0; + var totalAvg = 0; + var totalCount = 0; - result.rows.forEach(function(row) { - total_nulls += row.nulls_count; - total_infinities += row.infinities_count; - total_nans += row.nans_count; - total_avg += row.avg * row.freq; - total_count += row.freq; + result.rows.forEach(function (row) { + totalNulls += row.nulls_count; + totalInfinities += row.infinities_count; + totalNans += row.nans_count; + totalAvg += row.avg * row.freq; + totalCount += row.freq; }); - if (total_count !== 0) { - total_avg /= total_count; + if (totalCount !== 0) { + totalAvg /= totalCount; } return { bin_width: firstRow.bin_width, bins_count: firstRow.bins_number, bins_start: this._populateBinStart(firstRow, override), - nulls: total_nulls, - infinities: total_infinities, - nans: total_nans, - avg: total_avg + nulls: totalNulls, + infinities: totalInfinities, + nans: totalNans, + avg: totalAvg }; } @@ -180,7 +175,7 @@ ORDER BY 10;`; _populateBinStart (firstRow, override = {}) { let binStart; - if (override.hasOwnProperty('start')) { + if (Object.prototype.hasOwnProperty.call(override, 'start')) { binStart = this._getBinStart(override); } else { binStart = firstRow.min; @@ -188,5 +183,4 @@ ORDER BY 10;`; return binStart; } - }; diff --git a/lib/models/dataview/overviews/aggregation.js b/lib/models/dataview/overviews/aggregation.js index bc0b9116..da988731 100644 --- a/lib/models/dataview/overviews/aggregation.js +++ b/lib/models/dataview/overviews/aggregation.js @@ -91,7 +91,7 @@ var aggregationQueryTpl = dot.template([ var CATEGORIES_LIMIT = 6; - function Aggregation(query, options, queryRewriter, queryRewriteData, params, queries) { +function Aggregation (query, options, queryRewriter, queryRewriteData, params, queries) { BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params, queries); this._checkOptions(options); @@ -109,7 +109,7 @@ Aggregation.prototype.constructor = Aggregation; module.exports = Aggregation; -Aggregation.prototype.sql = function(psql, override, callback) { +Aggregation.prototype.sql = function (psql, override, callback) { var self = this; if (!callback) { @@ -132,9 +132,9 @@ Aggregation.prototype.sql = function(psql, override, callback) { } var aggregationSql; - if (!!override.ownFilter) { + if (override.ownFilter) { aggregationSql = [ - "WITH", + 'WITH', [ filteredQueryTpl({ _isFloatColumn: this._isFloatColumn, @@ -173,7 +173,7 @@ Aggregation.prototype.sql = function(psql, override, callback) { ].join('\n'); } else { aggregationSql = [ - "WITH", + 'WITH', [ filteredQueryTpl({ _isFloatColumn: this._isFloatColumn, @@ -218,7 +218,7 @@ Aggregation.prototype.sql = function(psql, override, callback) { var aggregationFnQueryTpl = { count: dot.template('sum(_feature_count)'), - sum: dot.template('sum({{=it._aggregationColumn}}*_feature_count)') + sum: dot.template('sum({{=it._aggregationColumn}}*_feature_count)') }; const VALID_OPERATIONS = { @@ -232,7 +232,7 @@ Aggregation.prototype._checkOptions = function (options) { } const requiredOptions = VALID_OPERATIONS[options.aggregation]; - const missingOptions = requiredOptions.filter(requiredOption => !options.hasOwnProperty(requiredOption)); + const missingOptions = requiredOptions.filter(requiredOption => !Object.prototype.hasOwnProperty.call(options, requiredOption)); if (missingOptions.length > 0) { throw new Error( @@ -241,7 +241,7 @@ Aggregation.prototype._checkOptions = function (options) { } }; -Aggregation.prototype.getAggregationSql = function() { +Aggregation.prototype.getAggregationSql = function () { return aggregationFnQueryTpl[this.aggregation]({ _aggregationFn: this.aggregation, _aggregationColumn: this.aggregationColumn || 1 diff --git a/lib/models/dataview/overviews/base.js b/lib/models/dataview/overviews/base.js index 9b1c7c58..f1bf03f6 100644 --- a/lib/models/dataview/overviews/base.js +++ b/lib/models/dataview/overviews/base.js @@ -3,15 +3,15 @@ var _ = require('underscore'); var BaseDataview = require('../base'); -function BaseOverviewsDataview(query, queryOptions, BaseDataview, queryRewriter, queryRewriteData, options, queries) { - this.BaseDataview = BaseDataview; - this.query = query; - this.queryOptions = queryOptions; - this.queryRewriter = queryRewriter; - this.queryRewriteData = queryRewriteData; - this.options = options; - this.queries = queries; - this.baseDataview = new this.BaseDataview(this.query, this.queryOptions, this.queries); +function BaseOverviewsDataview (query, queryOptions, BaseDataview, queryRewriter, queryRewriteData, options, queries) { + this.BaseDataview = BaseDataview; + this.query = query; + this.queryOptions = queryOptions; + this.queryRewriter = queryRewriter; + this.queryRewriteData = queryRewriteData; + this.options = options; + this.queries = queries; + this.baseDataview = new this.BaseDataview(this.query, this.queryOptions, this.queries); } module.exports = BaseOverviewsDataview; @@ -32,36 +32,36 @@ var SETTINGS = { // Compute zoom level so that the the resolution grid size of the // selected overview is smaller (zoomLevelFactor times smaller at least) // than the bounding box size. -BaseOverviewsDataview.prototype.zoomLevelForBbox = function(bbox) { +BaseOverviewsDataview.prototype.zoomLevelForBbox = function (bbox) { var pxPerTile = 256.0; var earthWidth = 360.0; // TODO: now we assume overviews are computed for 1-pixel tolerance; // should use extended overviews metadata to compute this properly. - if ( bbox ) { - var bboxValues = _.map(bbox.split(','), function(v) { return +v; }); - var w = Math.abs(bboxValues[2]-bboxValues[0]); - var h = Math.abs(bboxValues[3]-bboxValues[1]); - var maxDim = Math.min(w, h); + if (bbox) { + var bboxValues = _.map(bbox.split(','), function (v) { return +v; }); + var w = Math.abs(bboxValues[2] - bboxValues[0]); + var h = Math.abs(bboxValues[3] - bboxValues[1]); + var maxDim = Math.min(w, h); - // Find minimum suitable z - // note that the QueryRewirter will use the minimum level overview - // of level >= z if it exists, and otherwise the base table - var z = Math.ceil(-Math.log(maxDim*pxPerTile/earthWidth/SETTINGS.zoomLevelFactor)/Math.log(2.0)); - return Math.max(z, 0); + // Find minimum suitable z + // note that the QueryRewirter will use the minimum level overview + // of level >= z if it exists, and otherwise the base table + var z = Math.ceil(-Math.log(maxDim * pxPerTile / earthWidth / SETTINGS.zoomLevelFactor) / Math.log(2.0)); + return Math.max(z, 0); } return 0; }; -BaseOverviewsDataview.prototype.rewrittenQuery = function(query) { - var zoom_level = this.zoomLevelForBbox(this.options.bbox); - return this.queryRewriter.query(query, this.queryRewriteData, { zoom_level: zoom_level }); +BaseOverviewsDataview.prototype.rewrittenQuery = function (query) { + var zoomLevel = this.zoomLevelForBbox(this.options.bbox); + return this.queryRewriter.query(query, this.queryRewriteData, { zoom_level: zoomLevel }); }; // Default behaviour -BaseOverviewsDataview.prototype.defaultSql = function(psql, override, callback) { +BaseOverviewsDataview.prototype.defaultSql = function (psql, override, callback) { var query = this.query; var dataview = this.baseDataview; - if ( SETTINGS.defaultOverviews ) { + if (SETTINGS.defaultOverviews) { query = this.rewrittenQuery(query); dataview = new this.BaseDataview(query, this.queryOptions); } @@ -70,22 +70,22 @@ BaseOverviewsDataview.prototype.defaultSql = function(psql, override, callback) // default implementation that can be override in derived classes: -BaseOverviewsDataview.prototype.sql = function(psql, override, callback) { +BaseOverviewsDataview.prototype.sql = function (psql, override, callback) { return this.defaultSql(psql, override, callback); }; -BaseOverviewsDataview.prototype.search = function(psql, userQuery, callback) { +BaseOverviewsDataview.prototype.search = function (psql, userQuery, callback) { return this.baseDataview.search(psql, userQuery, callback); }; -BaseOverviewsDataview.prototype.format = function(result) { +BaseOverviewsDataview.prototype.format = function (result) { return this.baseDataview.format(result); }; -BaseOverviewsDataview.prototype.getType = function() { +BaseOverviewsDataview.prototype.getType = function () { return this.baseDataview.getType(); }; -BaseOverviewsDataview.prototype.toString = function() { +BaseOverviewsDataview.prototype.toString = function () { return this.baseDataview.toString(); }; diff --git a/lib/models/dataview/overviews/factory.js b/lib/models/dataview/overviews/factory.js index c67aea8e..9b9f16e4 100644 --- a/lib/models/dataview/overviews/factory.js +++ b/lib/models/dataview/overviews/factory.js @@ -3,16 +3,16 @@ var parentFactory = require('../factory'); var dataviews = require('.'); -function OverviewsDataviewFactory(queryRewriter, queryRewriteData, options) { +function OverviewsDataviewFactory (queryRewriter, queryRewriteData, options) { this.queryRewriter = queryRewriter; this.queryRewriteData = queryRewriteData; this.options = options; } -OverviewsDataviewFactory.prototype.getDataview = function(query, dataviewDefinition) { +OverviewsDataviewFactory.prototype.getDataview = function (query, dataviewDefinition) { var type = dataviewDefinition.type; var dataviews = OverviewsDataviewMetaFactory.dataviews; - if ( !this.queryRewriter || !this.queryRewriteData || !dataviews[type] ) { + if (!this.queryRewriter || !this.queryRewriteData || !dataviews[type]) { return parentFactory.getDataview(query, dataviewDefinition); } return new dataviews[type]( @@ -22,14 +22,14 @@ OverviewsDataviewFactory.prototype.getDataview = function(query, dataviewDefinit }; var OverviewsDataviewMetaFactory = { - dataviews: Object.keys(dataviews).reduce(function(allDataviews, dataviewClassName) { + dataviews: Object.keys(dataviews).reduce(function (allDataviews, dataviewClassName) { allDataviews[dataviewClassName.toLowerCase()] = dataviews[dataviewClassName]; return allDataviews; }, {}), - getFactory: function(queryRewriter, queryRewriteData, options) { + getFactory: function (queryRewriter, queryRewriteData, options) { return new OverviewsDataviewFactory(queryRewriter, queryRewriteData, options); - }, + } }; module.exports = OverviewsDataviewMetaFactory; diff --git a/lib/models/dataview/overviews/formula.js b/lib/models/dataview/overviews/formula.js index 73aa2f57..35d52008 100644 --- a/lib/models/dataview/overviews/formula.js +++ b/lib/models/dataview/overviews/formula.js @@ -14,28 +14,28 @@ const VALID_OPERATIONS = { avg: true }; -/** Formulae to calculate the end result using _feature_count from the overview table*/ -function dataviewResult(ctx) { +/** Formulae to calculate the end result using _feature_count from the overview table */ +function dataviewResult (ctx) { switch (ctx.operation) { - case 'count': - return `sum(_feature_count)`; - case 'sum': - return `sum(${utils.handleFloatColumn(ctx)}*_feature_count)`; - case 'avg': - return `sum(${utils.handleFloatColumn(ctx)}*_feature_count)/sum(_feature_count) `; + case 'count': + return 'sum(_feature_count)'; + case 'sum': + return `sum(${utils.handleFloatColumn(ctx)}*_feature_count)`; + case 'avg': + return `sum(${utils.handleFloatColumn(ctx)}*_feature_count)/sum(_feature_count) `; } return `${ctx.operation}(${utils.handleFloatColumn(ctx)})`; } const formulaQueryTpl = ctx => -`SELECT + `SELECT ${dataviewResult(ctx)} AS result, ${utils.countNULLs(ctx)} AS nulls_count - ${ctx.isFloatColumn ? `,${utils.countInfinites(ctx)} AS infinities_count,` : ``} - ${ctx.isFloatColumn ? `${utils.countNaNs(ctx)} AS nans_count` : ``} + ${ctx.isFloatColumn ? `,${utils.countInfinites(ctx)} AS infinities_count,` : ''} + ${ctx.isFloatColumn ? `${utils.countNaNs(ctx)} AS nans_count` : ''} FROM (${ctx.query}) __cdb_formula`; -function Formula(query, options, queryRewriter, queryRewriteData, params, queries) { +function Formula (query, options, queryRewriter, queryRewriteData, params, queries) { BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params, queries); this.column = options.column || '1'; this.operation = options.operation; diff --git a/lib/models/dataview/overviews/histogram.js b/lib/models/dataview/overviews/histogram.js index 91c2818c..4df5bd01 100644 --- a/lib/models/dataview/overviews/histogram.js +++ b/lib/models/dataview/overviews/histogram.js @@ -133,7 +133,7 @@ var histogramQueryTpl = dot.template([ 'ORDER BY bin' ].join('\n')); -function Histogram(query, options, queryRewriter, queryRewriteData, params, queries) { +function Histogram (query, options, queryRewriter, queryRewriteData, params, queries) { BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params, queries); this.query = query; @@ -149,7 +149,7 @@ Histogram.prototype.constructor = Histogram; module.exports = Histogram; -Histogram.prototype.sql = function(psql, override, callback) { +Histogram.prototype.sql = function (psql, override, callback) { var self = this; if (!callback) { @@ -157,7 +157,6 @@ Histogram.prototype.sql = function(psql, override, callback) { override = {}; } - if (this._columnType === null) { this.getColumnType(psql, this.column, this.queries.no_filters, function (err, type) { // assume numeric, will fail later @@ -259,7 +258,7 @@ Histogram.prototype._buildQuery = function (override) { } var histogramSql = [ - "WITH", + 'WITH', cteSql.join(',\n'), histogramQueryTpl({ _isFloatColumn: this._columnType === 'float', diff --git a/lib/models/dataview/overviews/index.js b/lib/models/dataview/overviews/index.js index 8b5cf9f7..0fc107d3 100644 --- a/lib/models/dataview/overviews/index.js +++ b/lib/models/dataview/overviews/index.js @@ -1,7 +1,7 @@ 'use strict'; module.exports = { - Aggregation: require('./aggregation'), - Formula: require('./formula'), - Histogram: require('./histogram') + Aggregation: require('./aggregation'), + Formula: require('./formula'), + Histogram: require('./histogram') }; diff --git a/lib/models/filter/analysis.js b/lib/models/filter/analysis.js index 1da580c6..ad931c50 100644 --- a/lib/models/filter/analysis.js +++ b/lib/models/filter/analysis.js @@ -5,33 +5,33 @@ var filters = { range: require('./analysis/range') }; -function createFilter(filterDefinition) { +function createFilter (filterDefinition) { var filterType = filterDefinition.type.toLowerCase(); - if (!filters.hasOwnProperty(filterType)) { + if (!Object.prototype.hasOwnProperty.call(filters, filterType)) { throw new Error('Unknown filter type: ' + filterType); } return new filters[filterType](filterDefinition.column, filterDefinition.params); } -function AnalysisFilters(filters) { +function AnalysisFilters (filters) { this.filters = filters; } -AnalysisFilters.prototype.sql = function(rawSql) { - var filters = this.filters || {}; - var applyFilters = {}; +AnalysisFilters.prototype.sql = function (rawSql) { + var filters = this.filters || {}; + var applyFilters = {}; - return Object.keys(filters) - .filter(function(filterName) { - return applyFilters.hasOwnProperty(filterName) ? applyFilters[filterName] : true; - }) - .map(function(filterName) { - var filterDefinition = filters[filterName]; - return createFilter(filterDefinition); - }) - .reduce(function(sql, filter) { - return filter.sql(sql); - }, rawSql); + return Object.keys(filters) + .filter(function (filterName) { + return Object.prototype.hasOwnProperty.call(applyFilters, filterName) ? applyFilters[filterName] : true; + }) + .map(function (filterName) { + var filterDefinition = filters[filterName]; + return createFilter(filterDefinition); + }) + .reduce(function (sql, filter) { + return filter.sql(sql); + }, rawSql); }; module.exports = AnalysisFilters; diff --git a/lib/models/filter/analysis/category.js b/lib/models/filter/analysis/category.js index 0b91655c..de46bff6 100644 --- a/lib/models/filter/analysis/category.js +++ b/lib/models/filter/analysis/category.js @@ -9,11 +9,11 @@ var filterQueryTpl = dot.template([ 'FROM ({{=it._sql}}) _analysis_category_filter', 'WHERE {{=it._filters}}' ].join('\n')); -var escapeStringTpl = dot.template('$escape_{{=it._i}}${{=it._value}}$escape_{{=it._i}}$'); +var escapeStringTpl = dot.template('$escape_{{=it._i}}${{=it._value}}$escape_{{=it._i}}$'); // eslint-disable-line no-template-curly-in-string var inConditionTpl = dot.template('{{=it._column}} IN ({{=it._values}})'); var notInConditionTpl = dot.template('{{=it._column}} NOT IN ({{=it._values}})'); -function Category(column, filterParams) { +function Category (column, filterParams) { this.column = column; if (!Array.isArray(filterParams.accept) && !Array.isArray(filterParams.reject)) { @@ -38,15 +38,15 @@ module.exports = Category; - accept: [] => reject all - reject: [] => accept all */ -Category.prototype.sql = function(rawSql) { +Category.prototype.sql = function (rawSql) { var valueFilters = []; if (Array.isArray(this.accept)) { if (this.accept.length > 0) { valueFilters.push(inConditionTpl({ _column: this.column, - _values: this.accept.map(function(value, i) { - return Number.isFinite(value) ? value : escapeStringTpl({_i: i, _value: value}); + _values: this.accept.map(function (value, i) { + return Number.isFinite(value) ? value : escapeStringTpl({ _i: i, _value: value }); }).join(',') })); } else { @@ -59,7 +59,7 @@ Category.prototype.sql = function(rawSql) { valueFilters.push(notInConditionTpl({ _column: this.column, _values: this.reject.map(function (value, i) { - return Number.isFinite(value) ? value : escapeStringTpl({_i: i, _value: value}); + return Number.isFinite(value) ? value : escapeStringTpl({ _i: i, _value: value }); }).join(',') })); } else { diff --git a/lib/models/filter/analysis/range.js b/lib/models/filter/analysis/range.js index 4a1ccfa7..71f76aea 100644 --- a/lib/models/filter/analysis/range.js +++ b/lib/models/filter/analysis/range.js @@ -8,7 +8,7 @@ var minFilterTpl = dot.template('{{=it._column}} >= {{=it._min}}'); var maxFilterTpl = dot.template('{{=it._column}} <= {{=it._max}}'); var filterQueryTpl = dot.template('SELECT * FROM ({{=it._sql}}) _analysis_range_filter WHERE {{=it._filter}}'); -function Range(column, filterParams) { +function Range (column, filterParams) { this.column = column; if (!Number.isFinite(filterParams.min) && !Number.isFinite(filterParams.max)) { @@ -22,7 +22,7 @@ function Range(column, filterParams) { module.exports = Range; -Range.prototype.sql = function(rawSql) { +Range.prototype.sql = function (rawSql) { var minMaxFilter; if (Number.isFinite(this.min) && Number.isFinite(this.max)) { minMaxFilter = betweenFilterTpl({ diff --git a/lib/models/filter/bbox.js b/lib/models/filter/bbox.js index 1766ba8c..67ea8c9d 100644 --- a/lib/models/filter/bbox.js +++ b/lib/models/filter/bbox.js @@ -33,14 +33,14 @@ var LONGITUDE_RANGE = LONGITUDE_UPPER_BOUND - LONGITUDE_LOWER_BOUND; “bbox”: "west,south,east,north" } */ -function BBox(filterDefinition, filterParams) { +function BBox (filterDefinition, filterParams) { var bbox = filterParams.bbox; if (!bbox) { throw new Error('BBox filter expects to have a bbox param'); } - var bboxElements = bbox.split(',').map(function(e) { return +e; }); + var bboxElements = bbox.split(',').map(function (e) { return +e; }); validateBboxElements(bboxElements); @@ -59,7 +59,7 @@ function BBox(filterDefinition, filterParams) { this.bboxes = getBoundingBoxes(west, south, east, north); } -function getBoundingBoxes(west, south, east, north) { +function getBoundingBoxes (west, south, east, north) { var bboxes = []; if (east - west >= 360) { @@ -75,10 +75,10 @@ function getBoundingBoxes(west, south, east, north) { return bboxes; } -function validateBboxElements(bboxElements) { +function validateBboxElements (bboxElements) { var isNumericBbox = bboxElements - .map(function(n) { return Number.isFinite(n); }) - .reduce(function(allFinite, isFinite) { + .map(function (n) { return Number.isFinite(n); }) + .reduce(function (allFinite, isFinite) { if (!allFinite) { return false; } @@ -90,7 +90,7 @@ function validateBboxElements(bboxElements) { } } -function adjustLongitudeRange(we) { +function adjustLongitudeRange (we) { var west = we[0]; west -= LONGITUDE_LOWER_BOUND; west = west - (LONGITUDE_RANGE * Math.floor(west / LONGITUDE_RANGE)) + LONGITUDE_LOWER_BOUND; @@ -106,11 +106,10 @@ module.exports.adjustLongitudeRange = adjustLongitudeRange; module.exports.LATITUDE_MAX_VALUE = LATITUDE_MAX_VALUE; module.exports.LONGITUDE_MAX_VALUE = LONGITUDE_UPPER_BOUND; - -BBox.prototype.sql = function(rawSql) { +BBox.prototype.sql = function (rawSql) { var bboxSql = filterQueryTpl({ _sql: rawSql, - _filters: this.bboxes.map(function(bbox) { + _filters: this.bboxes.map(function (bbox) { return bboxFilterTpl({ _column: this.column, _bbox: bbox.join(','), diff --git a/lib/models/layergroup-token.js b/lib/models/layergroup-token.js index 8c51bed5..1e4a6951 100644 --- a/lib/models/layergroup-token.js +++ b/lib/models/layergroup-token.js @@ -3,7 +3,7 @@ /** * @param {String} token might match the following pattern: {user}@{tpl_id}@{token}:{cache_buster} */ -function parse(token) { +function parse (token) { var signer, cacheBuster; var tokenSplit = token.split(':'); @@ -14,10 +14,10 @@ function parse(token) { } tokenSplit = token.split('@'); - if ( tokenSplit.length > 1 ) { + if (tokenSplit.length > 1) { signer = tokenSplit.shift(); - if ( tokenSplit.length > 1 ) { - /*var template_hash = */tokenSplit.shift(); // unused + if (tokenSplit.length > 1) { + /* var template_hash = */tokenSplit.shift(); // unused } token = tokenSplit.shift(); } diff --git a/lib/models/mapconfig/adapter/aggregation-mapconfig-adapter.js b/lib/models/mapconfig/adapter/aggregation-mapconfig-adapter.js index ceb3e031..4df87821 100644 --- a/lib/models/mapconfig/adapter/aggregation-mapconfig-adapter.js +++ b/lib/models/mapconfig/adapter/aggregation-mapconfig-adapter.js @@ -4,11 +4,11 @@ const AggregationMapConfig = require('../../aggregation/aggregation-mapconfig'); const queryUtils = require('../../../utils/query-utils'); const unsupportedGeometryTypeErrorMessage = ctx => -`Unsupported geometry type: ${ctx.geometryType}. ` + + `Unsupported geometry type: ${ctx.geometryType}. ` + `Aggregation is available only for geometry type: ${AggregationMapConfig.SUPPORTED_GEOMETRY_TYPES}`; const invalidAggregationParamValueErrorMessage = ctx => -`Invalid value for 'aggregation' query param: ${ctx.value}. Valid ones are 'true' or 'false'`; + `Invalid value for 'aggregation' query param: ${ctx.value}. Valid ones are 'true' or 'false'`; module.exports = class AggregationMapConfigAdapter { constructor (pgConnection) { @@ -27,7 +27,6 @@ module.exports = class AggregationMapConfigAdapter { return callback(err); } - if (!this._shouldAdapt(mapConfig, params)) { return callback(null, requestMapConfig); } @@ -101,8 +100,7 @@ module.exports = class AggregationMapConfigAdapter { try { aggregationSql = mapConfig.getAggregatedQuery(index); - } - catch (error) { + } catch (error) { return reject(error); } diff --git a/lib/models/mapconfig/adapter/analysis-mapconfig-adapter.js b/lib/models/mapconfig/adapter/analysis-mapconfig-adapter.js index c4a71272..a20347d5 100644 --- a/lib/models/mapconfig/adapter/analysis-mapconfig-adapter.js +++ b/lib/models/mapconfig/adapter/analysis-mapconfig-adapter.js @@ -7,13 +7,13 @@ var camshaft = require('camshaft'); var dot = require('dot'); dot.templateSettings.strip = false; -function AnalysisMapConfigAdapter(analysisBackend) { +function AnalysisMapConfigAdapter (analysisBackend) { this.analysisBackend = analysisBackend; } module.exports = AnalysisMapConfigAdapter; -AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) { +AnalysisMapConfigAdapter.prototype.getMapConfig = function (user, requestMapConfig, params, context, callback) { // jshint maxcomplexity:7 var self = this; @@ -41,11 +41,11 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi return callback(errors); } - var dataviewsFiltersBySourceId = Object.keys(dataviewsFilters).reduce(function(bySourceId, dataviewName) { + var dataviewsFiltersBySourceId = Object.keys(dataviewsFilters).reduce(function (bySourceId, dataviewName) { var dataview = dataviews[dataviewName]; if (dataview) { var sourceId = dataview.source.id; - if (!bySourceId.hasOwnProperty(sourceId)) { + if (!Object.prototype.hasOwnProperty.call(bySourceId, sourceId)) { bySourceId[sourceId] = {}; } @@ -67,7 +67,7 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi // }} requestMapConfig = appendFiltersToNodes(requestMapConfig, filters.analyses); - function createAnalysis(analysisDefinition, done) { + function createAnalysis (analysisDefinition, done) { self.analysisBackend.create(analysisConfiguration, analysisDefinition, function (err, analysis) { if (err) { var error = new Error(err.message); @@ -85,22 +85,22 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi } var analysesQueue = queue(1); - requestMapConfig.analyses.forEach(function(analysis) { + requestMapConfig.analyses.forEach(function (analysis) { analysesQueue.defer(createAnalysis, analysis); }); - analysesQueue.awaitAll(function(err, analysesResults) { + analysesQueue.awaitAll(function (err, analysesResults) { if (err) { return callback(err); } - var sourceId2Node = analysesResults.reduce(function(sourceId2Query, analysis) { + var sourceId2Node = analysesResults.reduce(function (sourceId2Query, analysis) { var rootNode = analysis.getRoot(); if (rootNode.params && rootNode.params.id) { sourceId2Query[rootNode.params.id] = rootNode; } - analysis.getNodes().forEach(function(node) { + analysis.getNodes().forEach(function (node) { if (node.params && node.params.id) { sourceId2Query[node.params.id] = node; } @@ -111,7 +111,7 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi var analysesErrors = []; - requestMapConfig.layers = requestMapConfig.layers.map(function(layer, layerIndex) { + requestMapConfig.layers = requestMapConfig.layers.map(function (layer, layerIndex) { if (getLayerSourceId(layer)) { var layerSourceId = getLayerSourceId(layer); var layerNode = sourceId2Node[layerSourceId]; @@ -135,7 +135,7 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi } } else { analysesErrors.push( - new Error('Missing analysis node.id="' + layerSourceId +'" for layer='+layerIndex) + new Error('Missing analysis node.id="' + layerSourceId + '" for layer=' + layerIndex) ); } } @@ -148,7 +148,7 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi } // Augment dataviews with sql from analyses - Object.keys(dataviews).forEach(function(dataviewName) { + Object.keys(dataviews).forEach(function (dataviewName) { var dataview = requestMapConfig.dataviews[dataviewName]; var dataviewSourceId = dataview.source.id; var dataviewNode = sourceId2Node[dataviewSourceId]; @@ -160,7 +160,7 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi own_filter_on: dataviewQuery(dataviewNode, dataviewName, true), own_filter_off: dataviewQuery(dataviewNode, dataviewName, false), no_filters: dataviewNode.getQuery(Object.keys(dataviewNode.getFilters()) - .reduce(function(applyFilters, filterId) { + .reduce(function (applyFilters, filterId) { applyFilters[filterId] = false; return applyFilters; }, {}) @@ -180,13 +180,13 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi }; var SKIP_COLUMNS = { - 'the_geom': true, - 'the_geom_webmercator': true + the_geom: true, + the_geom_webmercator: true }; -function skipColumns(columnNames) { +function skipColumns (columnNames) { return columnNames - .filter(function(columnName) { return !SKIP_COLUMNS[columnName]; }); + .filter(function (columnName) { return !SKIP_COLUMNS[columnName]; }); } var wrappedQueryTpl = dot.template([ @@ -194,7 +194,7 @@ var wrappedQueryTpl = dot.template([ 'FROM ({{=it._query}}) _cdb_analysis_query' ].join('\n')); -function layerQuery(node) { +function layerQuery (node) { if (node.type === 'source') { return node.getQuery(); } @@ -202,7 +202,7 @@ function layerQuery(node) { return wrappedQueryTpl({ _query: node.getQuery(), _columns: _columns.join(', ') }); } -function dataviewQuery(node, dataviewName, ownFilter) { +function dataviewQuery (node, dataviewName, ownFilter) { var applyFilters = {}; if (!ownFilter) { applyFilters[dataviewName] = false; @@ -215,15 +215,15 @@ function dataviewQuery(node, dataviewName, ownFilter) { return wrappedQueryTpl({ _query: node.getQuery(applyFilters), _columns: _columns.join(', ') }); } -function appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId) { +function appendFiltersToNodes (requestMapConfig, dataviewsFiltersBySourceId) { var analyses = requestMapConfig.analyses || []; dataviewsFiltersBySourceId = dataviewsFiltersBySourceId || {}; - requestMapConfig.analyses = analyses.map(function(analysisDefinition) { + requestMapConfig.analyses = analyses.map(function (analysisDefinition) { var analysisGraph = new camshaft.reference.AnalysisGraph(analysisDefinition); var definition = analysisDefinition; - Object.keys(dataviewsFiltersBySourceId).forEach(function(sourceId) { - definition = analysisGraph.getDefinitionWith(sourceId, {filters: dataviewsFiltersBySourceId[sourceId] }); + Object.keys(dataviewsFiltersBySourceId).forEach(function (sourceId) { + definition = analysisGraph.getDefinitionWith(sourceId, { filters: dataviewsFiltersBySourceId[sourceId] }); }); return definition; @@ -232,8 +232,8 @@ function appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId) { return requestMapConfig; } -function shouldAdaptLayers(requestMapConfig) { - return Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(getLayerSourceId) || +function shouldAdaptLayers (requestMapConfig) { + return (Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(getLayerSourceId)) || (Array.isArray(requestMapConfig.analyses) && requestMapConfig.analyses.length > 0) || requestMapConfig.dataviews; } @@ -242,7 +242,7 @@ var DATAVIEW_TYPE_2_FILTER_TYPE = { aggregation: 'category', histogram: 'range' }; -function getFilter(dataview, params) { +function getFilter (dataview, params) { var type = dataview.type; return { @@ -252,21 +252,21 @@ function getFilter(dataview, params) { }; } -function getLayerSourceId(layer) { +function getLayerSourceId (layer) { return layer.options.source && layer.options.source.id; } -function getDataviewSourceId(dataview) { +function getDataviewSourceId (dataview) { return dataview.source && dataview.source.id; } -function getLayerDataviews(layer, dataviews) { +function getLayerDataviews (layer, dataviews) { var layerDataviews = []; var layerSourceId = getLayerSourceId(layer); if (layerSourceId) { var dataviewsList = getDataviewsList(dataviews); - dataviewsList.forEach(function(dataview) { + dataviewsList.forEach(function (dataview) { if (getDataviewSourceId(dataview) === layerSourceId) { layerDataviews.push(dataview); } @@ -276,10 +276,10 @@ function getLayerDataviews(layer, dataviews) { return layerDataviews; } -function getDataviewsColumns(dataviews) { - return Object.keys(dataviews.reduce(function(columnsDict, dataview) { - getDataviewColumns(dataview).forEach(function(columnName) { - if (!!columnName) { +function getDataviewsColumns (dataviews) { + return Object.keys(dataviews.reduce(function (columnsDict, dataview) { + getDataviewColumns(dataview).forEach(function (columnName) { + if (columnName) { columnsDict[columnName] = true; } }); @@ -287,22 +287,22 @@ function getDataviewsColumns(dataviews) { }, {})); } -function getDataviewColumns(dataview) { +function getDataviewColumns (dataview) { var columns = []; var options = dataview.options; - ['column', 'aggregationColumn'].forEach(function(opt) { - if (options.hasOwnProperty(opt) && !!options[opt]) { + ['column', 'aggregationColumn'].forEach(function (opt) { + if (Object.prototype.hasOwnProperty.call(options, opt) && !!options[opt]) { columns.push(options[opt]); } }); return columns; } -function getDataviewsList(dataviews) { - return Object.keys(dataviews).map(function(dataviewKey) { return dataviews[dataviewKey]; }); +function getDataviewsList (dataviews) { + return Object.keys(dataviews).map(function (dataviewKey) { return dataviews[dataviewKey]; }); } -function getDataviewsErrors(dataviews) { +function getDataviewsErrors (dataviews) { var dataviewType = typeof dataviews; if (dataviewType !== 'object') { return [new Error('"dataviews" must be a valid JSON object: "' + dataviewType + '" type found')]; @@ -314,9 +314,9 @@ function getDataviewsErrors(dataviews) { var errors = []; - Object.keys(dataviews).forEach(function(dataviewName) { + Object.keys(dataviews).forEach(function (dataviewName) { var dataview = dataviews[dataviewName]; - if (!dataview.hasOwnProperty('source') || !dataview.source.id) { + if (!Object.prototype.hasOwnProperty.call(dataview, 'source') || !dataview.source.id) { errors.push(new Error('Dataview "' + dataviewName + '" is missing `source.id` attribute')); } @@ -328,13 +328,13 @@ function getDataviewsErrors(dataviews) { return errors; } -function getMissingDataviewsSourceIds(dataviews, sourceId2Node) { +function getMissingDataviewsSourceIds (dataviews, sourceId2Node) { var missingDataviewsSourceIds = []; - Object.keys(dataviews).forEach(function(dataviewName) { + Object.keys(dataviews).forEach(function (dataviewName) { var dataview = dataviews[dataviewName]; var dataviewSourceId = getDataviewSourceId(dataview); - if (!sourceId2Node.hasOwnProperty(dataviewSourceId)) { - missingDataviewsSourceIds.push(new AnalysisError('Node with `source.id="' + dataviewSourceId +'"`' + + if (!Object.prototype.hasOwnProperty.call(sourceId2Node, dataviewSourceId)) { + missingDataviewsSourceIds.push(new AnalysisError('Node with `source.id="' + dataviewSourceId + '"`' + ' not found in analyses for dataview "' + dataviewName + '"')); } }); @@ -342,19 +342,19 @@ function getMissingDataviewsSourceIds(dataviews, sourceId2Node) { return missingDataviewsSourceIds; } -function AnalysisError(message) { +function AnalysisError (message) { Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; this.type = 'analysis'; this.message = message; } -function getAllAffectedTablesFromSourceNodes(node) { +function getAllAffectedTablesFromSourceNodes (node) { var affectedTables = node.getAllInputNodes(function (node) { return node.getType() === 'source'; - }).reduce(function(list, node) { + }).reduce(function (list, node) { return list.concat(node.getAffectedTables()); - },[]); + }, []); return affectedTables; } diff --git a/lib/models/mapconfig/adapter/dataviews-widgets-adapter.js b/lib/models/mapconfig/adapter/dataviews-widgets-adapter.js index f59c0d27..7f586125 100644 --- a/lib/models/mapconfig/adapter/dataviews-widgets-adapter.js +++ b/lib/models/mapconfig/adapter/dataviews-widgets-adapter.js @@ -1,12 +1,11 @@ 'use strict'; -function DataviewsWidgetsMapConfigAdapter() { +function DataviewsWidgetsMapConfigAdapter () { } module.exports = DataviewsWidgetsMapConfigAdapter; - -DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) { +DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function (user, requestMapConfig, params, context, callback) { if (!shouldAdapt(requestMapConfig)) { return callback(null, requestMapConfig); } @@ -15,7 +14,7 @@ DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function(user, request requestMapConfig.analyses = requestMapConfig.analyses || []; requestMapConfig.dataviews = requestMapConfig.dataviews || {}; - requestMapConfig.layers.forEach(function(layer, index) { + requestMapConfig.layers.forEach(function (layer, index) { var layerSourceId = getLayerSourceId(layer); if (!layer.options.widgets) { @@ -41,7 +40,7 @@ DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function(user, request } var source = { id: dataviewSourceId }; var layerWidgets = layer.options.widgets || {}; - Object.keys(layerWidgets).forEach(function(widgetId) { + Object.keys(layerWidgets).forEach(function (widgetId) { var dataview = layerWidgets[widgetId]; requestMapConfig.dataviews[widgetId] = { source: source, @@ -54,7 +53,7 @@ DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function(user, request delete layer.options.sql; // don't delete widgets for now as it might be useful for old clients - //delete layer.options.widgets; + // delete layer.options.widgets; }); // filters have to be rewritten also @@ -62,9 +61,9 @@ DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function(user, request var layersFilters = filters.layers || []; filters.dataviews = filters.dataviews || {}; - layersFilters.forEach(function(layerFilters) { - Object.keys(layerFilters).forEach(function(filterName) { - if (!filters.dataviews.hasOwnProperty(filterName)) { + layersFilters.forEach(function (layerFilters) { + Object.keys(layerFilters).forEach(function (filterName) { + if (!Object.prototype.hasOwnProperty.call(filters.dataviews, filterName)) { filters.dataviews[filterName] = layerFilters[filterName]; } }); @@ -77,17 +76,17 @@ DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function(user, request return callback(null, requestMapConfig); }; -function shouldAdapt(requestMapConfig) { - return Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(function hasWidgets(layer) { +function shouldAdapt (requestMapConfig) { + return Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(function hasWidgets (layer) { return layer.options && layer.options.widgets && Object.keys(layer.options.widgets).length > 0; }); } -function getLayerSourceId(layer) { +function getLayerSourceId (layer) { return layer.options.source && layer.options.source.id; } -function getFilters(params) { +function getFilters (params) { var filters = {}; if (params.filters) { try { diff --git a/lib/models/mapconfig/adapter/index.js b/lib/models/mapconfig/adapter/index.js index dd82df32..a4e41efc 100644 --- a/lib/models/mapconfig/adapter/index.js +++ b/lib/models/mapconfig/adapter/index.js @@ -1,19 +1,19 @@ 'use strict'; -function MapConfigAdapter(adapters) { +function MapConfigAdapter (adapters) { this.adapters = Array.isArray(adapters) ? adapters : Array.apply(null, arguments); } module.exports = MapConfigAdapter; -MapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) { +MapConfigAdapter.prototype.getMapConfig = function (user, requestMapConfig, params, context, callback) { var self = this; var i = 0; var tasksLeft = this.adapters.length; let mapConfigStats = {}; - function next(err, _requestMapConfig, adapterStats = {}) { + function next (err, _requestMapConfig, adapterStats = {}) { if (err) { return callback(err); } diff --git a/lib/models/mapconfig/adapter/mapconfig-buffer-size-adapter.js b/lib/models/mapconfig/adapter/mapconfig-buffer-size-adapter.js index 07fc45bc..1596afcc 100644 --- a/lib/models/mapconfig/adapter/mapconfig-buffer-size-adapter.js +++ b/lib/models/mapconfig/adapter/mapconfig-buffer-size-adapter.js @@ -1,6 +1,6 @@ 'use strict'; -function MapConfigBufferSizeAdapter() { +function MapConfigBufferSizeAdapter () { this.formats = ['png', 'png32', 'mvt', 'grid.json']; } diff --git a/lib/models/mapconfig/adapter/mapconfig-named-layers-adapter.js b/lib/models/mapconfig/adapter/mapconfig-named-layers-adapter.js index 39721b41..4d0b5786 100644 --- a/lib/models/mapconfig/adapter/mapconfig-named-layers-adapter.js +++ b/lib/models/mapconfig/adapter/mapconfig-named-layers-adapter.js @@ -4,7 +4,7 @@ var queue = require('queue-async'); var _ = require('underscore'); var Datasource = require('windshaft').model.Datasource; -function MapConfigNamedLayersAdapter(templateMaps, pgConnection) { +function MapConfigNamedLayersAdapter (templateMaps, pgConnection) { this.templateMaps = templateMaps; this.pgConnection = pgConnection; } @@ -22,9 +22,8 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC var adaptLayersQueue = queue(layers.length); - function adaptLayer(layer, done) { + function adaptLayer (layer, done) { if (isNamedTypeLayer(layer)) { - if (!layer.options.name) { return done(new Error('Missing Named Map `name` in layer options')); } @@ -33,13 +32,13 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC var templateConfigParams = layer.options.config || {}; var templateAuthTokens = layer.options.auth_tokens; - self.templateMaps.getTemplate(user, templateName, function(err, template) { + self.templateMaps.getTemplate(user, templateName, function (err, template) { if (err || !template) { return done(new Error("Template '" + templateName + "' of user '" + user + "' not found")); } if (self.templateMaps.isAuthorized(template, templateAuthTokens)) { - var nestedNamedLayers = template.layergroup.layers.filter(function(layer) { + var nestedNamedLayers = template.layergroup.layers.filter(function (layer) { return layer.type === 'named'; }); @@ -63,7 +62,6 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC return done(unauthorizedError); } }); - } else { return done(null, { datasource: false, @@ -74,7 +72,7 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC var datasourceBuilder = new Datasource.Builder(); - function layersAdaptQueueFinish(err, layersResults) { + function layersAdaptQueueFinish (err, layersResults) { if (err) { return callback(err); } @@ -83,26 +81,24 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC return callback(new Error('Missing layers array from layergroup config')); } - var layers = [], - currentLayerIndex = 0; + var layers = []; + var currentLayerIndex = 0; - layersResults.forEach(function(layersResult) { - - layersResult.layers.forEach(function(layer) { + layersResults.forEach(function (layersResult) { + layersResult.layers.forEach(function (layer) { layers.push(layer); if (layersResult.datasource) { datasourceBuilder.withLayerDatasource(currentLayerIndex, { user: dbAuth.dbuser, - // Used internally (PSQL) + // Used internally (PSQL) pass: dbAuth.dbpassword, dbpassword: dbAuth.dbpassword, - // Used by Mapnik + // Used by Mapnik password: dbAuth.dbpassword }); } currentLayerIndex++; }); - }); requestMapConfig.layers = layers; @@ -111,15 +107,14 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC return callback(null, requestMapConfig); } - var dbAuth = {}; if (_.some(layers, isNamedTypeLayer)) { - this.pgConnection.setDBAuth(user, dbAuth, 'master', function(err) { + this.pgConnection.setDBAuth(user, dbAuth, 'master', function (err) { if (err) { return callback(err); } - layers.forEach(function(layer) { + layers.forEach(function (layer) { adaptLayersQueue.defer(adaptLayer, layer); }); adaptLayersQueue.awaitAll(layersAdaptQueueFinish); @@ -128,9 +123,8 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC context.datasource = datasourceBuilder.build(); return callback(null, requestMapConfig); } - }; -function isNamedTypeLayer(layer) { +function isNamedTypeLayer (layer) { return layer.type === 'named'; } diff --git a/lib/models/mapconfig/adapter/mapconfig-overviews-adapter.js b/lib/models/mapconfig/adapter/mapconfig-overviews-adapter.js index c2d9b784..3cb39a50 100644 --- a/lib/models/mapconfig/adapter/mapconfig-overviews-adapter.js +++ b/lib/models/mapconfig/adapter/mapconfig-overviews-adapter.js @@ -4,7 +4,7 @@ var queue = require('queue-async'); var _ = require('underscore'); const AggregationMapConfig = require('../../aggregation/aggregation-mapconfig'); -function MapConfigOverviewsAdapter(overviewsMetadataBackend, filterStatsBackend) { +function MapConfigOverviewsAdapter (overviewsMetadataBackend, filterStatsBackend) { this.overviewsMetadataBackend = overviewsMetadataBackend; this.filterStatsBackend = filterStatsBackend; } @@ -115,12 +115,12 @@ function getUnfilteredQuery (analysesResults, layer) { if (node) { var filters = node.getFilters(); - var filters_disabler = Object.keys(filters).reduce(function (disabler, filter_id) { - disabler[filter_id] = false; + var filtersDisabler = Object.keys(filters).reduce(function (disabler, filterId) { + disabler[filterId] = false; return disabler; }, {}); - return node.getQuery(filters_disabler); + return node.getQuery(filtersDisabler); } } } diff --git a/lib/models/mapconfig/adapter/sql-wrap-mapconfig-adapter.js b/lib/models/mapconfig/adapter/sql-wrap-mapconfig-adapter.js index e3f030ce..e1b1cd43 100644 --- a/lib/models/mapconfig/adapter/sql-wrap-mapconfig-adapter.js +++ b/lib/models/mapconfig/adapter/sql-wrap-mapconfig-adapter.js @@ -1,14 +1,13 @@ 'use strict'; -function SqlWrapMapConfigAdapter() { +function SqlWrapMapConfigAdapter () { } module.exports = SqlWrapMapConfigAdapter; - -SqlWrapMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) { +SqlWrapMapConfigAdapter.prototype.getMapConfig = function (user, requestMapConfig, params, context, callback) { if (requestMapConfig && Array.isArray(requestMapConfig.layers)) { - requestMapConfig.layers = requestMapConfig.layers.map(function(layer) { + requestMapConfig.layers = requestMapConfig.layers.map(function (layer) { if (layer.options) { var sqlQueryWrap = layer.options.sql_wrap; if (sqlQueryWrap) { diff --git a/lib/models/mapconfig/adapter/turbo-carto-adapter.js b/lib/models/mapconfig/adapter/turbo-carto-adapter.js index e54632d6..f127c7ac 100644 --- a/lib/models/mapconfig/adapter/turbo-carto-adapter.js +++ b/lib/models/mapconfig/adapter/turbo-carto-adapter.js @@ -13,7 +13,7 @@ var MapConfig = require('windshaft').model.MapConfig; const dbParamsFromReqParams = require('../../../utils/database-params'); -function TurboCartoAdapter() { +function TurboCartoAdapter () { } module.exports = TurboCartoAdapter; @@ -29,7 +29,7 @@ TurboCartoAdapter.prototype.getMapConfig = function (user, requestMapConfig, par var parseCartoQueue = queue(layers.length); - layers.forEach(function(layer, index) { + layers.forEach(function (layer, index) { var layerId = MapConfig.getLayerId(requestMapConfig, index); parseCartoQueue.defer(self._parseCartoCss.bind(self), user, params, layer, index, layerId); }); @@ -39,7 +39,7 @@ TurboCartoAdapter.prototype.getMapConfig = function (user, requestMapConfig, par return callback(err); } - var errors = results.reduce(function(errors, result) { + var errors = results.reduce(function (errors, result) { if (result.error) { errors.push(result.error); } @@ -49,9 +49,9 @@ TurboCartoAdapter.prototype.getMapConfig = function (user, requestMapConfig, par return callback(errors); } - requestMapConfig.layers = results.map(function(result) { return result.layer; }); + requestMapConfig.layers = results.map(function (result) { return result.layer; }); context.turboCarto = { - layers: results.map(function(result) { + layers: results.map(function (result) { return result.meta; }) }; @@ -91,7 +91,7 @@ TurboCartoAdapter.prototype._parseCartoCss = function (username, params, layer, } var pg = new PSQL(dbParamsFromReqParams(params)); - function processCallback(err, cartocss, meta) { + function processCallback (err, cartocss, meta) { // Only return turbo-carto errors if (err && err.name === 'TurboCartoError') { var error = new Error(err.message); @@ -121,8 +121,8 @@ TurboCartoAdapter.prototype._parseCartoCss = function (username, params, layer, // For wrapped queries we'll derive the tokens from the data extent // instead of the whole Earth/root tile. var self = this; - var tokensQuery = tokensQueryTpl({_sql: layerRawSql}); - return pg.query(tokensQuery, function(err, resultSet) { + var tokensQuery = tokensQueryTpl({ _sql: layerRawSql }); + return pg.query(tokensQuery, function (err, resultSet) { if (err) { return processCallback(err); } @@ -159,6 +159,6 @@ TurboCartoAdapter.prototype.process = function (psql, cartocss, sql, callback) { turboCarto(cartocss, datasource, callback); }; -function shouldParseLayerCartocss(layer) { +function shouldParseLayerCartocss (layer) { return layer && layer.options && layer.options.cartocss && layer.options.sql; } diff --git a/lib/models/mapconfig/adapter/vector-mapconfig-adapter.js b/lib/models/mapconfig/adapter/vector-mapconfig-adapter.js index dd03f3fe..45ccee04 100644 --- a/lib/models/mapconfig/adapter/vector-mapconfig-adapter.js +++ b/lib/models/mapconfig/adapter/vector-mapconfig-adapter.js @@ -10,11 +10,11 @@ const dateWrapper = require('../../../utils/date-wrapper'); * - This middleware is ONLY activated when the `dates_as_numbers` option is enabled for some layer in the mapConfig. */ class VectorMapConfigAdapter { - constructor(pgConnection) { + constructor (pgConnection) { this.pgConnection = pgConnection; } - getMapConfig(user, requestMapConfig, params, context, callback) { + getMapConfig (user, requestMapConfig, params, context, callback) { if (!this._isDatesAsNumbersFlagEnabled(requestMapConfig)) { return callback(null, requestMapConfig); } @@ -24,12 +24,12 @@ class VectorMapConfigAdapter { .catch(callback); } - _wrapDates(requestMapConfig, user) { + _wrapDates (requestMapConfig, user) { return Promise.all(requestMapConfig.layers.map(layer => this._wrapLayer(layer, user))) .then(() => requestMapConfig); } - _wrapLayer(layer, user) { + _wrapLayer (layer, user) { if (!layer.options.dates_as_numbers || !layer.options.sql) { return Promise.resolve(layer); } @@ -42,7 +42,7 @@ class VectorMapConfigAdapter { }); } - _getColumns(user, originalQuery) { + _getColumns (user, originalQuery) { return new Promise((resolve, reject) => { this.pgConnection.getConnection(user, (err, connection) => { if (err) { @@ -56,10 +56,9 @@ class VectorMapConfigAdapter { }); } - _isDatesAsNumbersFlagEnabled(requestMapConfig) { + _isDatesAsNumbersFlagEnabled (requestMapConfig) { return requestMapConfig.layers && requestMapConfig.layers.some(layer => layer.options.dates_as_numbers); } } - module.exports = VectorMapConfigAdapter; diff --git a/lib/models/mapconfig/provider/map-store-provider.js b/lib/models/mapconfig/provider/map-store-provider.js index b0dda9d1..a84478fd 100644 --- a/lib/models/mapconfig/provider/map-store-provider.js +++ b/lib/models/mapconfig/provider/map-store-provider.js @@ -4,7 +4,7 @@ const BaseMapConfigProvider = require('./base-mapconfig-adapter'); const dot = require('dot'); // Configure bases for cache keys suitable for string interpolation -const baseKey = '{{=it.dbname}}:{{=it.token}}'; +const baseKey = '{{=it.dbname}}:{{=it.token}}'; const rendererKey = baseKey + ':{{=it.dbuser}}:{{=it.format}}:{{=it.layer}}:{{=it.scale_factor}}'; const baseKeyTpl = dot.template(baseKey); diff --git a/lib/models/mapconfig/provider/named-map-provider.js b/lib/models/mapconfig/provider/named-map-provider.js index e49893a9..d0823f89 100644 --- a/lib/models/mapconfig/provider/named-map-provider.js +++ b/lib/models/mapconfig/provider/named-map-provider.js @@ -68,9 +68,9 @@ module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider { if (this.config) { try { - templateParams = Object.prototype.toString.call(this.config) === '[object String]' ? - JSON.parse(this.config) : - this.config; + templateParams = Object.prototype.toString.call(this.config) === '[object String]' + ? JSON.parse(this.config) + : this.config; } catch (e) { const err = new Error('malformed config parameter, should be a valid JSON'); return callback(err); @@ -96,15 +96,15 @@ module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider { this.mapConfigAdapter.getMapConfig( user, requestMapConfig, rendererParams, context, (err, mapConfig, stats = {}) => { - if (err) { - return callback(err); - } + if (err) { + return callback(err); + } - this.mapConfig = (mapConfig === null) ? null : new MapConfig(mapConfig, context.datasource); - this.analysesResults = context.analysesResults || []; + this.mapConfig = (mapConfig === null) ? null : new MapConfig(mapConfig, context.datasource); + this.analysesResults = context.analysesResults || []; - return callback(null, this.mapConfig, this.rendererParams, this.context, stats); - }); + return callback(null, this.mapConfig, this.rendererParams, this.context, stats); + }); }); }); } @@ -135,7 +135,7 @@ module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider { }, batch: { username: this.user, - apiKey: apiKey + apiKey } }; @@ -256,12 +256,12 @@ module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider { } }; -function createConfigHash(config) { +function createConfigHash (config) { if (!config) { return ''; } - return crypto.createHash('md5').update(JSON.stringify(config)).digest('hex').substring(0,8); + return crypto.createHash('md5').update(JSON.stringify(config)).digest('hex').substring(0, 8); } module.exports.configHash = createConfigHash; diff --git a/lib/models/resource-locator.js b/lib/models/resource-locator.js index 1eba6638..b287904a 100644 --- a/lib/models/resource-locator.js +++ b/lib/models/resource-locator.js @@ -3,7 +3,7 @@ var dot = require('dot'); dot.templateSettings.strip = false; -function ResourceLocator(environment) { +function ResourceLocator (environment) { this.environment = environment; this.resourcesUrlTemplates = null; @@ -23,7 +23,7 @@ function ResourceLocator(environment) { module.exports = ResourceLocator; -ResourceLocator.prototype.getTileUrls = function(username, resourcePath) { +ResourceLocator.prototype.getTileUrls = function (username, resourcePath) { if (this.resourcesUrlTemplates) { const urls = this.getUrlsFromTemplate(username, new TileResource(resourcePath)); return { @@ -42,7 +42,7 @@ ResourceLocator.prototype.getTileUrls = function(username, resourcePath) { } }; -ResourceLocator.prototype.getTemplateUrls = function(username, resourcePath) { +ResourceLocator.prototype.getTemplateUrls = function (username, resourcePath) { if (this.resourcesUrlTemplates) { return this.getUrlsFromTemplate(username, new TemplateResource(resourcePath), true); } @@ -60,7 +60,7 @@ ResourceLocator.prototype.getTemplateUrls = function(username, resourcePath) { } }; -ResourceLocator.prototype.getUrls = function(username, resourcePath) { +ResourceLocator.prototype.getUrls = function (username, resourcePath) { if (this.resourcesUrlTemplates) { return this.getUrlsFromTemplate(username, new Resource(resourcePath)); } @@ -80,7 +80,7 @@ ResourceLocator.prototype.urlForTemplate = function (tpl, username, cdnDomain, r if (templated) { return { urlTemplate: tpl({ - cdn_url: (cdnDomain.hasOwnProperty('urlTemplate') ? cdnDomain.urlTemplate : cdnDomain), + cdn_url: (Object.prototype.hasOwnProperty.call(cdnDomain, 'urlTemplate') ? cdnDomain.urlTemplate : cdnDomain), user: username, port: this.environment.port, resource: resource.getPath() @@ -105,7 +105,7 @@ ResourceLocator.prototype.urlForTemplate = function (tpl, username, cdnDomain, r } }; -ResourceLocator.prototype.getUrlsFromTemplate = function(username, resource, templated) { +ResourceLocator.prototype.getUrlsFromTemplate = function (username, resource, templated) { var urls = {}; var cdnDomain = getCdnDomain(this.environment.serverMetadata, resource) || {}; if (this.resourcesUrlTemplates.http) { @@ -156,10 +156,6 @@ class Resource { } class TileResource extends Resource { - constructor (resourcePath) { - super(resourcePath); - } - getDomain (domain, subdomains) { if (!subdomains) { return domain; @@ -179,10 +175,6 @@ class TileResource extends Resource { } class TemplateResource extends Resource { - constructor (resourcePath) { - super(resourcePath); - } - getDomain (domain, subdomains) { return { urlTemplate: domain, @@ -198,11 +190,11 @@ class TemplateResource extends Resource { } } -function getUrl(baseUrl, username, path) { +function getUrl (baseUrl, username, path) { return `${baseUrl}/${username}/api/v1/map/${path}`; } -function getCdnUrls(serverMetadata, username, resource) { +function getCdnUrls (serverMetadata, username, resource) { if (serverMetadata && serverMetadata.cdn_url) { var cdnUrl = serverMetadata.cdn_url; var httpUrls = resource.getUrl(`http://${cdnUrl.http}`, username); @@ -214,13 +206,13 @@ function getCdnUrls(serverMetadata, username, resource) { } return { http: httpUrls, - https: httpsUrls, + https: httpsUrls }; } return null; } -function getCdnDomain(serverMetadata, resource) { +function getCdnDomain (serverMetadata, resource) { if (serverMetadata && serverMetadata.cdn_url) { var cdnUrl = serverMetadata.cdn_url; var httpDomain = resource.getDomain(cdnUrl.http); @@ -236,36 +228,36 @@ function getCdnDomain(serverMetadata, resource) { } return { http: httpDomain, - https: httpsDomain, + https: httpsDomain }; } return null; } // ref https://jsperf.com/js-crc32 -function crcTable() { +function crcTable () { var c; var table = []; for (var n = 0; n < 256; n++) { - c = n; - for (var k = 0; k < 8; k++) { - c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); - } - table[n] = c; + c = n; + for (var k = 0; k < 8; k++) { + c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); + } + table[n] = c; } return table; } var CRC_TABLE = crcTable(); -function crc32(str) { +function crc32 (str) { var crc = 0 ^ (-1); for (var i = 0; i < str.length; i++) { - crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ str.charCodeAt(i)) & 0xFF]; + crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ str.charCodeAt(i)) & 0xFF]; } return (crc ^ (-1)) >>> 0; } -function subdomain(subdomains, resource) { +function subdomain (subdomains, resource) { var index = crc32(resource) % subdomains.length; return subdomains[index]; } diff --git a/lib/monitoring/health-check.js b/lib/monitoring/health-check.js index 31cc8245..55273bcd 100644 --- a/lib/monitoring/health-check.js +++ b/lib/monitoring/health-check.js @@ -2,15 +2,14 @@ var fs = require('fs'); -function HealthCheck(disableFile) { +function HealthCheck (disableFile) { this.disableFile = disableFile; } module.exports = HealthCheck; - -HealthCheck.prototype.check = function(callback) { - fs.readFile(this.disableFile, function handleDisabledFile(err, data) { +HealthCheck.prototype.check = function (callback) { + fs.readFile(this.disableFile, function handleDisabledFile (err, data) { var disabledError = null; if (!err) { disabledError = new Error(data || 'Unknown error'); diff --git a/lib/server-info-controller.js b/lib/server-info-controller.js index fe1f1a19..5913c09e 100644 --- a/lib/server-info-controller.js +++ b/lib/server-info-controller.js @@ -2,11 +2,10 @@ var HealthCheck = require('./monitoring/health-check'); -var WELCOME_MSG = "This is the CartoDB Maps API, " + - "see the documentation at http://docs.cartodb.com/cartodb-platform/maps-api.html"; +var WELCOME_MSG = 'This is the CartoDB Maps API, ' + + 'see the documentation at http://docs.cartodb.com/cartodb-platform/maps-api.html'; - -function ServerInfoController(versions) { +function ServerInfoController (versions) { this.healthConfig = global.environment.health || {}; this.healthCheck = new HealthCheck(global.environment.disabled_file); this.versions = versions || {}; @@ -14,24 +13,24 @@ function ServerInfoController(versions) { module.exports = ServerInfoController; -ServerInfoController.prototype.route = function(monitorRouter) { +ServerInfoController.prototype.route = function (monitorRouter) { monitorRouter.get('/health', this.health.bind(this)); monitorRouter.get('/', this.welcome.bind(this)); monitorRouter.get('/version', this.version.bind(this)); }; -ServerInfoController.prototype.welcome = function(req, res) { +ServerInfoController.prototype.welcome = function (req, res) { res.status(200).send(WELCOME_MSG); }; -ServerInfoController.prototype.version = function(req, res) { +ServerInfoController.prototype.version = function (req, res) { res.status(200).send(this.versions); }; -ServerInfoController.prototype.health = function(req, res) { - if (!!this.healthConfig.enabled) { +ServerInfoController.prototype.health = function (req, res) { + if (this.healthConfig.enabled) { var startTime = Date.now(); - this.healthCheck.check(function(err) { + this.healthCheck.check(function (err) { var ok = !err; var response = { enabled: true, @@ -42,9 +41,8 @@ ServerInfoController.prototype.health = function(req, res) { response.err = err.message; } res.status(ok ? 200 : 503).send(response); - }); } else { - res.status(200).send({enabled: false, ok: true}); + res.status(200).send({ enabled: false, ok: true }); } }; diff --git a/lib/server-options.js b/lib/server-options.js index dd138419..e89c0b1c 100644 --- a/lib/server-options.js +++ b/lib/server-options.js @@ -70,13 +70,13 @@ module.exports = { api: [{ paths: [ '/api/v1', - '/user/:user/api/v1', + '/user/:user/api/v1' ], // Base url for the Detached Maps API // "/api/v1/map" is the new API, map: [{ paths: [ - '/map', + '/map' ] }], // Base url for the Templated Maps API @@ -124,7 +124,7 @@ module.exports = { limits: analysisConfig.limits }, // Do not send unwatch on release. See http://github.com/CartoDB/Windshaft-cartodb/issues/161 - redis: _.extend(global.environment.redis, {unwatchOnRelease: false}), + redis: _.extend(global.environment.redis, { unwatchOnRelease: false }), enable_cors: global.environment.enable_cors, varnish_host: global.environment.varnish.host, varnish_port: global.environment.varnish.port, diff --git a/lib/server.js b/lib/server.js index 9f7b7ee0..a39b1cb5 100644 --- a/lib/server.js +++ b/lib/server.js @@ -14,7 +14,7 @@ const ServerInfoController = require('./server-info-controller'); const StatsClient = require('./stats/client'); module.exports = function createServer (serverOptions) { - if (!serverOptions.hasOwnProperty('routes')) { + if (!Object.prototype.hasOwnProperty.call(serverOptions, 'routes')) { throw new Error('Must initialise server with "routes" as base paths configuration'); } @@ -36,7 +36,7 @@ module.exports = function createServer (serverOptions) { // TODO: remove it before releasing next major version if (!Array.isArray(serverOptions.routes.api)) { - serverOptions.routes.api = [ serverOptions.routes.api ]; + serverOptions.routes.api = [serverOptions.routes.api]; } apiRouter.route(app, serverOptions.routes.api); @@ -49,23 +49,23 @@ module.exports = function createServer (serverOptions) { return app; }; -function bootstrapFonts(opts) { +function bootstrapFonts (opts) { // Set carto renderer configuration for MMLStore opts.grainstore.carto_env = opts.grainstore.carto_env || {}; var cenv = opts.grainstore.carto_env; cenv.validation_data = cenv.validation_data || {}; - if ( ! cenv.validation_data.fonts ) { + if (!cenv.validation_data.fonts) { mapnik.register_system_fonts(); mapnik.register_default_fonts(); cenv.validation_data.fonts = _.keys(mapnik.fontFiles()); } } -function mapnikVersion(opts) { +function mapnikVersion (opts) { return opts.grainstore.mapnik_version || mapnik.versions.mapnik; } -function getAndValidateVersions(options) { +function getAndValidateVersions (options) { var warn = console.warn.bind(console); // jshint ignore:line var packageDefinition = require('../package.json'); @@ -83,10 +83,10 @@ function getAndValidateVersions(options) { if (process.env.NODE_ENV !== 'test') { var dependenciesToValidate = ['camshaft', 'turbo-carto', 'windshaft']; - dependenciesToValidate.forEach(function(depName) { + dependenciesToValidate.forEach(function (depName) { var declaredDependencyVersion = declaredDependencies[depName]; var installedDependencyVersion = installedDependenciesVersions[depName]; - if (!semver.satisfies(installedDependencyVersion,declaredDependencyVersion)) { + if (!semver.satisfies(installedDependencyVersion, declaredDependencyVersion)) { warn(`Dependency="${depName}" installed version="${installedDependencyVersion}" does ` + `not match declared version="${declaredDependencyVersion}". Check your installation.`); } diff --git a/lib/stats/client.js b/lib/stats/client.js index be6f6c13..435be5ad 100644 --- a/lib/stats/client.js +++ b/lib/stats/client.js @@ -17,30 +17,28 @@ module.exports = { * @param config Configuration for StatsD, if undefined it will return an stub * @returns {StatsD|Object} */ - getInstance: function(config) { - + getInstance: function (config) { if (!this.instance) { - var instance; if (config) { instance = new StatsD(config); instance.last_error = { msg: '', count: 0 }; instance.socket.on('error', function (err) { - var last_err = instance.last_error; - var last_msg = last_err.msg; - var this_msg = '' + err; - if (this_msg !== last_msg) { - debug("statsd client socket error: " + err); + var lastErr = instance.last_error; + var lastMsg = lastErr.msg; + var thisMsg = '' + err; + if (thisMsg !== lastMsg) { + debug('statsd client socket error: ' + err); instance.last_error.count = 1; - instance.last_error.msg = this_msg; + instance.last_error.msg = thisMsg; } else { - ++last_err.count; - if (!last_err.interval) { + ++lastErr.count; + if (!lastErr.interval) { instance.last_error.interval = setInterval(function () { var count = instance.last_error.count; if (count > 1) { - debug("last statsd client socket error repeated " + count + " times"); + debug('last statsd client socket error repeated ' + count + ' times'); instance.last_error.count = 1; clearInterval(instance.last_error.interval); instance.last_error.interval = null; diff --git a/lib/stats/profiler-proxy.js b/lib/stats/profiler-proxy.js index 5ac60d57..9dad81f5 100644 --- a/lib/stats/profiler-proxy.js +++ b/lib/stats/profiler-proxy.js @@ -5,51 +5,51 @@ var Profiler = require('step-profiler'); /** * Proxy to encapsulate node-step-profiler module so there is no need to check if there is an instance */ -function ProfilerProxy(opts) { +function ProfilerProxy (opts) { this.profile = !!opts.profile; this.profiler = null; - if (!!opts.profile) { - this.profiler = new Profiler({statsd_client: opts.statsd_client}); + if (opts.profile) { + this.profiler = new Profiler({ statsd_client: opts.statsd_client }); } } -ProfilerProxy.prototype.done = function(what) { +ProfilerProxy.prototype.done = function (what) { if (this.profile) { this.profiler.done(what); } }; -ProfilerProxy.prototype.end = function() { +ProfilerProxy.prototype.end = function () { if (this.profile) { this.profiler.end(); } }; -ProfilerProxy.prototype.start = function(what) { +ProfilerProxy.prototype.start = function (what) { if (this.profile) { this.profiler.start(what); } }; -ProfilerProxy.prototype.add = function(what) { +ProfilerProxy.prototype.add = function (what) { if (this.profile) { this.profiler.add(what || {}); } }; -ProfilerProxy.prototype.sendStats = function() { +ProfilerProxy.prototype.sendStats = function () { if (this.profile) { this.profiler.sendStats(); } }; -ProfilerProxy.prototype.toString = function() { - return this.profile ? this.profiler.toString() : ""; +ProfilerProxy.prototype.toString = function () { + return this.profile ? this.profiler.toString() : ''; }; -ProfilerProxy.prototype.toJSONString = function() { - return this.profile ? this.profiler.toJSONString() : "{}"; +ProfilerProxy.prototype.toJSONString = function () { + return this.profile ? this.profiler.toJSONString() : '{}'; }; module.exports = ProfilerProxy; diff --git a/lib/stats/reporter/renderer.js b/lib/stats/reporter/renderer.js index 60899918..463eb114 100644 --- a/lib/stats/reporter/renderer.js +++ b/lib/stats/reporter/renderer.js @@ -8,7 +8,7 @@ var _ = require('underscore'); -function RendererStatsReporter(rendererCache, statsInterval) { +function RendererStatsReporter (rendererCache, statsInterval) { this.rendererCache = rendererCache; this.statsInterval = statsInterval || 6e4; this.renderersStatsIntervalId = null; @@ -16,9 +16,9 @@ function RendererStatsReporter(rendererCache, statsInterval) { module.exports = RendererStatsReporter; -RendererStatsReporter.prototype.start = function() { +RendererStatsReporter.prototype.start = function () { var self = this; - this.renderersStatsIntervalId = setInterval(function() { + this.renderersStatsIntervalId = setInterval(function () { var rendererCacheEntries = self.rendererCache.renderers; if (!rendererCacheEntries) { @@ -27,32 +27,32 @@ RendererStatsReporter.prototype.start = function() { global.statsClient.gauge('windshaft.rendercache.count', _.keys(rendererCacheEntries).length); - var renderersStats = _.reduce(rendererCacheEntries, function(_rendererStats, cacheEntry) { - var stats = cacheEntry.renderer && cacheEntry.renderer.getStats && cacheEntry.renderer.getStats(); - if (!stats) { - return _rendererStats; - } - - _rendererStats.pool.count += stats.pool.count; - _rendererStats.pool.unused += stats.pool.unused; - _rendererStats.pool.waiting += stats.pool.waiting; - - _rendererStats.cache.grid += stats.cache.grid; - _rendererStats.cache.png += stats.cache.png; - + var renderersStats = _.reduce(rendererCacheEntries, function (_rendererStats, cacheEntry) { + var stats = cacheEntry.renderer && cacheEntry.renderer.getStats && cacheEntry.renderer.getStats(); + if (!stats) { return _rendererStats; - }, - { - pool: { - count: 0, - unused: 0, - waiting: 0 - }, - cache: { - png: 0, - grid: 0 - } } + + _rendererStats.pool.count += stats.pool.count; + _rendererStats.pool.unused += stats.pool.unused; + _rendererStats.pool.waiting += stats.pool.waiting; + + _rendererStats.cache.grid += stats.cache.grid; + _rendererStats.cache.png += stats.cache.png; + + return _rendererStats; + }, + { + pool: { + count: 0, + unused: 0, + waiting: 0 + }, + cache: { + png: 0, + grid: 0 + } + } ); global.statsClient.gauge('windshaft.mapnik-cache.png', renderersStats.cache.png); @@ -67,15 +67,15 @@ RendererStatsReporter.prototype.start = function() { this.rendererCache.on('gc', gcTimingListener); }; -function rendererCacheErrorListener() { +function rendererCacheErrorListener () { global.statsClient.increment('windshaft.rendercache.error'); } -function gcTimingListener(gcTime) { +function gcTimingListener (gcTime) { global.statsClient.timing('windshaft.rendercache.gc', gcTime); } -RendererStatsReporter.prototype.stop = function() { +RendererStatsReporter.prototype.stop = function () { this.rendererCache.removeListener('err', rendererCacheErrorListener); this.rendererCache.removeListener('gc', gcTimingListener); diff --git a/lib/stats/timer.js b/lib/stats/timer.js index f15c423a..a6689990 100644 --- a/lib/stats/timer.js +++ b/lib/stats/timer.js @@ -1,29 +1,29 @@ 'use strict'; -function Timer() { +function Timer () { this.times = {}; } module.exports = Timer; -Timer.prototype.start = function(label) { +Timer.prototype.start = function (label) { this.timeIt(label, 'start'); }; -Timer.prototype.end = function(label) { +Timer.prototype.end = function (label) { this.timeIt(label, 'end'); }; -Timer.prototype.timeIt = function(label, what) { +Timer.prototype.timeIt = function (label, what) { this.times[label] = this.times[label] || {}; this.times[label][what] = Date.now(); }; -Timer.prototype.getTimes = function() { +Timer.prototype.getTimes = function () { var self = this; var times = {}; - Object.keys(this.times).forEach(function(label) { + Object.keys(this.times).forEach(function (label) { var stat = self.times[label]; if (stat.start && stat.end) { times[label] = Math.max(0, stat.end - stat.start); diff --git a/lib/utils/date-wrapper.js b/lib/utils/date-wrapper.js index 4cf4fd31..80ff96e9 100644 --- a/lib/utils/date-wrapper.js +++ b/lib/utils/date-wrapper.js @@ -13,10 +13,10 @@ const DATE_OIDS = Object.freeze({ * @param {*} originalQuery * @param {*} fields */ -function wrapDates(originalQuery, fields) { +function wrapDates (originalQuery, fields) { return ` SELECT - ${fields.map(field => _isDateType(field) ? _castColumnToEpoch(field.name) : `"${field.name}"`).join(',')} + ${fields.map(field => _isDateType(field) ? _castColumnToEpoch(field.name) : `"${field.name}"`).join(',')} FROM (${originalQuery}) _cdb_epoch_transformation `; } @@ -24,20 +24,20 @@ function wrapDates(originalQuery, fields) { /** * @param {object} field */ -function _isDateType(field) { - return DATE_OIDS.hasOwnProperty(field.dataTypeID); +function _isDateType (field) { + return Object.prototype.hasOwnProperty.call(DATE_OIDS, field.dataTypeID); } /** * Return a sql query to transform a date column into a unix epoch * @param {string} column - The name of the date column */ -function _castColumnToEpoch(columnName) { +function _castColumnToEpoch (columnName) { return `date_part('epoch', "${columnName}") as "${columnName}"`; } -function getColumnsWithWrappedDates(query) { - if(!query){ +function getColumnsWithWrappedDates (query) { + if (!query) { return; } if (!query.match(/\b_cdb_epoch_transformation\b/)) { diff --git a/lib/utils/icu-data-env-setter.js b/lib/utils/icu-data-env-setter.js index a4678821..64fee1a8 100644 --- a/lib/utils/icu-data-env-setter.js +++ b/lib/utils/icu-data-env-setter.js @@ -5,7 +5,7 @@ const path = require('path'); // See https://github.com/CartoDB/support/issues/984 // CartoCSS properties text-wrap-width/text-wrap-character not working -function setICUEnvVariable() { +function setICUEnvVariable () { if (process.env.ICU_DATA === undefined) { const regexedPath = '/node_modules/mapnik/lib/binding/*/share/mapnik/icu/'; const directory = glob.sync(path.join(__dirname, '../../..', regexedPath)); diff --git a/lib/utils/json-replacer.js b/lib/utils/json-replacer.js index 7ec959b3..a2a95c63 100644 --- a/lib/utils/json-replacer.js +++ b/lib/utils/json-replacer.js @@ -4,7 +4,7 @@ module.exports = function jsonReplacerFactory () { // Fix: https://github.com/CartoDB/Windshaft-cartodb/issues/705 // See: http://expressjs.com/en/4x/api.html#app.set return function jsonReplacer (key, value) { - if (value !== value) { + if (value !== value) { // eslint-disable-line no-self-compare return 'NaN'; } diff --git a/lib/utils/layergroup-metadata.js b/lib/utils/layergroup-metadata.js index 1a62f701..de2e2099 100644 --- a/lib/utils/layergroup-metadata.js +++ b/lib/utils/layergroup-metadata.js @@ -78,7 +78,7 @@ module.exports = class LayergroupMetadata { addAggregationContextMetadata (layergroup, mapConfig, context) { if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) { - layergroup.metadata.layers = layergroup.metadata.layers.map(function(layer, layerIndex) { + layergroup.metadata.layers = layergroup.metadata.layers.map(function (layer, layerIndex) { if (context.aggregation && Array.isArray(context.aggregation.layers)) { layer.meta.aggregation = context.aggregation.layers[layerIndex]; } @@ -90,7 +90,7 @@ module.exports = class LayergroupMetadata { addTileJsonMetadata (layergroup, user, mapconfig, userApiKey = null) { const isVectorOnlyMapConfig = mapconfig.isVectorOnlyMapConfig(); let hasMapnikLayers = false; - const apiKey = userApiKey ? '?' + querystring.stringify({api_key: userApiKey}) : ''; + const apiKey = userApiKey ? '?' + querystring.stringify({ api_key: userApiKey }) : ''; layergroup.metadata.layers.forEach((layerMetadata, index) => { const layerId = mapconfig.getLayerId(index); @@ -145,7 +145,7 @@ module.exports = class LayergroupMetadata { layergroup.metadata.url = url; } - _getTilejson(tiles, grids) { + _getTilejson (tiles, grids) { const tilejson = { tilejson: '2.2.0', tiles: tiles.https || tiles.http @@ -158,13 +158,13 @@ module.exports = class LayergroupMetadata { return tilejson; } - _getTemplateUrl(url) { + _getTemplateUrl (url) { return url.https || url.http; } - addTurboCartoContextMetadata(layergroup, mapConfig, context) { + addTurboCartoContextMetadata (layergroup, mapConfig, context) { if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) { - layergroup.metadata.layers = layergroup.metadata.layers.map(function(layer, layerIndex) { + layergroup.metadata.layers = layergroup.metadata.layers.map(function (layer, layerIndex) { if (context.turboCarto && Array.isArray(context.turboCarto.layers)) { layer.meta.cartocss_meta = context.turboCarto.layers[layerIndex]; } @@ -175,7 +175,7 @@ module.exports = class LayergroupMetadata { addDateWrappingMetadata (layergroup, mapConfig) { if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) { - layergroup.metadata.layers = layergroup.metadata.layers.map(function(layer, layerIndex) { + layergroup.metadata.layers = layergroup.metadata.layers.map(function (layer, layerIndex) { const mapConfigLayer = mapConfig.layers[layerIndex]; const layerOptions = mapConfigLayer.options; if (layerOptions.dates_as_numbers && layerOptions.sql) { @@ -188,5 +188,4 @@ module.exports = class LayergroupMetadata { }); } } - }; diff --git a/lib/utils/overviews-query-rewriter.js b/lib/utils/overviews-query-rewriter.js index 82164d6d..01dc2cae 100644 --- a/lib/utils/overviews-query-rewriter.js +++ b/lib/utils/overviews-query-rewriter.js @@ -11,20 +11,19 @@ var FILTER_MIN_ROWS = 65536; // Maximum filtered fraction to not apply overviews var FILTER_MAX_FRACTION = 0.2; -function apply_filters_to_query(query, filters, bbox_filter) { - if ( filters && !_.isEmpty(filters)) { +function applyFiltersToQuery (query, filters, bboxFilter) { + if (filters && !_.isEmpty(filters)) { var analysisFilter = new AnalysisFilter(filters); query = analysisFilter.sql(query); } - if ( bbox_filter ) { - var bboxFilter = new BBoxFilter(bbox_filter.options, bbox_filter.params); - query = bboxFilter.sql(query); + if (bboxFilter) { + var filter = new BBoxFilter(bboxFilter.options, bboxFilter.params); + query = filter.sql(query); } return query; } -function OverviewsQueryRewriter(options) { - +function OverviewsQueryRewriter (options) { this.options = options; } @@ -37,77 +36,77 @@ module.exports = OverviewsQueryRewriter; // Build UNION expression to replace table, using overviews metadata // overviews metadata: { 1: 'table_ov1', ... } // assume table and overview names include schema if necessary and are quoted as needed -function overviews_view_for_table(table, overviews_metadata, indent) { - var condition, i, len, ov_table, overview_layers, selects, z_hi, z_lo; - var parsed_table = TableNameParser.parse(table); +function overviewsViewForTable (table, overviewsMetadata, indent) { + var condition, i, len, ovTable, overviewLayers, selects, zHi, zLo; + var parsedTable = TableNameParser.parse(table); - var sorted_overviews = []; // [[1, 'table_ov1'], ...] + var sortedOverviews = []; // [[1, 'table_ov1'], ...] indent = indent || ' '; - for (var z in overviews_metadata) { - if (overviews_metadata.hasOwnProperty(z) && z !== 'schema') { - sorted_overviews.push([z, overviews_metadata[z].table]); + for (var z in overviewsMetadata) { + if (Object.prototype.hasOwnProperty.call(overviewsMetadata, z) && z !== 'schema') { + sortedOverviews.push([z, overviewsMetadata[z].table]); } } - sorted_overviews.sort(function(a, b){ return a[0]-b[0]; }); + sortedOverviews.sort(function (a, b) { return a[0] - b[0]; }); - overview_layers = []; - z_lo = null; - for (i = 0, len = sorted_overviews.length; i < len; i++) { - z_hi = parseInt(sorted_overviews[i][0]); - ov_table = sorted_overviews[i][1]; - overview_layers.push([overview_z_condition(z_lo, z_hi), ov_table]); - z_lo = z_hi; + overviewLayers = []; + zLo = null; + for (i = 0, len = sortedOverviews.length; i < len; i++) { + zHi = parseInt(sortedOverviews[i][0]); + ovTable = sortedOverviews[i][1]; + overviewLayers.push([overviewZCondition(zLo, zHi), ovTable]); + zLo = zHi; } - overview_layers.push(["_vovw_z > " + z_lo, table]); + overviewLayers.push(['_vovw_z > ' + zLo, table]); - selects = overview_layers.map(function(condition_table) { - condition = condition_table[0]; - ov_table = TableNameParser.parse(condition_table[1]); - ov_table.schema = ov_table.schema || parsed_table.schema; - var ov_identifier = TableNameParser.table_identifier(ov_table); - return indent + "SELECT * FROM " + ov_identifier + ", _vovw_scale WHERE " + condition; + selects = overviewLayers.map(function (conditionTable) { + condition = conditionTable[0]; + ovTable = TableNameParser.parse(conditionTable[1]); + ovTable.schema = ovTable.schema || parsedTable.schema; + var ovIdentifier = TableNameParser.table_identifier(ovTable); + return indent + 'SELECT * FROM ' + ovIdentifier + ', _vovw_scale WHERE ' + condition; }); - return selects.join("\n"+indent+"UNION ALL\n"); + return selects.join('\n' + indent + 'UNION ALL\n'); } -function overview_z_condition(z_lo, z_hi) { - if (z_lo !== null) { - if (z_lo === z_hi - 1) { - return "_vovw_z = " + z_hi; +function overviewZCondition (zLo, zHi) { + if (zLo !== null) { + if (zLo === zHi - 1) { + return '_vovw_z = ' + zHi; } else { - return "_vovw_z > " + z_lo + " AND _vovw_z <= " + z_hi; + return '_vovw_z > ' + zLo + ' AND _vovw_z <= ' + zHi; } } else { - if (z_hi === 0) { - return "_vovw_z = " + z_hi; + if (zHi === 0) { + return '_vovw_z = ' + zHi; } else { - return "_vovw_z <= " + z_hi; + return '_vovw_z <= ' + zHi; } } } // name to be used for the view of the table using overviews -function overviews_view_name(table) { - var parsed_table = TableNameParser.parse(table); - parsed_table.table = '_vovw_' + parsed_table.table; - parsed_table.schema = null; - return TableNameParser.table_identifier(parsed_table); +function overviewsViewName (table) { + var parsedTable = TableNameParser.parse(table); + parsedTable.table = '_vovw_' + parsedTable.table; + parsedTable.schema = null; + return TableNameParser.table_identifier(parsedTable); } // replace a table name in a query by anoter name -function replace_table_in_query(sql, old_table_name, replacement) { - var old_table = TableNameParser.parse(old_table_name); - var old_table_ident = TableNameParser.table_identifier(old_table); +function replaceTableInQuery (sql, oldTableName, replacement) { + var oldTable = TableNameParser.parse(oldTableName); + var oldTableIdent = TableNameParser.table_identifier(oldTable); // regular expression prefix (beginning) to match a table name - function pattern_prefix(schema, identifier) { - if ( schema ) { + function patternPrefix (schema, identifier) { + if (schema) { // to match a table name including schema prefix // name should not be part of another name, so we require // to start a at a word boundary - if ( identifier[0] !== '"' ) { + if (identifier[0] !== '"') { return '\\b'; } else { return ''; @@ -118,15 +117,15 @@ function replace_table_in_query(sql, old_table_name, replacement) { // nor be part of another name // since the pattern matches the first character of the table // it must be put back in the replacement text - replacement = '$01'+replacement; - return '([^\.a-z0-9_]|^)'; + replacement = '$01' + replacement; + return '([^\.a-z0-9_]|^)'; // eslint-disable-line no-useless-escape } } // regular expression suffix (ending) to match a table name - function pattern_suffix(identifier) { + function patternSuffix (identifier) { // name shouldn't be the prefix of a longer name - if ( identifier[identifier.length-1] !== '"' ) { + if (identifier[identifier.length - 1] !== '"') { return '\\b'; } else { return ''; @@ -134,24 +133,23 @@ function replace_table_in_query(sql, old_table_name, replacement) { } // regular expression to match a table name - var regexp = pattern_prefix(old_table.schema, old_table_ident) + - old_table_ident + - pattern_suffix(old_table_ident); + var regexp = patternPrefix(oldTable.schema, oldTableIdent) + + oldTableIdent + + patternSuffix(oldTableIdent); // replace all occurrences of the table pattern return sql.replace(new RegExp(regexp, 'g'), replacement); } - -function replace_table_in_query_with_schema(query, table, schema, replacement) { - if ( replacement ) { - query = replace_table_in_query(query, table, replacement); - var parsed_table = TableNameParser.parse(table); - if (!parsed_table.schema && schema) { +function replaceTableInQueryWithSchema (query, table, schema, replacement) { + if (replacement) { + query = replaceTableInQuery(query, table, replacement); + var parsedTable = TableNameParser.parse(table); + if (!parsedTable.schema && schema) { // replace also the qualified table name, if the table wasn't qualified - parsed_table.schema = schema; - table = TableNameParser.table_identifier(parsed_table); - query = replace_table_in_query(query, table, replacement); + parsedTable.schema = schema; + table = TableNameParser.table_identifier(parsedTable); + query = replaceTableInQuery(query, table, replacement); } } return query; @@ -159,20 +157,20 @@ function replace_table_in_query_with_schema(query, table, schema, replacement) { // Build query to use overviews for a variant zoom level (given by a expression to // be evaluated by the database server) -function overviews_query_with_zoom_expression(query, overviews, zoom_level_expression) { - var replaced_query = query; - var sql = "WITH\n _vovw_scale AS ( SELECT " + zoom_level_expression + " AS _vovw_z )"; +function overviewsQueryWithZoomExpression (query, overviews, zoomLevelExpression) { + var replacedQuery = query; + var sql = 'WITH\n _vovw_scale AS ( SELECT ' + zoomLevelExpression + ' AS _vovw_z )'; var replacement; - _.each(Object.keys(overviews), function(table) { - var table_overviews = overviews[table]; - var table_view = overviews_view_name(table); - var schema = table_overviews.schema; - replacement = "(\n" + overviews_view_for_table(table, table_overviews) + "\n ) AS " + table_view; - replaced_query = replace_table_in_query_with_schema(replaced_query, table, schema, replacement); + _.each(Object.keys(overviews), function (table) { + var tableOverviews = overviews[table]; + var tableView = overviewsViewName(table); + var schema = tableOverviews.schema; + replacement = '(\n' + overviewsViewForTable(table, tableOverviews) + '\n ) AS ' + tableView; + replacedQuery = replaceTableInQueryWithSchema(replacedQuery, table, schema, replacement); }); - if ( replaced_query !== query ) { - sql += "\n"; - sql += replaced_query; + if (replacedQuery !== query) { + sql += '\n'; + sql += replacedQuery; } else { sql = query; } @@ -180,38 +178,38 @@ function overviews_query_with_zoom_expression(query, overviews, zoom_level_expre } // Build query to use overviews for a specific zoom level value -function overviews_query_with_definite_zoom(query, overviews, zoom_level) { - var replaced_query = query; +function overviewsQueryWithDefiniteZoom (query, overviews, zoomLevel) { + var replacedQuery = query; var replacement; - _.each(Object.keys(overviews), function(table) { - var table_overviews = overviews[table]; - var schema = table_overviews.schema; - replacement = overview_table_for_zoom_level(table_overviews, zoom_level); - replaced_query = replace_table_in_query_with_schema(replaced_query, table, schema, replacement); + _.each(Object.keys(overviews), function (table) { + var tableOverviews = overviews[table]; + var schema = tableOverviews.schema; + replacement = overviewTableForZoomLevel(tableOverviews, zoomLevel); + replacedQuery = replaceTableInQueryWithSchema(replacedQuery, table, schema, replacement); }); - return replaced_query; + return replacedQuery; } -// Find a suitable overview table for a specific zoom_level -function overview_table_for_zoom_level(table_overviews, zoom_level) { - var overview_table; - if ( table_overviews ) { - overview_table = table_overviews[zoom_level]; - if ( !overview_table ) { - _.every(Object.keys(table_overviews).sort(function(x,y){ return x-y; }), function(overview_zoom) { - if ( +overview_zoom > +zoom_level ) { - overview_table = table_overviews[overview_zoom]; - return false; - } else { - return true; - } +// Find a suitable overview table for a specific zoomLevel +function overviewTableForZoomLevel (tableOverviews, zoomLevel) { + var overviewTable; + if (tableOverviews) { + overviewTable = tableOverviews[zoomLevel]; + if (!overviewTable) { + _.every(Object.keys(tableOverviews).sort(function (x, y) { return x - y; }), function (overviewZoom) { + if (+overviewZoom > +zoomLevel) { + overviewTable = tableOverviews[overviewZoom]; + return false; + } else { + return true; + } }); } } - if ( overview_table ) { - overview_table = overview_table.table; + if (overviewTable) { + overviewTable = overviewTable.table; } - return overview_table; + return overviewTable; } // Transform an SQL query so that it uses overviews. @@ -228,88 +226,87 @@ function overview_table_for_zoom_level(table_overviews, zoom_level) { // { // overviews: // overview tables metadata // { 'table-name': {1: { table: 'overview-table-1' }, ... }, ... }, -// zoom_level: ..., // optional zoom level +// zoomLevel: ..., // optional zoom level // filters: ..., // filters definition -// unfiltered_query: ..., // query without the filters -// bbox_filter: ... // bounding-box filter +// unfilteredQuery: ..., // query without the filters +// bboxFilter: ... // bounding-box filter // } -OverviewsQueryRewriter.prototype.query = function(query, data, options) { +OverviewsQueryRewriter.prototype.query = function (query, data, options) { options = options || {}; - data = data || {}; + data = data || {}; - var overviews = data.overviews; - var unfiltered_query = data.unfiltered_query; - var filters = data.filters; - var bbox_filter = data.bbox_filter; + var overviews = data.overviews; + var unfilteredQuery = data.unfiltered_query; + var filters = data.filters; + var bboxFilter = data.bbox_filter; - if ( !unfiltered_query ) { - unfiltered_query = query; + if (!unfilteredQuery) { + unfilteredQuery = query; } - if ( !should_use_overviews(unfiltered_query, data) ) { + if (!shouldUseOverviews(unfilteredQuery, data)) { return query; } - var rewritten_query; + var rewrittenQuery; - var zoom_level_expression = this.options.zoom_level; - var zoom_level = zoom_level_for_query(unfiltered_query, zoom_level_expression, options); + var zoomLevelExpression = this.options.zoom_level; + var zoomLevel = zoomLevelForQuery(unfilteredQuery, zoomLevelExpression, options); - rewritten_query = overviews_query(unfiltered_query, overviews, zoom_level, zoom_level_expression); + rewrittenQuery = overviewsQuery(unfilteredQuery, overviews, zoomLevel, zoomLevelExpression); - if ( rewritten_query === unfiltered_query ) { + if (rewrittenQuery === unfilteredQuery) { // could not or didn't need to alter the query - rewritten_query = query; + rewrittenQuery = query; } else { - rewritten_query = apply_filters_to_query(rewritten_query, filters, bbox_filter); + rewrittenQuery = applyFiltersToQuery(rewrittenQuery, filters, bboxFilter); } - return rewritten_query; + return rewrittenQuery; }; -function zoom_level_for_query(query, zoom_level_expression, options) { - var zoom_level = null; - if ( _.has(options, 'zoom_level') ) { - zoom_level = options.zoom_level || '0'; +function zoomLevelForQuery (query, zoomLevelExpression, options) { + var zoomLevel = null; + if (_.has(options, 'zoom_level')) { + zoomLevel = options.zoom_level || '0'; } - if ( zoom_level === null && !zoom_level_expression ) { - zoom_level = '0'; + if (zoomLevel === null && !zoomLevelExpression) { + zoomLevel = '0'; } - return zoom_level; + return zoomLevel; } -function overviews_query(query, overviews, zoom_level, zoom_level_expression) { - if ( zoom_level || zoom_level === '0' || zoom_level === 0 ) { - return overviews_query_with_definite_zoom(query, overviews, zoom_level); +function overviewsQuery (query, overviews, zoomLevel, zoomLevelExpression) { + if (zoomLevel || zoomLevel === '0' || zoomLevel === 0) { + return overviewsQueryWithDefiniteZoom(query, overviews, zoomLevel); } else { - return overviews_query_with_zoom_expression(query, overviews, zoom_level_expression); + return overviewsQueryWithZoomExpression(query, overviews, zoomLevelExpression); } } -function should_use_overviews(query, data) { +function shouldUseOverviews (query, data) { data = data || {}; - var use_overviews = data.overviews && is_supported_query(query); - if ( use_overviews && data.filters && data.filter_stats ) { - var filtered_rows = data.filter_stats.filtered_rows; - var unfiltered_rows = data.filter_stats.unfiltered_rows; - if ( unfiltered_rows && (filtered_rows || filtered_rows === 0) ) { - use_overviews = filtered_rows >= FILTER_MIN_ROWS || - (filtered_rows/unfiltered_rows) > FILTER_MAX_FRACTION; + var useOverviews = data.overviews && isSupportedQuery(query); + if (useOverviews && data.filters && data.filter_stats) { + var filteredRows = data.filter_stats.filtered_rows; + var unfilteredRows = data.filter_stats.unfiltered_rows; + if (unfilteredRows && (filteredRows || filteredRows === 0)) { + useOverviews = filteredRows >= FILTER_MIN_ROWS || + (filteredRows / unfilteredRows) > FILTER_MAX_FRACTION; } } - return use_overviews; + return useOverviews; } -function is_supported_query(sql) { - var basic_query = - /\s*SELECT\s+[\*a-z0-9_,\s]+?\s+FROM\s+((\"[^"]+\"|[a-z0-9_]+)\.)?(\"[^"]+\"|[a-z0-9_]+)\s*;?\s*/i; - var unwrapped_query = new RegExp("^"+basic_query.source+"$", 'i'); +function isSupportedQuery (sql) { + var basicQuery = /\s*SELECT\s+[\*a-z0-9_,\s]+?\s+FROM\s+((\"[^"]+\"|[a-z0-9_]+)\.)?(\"[^"]+\"|[a-z0-9_]+)\s*;?\s*/i; // eslint-disable-line no-useless-escape + var unwrappedQuery = new RegExp('^' + basicQuery.source + '$', 'i'); // queries for named maps are wrapped like this: - var wrapped_query = new RegExp( - "^\\s*SELECT\\s+\\*\\s+FROM\\s+\\(" + - basic_query.source + - "\\)\\s+AS\\s+wrapped_query\\s+WHERE\\s+\\d+=1\\s*$", + var wrappedQuery = new RegExp( + '^\\s*SELECT\\s+\\*\\s+FROM\\s+\\(' + + basicQuery.source + + '\\)\\s+AS\\s+wrapped_query\\s+WHERE\\s+\\d+=1\\s*$', 'i' ); - return !!(sql.match(unwrapped_query) || sql.match(wrapped_query)); + return !!(sql.match(unwrappedQuery) || sql.match(wrappedQuery)); } diff --git a/lib/utils/query-utils.js b/lib/utils/query-utils.js index bd5a4a76..02c0b28d 100644 --- a/lib/utils/query-utils.js +++ b/lib/utils/query-utils.js @@ -7,12 +7,12 @@ module.exports.getQueryActualRowCount = function (query) { return `select COUNT(*) AS rows FROM (${substituteDummyTokens(query)}) AS __cdb_query`; }; -function getQueryRowEstimation(query) { +function getQueryRowEstimation (query) { return 'select cartodb.CDB_EstimateRowCount($windshaft$' + substituteDummyTokens(query) + '$windshaft$) as rows'; } module.exports.getQueryRowEstimation = getQueryRowEstimation; -function getQueryGeometryType(query, geometryColumn) { +function getQueryGeometryType (query, geometryColumn) { return ` SELECT ST_GeometryType(${geometryColumn}) AS geom_type FROM (${substituteDummyTokens(query)}) AS __cdb_query @@ -37,33 +37,33 @@ module.exports.getAggregationMetadata = ctx => ` `; /** Cast the column to epoch */ -module.exports.columnCastTpl = function columnCastTpl(ctx) { +module.exports.columnCastTpl = function columnCastTpl (ctx) { return `date_part('epoch', ${ctx.column})`; }; /** If the column type is float, ignore any non numeric result (infinity / NaN) */ -module.exports.handleFloatColumn = function handleFloatColumn(ctx) { - return `${!ctx.isFloatColumn ? `${ctx.column}` : - `nullif(nullif(nullif(${ctx.column}, 'infinity'::float), '-infinity'::float), 'NaN'::float)` +module.exports.handleFloatColumn = function handleFloatColumn (ctx) { + return `${!ctx.isFloatColumn ? `${ctx.column}` + : `nullif(nullif(nullif(${ctx.column}, 'infinity'::float), '-infinity'::float), 'NaN'::float)` }`; }; /** Count NULL appearances */ -module.exports.countNULLs = function countNULLs(ctx) { +module.exports.countNULLs = function countNULLs (ctx) { return `sum(CASE WHEN (${ctx.column} IS NULL) THEN 1 ELSE 0 END)`; }; /** Count only infinity (positive and negative) appearances */ -module.exports.countInfinites = function countInfinites(ctx) { - return `${!ctx.isFloatColumn ? '0' : - `sum(CASE WHEN (${ctx.column} = 'infinity'::float OR ${ctx.column} = '-infinity'::float) THEN 1 ELSE 0 END)` +module.exports.countInfinites = function countInfinites (ctx) { + return `${!ctx.isFloatColumn ? '0' + : `sum(CASE WHEN (${ctx.column} = 'infinity'::float OR ${ctx.column} = '-infinity'::float) THEN 1 ELSE 0 END)` }`; }; -/** Count only NaNs appearances*/ -module.exports.countNaNs = function countNaNs(ctx) { - return `${!ctx.isFloatColumn ? '0' : - `sum(CASE WHEN (${ctx.column} = 'NaN'::float) THEN 1 ELSE 0 END)` +/** Count only NaNs appearances */ +module.exports.countNaNs = function countNaNs (ctx) { + return `${!ctx.isFloatColumn ? '0' + : `sum(CASE WHEN (${ctx.column} = 'NaN'::float) THEN 1 ELSE 0 END)` }`; }; @@ -78,7 +78,7 @@ module.exports.getQueryTopCategories = function (query, column, topN, includeNul `; }; -function columnSelector(columns) { +function columnSelector (columns) { if (!columns) { return '*'; } @@ -110,7 +110,7 @@ module.exports.getSampleFromIdsQuery = function (query, ids, columns, column = ' `; }; -function getQueryLimited(query, limit = 0) { +function getQueryLimited (query, limit = 0) { return ` SELECT * FROM (${substituteDummyTokens(query)}) AS __cdb_query @@ -118,20 +118,20 @@ function getQueryLimited(query, limit = 0) { `; } -function queryPromise(dbConnection, query) { +function queryPromise (dbConnection, query) { return new Promise((resolve, reject) => { - dbConnection.query(query, (err, res) => err ? reject(err) : resolve(res)); + dbConnection.query(query, (err, res) => err ? reject(err) : resolve(res)); }); } -function substituteDummyTokens(sql) { +function substituteDummyTokens (sql) { return SubstitutionTokens.replace(sql); } -function substituteTokensForZoom(sql, zoom) { - const extent = new WebMercatorHelper().getExtent({ x : 0, y : 0, z : 0 }); +function substituteTokensForZoom (sql, zoom) { + const extent = new WebMercatorHelper().getExtent({ x: 0, y: 0, z: 0 }); const bbox = `ST_MakeEnvelope(${extent.xmin}, ${extent.ymin}, ${extent.xmax}, ${extent.ymax}, 3857)`; - return SubstitutionTokens.replaceXYZ(sql, { z : zoom, bbox: bbox }); + return SubstitutionTokens.replaceXYZ(sql, { z: zoom, bbox: bbox }); } module.exports.queryPromise = queryPromise; diff --git a/lib/utils/substitution-tokens.js b/lib/utils/substitution-tokens.js index b6bd3cf4..772a9c73 100644 --- a/lib/utils/substitution-tokens.js +++ b/lib/utils/substitution-tokens.js @@ -8,18 +8,18 @@ var SUBSTITUTION_TOKENS = { }; var SubstitutionTokens = { - tokens: function(sql) { - return Object.keys(SUBSTITUTION_TOKENS).filter(function(tokenName) { + tokens: function (sql) { + return Object.keys(SUBSTITUTION_TOKENS).filter(function (tokenName) { return !!sql.match(SUBSTITUTION_TOKENS[tokenName]); }); }, - hasTokens: function(sql) { + hasTokens: function (sql) { return this.tokens(sql).length > 0; }, - replace: function(sql, replaceValues) { - Object.keys(replaceValues).forEach(function(token) { + replace: function (sql, replaceValues) { + Object.keys(replaceValues).forEach(function (token) { if (SUBSTITUTION_TOKENS[token]) { sql = sql.replace(SUBSTITUTION_TOKENS[token], replaceValues[token]); } diff --git a/lib/utils/table-name-parser.js b/lib/utils/table-name-parser.js index f2550ad6..db9ad72d 100644 --- a/lib/utils/table-name-parser.js +++ b/lib/utils/table-name-parser.js @@ -1,100 +1,98 @@ 'use strict'; // Quote an PostgreSQL identifier if ncecessary -function quote_identifier_if_needed(txt) { - if ( txt && !txt.match(/^[a-z_][a-z_0-9]*$/)) { - return '"' + txt.replace(/\"/g, '""') + '"'; +function quoteIdentifierIfNeeded (txt) { + if (txt && !txt.match(/^[a-z_][a-z_0-9]*$/)) { + return '"' + txt.replace(/"/g, '""') + '"'; } else { return txt; } } // Parse PostgreSQL table name (possibly quoted and with optional schema).+ -// Returns { schema: 'schema_name', table: 'table_name' } -function parse_table_name(table) { - - function split_as_quoted_parts(table_name) { - // parse table into 'parts' that may be quoted, each part - // in the parts array being an object { part: 'text', quoted: false/true } - var parts = []; - var splitted = table_name.split(/\"/); - for (var i=0; i 0 && i < splitted.length-1 ) { - i++; - parts[parts.length - 1].part += '"' + splitted[i]; - } - } - else { - var is_quoted = (i > 0 && splitted[i-1] === '') || - (i < splitted.length - 1 && splitted[i+1] === ''); - parts.push({ part: splitted[i], quoted: is_quoted }); - } - } - return parts; +// Returns { schema: 'schema_name', table: 'tableName' } +function parseTableName (table) { + function splitAsQuotedParts (tableName) { + // parse table into 'parts' that may be quoted, each part + // in the parts array being an object { part: 'text', quoted: false/true } + var parts = []; + var splitted = tableName.split(/"/); + for (var i = 0; i < splitted.length; i++) { + if (splitted[i] === '') { + if (parts.length > 0 && i < splitted.length - 1) { + i++; + parts[parts.length - 1].part += '"' + splitted[i]; + } + } else { + var isQuoted = (i > 0 && splitted[i - 1] === '') || + (i < splitted.length - 1 && splitted[i + 1] === ''); + parts.push({ part: splitted[i], quoted: isQuoted }); + } + } + return parts; } - var parts = split_as_quoted_parts(table); + var parts = splitAsQuotedParts(table); - function split_single_part(part) { - var schema_part = null; - var table_part = null; - if ( part.quoted ) { - table_part = part.part; + function splitSinglePart (part) { + var schemaPart = null; + var tablePart = null; + if (part.quoted) { + tablePart = part.part; } else { var parts = part.part.split('.'); - if ( parts.length === 1 ) { - schema_part = null; - table_part = parts[0]; - } else if ( parts.length === 2 ) { - schema_part = parts[0]; - table_part = parts[1]; + if (parts.length === 1) { + schemaPart = null; + tablePart = parts[0]; + } else if (parts.length === 2) { + schemaPart = parts[0]; + tablePart = parts[1]; } // else invalid table name } return { - schema: schema_part, - table: table_part + schema: schemaPart, + table: tablePart }; } - function split_two_parts(part1, part2) { - var schema_part = null; - var table_part = null; - if ( part1.quoted && !part2.quoted ) { - if ( part2.part[0] === '.' ) { - schema_part = part1.part; - table_part = part2.part.slice(1); + function splitTwoParts (part1, part2) { + var schemaPart = null; + var tablePart = null; + if (part1.quoted && !part2.quoted) { + if (part2.part[0] === '.') { + schemaPart = part1.part; + tablePart = part2.part.slice(1); } // else invalid table name (missing dot) - } else if ( !part1.quoted && part2.quoted ) { - if ( part1.part[part1.part.length - 1] === '.' ) { - schema_part = part1.part.slice(0, -1); - table_part = part2.part; + } else if (!part1.quoted && part2.quoted) { + if (part1.part[part1.part.length - 1] === '.') { + schemaPart = part1.part.slice(0, -1); + tablePart = part2.part; } // else invalid table name (missing dot) } // else invalid table name (missing dot) return { - schema: schema_part, - table: table_part + schema: schemaPart, + table: tablePart }; } - if ( parts.length === 1 ) { - return split_single_part(parts[0]); - } else if ( parts.length === 2 ) { - return split_two_parts(parts[0], parts[1]); - } else if ( parts.length === 3 && parts[1].part === '.' ) { + if (parts.length === 1) { + return splitSinglePart(parts[0]); + } else if (parts.length === 2) { + return splitTwoParts(parts[0], parts[1]); + } else if (parts.length === 3 && parts[1].part === '.') { return { schema: parts[0].part, - table: parts[2].part + table: parts[2].part }; } // else invalid table name } -function table_identifier(parsed_name) { - if ( parsed_name && parsed_name.table ) { - if ( parsed_name.schema ) { - return quote_identifier_if_needed(parsed_name.schema) + '.' + quote_identifier_if_needed(parsed_name.table); +function tableIdentifier (parsedName) { + if (parsedName && parsedName.table) { + if (parsedName.schema) { + return quoteIdentifierIfNeeded(parsedName.schema) + '.' + quoteIdentifierIfNeeded(parsedName.table); } else { - return quote_identifier_if_needed(parsed_name.table); + return quoteIdentifierIfNeeded(parsedName.table); } } else { return null; @@ -102,7 +100,7 @@ function table_identifier(parsed_name) { } module.exports = { - parse: parse_table_name, - quote: quote_identifier_if_needed, - table_identifier: table_identifier + parse: parseTableName, + quote: quoteIdentifierIfNeeded, + table_identifier: tableIdentifier }; diff --git a/package-lock.json b/package-lock.json index 80265391..e27deb70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,63 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "@carto/cartonik": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@carto/cartonik/-/cartonik-0.7.0.tgz", @@ -61,6 +118,18 @@ "negotiator": "0.6.2" } }, + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true + }, "ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", @@ -79,6 +148,12 @@ "dev": true, "optional": true }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -145,6 +220,16 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -164,6 +249,12 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -284,6 +375,12 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", @@ -489,6 +586,12 @@ } } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -505,16 +608,21 @@ "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-1.1.1.tgz", "integrity": "sha1-m7lDSVkzbs51cAqq3+7ccYBtjAU=" }, - "cli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "exit": "0.1.2", - "glob": "^7.1.1" + "restore-cursor": "^2.0.0" } }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -535,6 +643,21 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, "colorbrewer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/colorbrewer/-/colorbrewer-1.0.0.tgz", @@ -560,20 +683,17 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } - }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -640,12 +760,6 @@ "assert-plus": "^1.0.0" } }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -698,6 +812,15 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -729,47 +852,13 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - } - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, - "domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "esutils": "^2.0.2" } }, "dot": { @@ -805,17 +894,17 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, - "entities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", - "dev": true - }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -824,6 +913,35 @@ "is-arrayish": "^0.2.1" } }, + "es-abstract": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", + "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-promise": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.1.2.tgz", @@ -870,11 +988,467 @@ } } }, + "eslint": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.1.tgz", + "integrity": "sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.2", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "eslint-config-standard": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz", + "integrity": "sha512-EF6XkrrGVbvv8hL/kYa/m6vnvmUT+K82pJJc4JJVMM6+Qgqh0pnwprSxdduDLB9p/7bIxD+YV5O0wfb8lmcPbA==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", + "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-es": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz", + "integrity": "sha512-f6fceVtg27BR02EYnBhgWLFQfK6bN4Ll0nQFrBHOlCsAyxeZkn0NHns5O0YZOPrV1B3ramd6cgFwaoFLcSkwEQ==", + "dev": true, + "requires": { + "eslint-utils": "^1.4.2", + "regexpp": "^3.0.0" + }, + "dependencies": { + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", + "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.11.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz", + "integrity": "sha512-1CSyM/QCjs6PXaT18+zuAXsjXGIGo5Rw630rSKwokSs2jrYURQc4R5JZpoanNCqwNmepg+0eZ9L7YiRUJb8jiQ==", + "dev": true, + "requires": { + "eslint-plugin-es": "^2.0.0", + "eslint-utils": "^1.4.2", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "dev": true + }, + "eslint-plugin-standard": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz", + "integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==", + "dev": true + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, + "requires": { + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, "estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", @@ -906,12 +1480,6 @@ "strip-eof": "^1.0.0" } }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, "express": { "version": "4.16.3", "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", @@ -1030,6 +1598,28 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -1059,6 +1649,24 @@ "request": "^2.55.0" } }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -1102,6 +1710,48 @@ "pinkie-promise": "^2.0.0" } }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -1140,6 +1790,18 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -2032,6 +2694,21 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", @@ -2173,6 +2850,15 @@ "har-schema": "^2.0.0" } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -2186,6 +2872,12 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -2227,33 +2919,6 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==" }, - "htmlparser2": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", - "dev": true, - "requires": { - "domelementtype": "1", - "domhandler": "2.3", - "domutils": "1.5", - "entities": "1.0", - "readable-stream": "1.1" - }, - "dependencies": { - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - } - } - }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -2288,6 +2953,12 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, "ignore-walk": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", @@ -2296,6 +2967,22 @@ "minimatch": "^3.0.4" } }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2315,6 +3002,114 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", @@ -2330,6 +3125,24 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -2338,11 +3151,44 @@ "number-is-nan": "^1.0.0" } }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -2448,6 +3294,12 @@ "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=" }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -2462,30 +3314,6 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, - "jshint": { - "version": "2.9.7", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.7.tgz", - "integrity": "sha512-Q8XN38hGsVQhdlM+4gd1Xl7OB1VieSuCJf+fEJjpo59JH99bVJhXRXAh26qQ15wfdd1VPMuDWNeSWoNl53T4YA==", - "dev": true, - "requires": { - "cli": "~1.0.0", - "console-browserify": "1.1.x", - "exit": "0.1.x", - "htmlparser2": "3.8.x", - "lodash": "~4.17.10", - "minimatch": "~3.0.2", - "shelljs": "0.3.x", - "strip-json-comments": "1.0.x" - }, - "dependencies": { - "strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", - "dev": true - } - } - }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -2496,6 +3324,12 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -2798,6 +3632,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "mv": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", @@ -2814,6 +3654,12 @@ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "ncp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", @@ -2856,6 +3702,12 @@ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, "nock": { "version": "9.2.6", "resolved": "https://registry.npmjs.org/nock/-/nock-9.2.6.tgz", @@ -2986,6 +3838,30 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -3007,6 +3883,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -3096,6 +3981,15 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz", "integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc=" }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -3236,6 +4130,26 @@ "pinkie": "^2.0.0" } }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + } + } + }, "postcss": { "version": "5.0.19", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.0.19.tgz", @@ -3314,6 +4228,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "propagate": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz", @@ -3451,6 +4371,12 @@ "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "request": { "version": "2.87.0", "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", @@ -3496,6 +4422,22 @@ "path-parse": "^1.0.6" } }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "rimraf": { "version": "2.4.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", @@ -3520,6 +4462,24 @@ } } }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -3615,12 +4575,6 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, - "shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", - "dev": true - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -3646,6 +4600,34 @@ "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-0.9.2.tgz", "integrity": "sha1-PjXLEDCPx2ljqk7nJS5qbqENKOQ=" }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, "sntp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", @@ -3768,6 +4750,26 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -3812,6 +4814,76 @@ "has-flag": "^1.0.0" } }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "tar": { "version": "4.4.13", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", @@ -3838,11 +4910,26 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "torque.js": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/torque.js/-/torque.js-3.1.1.tgz", @@ -3878,6 +4965,12 @@ "punycode": "^1.4.1" } }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -3966,6 +5059,23 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3981,6 +5091,12 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -4079,6 +5195,15 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index d10dc853..d3643a4d 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,13 @@ "yargs": "11.1.0" }, "devDependencies": { + "eslint": "^6.5.1", + "eslint-config-standard": "^14.1.0", + "eslint-plugin-import": "^2.18.2", + "eslint-plugin-node": "^10.0.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.1", "istanbul": "0.4.5", - "jshint": "2.9.7", "mocha": "5.2.0", "moment": "2.22.1", "nock": "9.2.6", @@ -63,7 +68,8 @@ "strftime": "0.10.0" }, "scripts": { - "lint": "jshint lib test app.js", + "lint:fix": "eslint --fix app.js \"lib/**/*.js\" \"test/**/*.js\"", + "lint": "eslint app.js \"lib/**/*.js\" \"test/**/*.js\"", "preinstall": "make pre-install", "test": "make test-all", "update-internal-deps": "rm -rf node_modules && npm install", diff --git a/scripts/lzma2config.js b/scripts/lzma2config.js index 0d8347b8..184cc0d2 100644 --- a/scripts/lzma2config.js +++ b/scripts/lzma2config.js @@ -6,7 +6,7 @@ if (process.argv.length !== 3) { var LZMA = require('lzma').LZMA; var lzmaWorker = new LZMA(); var lzmaInput = decodeURIComponent(process.argv[2]); -var lzmaBuffer = new Buffer(lzmaInput, 'base64') +var lzmaBuffer = Buffer.from(lzmaInput, 'base64') .toString('binary') .split('') .map(function(c) { diff --git a/test/acceptance/aggregation-test.js b/test/acceptance/aggregation-test.js index e1975f8a..9888f696 100644 --- a/test/acceptance/aggregation-test.js +++ b/test/acceptance/aggregation-test.js @@ -24,7 +24,7 @@ const suites = [ // The point location is spanned over a given length, by default it is 0 so // all points have the same location, which can be used to test aggregation dimensions // the default point is in tile -function pointsWithTimeSQL(n, startTime, endTime, span = 0, x0 = 0.1, y0 = 0.1) { +function pointsWithTimeSQL (n, startTime, endTime, span = 0, x0 = 0.1, y0 = 0.1) { return ` WITH params AS ( SELECT @@ -51,7 +51,6 @@ function pointsWithTimeSQL(n, startTime, endTime, span = 0, x0 = 0.1, y0 = 0.1) } describe('aggregation', function () { - const POINTS_SQL_1 = ` select x + 4 as cartodb_id, @@ -112,15 +111,15 @@ describe('aggregation', function () { WITH hgrid AS ( SELECT CDB_RectangleGrid ( - ST_Expand(!bbox!, ${webmercator.getResolution({ z : 1 })} * 12), - ${webmercator.getResolution({ z : 1 })} * 12, - ${webmercator.getResolution({ z : 1 })} * 12 + ST_Expand(!bbox!, ${webmercator.getResolution({ z: 1 })} * 12), + ${webmercator.getResolution({ z: 1 })} * 12, + ${webmercator.getResolution({ z: 1 })} * 12 ) as cell ) SELECT hgrid.cell as the_geom_webmercator, count(1) as agg_value, - count(1) /power( 12 * ${webmercator.getResolution({ z : 1 })}, 2 ) as agg_value_density, + count(1) /power( 12 * ${webmercator.getResolution({ z: 1 })}, 2 ) as agg_value_density, row_number() over () as cartodb_id FROM hgrid, (<%= sql %>) i WHERE ST_Intersects(i.the_geom_webmercator, hgrid.cell) GROUP BY hgrid.cell @@ -207,7 +206,7 @@ describe('aggregation', function () { // const POINTS_SQL_GRID = (z, resolution) => ` WITH params AS ( - SELECT ${webmercator.getResolution({ z : z })}*${resolution} AS l -- cell size for Z, resolution + SELECT ${webmercator.getResolution({ z: z })}*${resolution} AS l -- cell size for Z, resolution ) SELECT row_number() OVER () AS cartodb_id, @@ -297,7 +296,7 @@ describe('aggregation', function () { this.layerStatsConfig = global.environment.enabledFeatures.layerStats; }); - after(function (){ + after(function () { serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; }); @@ -334,7 +333,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -362,10 +361,10 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); - body.metadata.layers.forEach(layer => assert.equal(layer.meta.aggregation, undefined)); + body.metadata.layers.forEach(layer => assert.strictEqual(layer.meta.aggregation, undefined)); done(); }); @@ -398,7 +397,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -449,82 +448,42 @@ describe('aggregation', function () { }); it('should fail if cartocss uses "value" column and it\'s not defined in the aggregation', - function (done) { - const response = { - status: 400, - headers: { - 'Content-Type': 'application/json; charset=utf-8' - } - }; - - this.mapConfig = createVectorMapConfig([ - { - type: 'cartodb', - options: { - sql: POINTS_SQL_2, - aggregation: { - threshold: 1, - placement: 'centroid' - }, - cartocss: '#layer { marker-width: [value]; }', - cartocss_version: '2.3.0' + function (done) { + const response = { + status: 400, + headers: { + 'Content-Type': 'application/json; charset=utf-8' } - } - ]); + }; - this.testClient = new TestClient(this.mapConfig); - this.testClient.getLayergroup({ response }, (err, body) => { - if (err) { - return done(err); - } + this.mapConfig = createVectorMapConfig([ + { + type: 'cartodb', + options: { + sql: POINTS_SQL_2, + aggregation: { + threshold: 1, + placement: 'centroid' + }, + cartocss: '#layer { marker-width: [value]; }', + cartocss_version: '2.3.0' + } + } + ]); - assert.ok(body.errors[0].match(/column "value" does not exist/)); + this.testClient = new TestClient(this.mapConfig); + this.testClient.getLayergroup({ response }, (err, body) => { + if (err) { + return done(err); + } - done(); + assert.ok(body.errors[0].match(/column "value" does not exist/)); + + done(); + }); }); - }); it('should provide all columns in the default aggregation ', - function (done) { - const response = { - status: 200, - headers: { - 'Content-Type': 'application/json; charset=utf-8' - } - }; - - this.mapConfig = createVectorMapConfig([ - { - type: 'cartodb', - options: { - sql: POINTS_SQL_2, - aggregation: { - threshold: 1 - }, - cartocss: '#layer { marker-width: [value]; }', - cartocss_version: '2.3.0' - } - } - ]); - - this.testClient = new TestClient(this.mapConfig); - this.testClient.getLayergroup({ response }, (err, body) => { - if (err) { - return done(err); - } - - - assert.equal(typeof body.metadata, 'object'); - assert.ok(Array.isArray(body.metadata.layers)); - - body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); - body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.png)); - done(); - }); - }); - - ['centroid', 'point-sample', 'point-grid'].forEach(placement => { - it('should provide all the requested columns in non-default aggregation: ' + placement, function (done) { const response = { status: 200, @@ -539,19 +498,9 @@ describe('aggregation', function () { options: { sql: POINTS_SQL_2, aggregation: { - placement: placement, - columns: { - 'first_column': { - aggregate_function: 'sum', - aggregated_column: 'value' - } - }, - dimensions: { - second_column: 'sqrt_value' - }, threshold: 1 }, - cartocss: '#layer { marker-width: [first_column]; line-width: [second_column]; }', + cartocss: '#layer { marker-width: [value]; }', cartocss_version: '2.3.0' } } @@ -563,8 +512,7 @@ describe('aggregation', function () { return done(err); } - - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -573,51 +521,100 @@ describe('aggregation', function () { }); }); - it('should provide only the requested columns in non-default aggregation: ' + placement, - function (done) { - this.mapConfig = createVectorMapConfig([ - { - type: 'cartodb', - options: { - sql: POINTS_SQL_2, - aggregation: { - placement: placement, - columns: { - 'first_column': { - aggregate_function: 'sum', - aggregated_column: 'value' - } + ['centroid', 'point-sample', 'point-grid'].forEach(placement => { + it('should provide all the requested columns in non-default aggregation: ' + placement, + function (done) { + const response = { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8' + } + }; + + this.mapConfig = createVectorMapConfig([ + { + type: 'cartodb', + options: { + sql: POINTS_SQL_2, + aggregation: { + placement: placement, + columns: { + first_column: { + aggregate_function: 'sum', + aggregated_column: 'value' + } + }, + dimensions: { + second_column: 'sqrt_value' + }, + threshold: 1 }, - dimensions: { - second_column: 'sqrt_value' - }, - threshold: 1 + cartocss: '#layer { marker-width: [first_column]; line-width: [second_column]; }', + cartocss_version: '2.3.0' } } - } - ]); + ]); - this.testClient = new TestClient(this.mapConfig); + this.testClient = new TestClient(this.mapConfig); + this.testClient.getLayergroup({ response }, (err, body) => { + if (err) { + return done(err); + } - this.testClient.getTile(0, 0, 0, { format: 'mvt' }, function (err, res, mvt) { - if (err) { - return done(err); - } + assert.strictEqual(typeof body.metadata, 'object'); + assert.ok(Array.isArray(body.metadata.layers)); - const geojsonTile = JSON.parse(mvt.toGeoJSONSync(0)); - let columns = new Set(); - geojsonTile.features.forEach(f => { - Object.keys(f.properties).forEach(p => columns.add(p)); + body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); + body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.png)); + done(); + }); + }); + + it('should provide only the requested columns in non-default aggregation: ' + placement, + function (done) { + this.mapConfig = createVectorMapConfig([ + { + type: 'cartodb', + options: { + sql: POINTS_SQL_2, + aggregation: { + placement: placement, + columns: { + first_column: { + aggregate_function: 'sum', + aggregated_column: 'value' + } + }, + dimensions: { + second_column: 'sqrt_value' + }, + threshold: 1 + } + } + } + ]); + + this.testClient = new TestClient(this.mapConfig); + + this.testClient.getTile(0, 0, 0, { format: 'mvt' }, function (err, res, mvt) { + if (err) { + return done(err); + } + + const geojsonTile = JSON.parse(mvt.toGeoJSONSync(0)); + let columns = new Set(); + geojsonTile.features.forEach(f => { + Object.keys(f.properties).forEach(p => columns.add(p)); + }); + columns = Array.from(columns); + const expectedColumns = [ + '_cdb_feature_count', 'cartodb_id', 'first_column', 'second_column' + ]; + assert.deepStrictEqual(columns.sort(), expectedColumns.sort()); + + done(); }); - columns = Array.from(columns); - const expected_columns = [ - '_cdb_feature_count', 'cartodb_id', 'first_column', 'second_column' - ]; - assert.deepEqual(columns.sort(), expected_columns.sort()); - - done(); }); - }); }); it('should skip aggregation to create a layergroup with aggregation defined already', function (done) { @@ -647,10 +644,10 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); - body.metadata.layers.forEach(layer => assert.equal(layer.meta.aggregation, undefined)); + body.metadata.layers.forEach(layer => assert.strictEqual(layer.meta.aggregation, undefined)); done(); }); @@ -686,11 +683,11 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); - assert.equal(body.metadata.layers[0].meta.aggregation.mvt, true); - assert.equal(body.metadata.layers[1].meta.aggregation.mvt, false); + assert.strictEqual(body.metadata.layers[0].meta.aggregation.mvt, true); + assert.strictEqual(body.metadata.layers[1].meta.aggregation.mvt, false); done(); }); @@ -716,11 +713,11 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); - assert.equal(body.metadata.layers[0].meta.aggregation.mvt, true); - assert.equal(body.metadata.layers[0].meta.aggregation.png, true); + assert.strictEqual(body.metadata.layers[0].meta.aggregation.mvt, true); + assert.strictEqual(body.metadata.layers[0].meta.aggregation.png, true); done(); }); @@ -746,11 +743,11 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); - assert.equal(body.metadata.layers[0].meta.aggregation.mvt, false); - assert.equal(body.metadata.layers[0].meta.aggregation.png, false); + assert.strictEqual(body.metadata.layers[0].meta.aggregation.mvt, false); + assert.strictEqual(body.metadata.layers[0].meta.aggregation.png, false); done(); }); @@ -782,12 +779,12 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { + assert.deepStrictEqual(body, { errors: [ "Invalid value for 'aggregation' query param: wadus." + " Valid ones are 'true' or 'false'" ], - errors_with_context:[{ + errors_with_context: [{ type: 'unknown', message: "Invalid value for 'aggregation' query param: wadus." + " Valid ones are 'true' or 'false'" @@ -825,11 +822,11 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); - body.metadata.layers.forEach(layer =>{ - assert.deepEqual(layer.meta.aggregation, { png: false, mvt: false }); + body.metadata.layers.forEach(layer => { + assert.deepStrictEqual(layer.meta.aggregation, { png: false, mvt: false }); }); done(); @@ -863,12 +860,12 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { + assert.deepStrictEqual(body, { errors: [ 'Unsupported geometry type: ST_Polygon.' + ' Aggregation is available only for geometry type: ST_Point' ], - errors_with_context:[{ + errors_with_context: [{ type: 'layer', message: 'Unsupported geometry type: ST_Polygon.' + ' Aggregation is available only for geometry type: ST_Point', @@ -906,7 +903,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -943,38 +940,38 @@ describe('aggregation', function () { }); it('when dimensions is provided should return a tile returning the column used as dimensions', - function (done) { - this.mapConfig = createVectorMapConfig([ - { - type: 'cartodb', - options: { - sql: POINTS_SQL_1, - aggregation: { - threshold: 1, - dimensions: { - value: "value" + function (done) { + this.mapConfig = createVectorMapConfig([ + { + type: 'cartodb', + options: { + sql: POINTS_SQL_1, + aggregation: { + threshold: 1, + dimensions: { + value: 'value' + } } } } - } - ]); + ]); - this.testClient = new TestClient(this.mapConfig); - const options = { - format: 'mvt' - }; - this.testClient.getTile(0, 0, 0, options, (err, res, tile) => { - if (err) { - return done(err); - } + this.testClient = new TestClient(this.mapConfig); + const options = { + format: 'mvt' + }; + this.testClient.getTile(0, 0, 0, options, (err, res, tile) => { + if (err) { + return done(err); + } - const tileJSON = tile.toJSON(); + const tileJSON = tile.toJSON(); - tileJSON[0].features.forEach(feature => assert.equal(typeof feature.properties.value, 'number')); + tileJSON[0].features.forEach(feature => assert.strictEqual(typeof feature.properties.value, 'number')); - done(); + done(); + }); }); - }); it('time dimensions', function (done) { this.mapConfig = createVectorMapConfig([ @@ -1009,7 +1006,7 @@ describe('aggregation', function () { const tileJSON = tile.toJSON(); - tileJSON[0].features.forEach(feature => assert.equal(typeof feature.properties.dow, 'number')); + tileJSON[0].features.forEach(feature => assert.strictEqual(typeof feature.properties.dow, 'number')); done(); }); @@ -1024,7 +1021,7 @@ describe('aggregation', function () { sql: pointsWithTimeSQL(nPoints, '2000-01-01T00:00:00+00', '2019-12-31T23:59:59+00', 0), dates_as_numbers: true, aggregation: { - threshold: 1, + threshold: 1 } } } @@ -1041,7 +1038,7 @@ describe('aggregation', function () { const tileJSON = tile.toJSON(); // Everything's aggregated into a single feature because the only // dimension is space and all points are in the same place. - assert.deepEqual(tileJSON[0].features.map(f => f.properties._cdb_feature_count), [nPoints]); + assert.deepStrictEqual(tileJSON[0].features.map(f => f.properties._cdb_feature_count), [nPoints]); done(); }); }); @@ -1065,7 +1062,7 @@ describe('aggregation', function () { } } - }, + } } } ]); @@ -1081,9 +1078,9 @@ describe('aggregation', function () { const tileJSON = tile.toJSON(); // Now all features have same location, but the year is an additional dimension // with 20 different values, so we'll have an aggregated feature for each. - const expectedYears = Array.from({length: 20}, (_, k) => 2000 + k); // 2000 to 2019 + const expectedYears = Array.from({ length: 20 }, (_, k) => 2000 + k); // 2000 to 2019 const resultYears = tileJSON[0].features.map(f => f.properties.year).sort((a, b) => a - b); - assert.deepEqual(resultYears, expectedYears); + assert.deepStrictEqual(resultYears, expectedYears); done(); }); @@ -1109,7 +1106,7 @@ describe('aggregation', function () { } } - }, + } } } ]); @@ -1123,9 +1120,9 @@ describe('aggregation', function () { return done(err); } const tileJSON = tile.toJSON(); - assert.equal(tileJSON[0].features.length, 3); + assert.strictEqual(tileJSON[0].features.length, 3); const resultQuimesters = tileJSON[0].features.map(f => f.properties.month).sort((a, b) => a - b); - assert.deepEqual(resultQuimesters, [1, 2, 3]); + assert.deepStrictEqual(resultQuimesters, [1, 2, 3]); done(); }); @@ -1165,7 +1162,7 @@ describe('aggregation', function () { } const tileJSON = tile.toJSON(); const resultMonths = tileJSON[0].features.map(f => f.properties.month).sort((a, b) => a - b); - assert.deepEqual(resultMonths, [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]); + assert.deepStrictEqual(resultMonths, [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]); done(); }); @@ -1205,7 +1202,7 @@ describe('aggregation', function () { } const tileJSON = tile.toJSON(); // In UTC all times are in the same month 2018-01 - assert.equal(tileJSON[0].features.length, 1); + assert.strictEqual(tileJSON[0].features.length, 1); done(); }); @@ -1245,7 +1242,7 @@ describe('aggregation', function () { } const tileJSON = tile.toJSON(); // In UTC+2 some times are in a different month - assert.equal(tileJSON[0].features.length, 2); + assert.strictEqual(tileJSON[0].features.length, 2); done(); }); }); @@ -1276,20 +1273,24 @@ describe('aggregation', function () { ]); this.testClient = new TestClient(this.mapConfig); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ifError(err); const expectedDimensions = { dow: - { params: - { time: 'to_timestamp("date")', - timezone: 'utc', - units: 'dayOfWeek', - count: 1 }, - min: 4, - max: 7, - type: 'number' } + { + params: + { + time: 'to_timestamp("date")', + timezone: 'utc', + units: 'dayOfWeek', + count: 1 + }, + min: 4, + max: 7, + type: 'number' + } }; - assert.deepEqual(layergroup.metadata.layers[0].meta.stats.dimensions, expectedDimensions); + assert.deepStrictEqual(layergroup.metadata.layers[0].meta.stats.dimensions, expectedDimensions); done(); }); }); @@ -1317,7 +1318,7 @@ describe('aggregation', function () { ]); this.testClient = new TestClient(this.mapConfig); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ifError(err); assert(!layergroup.metadata.layers[0].meta.stats.dimensions); done(); @@ -1337,7 +1338,7 @@ describe('aggregation', function () { month: { column: 'date', group: { - units: 'month', + units: 'month' }, format: 'iso' } @@ -1358,8 +1359,8 @@ describe('aggregation', function () { } const tileJSON = tile.toJSON(); const resultMonths = tileJSON[0].features.map(f => f.properties.month).sort(); - assert.deepEqual(resultMonths, [ - '2018-01', '2018-02', '2018-03', '2018-04', '2018-05','2018-06', + assert.deepStrictEqual(resultMonths, [ + '2018-01', '2018-02', '2018-03', '2018-04', '2018-05', '2018-06', '2018-07', '2018-08', '2018-09', '2018-10', '2018-11', '2018-12' ]); done(); @@ -1382,7 +1383,7 @@ describe('aggregation', function () { units: 'month', timezone: '+7200' }, - format: 'iso', + format: 'iso' } } @@ -1401,7 +1402,7 @@ describe('aggregation', function () { } const tileJSON = tile.toJSON(); const resultMonths = tileJSON[0].features.map(f => f.properties.month).sort(); - assert.deepEqual(resultMonths, [ + assert.deepStrictEqual(resultMonths, [ '2018-01', '2018-02', '2018-03', '2018-04', '2018-05', '2018-06', '2018-07', '2018-08', '2018-09', '2018-10', '2018-11', '2018-12', '2019-01' @@ -1427,7 +1428,7 @@ describe('aggregation', function () { units: 'hour', timezone: '+7200' }, - format: 'iso', + format: 'iso' } } @@ -1446,49 +1447,49 @@ describe('aggregation', function () { } const tileJSON = tile.toJSON(); const resultHours = tileJSON[0].features.map(f => f.properties.hour).sort(); - assert.deepEqual(resultHours, [ - "2018-01-01T00", - "2018-01-01T01", - "2018-01-01T02", - "2018-01-01T03", - "2018-01-01T04", - "2018-01-01T05", - "2018-01-01T06", - "2018-01-01T07", - "2018-01-01T08", - "2018-01-01T09", - "2018-01-01T10", - "2018-01-01T11", - "2018-01-01T12", - "2018-01-01T13", - "2018-01-01T14", - "2018-01-01T15", - "2018-01-01T16", - "2018-01-01T17", - "2018-01-01T18", - "2018-01-01T19", - "2018-01-01T20", - "2018-01-01T21", - "2018-01-01T22", - "2018-01-01T23" + assert.deepStrictEqual(resultHours, [ + '2018-01-01T00', + '2018-01-01T01', + '2018-01-01T02', + '2018-01-01T03', + '2018-01-01T04', + '2018-01-01T05', + '2018-01-01T06', + '2018-01-01T07', + '2018-01-01T08', + '2018-01-01T09', + '2018-01-01T10', + '2018-01-01T11', + '2018-01-01T12', + '2018-01-01T13', + '2018-01-01T14', + '2018-01-01T15', + '2018-01-01T16', + '2018-01-01T17', + '2018-01-01T18', + '2018-01-01T19', + '2018-01-01T20', + '2018-01-01T21', + '2018-01-01T22', + '2018-01-01T23' ]); - tileJSON[0].features.forEach(f => assert.equal(f.properties._cdb_feature_count, 4)); + tileJSON[0].features.forEach(f => assert.strictEqual(f.properties._cdb_feature_count, 4)); done(); }); }); ['centroid', 'point-sample', 'point-grid'].forEach(placement => { - it(`dimensions should work for ${placement} placement`, function(done) { + it(`dimensions should work for ${placement} placement`, function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', options: { sql: POINTS_SQL_1, aggregation: { - placement: placement , + placement: placement, threshold: 1, dimensions: { - value: "value" + value: 'value' } } } @@ -1507,7 +1508,7 @@ describe('aggregation', function () { const tileJSON = tile.toJSON(); tileJSON[0].features.forEach( - feature => assert.equal(typeof feature.properties.value, 'number') + feature => assert.strictEqual(typeof feature.properties.value, 'number') ); done(); @@ -1516,17 +1517,17 @@ describe('aggregation', function () { }); ['centroid', 'point-sample', 'point-grid'].forEach(placement => { - it(`dimensions with alias should work for ${placement} placement`, function(done) { + it(`dimensions with alias should work for ${placement} placement`, function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', options: { sql: POINTS_SQL_1, aggregation: { - placement: placement , + placement: placement, threshold: 1, dimensions: { - value2: "value" + value2: 'value' } } } @@ -1545,7 +1546,7 @@ describe('aggregation', function () { const tileJSON = tile.toJSON(); tileJSON[0].features.forEach( - feature => assert.equal(typeof feature.properties.value2, 'number') + feature => assert.strictEqual(typeof feature.properties.value2, 'number') ); done(); @@ -1553,8 +1554,7 @@ describe('aggregation', function () { }); }); - - it(`dimensions should trigger non-default aggregation`, function(done) { + it('dimensions should trigger non-default aggregation', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -1563,7 +1563,7 @@ describe('aggregation', function () { aggregation: { threshold: 1, dimensions: { - value: "value" + value: 'value' } } } @@ -1582,17 +1582,17 @@ describe('aggregation', function () { const tileJSON = tile.toJSON(); tileJSON[0].features.forEach( - feature => assert.equal(typeof feature.properties.value, 'number') + feature => assert.strictEqual(typeof feature.properties.value, 'number') ); tileJSON[0].features.forEach( - feature => assert.equal(typeof feature.properties.sqrt_value, 'undefined') + feature => assert.strictEqual(typeof feature.properties.sqrt_value, 'undefined') ); done(); }); }); - it(`aggregation columns should trigger non-default aggregation`, function(done) { + it('aggregation columns should trigger non-default aggregation', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -1623,10 +1623,10 @@ describe('aggregation', function () { const tileJSON = tile.toJSON(); tileJSON[0].features.forEach( - feature => assert.equal(typeof feature.properties.value, 'number') + feature => assert.strictEqual(typeof feature.properties.value, 'number') ); tileJSON[0].features.forEach( - feature => assert.equal(typeof feature.properties.sqrt_value, 'undefined') + feature => assert.strictEqual(typeof feature.properties.sqrt_value, 'undefined') ); done(); @@ -1634,14 +1634,14 @@ describe('aggregation', function () { }); ['centroid', 'point-sample', 'point-grid'].forEach(placement => { - it(`aggregations with base column names should work for ${placement} placement`, function(done) { + it(`aggregations with base column names should work for ${placement} placement`, function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', options: { sql: POINTS_SQL_1, aggregation: { - placement: placement , + placement: placement, threshold: 1, columns: { value: { @@ -1666,7 +1666,7 @@ describe('aggregation', function () { const tileJSON = tile.toJSON(); tileJSON[0].features.forEach( - feature => assert.equal(typeof feature.properties.value, 'number') + feature => assert.strictEqual(typeof feature.properties.value, 'number') ); done(); @@ -1702,7 +1702,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -1744,7 +1744,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -1786,7 +1786,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -1828,7 +1828,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -1865,7 +1865,7 @@ describe('aggregation', function () { const feature = geojsonTile.features[0]; - assert.ok(feature.properties.hasOwnProperty('value'), 'Missing value property'); + assert.ok(Object.prototype.hasOwnProperty.call(feature.properties, 'value'), 'Missing value property'); done(); }); @@ -1879,7 +1879,7 @@ describe('aggregation', function () { options: { sql: POINTS_SQL_1, aggregation: { - resolution: 'wadus', + resolution: 'wadus' } } } @@ -1898,15 +1898,15 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { - errors: [ 'Invalid resolution, should be a number greather than 0' ], - errors_with_context:[{ + assert.deepStrictEqual(body, { + errors: ['Invalid resolution, should be a number greather than 0'], + errors_with_context: [{ type: 'layer', message: 'Invalid resolution, should be a number greather than 0', layer: { - "id": "wadus", - "index": 0, - "type": "mapnik" + id: 'wadus', + index: 0, + type: 'mapnik' } }] }); @@ -1921,7 +1921,7 @@ describe('aggregation', function () { options: { sql: POINTS_SQL_1, aggregation: { - placement: 'wadus', + placement: 'wadus' } } } @@ -1940,15 +1940,15 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { - errors: [ 'Invalid placement. Valid values: centroid, point-grid, point-sample'], - errors_with_context:[{ + assert.deepStrictEqual(body, { + errors: ['Invalid placement. Valid values: centroid, point-grid, point-sample'], + errors_with_context: [{ type: 'layer', message: 'Invalid placement. Valid values: centroid, point-grid, point-sample', layer: { - id: "layer0", + id: 'layer0', index: 0, - type: "mapnik", + type: 'mapnik' } }] }); @@ -1964,7 +1964,7 @@ describe('aggregation', function () { options: { sql: POINTS_SQL_1, aggregation: { - threshold: 'wadus', + threshold: 'wadus' } } } @@ -1983,15 +1983,15 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { - errors: [ 'Invalid threshold, should be a number greather than 0' ], - errors_with_context:[{ + assert.deepStrictEqual(body, { + errors: ['Invalid threshold, should be a number greather than 0'], + errors_with_context: [{ type: 'layer', message: 'Invalid threshold, should be a number greather than 0', layer: { - "id": "layer0", - "index": 0, - "type": "mapnik" + id: 'layer0', + index: 0, + type: 'mapnik' } }] }); @@ -2007,12 +2007,12 @@ describe('aggregation', function () { options: { sql: POINTS_SQL_1, aggregation: { - columns : { + columns: { '': { aggregate_function: 'count', - aggregated_column: 'value', + aggregated_column: 'value' } - }, + } } } } @@ -2031,15 +2031,15 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { - errors: [ 'Invalid column name, should be a non empty string' ], - errors_with_context:[{ + assert.deepStrictEqual(body, { + errors: ['Invalid column name, should be a non empty string'], + errors_with_context: [{ type: 'layer', message: 'Invalid column name, should be a non empty string', layer: { - "id": "layer0", - "index": 0, - "type": "mapnik" + id: 'layer0', + index: 0, + type: 'mapnik' } }] }); @@ -2055,12 +2055,12 @@ describe('aggregation', function () { options: { sql: POINTS_SQL_1, aggregation: { - columns : { - 'wadus_function': { + columns: { + wadus_function: { aggregate_function: 'wadus', - aggregated_column: 'value', + aggregated_column: 'value' } - }, + } } } } @@ -2079,17 +2079,17 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { - errors: [ 'Unsupported aggregation function wadus, ' + - 'valid ones: count, avg, sum, min, max, mode' ], - errors_with_context:[{ + assert.deepStrictEqual(body, { + errors: ['Unsupported aggregation function wadus, ' + + 'valid ones: count, avg, sum, min, max, mode'], + errors_with_context: [{ type: 'layer', message: 'Unsupported aggregation function wadus, ' + 'valid ones: count, avg, sum, min, max, mode', layer: { - "id": "layer0", - "index": 0, - "type": "mapnik" + id: 'layer0', + index: 0, + type: 'mapnik' } }] }); @@ -2105,12 +2105,12 @@ describe('aggregation', function () { options: { sql: POINTS_SQL_1, aggregation: { - columns : { - 'total_wadus': { + columns: { + total_wadus: { aggregate_function: 'sum', - aggregated_column: '', + aggregated_column: '' } - }, + } } } } @@ -2128,15 +2128,15 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { - errors: [ 'Invalid aggregated column, should be a non empty string' ], - errors_with_context:[{ + assert.deepStrictEqual(body, { + errors: ['Invalid aggregated column, should be a non empty string'], + errors_with_context: [{ type: 'layer', message: 'Invalid aggregated column, should be a non empty string', layer: { - "id": "layer0", - "index": 0, - "type": "mapnik" + id: 'layer0', + index: 0, + type: 'mapnik' } }] }); @@ -2145,102 +2145,101 @@ describe('aggregation', function () { }); }); - it('should skip aggregation w/o failing when is Vector Only MapConfig and layer has polygons', - function (done) { - this.mapConfig = createVectorMapConfig([ - { - type: 'cartodb', - options: { - sql: POLYGONS_SQL_1 - } - } - ]); - - this.testClient = new TestClient(this.mapConfig); - - this.testClient.getLayergroup((err, body) => { - if (err) { - return done(err); - } - - assert.equal(typeof body.metadata, 'object'); - assert.ok(Array.isArray(body.metadata.layers)); - - body.metadata.layers.forEach(layer => assert.ok(!layer.meta.aggregation.mvt)); - body.metadata.layers.forEach(layer => assert.ok(!layer.meta.aggregation.png)); - - const options = { - format: 'mvt' - }; - - this.testClient.getTile(0, 0, 0, options, (err, res, tile) => { - if (err) { - return done(err); - } - - const tileJSON = tile.toJSON(); - - assert.equal(tileJSON[0].features.length, 7); - - done(); - }); - }); - }); - - it('should skip aggregation for polygons (w/o failing) and aggregate when the layer has points', - function (done) { - this.mapConfig = createVectorMapConfig([ - { - type: 'cartodb', - options: { - sql: POLYGONS_SQL_1 - } - }, - { - type: 'cartodb', - options: { - sql: POINTS_SQL_1, - aggregation: { - threshold: 1 + function (done) { + this.mapConfig = createVectorMapConfig([ + { + type: 'cartodb', + options: { + sql: POLYGONS_SQL_1 } } - } - ]); + ]); - this.testClient = new TestClient(this.mapConfig); + this.testClient = new TestClient(this.mapConfig); - this.testClient.getLayergroup((err, body) => { - if (err) { - return done(err); - } - - assert.equal(typeof body.metadata, 'object'); - assert.ok(Array.isArray(body.metadata.layers)); - - assert.equal(body.metadata.layers[0].meta.aggregation.mvt, false); - assert.equal(body.metadata.layers[1].meta.aggregation.mvt, true); - - const options = { - format: 'mvt' - }; - - this.testClient.getTile(0, 0, 0, options, (err, res, tile) => { + this.testClient.getLayergroup((err, body) => { if (err) { return done(err); } - const tileJSON = tile.toJSON(); + assert.strictEqual(typeof body.metadata, 'object'); + assert.ok(Array.isArray(body.metadata.layers)); - assert.equal(tileJSON[0].features.length, 7); + body.metadata.layers.forEach(layer => assert.ok(!layer.meta.aggregation.mvt)); + body.metadata.layers.forEach(layer => assert.ok(!layer.meta.aggregation.png)); - done(); + const options = { + format: 'mvt' + }; + + this.testClient.getTile(0, 0, 0, options, (err, res, tile) => { + if (err) { + return done(err); + } + + const tileJSON = tile.toJSON(); + + assert.strictEqual(tileJSON[0].features.length, 7); + + done(); + }); + }); + }); + + it('should skip aggregation for polygons (w/o failing) and aggregate when the layer has points', + function (done) { + this.mapConfig = createVectorMapConfig([ + { + type: 'cartodb', + options: { + sql: POLYGONS_SQL_1 + } + }, + { + type: 'cartodb', + options: { + sql: POINTS_SQL_1, + aggregation: { + threshold: 1 + } + } + } + ]); + + this.testClient = new TestClient(this.mapConfig); + + this.testClient.getLayergroup((err, body) => { + if (err) { + return done(err); + } + + assert.strictEqual(typeof body.metadata, 'object'); + assert.ok(Array.isArray(body.metadata.layers)); + + assert.strictEqual(body.metadata.layers[0].meta.aggregation.mvt, false); + assert.strictEqual(body.metadata.layers[1].meta.aggregation.mvt, true); + + const options = { + format: 'mvt' + }; + + this.testClient.getTile(0, 0, 0, options, (err, res, tile) => { + if (err) { + return done(err); + } + + const tileJSON = tile.toJSON(); + + assert.strictEqual(tileJSON[0].features.length, 7); + + done(); + }); }); }); - }); ['centroid', 'point-sample', 'point-grid', 'default'].forEach(placement => { - it(`cartodb_id should be present in ${placement} aggregation`, function(done) { + it(`cartodb_id should be present in ${placement} aggregation`, function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -2263,7 +2262,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -2293,7 +2292,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -2330,7 +2329,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -2341,16 +2340,15 @@ describe('aggregation', function () { }); }); - ['centroid', 'point-sample', 'point-grid'].forEach(placement => { - it(`filters should work for ${placement} placement`, function(done) { + it(`filters should work for ${placement} placement`, function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', options: { sql: POINTS_SQL_1, aggregation: { - placement: placement , + placement: placement, threshold: 1, columns: { value: { @@ -2389,14 +2387,14 @@ describe('aggregation', function () { }); ['centroid', 'point-sample', 'point-grid'].forEach(placement => { - it(`multiple ORed filters should work for ${placement} placement`, function(done) { + it(`multiple ORed filters should work for ${placement} placement`, function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', options: { sql: POINTS_SQL_1, aggregation: { - placement: placement , + placement: placement, threshold: 1, columns: { value: { @@ -2436,14 +2434,14 @@ describe('aggregation', function () { }); ['centroid', 'point-sample', 'point-grid'].forEach(placement => { - it(`multiple ANDed filters should work for ${placement} placement`, function(done) { + it(`multiple ANDed filters should work for ${placement} placement`, function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', options: { sql: POINTS_SQL_2, aggregation: { - placement: placement , + placement: placement, threshold: 1, columns: { value: { @@ -2484,7 +2482,7 @@ describe('aggregation', function () { }); }); - it(`supports IN filters`, function(done) { + it('supports IN filters', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -2525,7 +2523,7 @@ describe('aggregation', function () { }); }); - it(`supports NOT IN filters`, function(done) { + it('supports NOT IN filters', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -2566,7 +2564,7 @@ describe('aggregation', function () { }); }); - it(`supports EQUAL filters`, function(done) { + it('supports EQUAL filters', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -2581,7 +2579,7 @@ describe('aggregation', function () { } }, filters: { - value: [{ equal: 1}, { equal: 3}] + value: [{ equal: 1 }, { equal: 3 }] } } } @@ -2607,7 +2605,7 @@ describe('aggregation', function () { }); }); - it(`supports NOT EQUAL filters`, function(done) { + it('supports NOT EQUAL filters', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -2648,7 +2646,7 @@ describe('aggregation', function () { }); }); - it(`supports BETWEEN filters`, function(done) { + it('supports BETWEEN filters', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -2692,7 +2690,7 @@ describe('aggregation', function () { }); }); - it(`supports RANGE filters`, function(done) { + it('supports RANGE filters', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -2736,7 +2734,7 @@ describe('aggregation', function () { }); }); - it(`invalid filters cause errors`, function(done) { + it('invalid filters cause errors', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -2773,15 +2771,15 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { - errors: [ 'Invalid filter parameter name: not_a_valid_parameter'], - errors_with_context:[{ + assert.deepStrictEqual(body, { + errors: ['Invalid filter parameter name: not_a_valid_parameter'], + errors_with_context: [{ type: 'layer', message: 'Invalid filter parameter name: not_a_valid_parameter', layer: { - id: "layer0", + id: 'layer0', index: 0, - type: "mapnik", + type: 'mapnik' } }] }); @@ -2790,7 +2788,7 @@ describe('aggregation', function () { }); }); - it(`filters on invalid columns cause errors`, function(done) { + it('filters on invalid columns cause errors', function (done) { this.mapConfig = createVectorMapConfig([ { type: 'cartodb', @@ -2827,15 +2825,15 @@ describe('aggregation', function () { return done(err); } - assert.deepEqual(body, { - errors: [ 'Invalid filtered column: value'], - errors_with_context:[{ + assert.deepStrictEqual(body, { + errors: ['Invalid filtered column: value'], + errors_with_context: [{ type: 'layer', message: 'Invalid filtered column: value', layer: { - id: "layer0", + id: 'layer0', index: 0, - type: "mapnik", + type: 'mapnik' } }] }); @@ -2848,7 +2846,7 @@ describe('aggregation', function () { it(`for ${placement} and no points between tiles has unique ids`, function (done) { this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 0 }, + buffersize: { mvt: 0 }, layers: [ { type: 'cartodb', @@ -2867,7 +2865,7 @@ describe('aggregation', function () { this.testClient = new TestClient(this.mapConfig); - this.testClient.getTile(1, 0, 1, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(1, 0, 1, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } @@ -2877,7 +2875,7 @@ describe('aggregation', function () { assert.ok(Array.isArray(tile1.features)); assert.ok(tile1.features.length > 0); - this.testClient.getTile(1, 1, 0, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(1, 1, 0, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } @@ -2891,17 +2889,16 @@ describe('aggregation', function () { const tile2Ids = tile2.features.map(f => f.properties.cartodb_id); const repeatedIds = tile1Ids.filter(id => tile2Ids.includes(id)); - assert.equal(repeatedIds.length, 0); + assert.strictEqual(repeatedIds.length, 0); done(); }); - }); }); it(`for ${placement} has unique ids save between tiles`, function (done) { this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 0 }, + buffersize: { mvt: 0 }, layers: [ { type: 'cartodb', @@ -2920,7 +2917,7 @@ describe('aggregation', function () { this.testClient = new TestClient(this.mapConfig); - this.testClient.getTile(1, 0, 1, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(1, 0, 1, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } @@ -2930,7 +2927,7 @@ describe('aggregation', function () { assert.ok(Array.isArray(tile1.features)); assert.ok(tile1.features.length > 0); - this.testClient.getTile(1, 1, 0, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(1, 1, 0, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } @@ -2951,22 +2948,21 @@ describe('aggregation', function () { const tile1Features = tile1.features.filter(f => f.properties.cartodb_id === id); const tile2Features = tile2.features.filter(f => f.properties.cartodb_id === id); // repetitions cannot occur inside a tile - assert.equal(tile1Features.length, 1); - assert.equal(tile2Features.length, 1); + assert.strictEqual(tile1Features.length, 1); + assert.strictEqual(tile2Features.length, 1); const feature1 = tile1Features[0]; const feature2 = tile2Features[0]; // features should be identical (geometry and properties) - assert.deepEqual(feature1.properties, feature2.properties); - assert.deepEqual(feature1.geometry, feature2.geometry); + assert.deepStrictEqual(feature1.properties, feature2.properties); + assert.deepStrictEqual(feature1.geometry, feature2.geometry); // and geometry should be on the border; // for the dataset and zoom 1, only point with cartodb_id=4 (0,0) - assert.equal(feature1.properties.cartodb_id, 4); - assert.equal(feature2.properties.cartodb_id, 4); + assert.strictEqual(feature1.properties.cartodb_id, 4); + assert.strictEqual(feature2.properties.cartodb_id, 4); }); } done(); }); - }); }); @@ -2976,7 +2972,7 @@ describe('aggregation', function () { const query = POINTS_SQL_GRID(z, resolution); this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 0 }, + buffersize: { mvt: 0 }, layers: [ { type: 'cartodb', @@ -2997,44 +2993,43 @@ describe('aggregation', function () { const c = Math.pow(2, z - 1) - 1; // center tile coordinates - this.testClient.getTile(z, c + 0, c + 0, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c + 0, c + 0, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile00 = JSON.parse(mvt.toGeoJSONSync(0)); - this.testClient.getTile(z, c + 0, c + 1, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c + 0, c + 1, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile01 = JSON.parse(mvt.toGeoJSONSync(0)); - this.testClient.getTile(z, c + 1, c + 0, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c + 1, c + 0, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile10 = JSON.parse(mvt.toGeoJSONSync(0)); - this.testClient.getTile(z, c + 1, c + 1, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c + 1, c + 1, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile11 = JSON.parse(mvt.toGeoJSONSync(0)); // There needs to be 13 points - const count_features = ((tile) => + const countFeatures = (tile) => tile.features.map(f => f.properties) - .map(f => f._cdb_feature_count) - .reduce((a,b) => a + b, 0)); + .map(f => f._cdb_feature_count) + .reduce((a, b) => a + b, 0); - const tile00Count = count_features(tile00); - const tile10Count = count_features(tile10); - const tile01Count = count_features(tile01); - const tile11Count = count_features(tile11); - assert.equal(13, tile00Count + tile10Count + tile01Count + tile11Count); + const tile00Count = countFeatures(tile00); + const tile10Count = countFeatures(tile10); + const tile01Count = countFeatures(tile01); + const tile11Count = countFeatures(tile11); + assert.strictEqual(13, tile00Count + tile10Count + tile01Count + tile11Count); done(); }); }); }); - }); }); @@ -3048,7 +3043,7 @@ describe('aggregation', function () { this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 1 }, + buffersize: { mvt: 1 }, layers: [ { type: 'cartodb', @@ -3069,22 +3064,22 @@ describe('aggregation', function () { const c = Math.pow(2, z - 1) - 1; // center tile coordinates - this.testClient.getTile(z, c, c, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c, c, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile00 = JSON.parse(mvt.toGeoJSONSync(0)); - this.testClient.getTile(z, c, c + 1, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c, c + 1, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile01 = JSON.parse(mvt.toGeoJSONSync(0)); - this.testClient.getTile(z, c + 1, c, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c + 1, c, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile10 = JSON.parse(mvt.toGeoJSONSync(0)); - this.testClient.getTile(z, c + 1, c + 1, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c + 1, c + 1, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } @@ -3107,21 +3102,19 @@ describe('aggregation', function () { const tile01Actual = tile01.features.map(f => f.properties); const tile11Actual = tile11.features.map(f => f.properties); const orderById = (a, b) => a.cartodb_id - b.cartodb_id; - assert.deepEqual(tile00Actual.sort(orderById), tile00Expected); - assert.deepEqual(tile10Actual.sort(orderById), tile10Expected); - assert.deepEqual(tile01Actual.sort(orderById), tile01Expected); - assert.deepEqual(tile11Actual.sort(orderById), tile11Expected); + assert.deepStrictEqual(tile00Actual.sort(orderById), tile00Expected); + assert.deepStrictEqual(tile10Actual.sort(orderById), tile10Expected); + assert.deepStrictEqual(tile01Actual.sort(orderById), tile01Expected); + assert.deepStrictEqual(tile11Actual.sort(orderById), tile11Expected); done(); }); }); }); - }); }); it(`for ${placement} includes complete cells in buffer`, function (done) { - // use buffersize coincident with resolution, the buffer should include neighbour cells const z = 2; const resolution = 1; @@ -3129,7 +3122,7 @@ describe('aggregation', function () { this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 1 }, + buffersize: { mvt: 1 }, layers: [ { type: 'cartodb', @@ -3150,22 +3143,22 @@ describe('aggregation', function () { const c = Math.pow(2, z - 1) - 1; // center tile coordinates - this.testClient.getTile(z, c, c, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c, c, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile00 = JSON.parse(mvt.toGeoJSONSync(0)); - this.testClient.getTile(z, c, c + 1, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c, c + 1, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile01 = JSON.parse(mvt.toGeoJSONSync(0)); - this.testClient.getTile(z, c + 1, c, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c + 1, c, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile10 = JSON.parse(mvt.toGeoJSONSync(0)); - this.testClient.getTile(z, c + 1, c + 1, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(z, c + 1, c + 1, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } @@ -3178,14 +3171,14 @@ describe('aggregation', function () { const tile01Actual = tile01.features.map(f => f.properties); const tile11Actual = tile11.features.map(f => f.properties); - const allFeatures = [... tile00Actual, ...tile10Actual, - ...tile01Actual, ...tile11Actual]; + const allFeatures = [...tile00Actual, ...tile10Actual, + ...tile01Actual, ...tile11Actual]; for (let i = 0; i < allFeatures.length; i++) { for (let j = i + 1; j < allFeatures.length; j++) { const c1 = allFeatures[i]; const c2 = allFeatures[j]; if (c1.cartodb_id === c2.cartodb_id) { - assert.equal(c1._cdb_feature_count, c2._cdb_feature_count); + assert.strictEqual(c1._cdb_feature_count, c2._cdb_feature_count); } } } @@ -3193,7 +3186,6 @@ describe('aggregation', function () { }); }); }); - }); }); @@ -3201,7 +3193,7 @@ describe('aggregation', function () { // this test will fail due to !bbox! lack of accuracy if strict cell filtering is in place this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 0 }, + buffersize: { mvt: 0 }, layers: [ { type: 'cartodb', @@ -3220,17 +3212,17 @@ describe('aggregation', function () { this.testClient = new TestClient(this.mapConfig); - this.testClient.getTile(20, 1000000, 1000000, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(20, 1000000, 1000000, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile = JSON.parse(mvt.toGeoJSONSync(0)); - assert.equal(tile.features.length, 1); - assert.equal(tile.features[0].properties._cdb_feature_count, 4); + assert.strictEqual(tile.features.length, 1); + assert.strictEqual(tile.features[0].properties._cdb_feature_count, 4); if (placement === 'point-grid') { // check geometry x = 18181005.874444414, y = -18181043.94366749 - const expectedPoint = [ 163.322754576802, -83.3823797469878 ]; - assert.deepEqual(tile.features[0].geometry.coordinates, expectedPoint); + const expectedPoint = [163.322754576802, -83.3823797469878]; + assert.deepStrictEqual(tile.features[0].geometry.coordinates, expectedPoint); } done(); }); @@ -3239,7 +3231,7 @@ describe('aggregation', function () { it(`for ${placement} points aggregated into correct cluster`, function (done) { this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 0 }, + buffersize: { mvt: 0 }, layers: [ { type: 'cartodb', @@ -3258,17 +3250,17 @@ describe('aggregation', function () { this.testClient = new TestClient(this.mapConfig); - this.testClient.getTile(20, 1000000, 1000000, { format: 'mvt' }, (err, res, mvt) => { + this.testClient.getTile(20, 1000000, 1000000, { format: 'mvt' }, (err, res, mvt) => { if (err) { return done(err); } const tile = JSON.parse(mvt.toGeoJSONSync(0)); - assert.equal(tile.features.length, 1); - assert.equal(tile.features[0].properties._cdb_feature_count, 4); + assert.strictEqual(tile.features.length, 1); + assert.strictEqual(tile.features[0].properties._cdb_feature_count, 4); if (placement === 'point-grid') { // check geometry x = 18181006.023735486, y = -18181043.794376418 - const expectedPoint = [ 163.322755917907, -83.3823795924354 ]; - assert.deepEqual(tile.features[0].geometry.coordinates, expectedPoint); + const expectedPoint = [163.322755917907, -83.3823795924354]; + assert.deepStrictEqual(tile.features[0].geometry.coordinates, expectedPoint); } done(); }); @@ -3280,7 +3272,7 @@ describe('aggregation', function () { global.environment.enabledFeatures.layerStats = true; this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 0 }, + buffersize: { mvt: 0 }, layers: [ { type: 'cartodb', @@ -3303,7 +3295,7 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); assert.ok(body.metadata.layers[0].meta.aggregation.mvt); assert.ok(body.metadata.layers[0].meta.stats.estimatedFeatureCount > 0); @@ -3316,7 +3308,7 @@ describe('aggregation', function () { global.environment.enabledFeatures.layerStats = true; this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 0 }, + buffersize: { mvt: 0 }, layers: [ { type: 'cartodb', @@ -3342,10 +3334,10 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); assert.ok(body.metadata.layers[0].meta.aggregation.mvt); - assert.equal(body.metadata.layers[0].meta.stats.aggrFeatureCount, 13); + assert.strictEqual(body.metadata.layers[0].meta.stats.aggrFeatureCount, 13); done(); }); @@ -3355,7 +3347,7 @@ describe('aggregation', function () { global.environment.enabledFeatures.layerStats = true; this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 0 }, + buffersize: { mvt: 0 }, layers: [ { type: 'cartodb', @@ -3381,10 +3373,10 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); assert.ok(body.metadata.layers[0].meta.aggregation.mvt); - assert.equal(body.metadata.layers[0].meta.stats.aggrFeatureCount, 7); + assert.strictEqual(body.metadata.layers[0].meta.stats.aggrFeatureCount, 7); done(); }); @@ -3394,7 +3386,7 @@ describe('aggregation', function () { global.environment.enabledFeatures.layerStats = true; this.mapConfig = { version: '1.6.0', - buffersize: { 'mvt': 0 }, + buffersize: { mvt: 0 }, layers: [ { type: 'cartodb', @@ -3420,16 +3412,15 @@ describe('aggregation', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); assert.ok(body.metadata.layers[0].meta.aggregation.mvt); - assert.equal(body.metadata.layers[0].meta.stats.featureCount, 14); + assert.strictEqual(body.metadata.layers[0].meta.stats.featureCount, 14); done(); }); }); }); - }); }); }); diff --git a/test/acceptance/analysis/analyses-controller-test.js b/test/acceptance/analysis/analyses-controller-test.js index 04aea78c..c91dc3a0 100644 --- a/test/acceptance/analysis/analyses-controller-test.js +++ b/test/acceptance/analysis/analyses-controller-test.js @@ -5,7 +5,6 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); - describe('analyses controller', function () { const mapConfig = { version: '1.5.0', @@ -52,7 +51,7 @@ describe('analyses controller', function () { }); it('should support jsonp responses', function (done) { - this.testClient.getAnalysesCatalog({ jsonp: 'jsonp_test' }, (err, result) => { + this.testClient.getAnalysesCatalog({ jsonp: 'jsonpTest' }, (err, result) => { if (err) { return done(err); } @@ -60,14 +59,13 @@ describe('analyses controller', function () { assert.ok(result); let didRunJsonCallback = false; - // jshint ignore:start - function jsonp_test(body) { + /* eslint-disable no-unused-vars, no-eval */ + function jsonpTest (body) { assert.ok(Array.isArray(body.catalog)); didRunJsonCallback = true; } - eval(result); - // jshint ignore:end + /* eslint-enable */ assert.ok(didRunJsonCallback); @@ -84,7 +82,7 @@ describe('analyses controller', function () { return done(err); } - assert.deepEqual(result.errors[0], 'Unauthorized'); + assert.deepStrictEqual(result.errors[0], 'Unauthorized'); this.testClient.apiKey = apiKey; done(); }); @@ -102,15 +100,14 @@ describe('analyses controller', function () { } assert.ok(Array.isArray(result.catalog)); - assert.ok(result.catalog.length >= 2); // buffer & source at least + assert.ok(result.catalog.length >= 2); // buffer & source at least result.catalog .filter(analysis => analysis.node_id === '0a215e1f3405381cf0ea6b3b0deb6fdcfdc2fcaa') - .forEach(analysis => assert.equal(analysis.type, 'buffer')); + .forEach(analysis => assert.strictEqual(analysis.type, 'buffer')); this.testClient.drain(done); }); - }); }); }); diff --git a/test/acceptance/analysis/analyses-filters-params-test.js b/test/acceptance/analysis/analyses-filters-params-test.js index 342fcb4d..b3f039ac 100644 --- a/test/acceptance/analysis/analyses-filters-params-test.js +++ b/test/acceptance/analysis/analyses-filters-params-test.js @@ -6,7 +6,6 @@ const assert = require('../../support/assert'); const TestClient = require('../../support/test-client'); describe('analysis-filters-params', () => { - const CARTOCSS = `#layer { marker-fill-opacity: 1; marker-line-color: white; @@ -23,13 +22,13 @@ describe('analysis-filters-params', () => { version: '1.6.0', layers: [ { - "type": "cartodb", - "options": { - "source": { - "id": "a1" + type: 'cartodb', + options: { + source: { + id: 'a1' }, - "cartocss": CARTOCSS, - "cartocss_version": "2.3.0" + cartocss: CARTOCSS, + cartocss_version: '2.3.0' } } ], @@ -55,10 +54,10 @@ describe('analysis-filters-params', () => { }, analyses: [ { - "id": "a1", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'a1', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } } ] @@ -77,8 +76,7 @@ describe('analysis-filters-params', () => { } }; - - it('should get a filtered histogram dataview with all filters', function(done) { + it('should get a filtered histogram dataview with all filters', function (done) { const testClient = new TestClient(mapConfig, 1234); const testParams = Object.assign({}, params, { own_filter: 1 @@ -87,14 +85,14 @@ describe('analysis-filters-params', () => { testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins_count, 6); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins_count, 6); testClient.drain(done); }); }); - it('should get a filtered histogram dataview with all filters except my own filter', function(done) { + it('should get a filtered histogram dataview with all filters except my own filter', function (done) { const testClient = new TestClient(mapConfig, 1234); const testParams = Object.assign({}, params, { own_filter: 0 @@ -103,14 +101,14 @@ describe('analysis-filters-params', () => { testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins_count, 24); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins_count, 24); testClient.drain(done); }); }); - it('should get a filtered histogram dataview without filters', function(done) { + it('should get a filtered histogram dataview without filters', function (done) { const testClient = new TestClient(mapConfig, 1234); const testParams = Object.assign({}, params, { no_filters: 1 @@ -119,8 +117,8 @@ describe('analysis-filters-params', () => { testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins_count, 48); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins_count, 48); testClient.drain(done); }); @@ -144,7 +142,8 @@ describe('analysis-filters-params', () => { }); testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => { - assert.deepEqual(dataview, expectedError); + assert.ifError(err); + assert.deepStrictEqual(dataview, expectedError); testClient.drain(done); }); diff --git a/test/acceptance/analysis/analyses-filters-test.js b/test/acceptance/analysis/analyses-filters-test.js index 5e8390e2..b06723bd 100644 --- a/test/acceptance/analysis/analyses-filters-test.js +++ b/test/acceptance/analysis/analyses-filters-test.js @@ -6,7 +6,6 @@ const assert = require('../../support/assert'); const TestClient = require('../../support/test-client'); describe('analysis-layers-dataviews', () => { - const CARTOCSS = `#layer { marker-fill-opacity: 1; marker-line-color: white; @@ -23,13 +22,13 @@ describe('analysis-layers-dataviews', () => { version: '1.6.0', layers: [ { - "type": "cartodb", - "options": { - "source": { - "id": "a1" + type: 'cartodb', + options: { + source: { + id: 'a1' }, - "cartocss": CARTOCSS, - "cartocss_version": "2.3.0" + cartocss: CARTOCSS, + cartocss_version: '2.3.0' } } ], @@ -46,22 +45,22 @@ describe('analysis-layers-dataviews', () => { }, analyses: [ { - "id": "a1", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'a1', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } } ] }; - it('should get a filtered histogram dataview', function(done) { + it('should get a filtered histogram dataview', function (done) { const testClient = new TestClient(mapConfig, 1234); const params = { filters: { analyses: { - 'a1': [ + a1: [ { type: 'range', column: 'pop_max', @@ -77,8 +76,8 @@ describe('analysis-layers-dataviews', () => { testClient.getDataview('pop_max_histogram', params, (err, dataview) => { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins_start, 2008000); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins_start, 2008000); testClient.drain(done); }); diff --git a/test/acceptance/analysis/analysis-layers-dataviews-test.js b/test/acceptance/analysis/analysis-layers-dataviews-test.js index 95436185..3f4a52d6 100644 --- a/test/acceptance/analysis/analysis-layers-dataviews-test.js +++ b/test/acceptance/analysis/analysis-layers-dataviews-test.js @@ -6,43 +6,41 @@ var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); var dot = require('dot'); -describe('analysis-layers-dataviews', function() { - +describe('analysis-layers-dataviews', function () { var multitypeStyleTemplate = dot.template([ "#points['mapnik::geometry_type'=1] {", - " marker-fill-opacity: {{=it._opacity}};", - " marker-line-color: #FFF;", - " marker-line-width: 0.5;", - " marker-line-opacity: {{=it._opacity}};", - " marker-placement: point;", - " marker-type: ellipse;", - " marker-width: 8;", - " marker-fill: {{=it._color}};", - " marker-allow-overlap: true;", - "}", + ' marker-fill-opacity: {{=it._opacity}};', + ' marker-line-color: #FFF;', + ' marker-line-width: 0.5;', + ' marker-line-opacity: {{=it._opacity}};', + ' marker-placement: point;', + ' marker-type: ellipse;', + ' marker-width: 8;', + ' marker-fill: {{=it._color}};', + ' marker-allow-overlap: true;', + '}', "#lines['mapnik::geometry_type'=2] {", - " line-color: {{=it._color}};", - " line-width: 2;", - " line-opacity: {{=it._opacity}};", - "}", + ' line-color: {{=it._color}};', + ' line-width: 2;', + ' line-opacity: {{=it._opacity}};', + '}', "#polygons['mapnik::geometry_type'=3] {", - " polygon-fill: {{=it._color}};", - " polygon-opacity: {{=it._opacity}};", - " line-color: #FFF;", - " line-width: 0.5;", - " line-opacity: {{=it._opacity}};", - "}" + ' polygon-fill: {{=it._color}};', + ' polygon-opacity: {{=it._opacity}};', + ' line-color: #FFF;', + ' line-width: 0.5;', + ' line-opacity: {{=it._opacity}};', + '}' ].join('\n')); - - function cartocss(color, opacity) { + function cartocss (color, opacity) { return multitypeStyleTemplate({ _color: color || '#F11810', _opacity: Number.isFinite(opacity) ? opacity : 1 }); } - function createMapConfig(layers, dataviews, analysis) { + function createMapConfig (layers, dataviews, analysis) { return { version: '1.5.0', layers: layers, @@ -56,13 +54,13 @@ describe('analysis-layers-dataviews', function() { var mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "2570e105-7b37-40d2-bdf4-1af889598745" + type: 'cartodb', + options: { + source: { + id: '2570e105-7b37-40d2-bdf4-1af889598745' }, - "cartocss": DEFAULT_MULTITYPE_STYLE, - "cartocss_version": "2.3.0" + cartocss: DEFAULT_MULTITYPE_STYLE, + cartocss_version: '2.3.0' } } ], @@ -79,29 +77,29 @@ describe('analysis-layers-dataviews', function() { }, [ { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } } ] ); - it('should get histogram dataview', function(done) { + it('should get histogram dataview', function (done) { var testClient = new TestClient(mapConfig, 1234); - testClient.getDataview('pop_max_histogram', function(err, dataview) { + testClient.getDataview('pop_max_histogram', function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins_start, 0); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins_start, 0); testClient.drain(done); }); }); - it('should get a filtered histogram dataview', function(done) { + it('should get a filtered histogram dataview', function (done) { var testClient = new TestClient(mapConfig, 1234); var params = { @@ -115,17 +113,17 @@ describe('analysis-layers-dataviews', function() { own_filter: 1 }; - testClient.getDataview('pop_max_histogram', params, function(err, dataview) { + testClient.getDataview('pop_max_histogram', params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins_start, 2008000); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins_start, 2008000); testClient.drain(done); }); }); - it('should skip the filter when sending own_filter=0 for histogram dataview', function(done) { + it('should skip the filter when sending own_filter=0 for histogram dataview', function (done) { var testClient = new TestClient(mapConfig, 1234); var params = { @@ -139,11 +137,11 @@ describe('analysis-layers-dataviews', function() { own_filter: 0 }; - testClient.getDataview('pop_max_histogram', params, function(err, dataview) { + testClient.getDataview('pop_max_histogram', params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins_start, 0); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins_start, 0); testClient.drain(done); }); diff --git a/test/acceptance/analysis/analysis-layers-test.js b/test/acceptance/analysis/analysis-layers-test.js index 2c871a3b..07623d2a 100644 --- a/test/acceptance/analysis/analysis-layers-test.js +++ b/test/acceptance/analysis/analysis-layers-test.js @@ -6,45 +6,43 @@ var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); var dot = require('dot'); -describe('analysis-layers', function() { - +describe('analysis-layers', function () { var IMAGE_TOLERANCE_PER_MIL = 20; var multitypeStyleTemplate = dot.template([ "#points['mapnik::geometry_type'=1] {", - " marker-fill-opacity: {{=it._opacity}};", - " marker-line-color: #FFF;", - " marker-line-width: 0.5;", - " marker-line-opacity: {{=it._opacity}};", - " marker-placement: point;", - " marker-type: ellipse;", - " marker-width: 8;", - " marker-fill: {{=it._color}};", - " marker-allow-overlap: true;", - "}", + ' marker-fill-opacity: {{=it._opacity}};', + ' marker-line-color: #FFF;', + ' marker-line-width: 0.5;', + ' marker-line-opacity: {{=it._opacity}};', + ' marker-placement: point;', + ' marker-type: ellipse;', + ' marker-width: 8;', + ' marker-fill: {{=it._color}};', + ' marker-allow-overlap: true;', + '}', "#lines['mapnik::geometry_type'=2] {", - " line-color: {{=it._color}};", - " line-width: 2;", - " line-opacity: {{=it._opacity}};", - "}", + ' line-color: {{=it._color}};', + ' line-width: 2;', + ' line-opacity: {{=it._opacity}};', + '}', "#polygons['mapnik::geometry_type'=3] {", - " polygon-fill: {{=it._color}};", - " polygon-opacity: {{=it._opacity}};", - " line-color: #FFF;", - " line-width: 0.5;", - " line-opacity: {{=it._opacity}};", - "}" + ' polygon-fill: {{=it._color}};', + ' polygon-opacity: {{=it._opacity}};', + ' line-color: #FFF;', + ' line-width: 0.5;', + ' line-opacity: {{=it._opacity}};', + '}' ].join('\n')); - - function cartocss(color, opacity) { + function cartocss (color, opacity) { return multitypeStyleTemplate({ _color: color || '#F11810', _opacity: Number.isFinite(opacity) ? opacity : 1 }); } - function mapConfig(layers, dataviews, analysis) { + function mapConfig (layers, dataviews, analysis) { return { version: '1.5.0', layers: layers, @@ -64,23 +62,23 @@ describe('analysis-layers', function() { mapConfig: mapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "2570e105-7b37-40d2-bdf4-1af889598745" + type: 'cartodb', + options: { + source: { + id: '2570e105-7b37-40d2-bdf4-1af889598745' }, - "cartocss": DEFAULT_MULTITYPE_STYLE, - "cartocss_version": "2.3.0" + cartocss: DEFAULT_MULTITYPE_STYLE, + cartocss_version: '2.3.0' } } ], {}, [ { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } } ] @@ -94,30 +92,30 @@ describe('analysis-layers', function() { mapConfig: mapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "HEAD" + type: 'cartodb', + options: { + source: { + id: 'HEAD' }, - "cartocss": DEFAULT_MULTITYPE_STYLE, - "cartocss_version": "2.3.0" + cartocss: DEFAULT_MULTITYPE_STYLE, + cartocss_version: '2.3.0' } } ], {}, [ { - "id": "HEAD", - "type": "buffer", - "params": { - "source": { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'HEAD', + type: 'buffer', + params: { + source: { + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } }, - "radius": 50000 + radius: 50000 } } ] @@ -125,21 +123,20 @@ describe('analysis-layers', function() { } ]; - useCases.forEach(function(useCase) { - it('should implement use case: "' + useCase.desc + '"', function(done) { - + useCases.forEach(function (useCase) { + it('should implement use case: "' + useCase.desc + '"', function (done) { var testClient = new TestClient(useCase.mapConfig, 1234); var tile = useCase.tile || TILE_ANALYSIS_TABLES; - testClient.getTile(tile.z, tile.x, tile.y, function(err, res, image) { + testClient.getTile(tile.z, tile.x, tile.y, function (err, res, image) { assert.ok(!err, err); // To generate images use: // image.save('/tmp/' + useCase.desc.replace(/\s/g, '-') + '.png'); var fixturePath = './test/fixtures/analysis/' + useCase.fixture; - assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, function(err) { + assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, function (err) { assert.ok(!err, err); testClient.drain(done); @@ -148,22 +145,22 @@ describe('analysis-layers', function() { }); }); - it('should NOT fail for non-authenticated requests when it is just source', function(done) { + it('should NOT fail for non-authenticated requests when it is just source', function (done) { var useCase = useCases[0]; // No API key here var testClient = new TestClient(useCase.mapConfig); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.metadata.layers.length, 1); + assert.strictEqual(layergroupResult.metadata.layers.length, 1); testClient.drain(done); }); }); - it('should fail for non-authenticated requests that has a node other than "source"', function(done) { + it('should fail for non-authenticated requests that has a node other than "source"', function (done) { var useCase = useCases[1]; // No API key here @@ -176,78 +173,76 @@ describe('analysis-layers', function() { } }; - - - testClient.getLayergroup({ response: PERMISSION_DENIED_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: PERMISSION_DENIED_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.deepEqual( + assert.deepStrictEqual( layergroupResult.errors, - ["Analysis requires authentication with API key: permission denied."] + ['Analysis requires authentication with API key: permission denied.'] ); testClient.drain(done); }); }); - it('should retrieve enough metadata about analyses', function(done) { + it('should retrieve enough metadata about analyses', function (done) { var useCase = useCases[1]; // No API key here var testClient = new TestClient(useCase.mapConfig, 1234); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); assert.ok( Array.isArray(layergroupResult.metadata.analyses), - 'Missing "analyses" array metadata from: ' + JSON.stringify(layergroupResult) + 'Missing "analyses" array metadata from: ' + JSON.stringify(layergroupResult) ); var analyses = layergroupResult.metadata.analyses; - assert.equal(analyses.length, 1, 'Invalid number of analyses in metadata'); + assert.strictEqual(analyses.length, 1, 'Invalid number of analyses in metadata'); var nodes = analyses[0].nodes; var nodesIds = Object.keys(nodes); - assert.deepEqual(nodesIds, ['HEAD', '2570e105-7b37-40d2-bdf4-1af889598745']); - nodesIds.forEach(function(nodeId) { + assert.deepStrictEqual(nodesIds, ['HEAD', '2570e105-7b37-40d2-bdf4-1af889598745']); + nodesIds.forEach(function (nodeId) { var node = nodes[nodeId]; - assert.ok(node.hasOwnProperty('url'), 'Missing "url" attribute in node'); - assert.ok(node.hasOwnProperty('status'), 'Missing "status" attribute in node'); - assert.ok(node.hasOwnProperty('query'), 'Missing "status" attribute in node'); + assert.ok(Object.prototype.hasOwnProperty.call(node, 'url'), 'Missing "url" attribute in node'); + assert.ok(Object.prototype.hasOwnProperty.call(node, 'status'), 'Missing "status" attribute in node'); + assert.ok(Object.prototype.hasOwnProperty.call(node, 'query'), 'Missing "status" attribute in node'); }); testClient.drain(done); }); }); - it('should have analysis metadata when dataviews point to source node', function(done) { + it('should have analysis metadata when dataviews point to source node', function (done) { var useCase = { desc: 'basic source-id mapnik layer', fixture: 'basic-source-id-mapnik-layer.png', mapConfig: mapConfig( [ { - "type": "cartodb", - "options": { - "sql": "select * from populated_places_simple_reduced", - "cartocss": DEFAULT_MULTITYPE_STYLE, - "cartocss_version": "2.3.0" + type: 'cartodb', + options: { + sql: 'select * from populated_places_simple_reduced', + cartocss: DEFAULT_MULTITYPE_STYLE, + cartocss_version: '2.3.0' } }, { - "type": "cartodb", - "options": { - "source": { - "id": "2570e105-7b37-40d2-bdf4-1af889598745" + type: 'cartodb', + options: { + source: { + id: '2570e105-7b37-40d2-bdf4-1af889598745' }, - "cartocss": DEFAULT_MULTITYPE_STYLE, - "cartocss_version": "2.3.0" + cartocss: DEFAULT_MULTITYPE_STYLE, + cartocss_version: '2.3.0' } }, { - "type": "cartodb", - "options": { - "sql": "select * from populated_places_simple_reduced", - "cartocss": DEFAULT_MULTITYPE_STYLE, - "cartocss_version": "2.3.0" + type: 'cartodb', + options: { + sql: 'select * from populated_places_simple_reduced', + cartocss: DEFAULT_MULTITYPE_STYLE, + cartocss_version: '2.3.0' } } ], @@ -273,10 +268,10 @@ describe('analysis-layers', function() { }, [ { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } } ] @@ -285,44 +280,44 @@ describe('analysis-layers', function() { var testClient = new TestClient(useCase.mapConfig, 1234); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); assert.ok( Array.isArray(layergroupResult.metadata.analyses), - 'Missing "analyses" array metadata from: ' + JSON.stringify(layergroupResult) + 'Missing "analyses" array metadata from: ' + JSON.stringify(layergroupResult) ); var analyses = layergroupResult.metadata.analyses; - assert.equal(analyses.length, 1, 'Invalid number of analyses in metadata'); + assert.strictEqual(analyses.length, 1, 'Invalid number of analyses in metadata'); var nodes = analyses[0].nodes; var nodesIds = Object.keys(nodes); - assert.deepEqual(nodesIds, ['2570e105-7b37-40d2-bdf4-1af889598745']); - nodesIds.forEach(function(nodeId) { + assert.deepStrictEqual(nodesIds, ['2570e105-7b37-40d2-bdf4-1af889598745']); + nodesIds.forEach(function (nodeId) { var node = nodes[nodeId]; - assert.ok(node.hasOwnProperty('url'), 'Missing "url" attribute in node'); - assert.ok(node.hasOwnProperty('status'), 'Missing "status" attribute in node'); - assert.ok(node.hasOwnProperty('query'), 'Missing "status" attribute in node'); + assert.ok(Object.prototype.hasOwnProperty.call(node, 'url'), 'Missing "url" attribute in node'); + assert.ok(Object.prototype.hasOwnProperty.call(node, 'status'), 'Missing "status" attribute in node'); + assert.ok(Object.prototype.hasOwnProperty.call(node, 'query'), 'Missing "status" attribute in node'); }); testClient.drain(done); }); }); - it('should response with custom cache headers for node status endpoints', function(done) { + it('should response with custom cache headers for node status endpoints', function (done) { var useCase = useCases[1]; // No API key here var testClient = new TestClient(useCase.mapConfig, 1234); - testClient.getNodeStatus('HEAD', function(err, response, nodeStatus) { + testClient.getNodeStatus('HEAD', function (err, response, nodeStatus) { assert.ok(!err, err); - assert.equal(nodeStatus.status, 'ready'); + assert.strictEqual(nodeStatus.status, 'ready'); var headers = response.headers; - assert.equal(headers['cache-control'], 'public,max-age=5'); + assert.strictEqual(headers['cache-control'], 'public,max-age=5'); var lastModified = new Date(headers['last-modified']); var tenSecondsInMs = 1e5; @@ -332,39 +327,39 @@ describe('analysis-layers', function() { }); }); - it('should wrap queries from analyses', function(done) { + it('should wrap queries from analyses', function (done) { var testClient = new TestClient(mapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "2570e105-7b37-40d2-bdf4-1af889598745" + type: 'cartodb', + options: { + source: { + id: '2570e105-7b37-40d2-bdf4-1af889598745' }, - "sql_wrap": "SELECT * FROM (<%= sql %>) __wrapped WHERE adm0cap = 1", - "cartocss": DEFAULT_MULTITYPE_STYLE, - "cartocss_version": "2.3.0" + sql_wrap: 'SELECT * FROM (<%= sql %>) __wrapped WHERE adm0cap = 1', + cartocss: DEFAULT_MULTITYPE_STYLE, + cartocss_version: '2.3.0' } } ], {}, [ { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } } ] ), 1234); var tile = TILE_ANALYSIS_TABLES; - testClient.getTile(tile.z, tile.x, tile.y, function(err, res, image) { + testClient.getTile(tile.z, tile.x, tile.y, function (err, res, image) { assert.ok(!err, err); var fixturePath = './test/fixtures/analysis/adm0cap-source-id-mapnik-layer.png'; - assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, function(err) { + assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, function (err) { assert.ok(!err, err); testClient.drain(done); diff --git a/test/acceptance/analysis/analysis-layers-use-cases-test.js b/test/acceptance/analysis/analysis-layers-use-cases-test.js index d765ae4e..7fde6bb3 100644 --- a/test/acceptance/analysis/analysis-layers-use-cases-test.js +++ b/test/acceptance/analysis/analysis-layers-use-cases-test.js @@ -8,8 +8,6 @@ var dot = require('dot'); var debug = require('debug')('windshaft:cartodb:test'); describe('analysis-layers use cases', function () { - - var multitypeStyleTemplate = dot.template( `#points['mapnik::geometry_type'=1] { marker-fill-opacity: {{=it._opacity}}; @@ -36,15 +34,14 @@ describe('analysis-layers use cases', function () { }` ); - - function cartocss(color, opacity) { + function cartocss (color, opacity) { return multitypeStyleTemplate({ _color: color || '#F11810', _opacity: Number.isFinite(opacity) ? opacity : 1 }); } - function mapConfig(layers, dataviews, analysis) { + function mapConfig (layers, dataviews, analysis) { return { version: '1.5.0', layers: layers, @@ -158,10 +155,10 @@ describe('analysis-layers use cases', function () { } } ], - {}, - [ - bufferDef - ] + {}, + [ + bufferDef + ] ) }, @@ -187,10 +184,10 @@ describe('analysis-layers use cases', function () { } } ], - {}, - [ - pointInPolygonDef - ] + {}, + [ + pointInPolygonDef + ] ) }, @@ -267,11 +264,10 @@ describe('analysis-layers use cases', function () { ]; useCases.forEach(function (useCase) { - if (!!useCase.skip) { + if (useCase.skip) { return debug(JSON.stringify(useCase.mapConfig, null, 4)); } it(`should implement use case: '${useCase.desc}'`, function (done) { - var testClient = new TestClient(useCase.mapConfig, 1234); var tile = useCase.tile || TILE_ANALYSIS_TABLES; @@ -279,9 +275,9 @@ describe('analysis-layers use cases', function () { testClient.getTile(tile.z, tile.x, tile.y, function (err, res, image) { assert.ok(!err, err); - //image.save('/tmp/tests/' + imageIdx + '---' + useCase.desc.replace(/\s/g, '-') + '.png'); + // image.save('/tmp/tests/' + imageIdx + '---' + useCase.desc.replace(/\s/g, '-') + '.png'); - assert.equal(image.width(), 256); + assert.strictEqual(image.width(), 256); testClient.drain(done); }); diff --git a/test/acceptance/analysis/error-cases-test.js b/test/acceptance/analysis/error-cases-test.js index eeb8d3e3..fe30fe79 100644 --- a/test/acceptance/analysis/error-cases-test.js +++ b/test/acceptance/analysis/error-cases-test.js @@ -5,8 +5,8 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('analysis-layers error cases', function() { - function createMapConfig(layers, dataviews, analysis) { +describe('analysis-layers error cases', function () { + function createMapConfig (layers, dataviews, analysis) { return { version: '1.5.0', layers: layers, @@ -29,34 +29,34 @@ describe('analysis-layers error cases', function() { } }; - it('should handle missing analysis nodes for layers', function(done) { + it('should handle missing analysis nodes for layers', function (done) { var mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "INVALID-SOURCE-ID" + type: 'cartodb', + options: { + source: { + id: 'INVALID-SOURCE-ID' }, - "cartocss": '#polygons { polygon-fill: red; }', - "cartocss_version": "2.3.0" + cartocss: '#polygons { polygon-fill: red; }', + cartocss_version: '2.3.0' } } ], {}, [ { - "id": "HEAD", - "type": "buffer", - "params": { - "source": { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'HEAD', + type: 'buffer', + params: { + source: { + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } }, - "radius": 50000 + radius: 50000 } } ] @@ -64,34 +64,34 @@ describe('analysis-layers error cases', function() { var testClient = new TestClient(mapConfig, 1234); - testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.errors.length, 1); - assert.equal(layergroupResult.errors[0], 'Missing analysis node.id="INVALID-SOURCE-ID" for layer=0'); + assert.strictEqual(layergroupResult.errors.length, 1); + assert.strictEqual(layergroupResult.errors[0], 'Missing analysis node.id="INVALID-SOURCE-ID" for layer=0'); testClient.drain(done); }); }); - it('should handle missing analyses when layers point to nonexistent one', function(done) { + it('should handle missing analyses when layers point to nonexistent one', function (done) { var mapConfig = createMapConfig( [ { - "type": "http", - "options": { - "urlTemplate": "http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png", - "subdomains": "abcd" + type: 'http', + options: { + urlTemplate: 'http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', + subdomains: 'abcd' } }, { - "type": "cartodb", - "options": { - "source": { - "id": "ID-FOR-NONEXISTENT-ANALYSIS" + type: 'cartodb', + options: { + source: { + id: 'ID-FOR-NONEXISTENT-ANALYSIS' }, - "cartocss": '#polygons { polygon-fill: red; }', - "cartocss_version": "2.3.0" + cartocss: '#polygons { polygon-fill: red; }', + cartocss_version: '2.3.0' } } ] @@ -99,11 +99,11 @@ describe('analysis-layers error cases', function() { var testClient = new TestClient(mapConfig, 1234); - testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.errors.length, 1); - assert.equal( + assert.strictEqual(layergroupResult.errors.length, 1); + assert.strictEqual( layergroupResult.errors[0], 'Missing analysis node.id="ID-FOR-NONEXISTENT-ANALYSIS" for layer=1' ); @@ -112,22 +112,22 @@ describe('analysis-layers error cases', function() { }); }); - it('should handle missing analyses when dataviews point to nonexistent one', function(done) { + it('should handle missing analyses when dataviews point to nonexistent one', function (done) { var mapConfig = createMapConfig( [ { - "type": "http", - "options": { - "urlTemplate": "http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png", - "subdomains": "abcd" + type: 'http', + options: { + urlTemplate: 'http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', + subdomains: 'abcd' } }, { - "type": "cartodb", - "options": { - "sql": "select * from populated_places_simple_reduced", - "cartocss": '#polygons { polygon-fill: red; }', - "cartocss_version": "2.3.0" + type: 'cartodb', + options: { + sql: 'select * from populated_places_simple_reduced', + cartocss: '#polygons { polygon-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -146,99 +146,98 @@ describe('analysis-layers error cases', function() { var testClient = new TestClient(mapConfig, 1234); - testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.errors.length, 1); - assert.equal(layergroupResult.errors[0], 'Node with `source.id="ID-FOR-NONEXISTENT-ANALYSIS"`' + + assert.strictEqual(layergroupResult.errors.length, 1); + assert.strictEqual(layergroupResult.errors[0], 'Node with `source.id="ID-FOR-NONEXISTENT-ANALYSIS"`' + ' not found in analyses for dataview "pop_max_histogram"'); testClient.drain(done); }); }); - it('camshaft: should return error missing analysis nodes for layers with some context', function(done) { + it('camshaft: should return error missing analysis nodes for layers with some context', function (done) { var mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "HEAD" + type: 'cartodb', + options: { + source: { + id: 'HEAD' }, - "cartocss": '#polygons { polygon-fill: red; }', - "cartocss_version": "2.3.0" + cartocss: '#polygons { polygon-fill: red; }', + cartocss_version: '2.3.0' } } ], {}, [ { - "id": "HEAD", - "type": "buffer", - "params": { - "source": { - "id": "HEAD", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'HEAD', + type: 'buffer', + params: { + source: { + id: 'HEAD', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } }, - "radius": 50000 + radius: 50000 } } ] ); - var testClient = new TestClient(mapConfig); //No apikey provided -> using default public apikey + var testClient = new TestClient(mapConfig); // No apikey provided -> using default public apikey - testClient.getLayergroup({ response: AUTH_ERROR_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: AUTH_ERROR_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.errors.length, 1); - assert.equal( + assert.strictEqual(layergroupResult.errors.length, 1); + assert.strictEqual( layergroupResult.errors[0], 'Analysis requires authentication with API key: permission denied.' ); - assert.equal(layergroupResult.errors_with_context[0].type, 'analysis'); - assert.equal( + assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis'); + assert.strictEqual( layergroupResult.errors_with_context[0].message, 'Analysis requires authentication with API key: permission denied.' ); - assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); - assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); testClient.drain(done); }); }); - - it('camshaft: should return error: Missing required param "radius"; with context', function(done) { + it('camshaft: should return error: Missing required param "radius"; with context', function (done) { var mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "HEAD" + type: 'cartodb', + options: { + source: { + id: 'HEAD' }, - "cartocss": '#polygons { polygon-fill: red; }', - "cartocss_version": "2.3.0" + cartocss: '#polygons { polygon-fill: red; }', + cartocss_version: '2.3.0' } } ], {}, [ { - "id": "HEAD", - "type": "buffer", - "params": { - "source": { - "id": "HEAD2", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'HEAD', + type: 'buffer', + params: { + source: { + id: 'HEAD2', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } } } @@ -248,50 +247,50 @@ describe('analysis-layers error cases', function() { var testClient = new TestClient(mapConfig, 1234); - testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.errors.length, 1); - assert.equal( + assert.strictEqual(layergroupResult.errors.length, 1); + assert.strictEqual( layergroupResult.errors[0], 'Missing required param "radius"' ); - assert.equal(layergroupResult.errors_with_context[0].type, 'analysis'); - assert.equal(layergroupResult.errors_with_context[0].message, 'Missing required param "radius"'); - assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); - assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); + assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis'); + assert.strictEqual(layergroupResult.errors_with_context[0].message, 'Missing required param "radius"'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); testClient.drain(done); }); }); - it('should return missing param error of outer node indicating the node_id and context', function(done) { + it('should return missing param error of outer node indicating the node_id and context', function (done) { var mapConfig = createMapConfig([{ - "type": "cartodb", - "options": { - "source": { - "id": "HEAD" + type: 'cartodb', + options: { + source: { + id: 'HEAD' }, - "cartocss": '#polygons { polygon-fill: red; }', - "cartocss_version": "2.3.0" + cartocss: '#polygons { polygon-fill: red; }', + cartocss_version: '2.3.0' } }], {}, [{ - "id": "HEAD", - "type": "buffer", - "params": { - "source": { - "id": "HEAD2", - "type": "buffer", - "params": { - "source": { - "id": "HEAD3", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'HEAD', + type: 'buffer', + params: { + source: { + id: 'HEAD2', + type: 'buffer', + params: { + source: { + id: 'HEAD3', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } }, - "radius": 10 + radius: 10 } } } @@ -300,145 +299,142 @@ describe('analysis-layers error cases', function() { var testClient = new TestClient(mapConfig, 1234); - testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.errors.length, 1); - assert.equal( + assert.strictEqual(layergroupResult.errors.length, 1); + assert.strictEqual( layergroupResult.errors[0], 'Missing required param "radius"' ); - assert.equal(layergroupResult.errors_with_context[0].type, 'analysis'); - assert.equal(layergroupResult.errors_with_context[0].message, 'Missing required param "radius"'); - assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); - assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); - assert.equal(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD'); + assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis'); + assert.strictEqual(layergroupResult.errors_with_context[0].message, 'Missing required param "radius"'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD'); testClient.drain(done); }); }); - it('should return invalid param type error of inner node indicating the node_id and context', function(done) { + it('should return invalid param type error of inner node indicating the node_id and context', function (done) { var mapConfig = createMapConfig([{ - "type": "cartodb", - "options": { - "source": { - "id": "HEAD" + type: 'cartodb', + options: { + source: { + id: 'HEAD' }, - "cartocss": '#polygons { polygon-fill: red; }', - "cartocss_version": "2.3.0" + cartocss: '#polygons { polygon-fill: red; }', + cartocss_version: '2.3.0' } }], {}, [{ - "id": "HEAD", - "type": "buffer", - "params": { - "source": { - "id": "HEAD2", - "type": "buffer", - "params": { - "source": { - "id": "HEAD3", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'HEAD', + type: 'buffer', + params: { + source: { + id: 'HEAD2', + type: 'buffer', + params: { + source: { + id: 'HEAD3', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } }, - "radius": 'invalid_radius' + radius: 'invalid_radius' } }, - "radius": 10 + radius: 10 } }]); var testClient = new TestClient(mapConfig, 1234); - testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.errors.length, 1); - assert.equal( + assert.strictEqual(layergroupResult.errors.length, 1); + assert.strictEqual( layergroupResult.errors[0], 'Invalid type for param "radius", expects "number" type, got `"invalid_radius"`' ); - assert.equal(layergroupResult.errors_with_context[0].type, 'analysis'); - assert.equal( + assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis'); + assert.strictEqual( layergroupResult.errors_with_context[0].message, 'Invalid type for param "radius", expects "number" type, got `"invalid_radius"`' ); - assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); - assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); - assert.equal(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD2'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD2'); testClient.drain(done); }); }); - it('should return "function does not exist" indicating the node_id and context', function(done) { + it('should return "function does not exist" indicating the node_id and context', function (done) { var mapConfig = createMapConfig([{ - "type": "cartodb", - "options": { - "source": { - "id": "HEAD" + type: 'cartodb', + options: { + source: { + id: 'HEAD' }, - "cartocss": '#polygons { polygon-fill: red; }', - "cartocss_version": "2.3.0" + cartocss: '#polygons { polygon-fill: red; }', + cartocss_version: '2.3.0' } }], {}, [{ - "id": "HEAD", - "type": "buffer", - "params": { - "source": { - "id": "HEAD2", - "type": "buffer", - "params": { - "source": { - "id": "HEAD3", - "type": 'deprecated-sql-function', - "params": { - "id": "HEAD4", - "function_name": 'DEP_EXT_does_not_exist_fn', - "primary_source": { - "type": 'source', - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'HEAD', + type: 'buffer', + params: { + source: { + id: 'HEAD2', + type: 'buffer', + params: { + source: { + id: 'HEAD3', + type: 'deprecated-sql-function', + params: { + id: 'HEAD4', + function_name: 'DEP_EXT_does_not_exist_fn', + primary_source: { + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } }, - "function_args": ['wadus'] + function_args: ['wadus'] } }, - "radius": 10 + radius: 10 } }, - "radius": 10 + radius: 10 } }]); var testClient = new TestClient(mapConfig, 1234); - testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.errors.length, 1); - assert.equal( + assert.strictEqual(layergroupResult.errors.length, 1); + assert.strictEqual( layergroupResult.errors[0], 'function dep_ext_does_not_exist_fn(unknown, unknown, unknown, text[], unknown) does not exist' ); - assert.equal(layergroupResult.errors_with_context[0].type, 'analysis'); - assert.equal( + assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis'); + assert.strictEqual( layergroupResult.errors_with_context[0].message, 'function dep_ext_does_not_exist_fn(unknown, unknown, unknown, text[], unknown) does not exist' ); - assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); - assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); - assert.equal(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD3'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer'); + assert.strictEqual(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD3'); testClient.drain(done); }); }); - - - }); diff --git a/test/acceptance/analysis/named-maps-test.js b/test/acceptance/analysis/named-maps-test.js index 5a092a11..d04beadd 100644 --- a/test/acceptance/analysis/named-maps-test.js +++ b/test/acceptance/analysis/named-maps-test.js @@ -10,33 +10,32 @@ var TestClient = require('../../support/test-client'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('named-maps analysis', function() { +describe('named-maps analysis', function () { var server; before(function () { server = new CartodbWindshaft(serverOptions); }); - var IMAGE_TOLERANCE_PER_MIL = 20; var username = 'localhost'; var widgetsTemplateName = 'widgets-template'; - var widgetsTemplate = { + var widgetsTemplate = { version: '0.0.1', name: widgetsTemplateName, - layergroup: { + layergroup: { version: '1.5.0', layers: [ { - "type": "cartodb", - "options": { - "source": { - "id": "HEAD" + type: 'cartodb', + options: { + source: { + id: 'HEAD' }, - "cartocss": '#buffer { polygon-fill: red; }', - "cartocss_version": "2.3.0" + cartocss: '#buffer { polygon-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -53,24 +52,24 @@ describe('named-maps analysis', function() { }, analyses: [ { - "id": "HEAD", - "type": "buffer", - "params": { - "source": { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: 'HEAD', + type: 'buffer', + params: { + source: { + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } }, - "radius": 50000 + radius: 50000 } } ] } }; - beforeEach(function createTemplate(done) { + beforeEach(function createTemplate (done) { assert.response( server, { @@ -85,14 +84,14 @@ describe('named-maps analysis', function() { { status: 200 }, - function(res, err) { - assert.deepEqual(JSON.parse(res.body), { template_id: widgetsTemplateName }); + function (res, err) { + assert.deepStrictEqual(JSON.parse(res.body), { template_id: widgetsTemplateName }); return done(err); } ); }); - afterEach(function deleteTemplate(done) { + afterEach(function deleteTemplate (done) { assert.response( server, { @@ -105,18 +104,18 @@ describe('named-maps analysis', function() { { status: 204 }, - function(res, err) { + function (res, err) { return done(err); } ); }); - describe('layergroup', function() { + describe('layergroup', function () { var layergroupid; var layergroup; var keysToDelete; - beforeEach(function(done) { + beforeEach(function (done) { keysToDelete = {}; assert.response( @@ -133,27 +132,27 @@ describe('named-maps analysis', function() { { status: 200 }, - function(res, err) { + function (res, err) { assert.ifError(err); layergroup = JSON.parse(res.body); - assert.ok(layergroup.hasOwnProperty('layergroupid'), "Missing 'layergroupid' from: " + res.body); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'), "Missing 'layergroupid' from: " + res.body); layergroupid = layergroup.layergroupid; assert.ok( Array.isArray(layergroup.metadata.analyses), - 'Missing "analyses" array metadata from: ' + res.body + 'Missing "analyses" array metadata from: ' + res.body ); var analyses = layergroup.metadata.analyses; - assert.equal(analyses.length, 1, 'Invalid number of analyses in metadata'); + assert.strictEqual(analyses.length, 1, 'Invalid number of analyses in metadata'); var nodes = analyses[0].nodes; var nodesIds = Object.keys(nodes); - assert.deepEqual(nodesIds, ['HEAD', '2570e105-7b37-40d2-bdf4-1af889598745']); - nodesIds.forEach(function(nodeId) { + assert.deepStrictEqual(nodesIds, ['HEAD', '2570e105-7b37-40d2-bdf4-1af889598745']); + nodesIds.forEach(function (nodeId) { var node = nodes[nodeId]; - assert.ok(node.hasOwnProperty('url'), 'Missing "url" attribute in node'); - assert.ok(node.hasOwnProperty('status'), 'Missing "status" attribute in node'); - assert.ok(!node.hasOwnProperty('query'), 'Unexpected "query" attribute in node'); + assert.ok(Object.prototype.hasOwnProperty.call(node, 'url'), 'Missing "url" attribute in node'); + assert.ok(Object.prototype.hasOwnProperty.call(node, 'status'), 'Missing "status" attribute in node'); + assert.ok(!Object.prototype.hasOwnProperty.call(node, 'query'), 'Unexpected "query" attribute in node'); }); keysToDelete['map_cfg|' + LayergroupToken.parse(layergroup.layergroupid).token] = 0; @@ -162,14 +161,13 @@ describe('named-maps analysis', function() { return done(); } ); - }); - afterEach(function(done) { + afterEach(function (done) { helper.deleteRedisKeys(keysToDelete, done); }); - it('should be able to retrieve images from analysis', function(done) { + it('should be able to retrieve images from analysis', function (done) { assert.response( server, { @@ -186,22 +184,21 @@ describe('named-maps analysis', function() { 'Content-Type': 'image/png' } }, - function(res, err) { + function (res, err) { if (err) { return done(err); } var fixturePath = './test/fixtures/analysis/named-map-buffer.png'; - assert.imageBufferIsSimilarToFile(res.body, fixturePath, IMAGE_TOLERANCE_PER_MIL, function(err) { + assert.imageBufferIsSimilarToFile(res.body, fixturePath, IMAGE_TOLERANCE_PER_MIL, function (err) { assert.ok(!err, err); done(); }); - } ); }); - it('should be able to retrieve dataviews from analysis', function(done) { + it('should be able to retrieve dataviews from analysis', function (done) { assert.response( server, { @@ -217,21 +214,21 @@ describe('named-maps analysis', function() { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return done(err); } var dataview = JSON.parse(res.body); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins_start, 0); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins_start, 0); done(); } ); }); - it('should be able to retrieve static map preview via layergroup', function(done) { + it('should be able to retrieve static map preview via layergroup', function (done) { assert.response( server, { @@ -248,23 +245,22 @@ describe('named-maps analysis', function() { 'Content-Type': 'image/png' } }, - function(res, err) { + function (res, err) { if (err) { return done(err); } var fixturePath = './test/fixtures/analysis/named-map-buffer-layergroup-static-preview.png'; - assert.imageBufferIsSimilarToFile(res.body, fixturePath, IMAGE_TOLERANCE_PER_MIL, function(err) { + assert.imageBufferIsSimilarToFile(res.body, fixturePath, IMAGE_TOLERANCE_PER_MIL, function (err) { assert.ok(!err, err); done(); }); - } ); }); it('should fail to retrieve static map preview via layergroup ' + - 'when filtering by invalid layers', function(done) { + 'when filtering by invalid layers', function (done) { assert.response( server, { @@ -278,13 +274,13 @@ describe('named-maps analysis', function() { { status: 400 }, - function(res, err) { + function (res, err) { done(err); } ); }); - it('should return and an error requesting unsupported image format', function(done) { + it('should return and an error requesting unsupported image format', function (done) { assert.response( server, { @@ -301,37 +297,34 @@ describe('named-maps analysis', function() { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { assert.ifError(err); - assert.deepEqual( + assert.deepStrictEqual( JSON.parse(res.body), { - errors:['Unsupported image format \"gif\"'], - errors_with_context:[{ + errors: ['Unsupported image format "gif"'], + errors_with_context: [{ type: 'unknown', - message: 'Unsupported image format \"gif\"' + message: 'Unsupported image format "gif"' }] } ); done(); - } ); }); - }); - describe('auto-instantiation', function() { - it('should be able to retrieve static map preview via fixed url', function(done) { - TestClient.getStaticMap(widgetsTemplateName, function(err, image) { + describe('auto-instantiation', function () { + it('should be able to retrieve static map preview via fixed url', function (done) { + TestClient.getStaticMap(widgetsTemplateName, function (err, image) { assert.ok(!err, err); var fixturePath = './test/fixtures/analysis/named-map-buffer-static-preview.png'; - assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, function(err) { + assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, function (err) { assert.ok(!err, err); done(); }); }); }); }); - }); diff --git a/test/acceptance/analysis/regressions-test.js b/test/acceptance/analysis/regressions-test.js index c1758a20..d576515a 100644 --- a/test/acceptance/analysis/regressions-test.js +++ b/test/acceptance/analysis/regressions-test.js @@ -5,84 +5,84 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('analysis-layers regressions', function() { - it('should return a complete list of nodes from analysis', function(done) { +describe('analysis-layers regressions', function () { + it('should return a complete list of nodes from analysis', function (done) { var mapConfig = { - "version": "1.5.0", - "layers": [ + version: '1.5.0', + layers: [ { - "type": "cartodb", - "options": { - "cartocss": TestClient.CARTOCSS.POINTS, - "cartocss_version": "2.1.1", - "interactivity": [], - "source": { - "id": "a4" + type: 'cartodb', + options: { + cartocss: TestClient.CARTOCSS.POINTS, + cartocss_version: '2.1.1', + interactivity: [], + source: { + id: 'a4' } } }, { - "type": "cartodb", - "options": { - "cartocss": TestClient.CARTOCSS.POINTS, - "cartocss_version": "2.1.0", - "interactivity": [], - "source": { - "id": "b1" + type: 'cartodb', + options: { + cartocss: TestClient.CARTOCSS.POINTS, + cartocss_version: '2.1.0', + interactivity: [], + source: { + id: 'b1' } } } ], - "dataviews": { - "74493a30-4679-4b72-a60c-b6f808b57c98": { - "type": "histogram", - "source": { - "id": "b0" + dataviews: { + '74493a30-4679-4b72-a60c-b6f808b57c98': { + type: 'histogram', + source: { + id: 'b0' }, - "options": { - "column": "customer_value", - "bins": 10 + options: { + column: 'customer_value', + bins: 10 } } }, - "analyses": [ + analyses: [ { - "id": "a4", - "type": "point-in-polygon", - "params": { - "polygons_source": { - "id": "a3", - "type": "buffer", - "params": { - "source": { - "id": "a2", - "type": "centroid", - "params": { - "source": { - "id": "b1", - "type": "kmeans", - "params": { - "source": { - "id": "b0", - "type": "source", - "params": { - "query": "SELECT * FROM populated_places_simple_reduced" + id: 'a4', + type: 'point-in-polygon', + params: { + polygons_source: { + id: 'a3', + type: 'buffer', + params: { + source: { + id: 'a2', + type: 'centroid', + params: { + source: { + id: 'b1', + type: 'kmeans', + params: { + source: { + id: 'b0', + type: 'source', + params: { + query: 'SELECT * FROM populated_places_simple_reduced' } }, - "clusters": 5 + clusters: 5 } }, - "category_column": "cluster_no" + category_column: 'cluster_no' } }, - "radius": 200000 + radius: 200000 } }, - "points_source": { - "id": "customer_home_locations", - "type": "source", - "params": { - "query": "SELECT * FROM populated_places_simple_reduced" + points_source: { + id: 'customer_home_locations', + type: 'source', + params: { + query: 'SELECT * FROM populated_places_simple_reduced' } } } @@ -92,26 +92,25 @@ describe('analysis-layers regressions', function() { var testClient = new TestClient(mapConfig, 1234); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); assert.ok(layergroupResult); assert.ok(layergroupResult.metadata); var analyses = layergroupResult.metadata.analyses; assert.ok(analyses); - assert.equal(analyses.length, 1); + assert.strictEqual(analyses.length, 1); var expectedIds = ['customer_home_locations', 'b0', 'b1', 'a2', 'a3', 'a4']; - expectedIds.forEach(function(expectedId) { + expectedIds.forEach(function (expectedId) { assert.ok( - analyses[0].nodes.hasOwnProperty(expectedId), + Object.prototype.hasOwnProperty.call(analyses[0].nodes, expectedId), 'Missing "' + expectedId + '" from node list.' ); }); - assert.equal(Object.keys(analyses[0].nodes).length, expectedIds.length, Object.keys(analyses[0].nodes)); + assert.strictEqual(Object.keys(analyses[0].nodes).length, expectedIds.length, Object.keys(analyses[0].nodes)); testClient.drain(done); }); }); - }); diff --git a/test/acceptance/auth/authorization-basic-use-cases-test.js b/test/acceptance/auth/authorization-basic-use-cases-test.js index 491b81b0..9e48077b 100644 --- a/test/acceptance/auth/authorization-basic-use-cases-test.js +++ b/test/acceptance/auth/authorization-basic-use-cases-test.js @@ -6,7 +6,7 @@ const CartodbWindshaft = require('../../../lib/server'); const serverOptions = require('../../../lib/server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -function singleLayergroupConfig(sql, cartocss) { +function singleLayergroupConfig (sql, cartocss) { return { version: '1.7.0', layers: [ @@ -22,7 +22,7 @@ function singleLayergroupConfig(sql, cartocss) { }; } -function createRequest(layergroup, userHost, apiKey) { +function createRequest (layergroup, userHost, apiKey) { var url = layergroupUrl; if (apiKey) { url += '?api_key=' + apiKey; @@ -39,8 +39,8 @@ function createRequest(layergroup, userHost, apiKey) { } var layergroupUrl = '/api/v1/map'; -var pointSqlMaster = "select * from test_table_private_1"; -var pointSqlPublic = "select * from test_table"; +var pointSqlMaster = 'select * from test_table_private_1'; +var pointSqlPublic = 'select * from test_table'; var keysToDelete; describe('Basic authorization use cases', function () { @@ -58,7 +58,7 @@ describe('Basic authorization use cases', function () { testHelper.deleteRedisKeys(keysToDelete, done); }); - it("succeed with master", function (done) { + it('succeed with master', function (done) { var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }'); assert.response(server, @@ -71,7 +71,7 @@ describe('Basic authorization use cases', function () { var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); - assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid); keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; @@ -81,8 +81,7 @@ describe('Basic authorization use cases', function () { ); }); - - it("succeed with default - sending default_public", function (done) { + it('succeed with default - sending default_public', function (done) { var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }'); assert.response(server, @@ -95,7 +94,7 @@ describe('Basic authorization use cases', function () { var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); - assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid); keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; @@ -105,7 +104,7 @@ describe('Basic authorization use cases', function () { ); }); - it("fail with non-existent api key", function (done) { + it('fail with non-existent api key', function (done) { var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }'); assert.response(server, @@ -116,15 +115,15 @@ describe('Basic authorization use cases', function () { function (res, err) { assert.ifError(err); var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors')); - assert.equal(parsed.errors.length, 1); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors')); + assert.strictEqual(parsed.errors.length, 1); assert.ok(parsed.errors[0].match(/Unauthorized/)); done(); } ); }); - it("fail with default", function (done) { + it('fail with default', function (done) { var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }'); assert.response(server, @@ -141,7 +140,7 @@ describe('Basic authorization use cases', function () { }); describe('No api key provided - fallback to default_public', function () { - it("succeed with default - public dataset", function (done) { + it('succeed with default - public dataset', function (done) { var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }'); assert.response(server, @@ -154,7 +153,7 @@ describe('Basic authorization use cases', function () { var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); - assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid); keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; @@ -164,7 +163,7 @@ describe('Basic authorization use cases', function () { ); }); - it("fail with default - private dataset", function (done) { + it('fail with default - private dataset', function (done) { var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }'); assert.response(server, diff --git a/test/acceptance/auth/authorization-test.js b/test/acceptance/auth/authorization-test.js index 62384d84..cd277153 100644 --- a/test/acceptance/auth/authorization-test.js +++ b/test/acceptance/auth/authorization-test.js @@ -4,7 +4,7 @@ require('../../support/test-helper'); const assert = require('../../support/assert'); const TestClient = require('../../support/test-client'); -const mapnik = require('windshaft').mapnik; +const mapnik = require('windshaft').mapnik; const PERMISSION_DENIED_RESPONSE = { status: 403, @@ -13,8 +13,8 @@ const PERMISSION_DENIED_RESPONSE = { } }; -describe('authorization', function() { - it('should create a layergroup with regular apikey token', function(done) { +describe('authorization', function () { + it('should create a layergroup with regular apikey token', function (done) { const apikeyToken = 'regular1'; const mapConfig = { version: '1.7.0', @@ -39,7 +39,6 @@ describe('authorization', function() { }); }); - it('should fail getting a named map tile with default apikey token', function (done) { const apikeyTokenCreate = 'regular1'; const apikeyTokenGet = 'default_public'; @@ -68,12 +67,11 @@ describe('authorization', function() { response: PERMISSION_DENIED_RESPONSE }; - testClientGet.getTile(0, 0, 0, params, function(err, res, body) { - + testClientGet.getTile(0, 0, 0, params, function (err, res, body) { assert.ifError(err); - assert.ok(body.hasOwnProperty('errors')); - assert.equal(body.errors.length, 1); + assert.ok(Object.prototype.hasOwnProperty.call(body, 'errors')); + assert.strictEqual(body.errors.length, 1); assert.ok(body.errors[0].match(/permission denied/), body.errors[0]); testClientGet.drain(done); @@ -100,8 +98,8 @@ describe('authorization', function() { testClient.getLayergroup({ response: { status: 403 } }, function (err, layergroupResult) { assert.ifError(err); - assert.ok(layergroupResult.hasOwnProperty('errors')); - assert.equal(layergroupResult.errors.length, 1); + assert.ok(Object.prototype.hasOwnProperty.call(layergroupResult, 'errors')); + assert.strictEqual(layergroupResult.errors.length, 1); assert.ok(layergroupResult.errors[0].match(/permission denied/), layergroupResult.errors[0]); testClient.drain(done); @@ -152,7 +150,7 @@ describe('authorization', function() { testClient.getTile(0, 0, 0, function (err, res, tile) { assert.ifError(err); - assert.equal(res.statusCode, 200); + assert.strictEqual(res.statusCode, 200); assert.ok(tile instanceof mapnik.Image); testClient.drain(done); @@ -172,13 +170,13 @@ describe('authorization', function() { } ] }; - const testClient = new TestClient(mapConfig); //no apikey provided, using default + const testClient = new TestClient(mapConfig); // no apikey provided, using default - testClient.getLayergroup({ response: { status: 403 } }, function (err, layergroupResult) { //TODO 401 + testClient.getLayergroup({ response: { status: 403 } }, function (err, layergroupResult) { // TODO 401 assert.ifError(err); - assert.ok(layergroupResult.hasOwnProperty('errors')); - assert.equal(layergroupResult.errors.length, 1); + assert.ok(Object.prototype.hasOwnProperty.call(layergroupResult, 'errors')); + assert.strictEqual(layergroupResult.errors.length, 1); assert.ok(layergroupResult.errors[0].match(/permission denied/), layergroupResult.errors[0]); testClient.drain(done); @@ -204,8 +202,8 @@ describe('authorization', function() { testClient.getLayergroup({ response: { status: 403 } }, function (err, layergroupResult) { assert.ifError(err); - assert.ok(layergroupResult.hasOwnProperty('errors')); - assert.equal(layergroupResult.errors.length, 1); + assert.ok(Object.prototype.hasOwnProperty.call(layergroupResult, 'errors')); + assert.strictEqual(layergroupResult.errors.length, 1); assert.ok(layergroupResult.errors[0].match(/Forbidden/), layergroupResult.errors[0]); testClient.drain(done); @@ -305,8 +303,8 @@ describe('authorization', function() { ], analyses: [ { - id: "HEAD1", - type: "buffer", + id: 'HEAD1', + type: 'buffer', params: { source: { id: 'HEAD2', @@ -333,7 +331,6 @@ describe('authorization', function() { describe('Named maps', function () { describe('LIST Named maps', function () { - it('should fail while listing named maps with a regular apikey token', function (done) { const apikeyToken = 'regular1'; @@ -342,9 +339,9 @@ describe('authorization', function() { testClient.getNamedMapList({ response: { status: 403 } }, function (err, res, body) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(body.errors.length, 1); + assert.strictEqual(body.errors.length, 1); assert.ok(body.errors[0].match(/Forbidden/), body.errors[0]); testClient.drain(done); @@ -359,9 +356,9 @@ describe('authorization', function() { testClient.getNamedMapList({ response: { status: 403 } }, function (err, res, body) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(body.errors.length, 1); + assert.strictEqual(body.errors.length, 1); assert.ok(body.errors[0].match(/Forbidden/), body.errors[0]); testClient.drain(done); @@ -376,9 +373,9 @@ describe('authorization', function() { testClient.getNamedMapList({ response: { status: 401 } }, function (err, res, body) { assert.ifError(err); - assert.equal(res.statusCode, 401); + assert.strictEqual(res.statusCode, 401); - assert.equal(body.errors.length, 1); + assert.strictEqual(body.errors.length, 1); assert.ok(body.errors[0].match(/Unauthorized/), body.errors[0]); testClient.drain(done); @@ -393,7 +390,7 @@ describe('authorization', function() { testClient.getNamedMapList({}, function (err, res, body) { assert.ifError(err); - assert.equal(res.statusCode, 200); + assert.strictEqual(res.statusCode, 200); assert.ok(Array.isArray(body.template_ids)); testClient.drain(done); @@ -418,7 +415,7 @@ describe('authorization', function() { options: { sql: 'select * from test_table_localhost_regular1', cartocss: TestClient.CARTOCSS.POINTS, - cartocss_version: '2.3.0', + cartocss_version: '2.3.0' } }] } @@ -432,7 +429,7 @@ describe('authorization', function() { testClient.getTile(0, 0, 0, function (err, res, tile) { assert.ifError(err); - assert.equal(res.statusCode, 200); + assert.strictEqual(res.statusCode, 200); assert.ok(tile instanceof mapnik.Image); testClient.drain(done); @@ -447,9 +444,9 @@ describe('authorization', function() { testClient.createTemplate({ response: { status: 403 } }, function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]); testClient.drain(done); @@ -464,9 +461,9 @@ describe('authorization', function() { testClient.createTemplate({ response: { status: 403 } }, function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]); testClient.drain(done); @@ -481,9 +478,9 @@ describe('authorization', function() { testClient.createTemplate({ response: { status: 401 } }, function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 401); + assert.strictEqual(res.statusCode, 401); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Unauthorized/), response.errors[0]); testClient.drain(done); @@ -508,7 +505,7 @@ describe('authorization', function() { options: { sql: 'select * from test_table_localhost_regular1', cartocss: TestClient.CARTOCSS.POINTS, - cartocss_version: '2.3.0', + cartocss_version: '2.3.0' } }] } @@ -534,7 +531,7 @@ describe('authorization', function() { function (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 204); + assert.strictEqual(res.statusCode, 204); testClientDelete.drain(done); } @@ -562,9 +559,9 @@ describe('authorization', function() { function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]); testClientDelete.drain(done); @@ -593,9 +590,9 @@ describe('authorization', function() { function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]); testClientDelete.drain(done); @@ -624,9 +621,9 @@ describe('authorization', function() { function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 401); + assert.strictEqual(res.statusCode, 401); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Unauthorized/), response.errors[0]); testClientDelete.drain(done); @@ -653,7 +650,7 @@ describe('authorization', function() { options: { sql: 'select * from test_table_localhost_regular1', cartocss: TestClient.CARTOCSS.POINTS, - cartocss_version: '2.3.0', + cartocss_version: '2.3.0' } }] } @@ -679,7 +676,7 @@ describe('authorization', function() { function (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200); + assert.strictEqual(res.statusCode, 200); testClientDelete.drain(done); } @@ -707,9 +704,9 @@ describe('authorization', function() { function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]); testClientGet.drain(done); @@ -738,9 +735,9 @@ describe('authorization', function() { function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]); testClientGet.drain(done); @@ -769,9 +766,9 @@ describe('authorization', function() { function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 401); + assert.strictEqual(res.statusCode, 401); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Unauthorized/), response.errors[0]); testClientGet.drain(done); @@ -798,7 +795,7 @@ describe('authorization', function() { options: { sql: 'select * from test_table_localhost_regular1', cartocss: TestClient.CARTOCSS.POINTS, - cartocss_version: '2.3.0', + cartocss_version: '2.3.0' } }] } @@ -825,7 +822,7 @@ describe('authorization', function() { function (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200); + assert.strictEqual(res.statusCode, 200); testClientDelete.drain(done); } @@ -854,9 +851,9 @@ describe('authorization', function() { function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]); testClientDelete.drain(done); @@ -886,9 +883,9 @@ describe('authorization', function() { function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 403); + assert.strictEqual(res.statusCode, 403); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]); testClientDelete.drain(done); @@ -918,9 +915,9 @@ describe('authorization', function() { function (err, res, response) { assert.ifError(err); - assert.equal(res.statusCode, 401); + assert.strictEqual(res.statusCode, 401); - assert.equal(response.errors.length, 1); + assert.strictEqual(response.errors.length, 1); assert.ok(response.errors[0].match(/Unauthorized/), response.errors[0]); testClientDelete.drain(done); @@ -928,7 +925,6 @@ describe('authorization', function() { ); }); }); - }); }); }); diff --git a/test/acceptance/buffer-size-format-test.js b/test/acceptance/buffer-size-format-test.js index 62d19ccc..1a5e653a 100644 --- a/test/acceptance/buffer-size-format-test.js +++ b/test/acceptance/buffer-size-format-test.js @@ -39,13 +39,13 @@ function createMapConfig (bufferSize, cartocss) { version: '1.6.0', buffersize: bufferSize, layers: [{ - type: "cartodb", + type: 'cartodb', options: { sql: [ 'select', ' *', 'from', - ' populated_places_simple_reduced', + ' populated_places_simple_reduced' ].join('\n'), cartocss: cartocss, cartocss_version: '2.3.0', @@ -88,7 +88,7 @@ describe('buffer size per format', function () { assert: function (tile, callback) { var tileJSON = tile.toJSON(); var features = tileJSON[0].features; - assert.equal(features.length, 1); + assert.strictEqual(features.length, 1); callback(); } }, @@ -101,7 +101,7 @@ describe('buffer size per format', function () { assert: function (tile, callback) { var tileJSON = tile.toJSON(); var features = tileJSON[0].features; - assert.equal(features.length, 9); + assert.strictEqual(features.length, 9); callback(); } }, @@ -113,7 +113,7 @@ describe('buffer size per format', function () { fixturePath: './test/fixtures/buffer-size/tile-grid.json.7.64.48-buffer-size-0.grid.json', mapConfig: createMapConfig({ 'grid.json': 0 }), assert: function (tile, callback) { - assert.utfgridEqualsFile(tile, this.fixturePath, 2,callback); + assert.utfgridEqualsFile(tile, this.fixturePath, 2, callback); } }, { @@ -129,7 +129,7 @@ describe('buffer size per format', function () { } ]; - afterEach(function(done) { + afterEach(function (done) { if (testClient) { return testClient.drain(done); } @@ -162,7 +162,7 @@ describe('buffer size per format', function () { testFn(test); }); - describe('using mapnik mvt renderer', function() { + describe('using mapnik mvt renderer', function () { before(function () { serverOptions.renderer.mvt.usePostGIS = false; }); @@ -171,7 +171,7 @@ describe('buffer size per format', function () { }); }); - describe('using postgis mvt renderer', function() { + describe('using postgis mvt renderer', function () { before(function () { serverOptions.renderer.mvt.usePostGIS = true; }); @@ -185,15 +185,15 @@ function createBufferSizeTemplate (name, buffersize, placeholders, cartocss) { cartocss = cartocss || CARTOCSS_LABELS; return { - "version": "0.0.1", - "name": name, - "placeholders": placeholders || { - "buffersize": { - "type": "number", - "default": 0 + version: '0.0.1', + name: name, + placeholders: placeholders || { + buffersize: { + type: 'number', + default: 0 } }, - "layergroup": createMapConfig(buffersize) + layergroup: createMapConfig(buffersize) }; } @@ -204,7 +204,7 @@ describe('buffer size per format for named maps', function () { coords: { z: 7, x: 64, y: 48 }, format: 'png', fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-0.png', - template: createBufferSizeTemplate('named-default-buffer-size', {png: '<%= buffersize %>'}), + template: createBufferSizeTemplate('named-default-buffer-size', { png: '<%= buffersize %>' }), assert: function (tile, callback) { assert.imageIsSimilarToFile(tile, this.fixturePath, IMAGE_TOLERANCE_PER_MIL, callback); } @@ -215,7 +215,7 @@ describe('buffer size per format for named maps', function () { format: 'png', placeholders: { buffersize: 128 }, fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.png', - template: createBufferSizeTemplate('named-custom-buffer-size', { png: '<%= buffersize %>'}), + template: createBufferSizeTemplate('named-custom-buffer-size', { png: '<%= buffersize %>' }), assert: function (tile, callback) { assert.imageIsSimilarToFile(tile, this.fixturePath, IMAGE_TOLERANCE_PER_MIL, callback); } @@ -229,9 +229,9 @@ describe('buffer size per format for named maps', function () { template: createBufferSizeTemplate('named-default-buffer-size-by-format', { png: '<%= buffersize_png %>' }, { - "buffersize_png": { - "type": "number", - "default": "0" + buffersize_png: { + type: 'number', + default: '0' } }), assert: function (tile, callback) { @@ -247,9 +247,9 @@ describe('buffer size per format for named maps', function () { template: createBufferSizeTemplate('named-custom-buffer-size-by-format', { png: '<%= buffersize_png %>' }, { - "buffersize_png": { - "type": "number", - "default": "0" + buffersize_png: { + type: 'number', + default: '0' } }), assert: function (tile, callback) { @@ -266,13 +266,13 @@ describe('buffer size per format for named maps', function () { template: createBufferSizeTemplate('named-default-buffer-size-by-format-gridjson', { 'grid.json': '<%= buffersize_gridjson %>' }, { - "buffersize_gridjson": { - "type": "number", - "default": "0" + buffersize_gridjson: { + type: 'number', + default: '0' } }), assert: function (tile, callback) { - assert.utfgridEqualsFile(tile, this.fixturePath, 2,callback); + assert.utfgridEqualsFile(tile, this.fixturePath, 2, callback); } }, { @@ -285,9 +285,9 @@ describe('buffer size per format for named maps', function () { template: createBufferSizeTemplate('named-custom-buffer-size-by-format-gridjson', { 'grid.json': '<%= buffersize_gridjson %>' }, { - "buffersize_gridjson": { - "type": "number", - "default": "0" + buffersize_gridjson: { + type: 'number', + default: '0' } }), assert: function (tile, callback) { @@ -296,7 +296,7 @@ describe('buffer size per format for named maps', function () { } ]; - afterEach(function(done) { + afterEach(function (done) { if (this.testClient) { return this.testClient.drain(done); } @@ -315,14 +315,13 @@ describe('buffer size per format for named maps', function () { this.testClient.getTile(coords.z, coords.x, coords.y, options, function (err, res, tile) { assert.ifError(err); // To generate images use: - //tile.save('./test/fixtures/buffer-size/tile-7.64.48-buffer-size-0-test.png'); + // tile.save('./test/fixtures/buffer-size/tile-7.64.48-buffer-size-0-test.png'); test.assert(tile, done); }); }); }); }); - describe('buffer size per format for named maps w/o placeholders', function () { let testClient; @@ -378,7 +377,7 @@ describe('buffer size per format for named maps w/o placeholders', function () { var vtileJSON = vtile.toJSON(); var vtileFeatures = vtileJSON[0].features; - assert.equal(features.length, vtileFeatures.length); + assert.strictEqual(features.length, vtileFeatures.length); callback(); } }, @@ -403,7 +402,7 @@ describe('buffer size per format for named maps w/o placeholders', function () { var vtileJSON = vtile.toJSON(); var vtileFeatures = vtileJSON[0].features; - assert.equal(features.length, vtileFeatures.length); + assert.strictEqual(features.length, vtileFeatures.length); callback(); } }, @@ -420,7 +419,7 @@ describe('buffer size per format for named maps w/o placeholders', function () { fixturePath: './test/fixtures/buffer-size/tile-grid.json.7.64.48-buffer-size-0.grid.json', template: createBufferSizeTemplate('named-no-buffer-size-grid-json-0', {}, {}), assert: function (tile, callback) { - assert.utfgridEqualsFile(tile, this.fixturePath, 2,callback); + assert.utfgridEqualsFile(tile, this.fixturePath, 2, callback); } }, { @@ -454,11 +453,11 @@ describe('buffer size per format for named maps w/o placeholders', function () { assert: function (tile, callback) { assert.imageIsSimilarToFile(tile, this.fixturePath, IMAGE_TOLERANCE_PER_MIL, callback); } - }, + } ]; - afterEach(function(done) { + afterEach(function (done) { if (testClient) { return testClient.drain(done); } @@ -483,7 +482,7 @@ describe('buffer size per format for named maps w/o placeholders', function () { testClient.getTile(coords.z, coords.x, coords.y, options, function (err, res, tile) { assert.ifError(err); // To generate images use: - //tile.save(test.fixturePath); + // tile.save(test.fixturePath); // require('fs').writeFileSync(test.fixturePath, JSON.stringify(tile)); // require('fs').writeFileSync(test.fixturePath, tile.getDataSync()); test.assert(tile, done); @@ -495,7 +494,7 @@ describe('buffer size per format for named maps w/o placeholders', function () { testFn(test); }); - describe('using mapnik mvt renderer', function() { + describe('using mapnik mvt renderer', function () { before(function () { serverOptions.renderer.mvt.usePostGIS = false; }); @@ -504,7 +503,7 @@ describe('buffer size per format for named maps w/o placeholders', function () { }); }); - describe('using postgis mvt renderer', function() { + describe('using postgis mvt renderer', function () { before(function () { serverOptions.renderer.mvt.usePostGIS = true; }); diff --git a/test/acceptance/cache/cache-control-header-test.js b/test/acceptance/cache/cache-control-header-test.js index 3094c8a2..62a214bc 100644 --- a/test/acceptance/cache/cache-control-header-test.js +++ b/test/acceptance/cache/cache-control-header-test.js @@ -54,7 +54,7 @@ describe('cache-control header', function () { return done(err); } - assert.equal(res.headers['cache-control'], `public,max-age=${ttl}`); + assert.strictEqual(res.headers['cache-control'], `public,max-age=${ttl}`); testClient.drain(done); }); }); @@ -80,8 +80,8 @@ describe('cache-control header', function () { } const cacheControl = res.headers['cache-control']; - const [ , maxAge ] = cacheControl.split(','); - const [ , value ] = maxAge.split('='); + const [, maxAge] = cacheControl.split(','); + const [, value] = maxAge.split('='); assert.ok(Number(value) <= ttl); @@ -120,8 +120,8 @@ describe('cache-control header', function () { } const cacheControl = res.headers['cache-control']; - const [ , maxAge ] = cacheControl.split(','); - const [ , value ] = maxAge.split('='); + const [, maxAge] = cacheControl.split(','); + const [, value] = maxAge.split('='); assert.ok(Number(value) <= ttl); @@ -129,7 +129,7 @@ describe('cache-control header', function () { }); }); - it('tile from a dynamic query which doesn\'t use a table' , function (done) { + it('tile from a dynamic query which doesn\'t use a table', function (done) { const ttl = ONE_YEAR_IN_SECONDS; const mapConfig = createMapConfig(); @@ -140,7 +140,7 @@ describe('cache-control header', function () { return done(err); } - assert.equal(res.headers['cache-control'], `public,max-age=${ttl}`); + assert.strictEqual(res.headers['cache-control'], `public,max-age=${ttl}`); testClient.drain(done); }); }); @@ -181,7 +181,7 @@ describe('cache-control header', function () { return done(err); } - assert.equal(res.headers['cache-control'], `public,max-age=${ttl}`); + assert.strictEqual(res.headers['cache-control'], `public,max-age=${ttl}`); testClient.drain(done); }); }); diff --git a/test/acceptance/cache/cache-headers-test.js b/test/acceptance/cache/cache-headers-test.js index 974a60ff..c77a3b50 100644 --- a/test/acceptance/cache/cache-headers-test.js +++ b/test/acceptance/cache/cache-headers-test.js @@ -10,7 +10,7 @@ var serverOptions = require('../../../lib/server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('get requests with cache headers', function() { +describe('get requests with cache headers', function () { var server; before(function () { @@ -18,13 +18,12 @@ describe('get requests with cache headers', function() { server.setMaxListeners(0); }); - var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { + afterEach(function (done) { testHelper.deleteRedisKeys(keysToDelete, done); }); @@ -34,28 +33,28 @@ describe('get requests with cache headers', function() { 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"] + 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" + surrogate_keys: 't:77pJnX' }, - "data": + data: { version: '1.5.0', layers: [ { options: { source: { - id: "2570e105-7b37-40d2-bdf4-1af889598745" + 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', + id: 'cartodb_id', columns: [ 'name', 'address' @@ -66,39 +65,39 @@ describe('get requests with cache headers', function() { ], analyses: [ { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select * from test_table limit 2" + 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"] + 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" + surrogate_keys: 't:77pJnX t:iL4eth' }, - "data": + data: { version: '1.5.0', layers: [ { options: { source: { - id: "2570e105-7b37-40d2-bdf4-1af889598745" + 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', + id: 'cartodb_id', columns: [ 'name', 'address' @@ -109,23 +108,23 @@ describe('get requests with cache headers', function() { ], analyses: [ { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "buffer", - "params": { - "source": { - "type": "source", - "params": { - "query": "select * from test_table limit 2" + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'buffer', + params: { + source: { + type: 'source', + params: { + query: 'select * from test_table limit 2' } }, - "radius": 50000 + radius: 50000 } } ] } }]; - var layergroupRequest = function(mapConfig) { + var layergroupRequest = function (mapConfig) { return { url: '/api/v1/map?api_key=1234&config=' + encodeURIComponent(JSON.stringify(mapConfig)), method: 'GET', @@ -135,12 +134,12 @@ describe('get requests with cache headers', function() { }; }; - function getRequest(url, addApiKey, callbackName) { + function getRequest (url, addApiKey, callbackName) { var params = {}; - if (!!addApiKey) { + if (addApiKey) { params.api_key = '1234'; } - if (!!callbackName) { + if (callbackName) { params.callback = callbackName; } @@ -154,33 +153,33 @@ describe('get requests with cache headers', function() { }; } - function validateCacheHeaders(done, expectedCacheHeaders) { - return function(res, err) { + 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']); - assert.equal(res.headers.vary, 'Authorization'); + assert.strictEqual(res.headers.vary, 'Authorization'); if (expectedCacheHeaders) { validateXChannelHeaders(res.headers, expectedCacheHeaders); - assert.equal(res.headers['surrogate-key'], expectedCacheHeaders.surrogate_keys); + assert.strictEqual(res.headers['surrogate-key'], expectedCacheHeaders.surrogate_keys); } done(); }; } - function validateXChannelHeaders(headers, expectedCacheHeaders) { + 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()); + assert.strictEqual(dbName, expectedCacheHeaders.x_cache_channel.db_name); + assert.deepStrictEqual(tables, expectedCacheHeaders.x_cache_channel.tables.sort()); } - function noCacheHeaders(done) { - return function(res, err) { + function noCacheHeaders (done) { + return function (res, err) { if (err) { return done(err); } @@ -197,12 +196,12 @@ describe('get requests with cache headers', function() { }; } - function withLayergroupId(mapConfig, callback) { + function withLayergroupId (mapConfig, callback) { assert.response( server, layergroupRequest(mapConfig), statusOkResponse, - function(res, err) { + function (res, err) { if (err) { return callback(err); } @@ -214,19 +213,20 @@ describe('get requests with cache headers', function() { ); } - mapConfigs.forEach(function(mapConfigData) { - describe(mapConfigData.description, function() { + 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) { + it('/api/v1/map Map instantiation', function (done) { var testFn = validateCacheHeaders(done, expectedCacheHeaders); - withLayergroupId(mapConfig, function(err, layergroupId, res) { - testFn(res); + withLayergroupId(mapConfig, function (err, layergroupId, res) { + testFn(res, err); }); }); - it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik retina tiles', function(done) { - withLayergroupId(mapConfig, function(err, layergroupId) { + it('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik retina tiles', function (done) { + withLayergroupId(mapConfig, function (err, layergroupId) { + assert.ifError(err); assert.response( server, getRequest('/api/v1/map/' + layergroupId + '/0/0/0@2x.png', true), @@ -235,8 +235,9 @@ describe('get requests with cache headers', function() { }); }); - it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik tiles', function(done) { - withLayergroupId(mapConfig, function(err, layergroupId) { + it('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik tiles', function (done) { + withLayergroupId(mapConfig, function (err, layergroupId) { + assert.ifError(err); assert.response( server, getRequest('/api/v1/map/' + layergroupId + '/0/0/0.png', true), @@ -245,8 +246,9 @@ describe('get requests with cache headers', function() { }); }); - it ('/api/v1/map/:token/:layer/:z/:x/:y.(:format) Per :layer rendering', function(done) { - withLayergroupId(mapConfig, function(err, layergroupId) { + it('/api/v1/map/:token/:layer/:z/:x/:y.(:format) Per :layer rendering', function (done) { + withLayergroupId(mapConfig, function (err, layergroupId) { + assert.ifError(err); assert.response( server, getRequest('/api/v1/map/' + layergroupId + '/0/0/0/0.png', true), @@ -255,8 +257,9 @@ describe('get requests with cache headers', function() { }); }); - it ('/api/v1/map/:token/:layer/attributes/:fid endpoint for info windows', function(done) { - withLayergroupId(mapConfig, function(err, layergroupId) { + it('/api/v1/map/:token/:layer/attributes/:fid endpoint for info windows', function (done) { + withLayergroupId(mapConfig, function (err, layergroupId) { + assert.ifError(err); assert.response( server, getRequest('/api/v1/map/' + layergroupId + '/0/attributes/1', true), @@ -265,8 +268,9 @@ describe('get requests with cache headers', function() { }); }); - it ('/api/v1/map/static/center/:token/:z/:lat/:lng/:width/:height.:format static maps', function(done) { - withLayergroupId(mapConfig, function(err, layergroupId) { + it('/api/v1/map/static/center/:token/:z/:lat/:lng/:width/:height.:format static maps', function (done) { + withLayergroupId(mapConfig, function (err, layergroupId) { + assert.ifError(err); assert.response( server, getRequest('/api/v1/map/static/center/' + layergroupId + '/0/0/0/400/300.png', true), @@ -275,8 +279,9 @@ describe('get requests with cache headers', function() { }); }); - it ('/api/v1/map/static/bbox/:token/:bbox/:width/:height.:format static maps', function(done) { - withLayergroupId(mapConfig, function(err, layergroupId) { + it('/api/v1/map/static/bbox/:token/:bbox/:width/:height.:format static maps', function (done) { + withLayergroupId(mapConfig, function (err, layergroupId) { + assert.ifError(err); assert.response( server, getRequest('/api/v1/map/static/bbox/' + layergroupId + '/-45,-45,45,45/400/300.png', true), @@ -287,9 +292,8 @@ describe('get requests with cache headers', function() { }); }); - describe('cache headers should NOT be present', function() { - - it('/', function(done) { + describe('cache headers should NOT be present', function () { + it('/', function (done) { assert.response( server, getRequest('/'), @@ -298,7 +302,7 @@ describe('get requests with cache headers', function() { ); }); - it('/version', function(done) { + it('/version', function (done) { assert.response( server, getRequest('/version'), @@ -307,7 +311,7 @@ describe('get requests with cache headers', function() { ); }); - it('/health', function(done) { + it('/health', function (done) { assert.response( server, getRequest('/health'), @@ -316,7 +320,7 @@ describe('get requests with cache headers', function() { ); }); - it('/api/v1/map/named list named maps', function(done) { + it('/api/v1/map/named list named maps', function (done) { assert.response( server, getRequest('/api/v1/map/named', true), @@ -325,18 +329,17 @@ describe('get requests with cache headers', function() { ); }); - describe('with named maps', function() { - + describe('with named maps', function () { var templateName = 'x_cache'; - beforeEach(function(done) { - var template = { + beforeEach(function (done) { + var template = { version: '0.0.1', name: templateName, auth: { method: 'open' }, - layergroup: mapConfigs[0].data + layergroup: mapConfigs[0].data }; var namedMapRequest = { @@ -353,13 +356,13 @@ describe('get requests with cache headers', function() { server, namedMapRequest, statusOkResponse, - function(res, err) { + function (res, err) { done(err); } ); }); - afterEach(function(done) { + afterEach(function (done) { assert.response( server, { @@ -372,14 +375,13 @@ describe('get requests with cache headers', function() { { status: 204 }, - function(res, err) { + function (res, err) { done(err); } ); }); - - it('/api/v1/map/named/:template_id Named map retrieval', function(done) { + it('/api/v1/map/named/:template_id Named map retrieval', function (done) { assert.response( server, getRequest('/api/v1/map/named/' + templateName, true), @@ -388,7 +390,7 @@ describe('get requests with cache headers', function() { ); }); - it('/api/v1/map/named/:template_id/jsonp Named map retrieval', function(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'), diff --git a/test/acceptance/cache/surrogate-keys-invalidation-test.js b/test/acceptance/cache/surrogate-keys-invalidation-test.js index f884b07c..4e33947b 100644 --- a/test/acceptance/cache/surrogate-keys-invalidation-test.js +++ b/test/acceptance/cache/surrogate-keys-invalidation-test.js @@ -2,16 +2,15 @@ var testHelper = require('../../support/test-helper'); -var assert = require('../../support/assert'); -var step = require('step'); +var assert = require('../../support/assert'); +var step = require('step'); var FastlyPurge = require('fastly-purge'); var _ = require('underscore'); var NamedMapsCacheEntry = require('../../../lib/cache/model/named-maps-entry'); var CartodbWindshaft = require('../../../lib/server'); var nock = require('nock'); -describe('templates surrogate keys', function() { - +describe('templates surrogate keys', function () { var serverOptions = require('../../../lib/server-options'); // Enable Varnish purge for tests @@ -48,7 +47,7 @@ describe('templates surrogate keys', function() { auth: { method: 'open' }, - layergroup: { + layergroup: { version: '1.2.0', layers: [ { @@ -61,12 +60,16 @@ describe('templates surrogate keys', function() { ] } }; - var templateUpdated = _.extend({}, template, {layergroup: {layers: [{ - type: 'plain', - options: { - color: 'red' + var templateUpdated = _.extend({}, template, { + layergroup: { + layers: [{ + type: 'plain', + options: { + color: 'red' + } + }] } - }]} }); + }); var expectedBody = { template_id: expectedTemplateId }; var varnishHttpUrl = [ @@ -77,7 +80,7 @@ describe('templates surrogate keys', function() { var invalidationMatchHeader = '\\b' + cacheEntryKey + '\\b'; var fastlyPurgePath = '/service/' + FAKE_FASTLY_SERVICE_ID + '/purge/' + cacheEntryKey; - after(function(done) { + after(function (done) { serverOptions.varnish_purge_enabled = false; serverOptions.varnish_host = varnishHost; serverOptions.varnish_purge_enabled = varnishPurgeEnabled; @@ -90,7 +93,7 @@ describe('templates surrogate keys', function() { done(); }); - function createTemplate(callback) { + function createTemplate (callback) { var postTemplateRequest = { url: '/api/v1/map/named?api_key=1234', method: 'POST', @@ -102,34 +105,33 @@ describe('templates surrogate keys', function() { }; step( - function postTemplate() { + function postTemplate () { var next = this; assert.response(server, postTemplateRequest, { status: 200 }, - function(res) { + function (res) { next(null, res); } ); }, - function rePostTemplate(err, res) { + function rePostTemplate (err, res) { if (err) { throw err; } var parsedBody = JSON.parse(res.body); - assert.deepEqual(parsedBody, expectedBody); + assert.deepStrictEqual(parsedBody, expectedBody); return true; }, - function finish(err) { + function finish (err) { callback(err); } ); } - it("invalidates surrogate keys on template update", function(done) { - + it('invalidates surrogate keys on template update', function (done) { var scope = nock(varnishHttpUrl) .intercept('/key', 'PURGE') .matchHeader('Invalidation-Match', invalidationMatchHeader) @@ -140,14 +142,14 @@ describe('templates surrogate keys', function() { .matchHeader('Fastly-Key', FAKE_FASTLY_API_KEY) .matchHeader('Accept', 'application/json') .reply(200, { - status:'ok' + status: 'ok' }); step( - function createTemplateToUpdate() { + function createTemplateToUpdate () { createTemplate(this); }, - function putValidTemplate(err) { + function putValidTemplate (err) { if (err) { throw err; } @@ -166,36 +168,35 @@ describe('templates surrogate keys', function() { { status: 200 }, - function(res) { - setTimeout(function() { + function (res) { + setTimeout(function () { next(null, res); }, 50); } ); }, - function checkValidUpdate(err, res) { + function checkValidUpdate (err, res) { if (err) { throw err; } var parsedBody = JSON.parse(res.body); - assert.deepEqual(parsedBody, expectedBody); + assert.deepStrictEqual(parsedBody, expectedBody); - assert.equal(scope.pendingMocks().length, 0); - assert.equal(fastlyScope.pendingMocks().length, 0); + assert.strictEqual(scope.pendingMocks().length, 0); + assert.strictEqual(fastlyScope.pendingMocks().length, 0); return null; }, - function finish(err) { - if ( err ) { + function finish (err) { + if (err) { return done(err); } - testHelper.deleteRedisKeys({'map_tpl|localhost': 0}, done); + testHelper.deleteRedisKeys({ 'map_tpl|localhost': 0 }, done); } ); }); - it("invalidates surrogate on template deletion", function(done) { - + it('invalidates surrogate on template deletion', function (done) { var scope = nock(varnishHttpUrl) .intercept('/key', 'PURGE') .matchHeader('Invalidation-Match', invalidationMatchHeader) @@ -206,14 +207,14 @@ describe('templates surrogate keys', function() { .matchHeader('Fastly-Key', FAKE_FASTLY_API_KEY) .matchHeader('Accept', 'application/json') .reply(200, { - status:'ok' + status: 'ok' }); step( - function createTemplateToDelete() { + function createTemplateToDelete () { createTemplate(this); }, - function deleteValidTemplate(err) { + function deleteValidTemplate (err) { if (err) { throw err; } @@ -231,31 +232,30 @@ describe('templates surrogate keys', function() { { status: 204 }, - function(res) { - setTimeout(function() { + function (res) { + setTimeout(function () { next(null, res); }, 50); } ); }, - function checkValidUpdate(err) { + function checkValidUpdate (err) { if (err) { throw err; } - assert.equal(scope.pendingMocks().length, 0); - assert.equal(fastlyScope.pendingMocks().length, 0); + assert.strictEqual(scope.pendingMocks().length, 0); + assert.strictEqual(fastlyScope.pendingMocks().length, 0); return null; }, - function finish(err) { + function finish (err) { done(err); } ); }); - it("should update template even if surrogate key invalidation fails", function(done) { - + it('should update template even if surrogate key invalidation fails', function (done) { var scope = nock(varnishHttpUrl) .intercept('/key', 'PURGE') .matchHeader('Invalidation-Match', invalidationMatchHeader) @@ -266,14 +266,14 @@ describe('templates surrogate keys', function() { .matchHeader('Fastly-Key', FAKE_FASTLY_API_KEY) .matchHeader('Accept', 'application/json') .reply(200, { - status:'ok' + status: 'ok' }); step( - function createTemplateToUpdate() { + function createTemplateToUpdate () { createTemplate(this); }, - function putValidTemplate(err) { + function putValidTemplate (err) { if (err) { throw err; } @@ -292,32 +292,31 @@ describe('templates surrogate keys', function() { { status: 200 }, - function(res) { - setTimeout(function() { + function (res) { + setTimeout(function () { next(null, res); }, 50); } ); }, - function checkValidUpdate(err, res) { + function checkValidUpdate (err, res) { if (err) { throw err; } var parsedBody = JSON.parse(res.body); - assert.deepEqual(parsedBody, expectedBody); + assert.deepStrictEqual(parsedBody, expectedBody); - assert.equal(scope.pendingMocks().length, 0); - assert.equal(fastlyScope.pendingMocks().length, 0); + assert.strictEqual(scope.pendingMocks().length, 0); + assert.strictEqual(fastlyScope.pendingMocks().length, 0); return null; }, - function finish(err) { - if ( err ) { + function finish (err) { + if (err) { return done(err); } - testHelper.deleteRedisKeys({'map_tpl|localhost': 0}, done); + testHelper.deleteRedisKeys({ 'map_tpl|localhost': 0 }, done); } ); }); - }); diff --git a/test/acceptance/cluster-test.js b/test/acceptance/cluster-test.js index 33ea4234..656c10f2 100644 --- a/test/acceptance/cluster-test.js +++ b/test/acceptance/cluster-test.js @@ -48,7 +48,7 @@ describe('cluster', function () { }]); const testClient = new TestClient(mapConfig); const zoom = 0; - const cartodb_id = 1; + const cartodbId = 1; const layerId = 0; const params = { response: { @@ -56,14 +56,14 @@ describe('cluster', function () { } }; - testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => { + testClient.getClusterFeatures(zoom, cartodbId, layerId, params, (err, body) => { if (err) { return done(err); } assert.deepStrictEqual(body, { - errors:[ 'Map f697fb370c6479559ae2f66d684e8227 has no aggregation defined for layer 0' ], - errors_with_context:[ + errors: ['Map f697fb370c6479559ae2f66d684e8227 has no aggregation defined for layer 0'], + errors_with_context: [ { layer: { index: '0', @@ -90,7 +90,7 @@ describe('cluster', function () { }]); const testClient = new TestClient(mapConfig); const zoom = 0; - const cartodb_id = 1; + const cartodbId = 1; const layerId = 0; const params = { response: { @@ -98,14 +98,14 @@ describe('cluster', function () { } }; - testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => { + testClient.getClusterFeatures(zoom, cartodbId, layerId, params, (err, body) => { if (err) { return done(err); } assert.deepStrictEqual(body, { - errors:[ 'Map 7521bcd1029c401289dd651ce91d5d9d has no aggregation defined for layer 0' ], - errors_with_context:[ + errors: ['Map 7521bcd1029c401289dd651ce91d5d9d has no aggregation defined for layer 0'], + errors_with_context: [ { layer: { index: '0', @@ -129,85 +129,85 @@ describe('cluster', function () { zoom: 0, cartodb_id: 1, resolution: 0.5, - expected: [ { cartodb_id: 1, value: -3, type: 'odd' } ] + expected: [{ cartodb_id: 1, value: -3, type: 'odd' }] }, { zoom: 0, cartodb_id: 2, resolution: 0.5, - expected: [ { cartodb_id: 2, value: -2, type: 'even' } ] + expected: [{ cartodb_id: 2, value: -2, type: 'even' }] }, { zoom: 0, cartodb_id: 3, resolution: 0.5, - expected: [ { cartodb_id: 3, value: -1, type: 'odd' } ] + expected: [{ cartodb_id: 3, value: -1, type: 'odd' }] }, { zoom: 0, cartodb_id: 4, resolution: 0.5, - expected: [ { cartodb_id: 4, value: 0, type: 'even' } ] + expected: [{ cartodb_id: 4, value: 0, type: 'even' }] }, { zoom: 0, cartodb_id: 5, resolution: 0.5, - expected: [ { cartodb_id: 5, value: 1, type: 'odd' } ] + expected: [{ cartodb_id: 5, value: 1, type: 'odd' }] }, { zoom: 0, cartodb_id: 6, resolution: 0.5, - expected: [ { cartodb_id: 6, value: 2, type: 'even' } ] + expected: [{ cartodb_id: 6, value: 2, type: 'even' }] }, { zoom: 0, cartodb_id: 7, resolution: 0.5, - expected: [ { cartodb_id: 7, value: 3, type: 'odd' } ] + expected: [{ cartodb_id: 7, value: 3, type: 'odd' }] }, { zoom: 0, cartodb_id: 1, resolution: 1, - expected: [ { cartodb_id: 1, value: -3, type: 'odd' } ] + expected: [{ cartodb_id: 1, value: -3, type: 'odd' }] }, { zoom: 0, cartodb_id: 2, resolution: 1, - expected: [ { cartodb_id: 2, value: -2, type: 'even' } ] + expected: [{ cartodb_id: 2, value: -2, type: 'even' }] }, { zoom: 0, cartodb_id: 3, resolution: 1, - expected: [ { cartodb_id: 3, value: -1, type: 'odd' } ] + expected: [{ cartodb_id: 3, value: -1, type: 'odd' }] }, { zoom: 0, cartodb_id: 4, resolution: 1, - expected: [ { cartodb_id: 4, value: 0, type: 'even' } ] + expected: [{ cartodb_id: 4, value: 0, type: 'even' }] }, { zoom: 0, cartodb_id: 5, resolution: 1, - expected: [ { cartodb_id: 5, value: 1, type: 'odd' } ] + expected: [{ cartodb_id: 5, value: 1, type: 'odd' }] }, { zoom: 0, cartodb_id: 6, resolution: 1, - expected: [ { cartodb_id: 6, value: 2, type: 'even' } ] + expected: [{ cartodb_id: 6, value: 2, type: 'even' }] }, { zoom: 0, cartodb_id: 7, resolution: 1, - expected: [ { cartodb_id: 7, value: 3, type: 'odd' } ] + expected: [{ cartodb_id: 7, value: 3, type: 'odd' }] }, { zoom: 0, @@ -233,43 +233,43 @@ describe('cluster', function () { zoom: 1, cartodb_id: 1, resolution: 1, - expected: [ { cartodb_id: 1, value: -3, type: 'odd' } ] + expected: [{ cartodb_id: 1, value: -3, type: 'odd' }] }, { zoom: 1, cartodb_id: 2, resolution: 1, - expected: [ { cartodb_id: 2, value: -2, type: 'even' } ] + expected: [{ cartodb_id: 2, value: -2, type: 'even' }] }, { zoom: 1, cartodb_id: 3, resolution: 1, - expected: [ { cartodb_id: 3, value: -1, type: 'odd' } ] + expected: [{ cartodb_id: 3, value: -1, type: 'odd' }] }, { zoom: 1, cartodb_id: 4, resolution: 1, - expected: [ { cartodb_id: 4, value: 0, type: 'even' } ] + expected: [{ cartodb_id: 4, value: 0, type: 'even' }] }, { zoom: 1, cartodb_id: 5, resolution: 1, - expected: [ { cartodb_id: 5, value: 1, type: 'odd' } ] + expected: [{ cartodb_id: 5, value: 1, type: 'odd' }] }, { zoom: 1, cartodb_id: 6, resolution: 1, - expected: [ { cartodb_id: 6, value: 2, type: 'even' } ] + expected: [{ cartodb_id: 6, value: 2, type: 'even' }] }, { zoom: 1, cartodb_id: 7, resolution: 1, - expected: [ { cartodb_id: 7, value: 3, type: 'odd' } ] + expected: [{ cartodb_id: 7, value: 3, type: 'odd' }] }, { zoom: 1, @@ -277,7 +277,7 @@ describe('cluster', function () { resolution: 50, expected: [ { cartodb_id: 1, value: -3, type: 'odd' }, - { cartodb_id: 2, value: -2, type: 'even'} + { cartodb_id: 2, value: -2, type: 'even' } ] }, { @@ -291,8 +291,8 @@ describe('cluster', function () { } ]; - suite.forEach(({ zoom, cartodb_id, resolution, expected }) => { - const description = `should get features for z: ${zoom} cartodb_id: ${cartodb_id}, res: ${resolution}`; + suite.forEach(({ zoom, cartodb_id: cartodbId, resolution, expected }) => { + const description = `should get features for z: ${zoom} cartodb_id: ${cartodbId}, res: ${resolution}`; it(description, function (done) { const mapConfig = createVectorMapConfig([{ type: 'cartodb', @@ -308,7 +308,7 @@ describe('cluster', function () { const layerId = 0; const params = {}; - testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => { + testClient.getClusterFeatures(zoom, cartodbId, layerId, params, (err, body) => { if (err) { return done(err); } @@ -327,49 +327,49 @@ describe('cluster', function () { cartodb_id: 1, resolution: 1, aggregation: { columns: ['type'] }, - expected: [ { _cdb_feature_count: 1, type: 'odd' } ] + expected: [{ _cdb_feature_count: 1, type: 'odd' }] }, { zoom: 0, cartodb_id: 2, resolution: 1, aggregation: { columns: ['type'] }, - expected: [ { _cdb_feature_count: 1, type: 'even' } ] + expected: [{ _cdb_feature_count: 1, type: 'even' }] }, { zoom: 0, cartodb_id: 3, resolution: 1, aggregation: { columns: ['type'] }, - expected: [ { _cdb_feature_count: 1, type: 'odd' } ] + expected: [{ _cdb_feature_count: 1, type: 'odd' }] }, { zoom: 0, cartodb_id: 4, resolution: 1, aggregation: { columns: ['type'] }, - expected: [ { _cdb_feature_count: 1, type: 'even' } ] + expected: [{ _cdb_feature_count: 1, type: 'even' }] }, { zoom: 0, cartodb_id: 5, resolution: 1, aggregation: { columns: ['type'] }, - expected: [ { _cdb_feature_count: 1, type: 'odd' } ] + expected: [{ _cdb_feature_count: 1, type: 'odd' }] }, { zoom: 0, cartodb_id: 6, resolution: 1, aggregation: { columns: ['type'] }, - expected: [ { _cdb_feature_count: 1, type: 'even' } ] + expected: [{ _cdb_feature_count: 1, type: 'even' }] }, { zoom: 0, cartodb_id: 7, resolution: 1, aggregation: { columns: ['type'] }, - expected: [ { _cdb_feature_count: 1, type: 'odd' } ] + expected: [{ _cdb_feature_count: 1, type: 'odd' }] }, { zoom: 0, @@ -396,116 +396,116 @@ describe('cluster', function () { cartodb_id: 1, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', - aggregated_column: 'value', + aggregated_column: 'value' } } }, - expected: [ { _cdb_feature_count: 1, type: 'odd', max_value: -3 } ] + expected: [{ _cdb_feature_count: 1, type: 'odd', max_value: -3 }] }, { zoom: 0, cartodb_id: 2, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', - aggregated_column: 'value', + aggregated_column: 'value' } } }, - expected: [ { _cdb_feature_count: 1, type: 'even', max_value: -2 } ] + expected: [{ _cdb_feature_count: 1, type: 'even', max_value: -2 }] }, { zoom: 0, cartodb_id: 3, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', - aggregated_column: 'value', + aggregated_column: 'value' } } }, - expected: [ { _cdb_feature_count: 1, type: 'odd', max_value: -1 } ] + expected: [{ _cdb_feature_count: 1, type: 'odd', max_value: -1 }] }, { zoom: 0, cartodb_id: 4, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', - aggregated_column: 'value', + aggregated_column: 'value' } } }, - expected: [ { _cdb_feature_count: 1, type: 'even', max_value: 0 } ] + expected: [{ _cdb_feature_count: 1, type: 'even', max_value: 0 }] }, { zoom: 0, cartodb_id: 5, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', - aggregated_column: 'value', + aggregated_column: 'value' } } }, - expected: [ { _cdb_feature_count: 1, type: 'odd', max_value: 1 } ] + expected: [{ _cdb_feature_count: 1, type: 'odd', max_value: 1 }] }, { zoom: 0, cartodb_id: 6, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', - aggregated_column: 'value', + aggregated_column: 'value' } } }, - expected: [ { _cdb_feature_count: 1, type: 'even', max_value: 2 } ] + expected: [{ _cdb_feature_count: 1, type: 'even', max_value: 2 }] }, { zoom: 0, cartodb_id: 7, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', - aggregated_column: 'value', + aggregated_column: 'value' } } }, - expected: [ { _cdb_feature_count: 1, type: 'odd', max_value: 3 } ] + expected: [{ _cdb_feature_count: 1, type: 'odd', max_value: 3 }] }, { zoom: 0, cartodb_id: 1, resolution: 50, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', - aggregated_column: 'value', + aggregated_column: 'value' } } }, @@ -519,11 +519,11 @@ describe('cluster', function () { cartodb_id: 5, resolution: 50, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', - aggregated_column: 'value', + aggregated_column: 'value' } } }, @@ -534,8 +534,8 @@ describe('cluster', function () { } ]; - suite.forEach(({ zoom, cartodb_id, resolution, aggregation, expected }) => { - it(`should aggregate by type; z: ${zoom}, cartodb_id: ${cartodb_id}, res: ${resolution}`, function (done) { + suite.forEach(({ zoom, cartodb_id: cartodbId, resolution, aggregation, expected }) => { + it(`should aggregate by type; z: ${zoom}, cartodb_id: ${cartodbId}, res: ${resolution}`, function (done) { const mapConfig = createVectorMapConfig([{ type: 'cartodb', options: { @@ -550,19 +550,19 @@ describe('cluster', function () { const layerId = 0; const params = { aggregation }; - testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => { + testClient.getClusterFeatures(zoom, cartodbId, layerId, params, (err, body) => { if (err) { return done(err); } - const sort_f = ((a, b) => { + const sortFn = (a, b) => { return (a._cdb_feature_count < b._cdb_feature_count) || (a._cdb_feature_count === b._cdb_feature_count && (a.type < b.type || - a.type === b.type && a.max_value < b.max_value)); - }); + (a.type === b.type && a.max_value < b.max_value))); + }; - assert.deepStrictEqual(body.rows.sort(sort_f), expected.sort(sort_f)); + assert.deepStrictEqual(body.rows.sort(sortFn), expected.sort(sortFn)); testClient.drain(done); }); @@ -572,8 +572,8 @@ describe('cluster', function () { describe('invalid aggregation input', function () { const expectedColumnsError = { - errors:[ 'Invalid aggregation input, columns should be and array of column names' ], - errors_with_context:[ + errors: ['Invalid aggregation input, columns should be and array of column names'], + errors_with_context: [ { layer: { index: '0', @@ -587,8 +587,8 @@ describe('cluster', function () { }; const expectedExpressionsError = { - errors:[ 'Invalid aggregation input, expressions should be and object with valid functions' ], - errors_with_context:[ + errors: ['Invalid aggregation input, expressions should be and object with valid functions'], + errors_with_context: [ { layer: { index: '0', @@ -602,8 +602,8 @@ describe('cluster', function () { }; const invalidFunctionExpressionsError = { - errors:[ 'function wadus(integer) does not exist' ], - errors_with_context:[ + errors: ['function wadus(integer) does not exist'], + errors_with_context: [ { message: 'function wadus(integer) does not exist', type: 'unknown' @@ -612,19 +612,18 @@ describe('cluster', function () { }; const invalidColumnExpressionsError = { - errors:[ 'column \"wadus\" does not exist' ], - errors_with_context:[ + errors: ['column "wadus" does not exist'], + errors_with_context: [ { - message: 'column \"wadus\" does not exist', + message: 'column "wadus" does not exist', type: 'unknown' } ] }; - const expectedAggregatedColumnError = { - errors:[ 'Invalid aggregation input, aggregated column should be an string' ], - errors_with_context:[ + errors: ['Invalid aggregation input, aggregated column should be an string'], + errors_with_context: [ { layer: { index: '0', @@ -638,8 +637,8 @@ describe('cluster', function () { }; const expectedAggregateFunctionError = { - errors:[ 'Invalid aggregation input, aggregate function should be an string' ], - errors_with_context:[ + errors: ['Invalid aggregation input, aggregate function should be an string'], + errors_with_context: [ { layer: { index: '0', @@ -714,7 +713,7 @@ describe('cluster', function () { zoom: 0, cartodb_id: 1, resolution: 1, - aggregation: { columns: [ 'type' ], expressions: [] }, + aggregation: { columns: ['type'], expressions: [] }, expected: expectedExpressionsError }, { @@ -722,7 +721,7 @@ describe('cluster', function () { zoom: 0, cartodb_id: 1, resolution: 1, - aggregation: { columns: [ 'type' ], expressions: 1 }, + aggregation: { columns: ['type'], expressions: 1 }, expected: expectedExpressionsError }, { @@ -730,7 +729,7 @@ describe('cluster', function () { zoom: 0, cartodb_id: 1, resolution: 1, - aggregation: { columns: [ 'type' ], expressions: 'wadus' }, + aggregation: { columns: ['type'], expressions: 'wadus' }, expected: expectedExpressionsError }, { @@ -738,7 +737,7 @@ describe('cluster', function () { zoom: 0, cartodb_id: 1, resolution: 1, - aggregation: { columns: [ 'type' ], expressions: null }, + aggregation: { columns: ['type'], expressions: null }, expected: expectedExpressionsError }, { @@ -747,7 +746,7 @@ describe('cluster', function () { cartodb_id: 1, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'wadus', @@ -763,7 +762,7 @@ describe('cluster', function () { cartodb_id: 1, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', @@ -780,7 +779,7 @@ describe('cluster', function () { cartodb_id: 1, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 'max', @@ -796,7 +795,7 @@ describe('cluster', function () { cartodb_id: 1, resolution: 1, aggregation: { - columns: [ 'type' ], + columns: ['type'], expressions: { max_value: { aggregate_function: 1, @@ -808,7 +807,7 @@ describe('cluster', function () { } ]; - suite.forEach(({ description, zoom, cartodb_id, resolution, aggregation, expected, status = 400 }) => { + suite.forEach(({ description, zoom, cartodb_id: cartodbId, resolution, aggregation, expected, status = 400 }) => { it(description, function (done) { const mapConfig = createVectorMapConfig([{ type: 'cartodb', @@ -827,7 +826,7 @@ describe('cluster', function () { aggregation }; - testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => { + testClient.getClusterFeatures(zoom, cartodbId, layerId, params, (err, body) => { if (err) { return done(err); } diff --git a/test/acceptance/custom-middlewares-test.js b/test/acceptance/custom-middlewares-test.js index 7348479c..a6bb9434 100644 --- a/test/acceptance/custom-middlewares-test.js +++ b/test/acceptance/custom-middlewares-test.js @@ -20,7 +20,7 @@ describe('custom middlewares', function () { api: [{ paths: [ '/api/v1', - '/user/:user/api/v1', + '/user/:user/api/v1' ], middlewares: [ function teapot () { @@ -33,7 +33,7 @@ describe('custom middlewares', function () { // "/api/v1/map" is the new API, map: [{ paths: [ - '/map', + '/map' ] }], // Base url for the Templated Maps API @@ -79,7 +79,7 @@ describe('custom middlewares', function () { return done(err); } - assert.equal(res.body, 'I\'m a teapot'); + assert.strictEqual(res.body, 'I\'m a teapot'); done(); }); @@ -109,7 +109,7 @@ describe('custom middlewares', function () { return done(err); } - assert.equal(res.body, 'I\'m a teapot'); + assert.strictEqual(res.body, 'I\'m a teapot'); done(); }); @@ -123,13 +123,13 @@ describe('custom middlewares', function () { api: [{ paths: [ '/api/v1', - '/user/:user/api/v1', + '/user/:user/api/v1' ], // Base url for the Detached Maps API // "/api/v1/map" is the new API, map: [{ paths: [ - '/map', + '/map' ], middlewares: [ function teapot () { @@ -187,9 +187,9 @@ describe('custom middlewares', function () { const body = JSON.parse(res.body); - assert.deepEqual(body, { template_id: templateid }); + assert.deepStrictEqual(body, { template_id: templateid }); - helper.deleteRedisKeys({ ['map_tpl|localhost']: 0 }, done); + helper.deleteRedisKeys({ 'map_tpl|localhost': 0 }, done); }); }); @@ -217,7 +217,7 @@ describe('custom middlewares', function () { return done(err); } - assert.equal(res.body, 'I\'m a teapot'); + assert.strictEqual(res.body, 'I\'m a teapot'); done(); }); @@ -231,13 +231,13 @@ describe('custom middlewares', function () { api: [{ paths: [ '/api/v1', - '/user/:user/api/v1', + '/user/:user/api/v1' ], // Base url for the Detached Maps API // "/api/v1/map" is the new API, map: [{ paths: [ - '/map', + '/map' ] }], // Base url for the Templated Maps API @@ -290,7 +290,7 @@ describe('custom middlewares', function () { return done(err); } - assert.equal(res.body, 'I\'m a teapot'); + assert.strictEqual(res.body, 'I\'m a teapot'); done(); }); @@ -324,7 +324,7 @@ describe('custom middlewares', function () { assert.ok(body.layergroupid); - helper.deleteRedisKeys({ ['user:localhost:mapviews:global']: 5 }, done); + helper.deleteRedisKeys({ 'user:localhost:mapviews:global': 5 }, done); }); }); }); diff --git a/test/acceptance/dataviews/aggregation-test.js b/test/acceptance/dataviews/aggregation-test.js index ae357dce..c4bb28d8 100644 --- a/test/acceptance/dataviews/aggregation-test.js +++ b/test/acceptance/dataviews/aggregation-test.js @@ -4,9 +4,8 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('aggregations happy cases', function() { - - afterEach(function(done) { +describe('aggregations happy cases', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -14,7 +13,7 @@ describe('aggregations happy cases', function() { } }); - function aggregationOperationMapConfig(operation, query, column, aggregationColumn) { + function aggregationOperationMapConfig (operation, query, column, aggregationColumn) { column = column || 'adm0name'; aggregationColumn = aggregationColumn || 'pop_max'; query = query || 'select * from populated_places_simple_reduced'; @@ -48,16 +47,15 @@ describe('aggregations happy cases', function() { var operations = ['count', 'sum', 'avg', 'max', 'min']; - operations.forEach(function(operation) { - it('should be able to use "' + operation + '" as aggregation operation', function(done) { - + operations.forEach(function (operation) { + it('should be able to use "' + operation + '" as aggregation operation', function (done) { this.testClient = new TestClient(aggregationOperationMapConfig(operation)); this.testClient.getDataview('adm0name', { own_filter: 0 }, function (err, aggregation) { assert.ok(!err, err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); - assert.equal(aggregation.aggregation, operation); + assert.strictEqual(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.aggregation, operation); done(); }); @@ -81,11 +79,11 @@ describe('aggregations happy cases', function() { assert.ifError(err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.type, 'aggregation'); assert.ok(aggregation.categories); - assert.equal(aggregation.categoriesCount, 3); - assert.equal(aggregation.count, 4); - assert.equal(aggregation.nulls, 1); + assert.strictEqual(aggregation.categoriesCount, 3); + assert.strictEqual(aggregation.count, 4); + assert.strictEqual(aggregation.nulls, 1); var hasNullCategory = false; aggregation.categories.forEach(function (category) { @@ -100,9 +98,9 @@ describe('aggregations happy cases', function() { }); }); - var operations_and_values = {'count': 9, 'sum': 45, 'avg': 5, 'max': 9, 'min': 1}; + var operationsAndValues = { count: 9, sum: 45, avg: 5, max: 9, min: 1 }; - var query_other = [ + var queryOther = [ 'select generate_series(1,3) as val, \'other_a\' as cat, NULL as the_geom_webmercator', 'select generate_series(4,6) as val, \'other_b\' as cat, NULL as the_geom_webmercator', 'select generate_series(7,9) as val, \'other_c\' as cat, NULL as the_geom_webmercator', @@ -113,26 +111,26 @@ describe('aggregations happy cases', function() { 'select generate_series(10,12) as val, \'category_5\' as cat, NULL as the_geom_webmercator' ].join(' UNION ALL '); - Object.keys(operations_and_values).forEach(function (operation) { + Object.keys(operationsAndValues).forEach(function (operation) { var description = 'should aggregate OTHER category using "' + operation + '"'; it(description, function (done) { - this.testClient = new TestClient(aggregationOperationMapConfig(operation, query_other, 'cat', 'val')); + this.testClient = new TestClient(aggregationOperationMapConfig(operation, queryOther, 'cat', 'val')); this.testClient.getDataview('cat', { own_filter: 0 }, function (err, aggregation) { assert.ifError(err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.type, 'aggregation'); assert.ok(aggregation.categories); - assert.equal(aggregation.categoriesCount, 8); - assert.equal(aggregation.count, 24); - assert.equal(aggregation.nulls, 0); + assert.strictEqual(aggregation.categoriesCount, 8); + assert.strictEqual(aggregation.count, 24); + assert.strictEqual(aggregation.nulls, 0); - var aggregated_categories = aggregation.categories.filter( function(category) { + var aggregatedCategories = aggregation.categories.filter(function (category) { return category.agg === true; }); - assert.equal(aggregated_categories.length, 1); - assert.equal(aggregated_categories[0].value, operations_and_values[operation]); + assert.strictEqual(aggregatedCategories.length, 1); + assert.strictEqual(aggregatedCategories[0].value, operationsAndValues[operation]); done(); }); @@ -140,26 +138,26 @@ describe('aggregations happy cases', function() { }); var widgetSearchExpects = { - 'count': [ { category: 'other_a', value: 3 } ], - 'sum': [ { category: 'other_a', value: 6 } ], - 'avg': [ { category: 'other_a', value: 2 } ], - 'max': [ { category: 'other_a', value: 3 } ], - 'min': [ { category: 'other_a', value: 1 } ] + count: [{ category: 'other_a', value: 3 }], + sum: [{ category: 'other_a', value: 6 }], + avg: [{ category: 'other_a', value: 2 }], + max: [{ category: 'other_a', value: 3 }], + min: [{ category: 'other_a', value: 1 }] }; - Object.keys(operations_and_values).forEach(function (operation) { + Object.keys(operationsAndValues).forEach(function (operation) { var description = 'should search OTHER category using "' + operation + '"'; it(description, function (done) { - this.testClient = new TestClient(aggregationOperationMapConfig(operation, query_other, 'cat', 'val')); + this.testClient = new TestClient(aggregationOperationMapConfig(operation, queryOther, 'cat', 'val')); this.testClient.widgetSearch('cat', 'other_a', function (err, res, searchResult) { assert.ifError(err); assert.ok(searchResult); - assert.equal(searchResult.type, 'aggregation'); + assert.strictEqual(searchResult.type, 'aggregation'); - assert.equal(searchResult.categories.length, 1); - assert.deepEqual( + assert.strictEqual(searchResult.categories.length, 1); + assert.deepStrictEqual( searchResult.categories, widgetSearchExpects[operation] ); @@ -169,9 +167,8 @@ describe('aggregations happy cases', function() { }); }); -describe('aggregation-dataview: special float values', function() { - - afterEach(function(done) { +describe('aggregation-dataview: special float values', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -179,7 +176,7 @@ describe('aggregation-dataview: special float values', function() { } }); - function createMapConfig(layers, dataviews, analysis) { + function createMapConfig (layers, dataviews, analysis) { return { version: '1.5.0', layers: layers, @@ -191,13 +188,13 @@ describe('aggregation-dataview: special float values', function() { var mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "a0" + type: 'cartodb', + options: { + source: { + id: 'a0' }, - "cartocss": "#points { marker-width: 10; marker-fill: red; }", - "cartocss_version": "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -227,10 +224,10 @@ describe('aggregation-dataview: special float values', function() { }, [ { - "id": "a0", - "type": "source", - "params": { - "query": [ + id: 'a0', + type: 'source', + params: { + query: [ 'SELECT', ' null::geometry the_geom_webmercator,', ' CASE', @@ -247,10 +244,10 @@ describe('aggregation-dataview: special float values', function() { ].join('\n') } }, { - "id": "a1", - "type": "source", - "params": { - "query": [ + id: 'a1', + type: 'source', + params: { + query: [ 'SELECT', ' null::geometry the_geom_webmercator,', ' CASE', @@ -288,9 +285,9 @@ describe('aggregation-dataview: special float values', function() { var filters = [{ own_filter: 0 }, {}]; filters.forEach(function (filter) { - it('should handle special float values using filter: ' + JSON.stringify(filter), function(done) { + it('should handle special float values using filter: ' + JSON.stringify(filter), function (done) { this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getDataview('val_aggregation', filter, function(err, dataview) { + this.testClient.getDataview('val_aggregation', filter, function (err, dataview) { assert.ifError(err); assert.ok(dataview.infinities === (250 + 250)); assert.ok(dataview.nans === 250); @@ -303,9 +300,9 @@ describe('aggregation-dataview: special float values', function() { }); }); - it('should handle special numeric values using filter: ' + JSON.stringify(filter), function(done) { + it('should handle special numeric values using filter: ' + JSON.stringify(filter), function (done) { this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getDataview('sum_aggregation_numeric', filter, function(err, dataview) { + this.testClient.getDataview('sum_aggregation_numeric', filter, function (err, dataview) { assert.ifError(err); assert.ok(dataview.nans === 333); assert.ok(dataview.categories.length === 2); @@ -323,13 +320,13 @@ describe('aggregation dataview tuned by categories query param', function () { version: '1.5.0', layers: [ { - type: "cartodb", + type: 'cartodb', options: { source: { - "id": "a0" + id: 'a0' }, - cartocss: "#points { marker-width: 10; marker-fill: red; }", - cartocss_version: "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -348,8 +345,8 @@ describe('aggregation dataview tuned by categories query param', function () { }, analyses: [ { - id: "a0", - type: "source", + id: 'a0', + type: 'source', params: { query: ` SELECT @@ -412,27 +409,25 @@ describe('aggregation dataview tuned by categories query param', function () { it(`should handle cartegories to customize aggregations: ${JSON.stringify(scenario.params)}`, function (done) { this.testClient.getDataview('categories', scenario.params, (err, dataview) => { assert.ifError(err); - assert.equal(dataview.categories.length, scenario.categoriesExpected); + assert.strictEqual(dataview.categories.length, scenario.categoriesExpected); done(); }); }); }); }); - - describe('Count aggregation', function () { const mapConfig = { version: '1.5.0', layers: [ { - type: "cartodb", + type: 'cartodb', options: { source: { - "id": "a0" + id: 'a0' }, - cartocss: "#points { marker-width: 10; marker-fill: red; }", - cartocss_version: "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -450,8 +445,8 @@ describe('Count aggregation', function () { }, analyses: [ { - id: "a0", - type: "source", + id: 'a0', + type: 'source', params: { query: ` SELECT @@ -475,21 +470,21 @@ describe('Count aggregation', function () { ] }; - it(`should handle null values correctly when aggregationColumn isn't provided`, function (done) { + it('should handle null values correctly when aggregationColumn isn\'t provided', function (done) { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('categories', { own_filter: 0, categories: 0 }, (err, dataview) => { assert.ifError(err); - assert.equal(dataview.categories.length, 3); + assert.strictEqual(dataview.categories.length, 3); this.testClient.drain(done); }); }); - it(`should handle null values correctly when aggregationColumn is provided`, function (done) { + it('should handle null values correctly when aggregationColumn is provided', function (done) { mapConfig.dataviews.categories.options.aggregationColumn = 'val'; this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('categories', { own_filter: 0, categories: 0 }, (err, dataview) => { assert.ifError(err); - assert.equal(dataview.categories.length, 3); + assert.strictEqual(dataview.categories.length, 3); this.testClient.drain(done); }); }); diff --git a/test/acceptance/dataviews/error-cases-test.js b/test/acceptance/dataviews/error-cases-test.js index 64af27a2..51b7f043 100644 --- a/test/acceptance/dataviews/error-cases-test.js +++ b/test/acceptance/dataviews/error-cases-test.js @@ -5,11 +5,9 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('dataview error cases', function() { - - describe('generic errors', function() { - - afterEach(function(done) { +describe('dataview error cases', function () { + describe('generic errors', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -24,62 +22,62 @@ describe('dataview error cases', function() { } }; - function createMapConfig(dataviews) { + function createMapConfig (dataviews) { return { version: '1.5.0', layers: [ { - "type": "cartodb", - "options": { - "source": { - "id": "HEAD" + type: 'cartodb', + options: { + source: { + id: 'HEAD' }, - "cartocss": "#points { marker-width: 10; marker-fill: red; }", - "cartocss_version": "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], dataviews: dataviews, analyses: [ { - "id": "HEAD", - "type": "source", - "params": { - "query": "select null::geometry the_geom_webmercator, x from generate_series(0,1000) x" + id: 'HEAD', + type: 'source', + params: { + query: 'select null::geometry the_geom_webmercator, x from generate_series(0,1000) x' } } ] }; } - it('should fail when invalid dataviews object is provided, string case', function(done) { - var mapConfig = createMapConfig("wadus-string"); + it('should fail when invalid dataviews object is provided, string case', function (done) { + var mapConfig = createMapConfig('wadus-string'); this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, errObj) { + this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, errObj) { assert.ok(!err, err); - assert.deepEqual(errObj.errors, [ '"dataviews" must be a valid JSON object: "string" type found' ]); + assert.deepStrictEqual(errObj.errors, ['"dataviews" must be a valid JSON object: "string" type found']); done(); }); }); - it('should fail when invalid dataviews object is provided, array case', function(done) { + it('should fail when invalid dataviews object is provided, array case', function (done) { var mapConfig = createMapConfig([]); this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, errObj) { + this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, errObj) { assert.ok(!err, err); - assert.deepEqual(errObj.errors, [ '"dataviews" must be a valid JSON object: "array" type found' ]); + assert.deepStrictEqual(errObj.errors, ['"dataviews" must be a valid JSON object: "array" type found']); done(); }); }); - it('should work with empty but valid objects', function(done) { + it('should work with empty but valid objects', function (done) { var mapConfig = createMapConfig({}); this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ok(!err, err); assert.ok(layergroup); @@ -90,9 +88,8 @@ describe('dataview error cases', function() { }); }); - describe('pg_typeof', function() { - - afterEach(function(done) { + describe('pg_typeof', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -100,7 +97,7 @@ describe('dataview error cases', function() { } }); - function createMapConfig(query) { + function createMapConfig (query) { query = query || 'select * from populated_places_simple_reduced'; return { @@ -112,54 +109,54 @@ describe('dataview error cases', function() { sql: query, cartocss: '#layer0 { marker-fill: red; marker-width: 10; }', cartocss_version: '2.0.1', - source: { id: "a0" } + source: { id: 'a0' } } } ], analyses: [{ - id: "a0", - type: "source", + id: 'a0', + type: 'source', params: { query: query } }], - dataviews: { + dataviews: { aggregation_count_dataview: { - type: "aggregation", - source: { id: "a0" }, + type: 'aggregation', + source: { id: 'a0' }, options: { - column: "adm0name", - aggregation: "count", - aggregationColumn: "adm0name" + column: 'adm0name', + aggregation: 'count', + aggregationColumn: 'adm0name' } } } }; } - it('should work without filters', function(done) { + it('should work without filters', function (done) { this.testClient = new TestClient(createMapConfig()); - this.testClient.getDataview('aggregation_count_dataview', { own_filter: 0 }, function(err) { + this.testClient.getDataview('aggregation_count_dataview', { own_filter: 0 }, function (err) { assert.ifError(err); done(); }); }); - it('should work with filters', function(done) { + it('should work with filters', function (done) { var params = { filters: { - dataviews: {aggregation_count_dataview: {accept: ['Canada']}} + dataviews: { aggregation_count_dataview: { accept: ['Canada'] } } } }; this.testClient = new TestClient(createMapConfig()); - this.testClient.getDataview('aggregation_count_dataview', params, function(err) { + this.testClient.getDataview('aggregation_count_dataview', params, function (err) { assert.ifError(err); done(); }); }); - it('should return an error if the column used by dataview does not exist', function(done) { + it('should return an error if the column used by dataview does not exist', function (done) { const query = 'select cartodb_id, the_geom, the_geom_webmercator from populated_places_simple_reduced'; const params = { @@ -172,22 +169,22 @@ describe('dataview error cases', function() { }; const expectedResponseBody = { - errors:['column "adm0name" does not exist'], - errors_with_context:[{ - type:'unknown', - message:'column "adm0name" does not exist' + errors: ['column "adm0name" does not exist'], + errors_with_context: [{ + type: 'unknown', + message: 'column "adm0name" does not exist' }] }; this.testClient = new TestClient(createMapConfig(query)); - this.testClient.getDataview('aggregation_count_dataview', params, function(err, result) { + this.testClient.getDataview('aggregation_count_dataview', params, function (err, result) { assert.ifError(err); - assert.deepEqual(result, expectedResponseBody); + assert.deepStrictEqual(result, expectedResponseBody); done(); }); }); - it('should not fail if query does not return rows', function(done) { + it('should not fail if query does not return rows', function (done) { const query = 'select * from populated_places_simple_reduced limit 0'; const expectedResponseBody = { @@ -204,12 +201,11 @@ describe('dataview error cases', function() { }; this.testClient = new TestClient(createMapConfig(query)); - this.testClient.getDataview('aggregation_count_dataview', { own_filter: 0 }, function(err, result) { + this.testClient.getDataview('aggregation_count_dataview', { own_filter: 0 }, function (err, result) { assert.ifError(err); - assert.deepEqual(result, expectedResponseBody); + assert.deepStrictEqual(result, expectedResponseBody); done(); }); }); - }); }); diff --git a/test/acceptance/dataviews/formula-test.js b/test/acceptance/dataviews/formula-test.js index 9f8b2877..31f464d4 100644 --- a/test/acceptance/dataviews/formula-test.js +++ b/test/acceptance/dataviews/formula-test.js @@ -4,7 +4,7 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -function createMapConfig(layers, dataviews, analysis) { +function createMapConfig (layers, dataviews, analysis) { return { version: '1.5.0', layers: layers, @@ -13,16 +13,16 @@ function createMapConfig(layers, dataviews, analysis) { }; } -function getMapConfig(operation, lastNumber) { +function getMapConfig (operation, lastNumber) { return createMapConfig([ { - "type": "cartodb", - "options": { - "source": { - "id": "a0" + type: 'cartodb', + options: { + source: { + id: 'a0' }, - "cartocss": "#points { marker-width: 10; marker-fill: red; }", - "cartocss_version": "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -40,8 +40,8 @@ function getMapConfig(operation, lastNumber) { }, [ { - id: "a0", - type: "source", + id: 'a0', + type: 'source', params: { query: ` SELECT @@ -60,9 +60,9 @@ function getMapConfig(operation, lastNumber) { ]); } -describe('formula-dataview: special float values', function() { - describe('easy numbers', function() { // not needed, but I keep it here to help human calc - afterEach(function(done) { +describe('formula-dataview: special float values', function () { + describe('easy numbers', function () { // not needed, but I keep it here to help human calc + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -73,33 +73,33 @@ describe('formula-dataview: special float values', function() { const lastNumber = 10; [ - {operation: 'count', result: 2}, - {operation: 'avg', result: 7.5}, - {operation: 'sum', result: 15}, - {operation: 'min', result: 5}, - {operation: 'max', result: 10} + { operation: 'count', result: 2 }, + { operation: 'avg', result: 7.5 }, + { operation: 'sum', result: 15 }, + { operation: 'min', result: 5 }, + { operation: 'max', result: 10 } ] - .forEach(operationData => { - it(operationData.operation, function(done) { - this.testClient = new TestClient(getMapConfig(operationData.operation, lastNumber), 1234); - this.testClient.getDataview('val_formula', {}, function(err, dataview) { - assert.ok(!err, err); - assert.deepStrictEqual(dataview, { - type: 'formula', - operation: operationData.operation, - result: operationData.result, - nulls: lastNumber / 5, - nans: lastNumber / 5, - infinities: 2 * lastNumber / 5 + .forEach(operationData => { + it(operationData.operation, function (done) { + this.testClient = new TestClient(getMapConfig(operationData.operation, lastNumber), 1234); + this.testClient.getDataview('val_formula', {}, function (err, dataview) { + assert.ok(!err, err); + assert.deepStrictEqual(dataview, { + type: 'formula', + operation: operationData.operation, + result: operationData.result, + nulls: lastNumber / 5, + nans: lastNumber / 5, + infinities: 2 * lastNumber / 5 + }); + done(); }); - done(); }); }); - }); }); - describe('bigger numbers', function() { - afterEach(function(done) { + describe('bigger numbers', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -110,28 +110,28 @@ describe('formula-dataview: special float values', function() { const lastNumber = 1000; [ - {operation: 'count', result: 200}, - {operation: 'avg', result: 502.5}, - {operation: 'sum', result: 100500}, - {operation: 'min', result: 5}, - {operation: 'max', result: 1000} + { operation: 'count', result: 200 }, + { operation: 'avg', result: 502.5 }, + { operation: 'sum', result: 100500 }, + { operation: 'min', result: 5 }, + { operation: 'max', result: 1000 } ] - .forEach(operationData => { - it(operationData.operation, function(done) { - this.testClient = new TestClient(getMapConfig(operationData.operation, lastNumber), 1234); - this.testClient.getDataview('val_formula', {}, function(err, dataview) { - assert.ok(!err, err); - assert.deepStrictEqual(dataview, { - type: 'formula', - operation: operationData.operation, - result: operationData.result, - nulls: lastNumber / 5, - nans: lastNumber / 5, - infinities: 2 * lastNumber / 5 + .forEach(operationData => { + it(operationData.operation, function (done) { + this.testClient = new TestClient(getMapConfig(operationData.operation, lastNumber), 1234); + this.testClient.getDataview('val_formula', {}, function (err, dataview) { + assert.ok(!err, err); + assert.deepStrictEqual(dataview, { + type: 'formula', + operation: operationData.operation, + result: operationData.result, + nulls: lastNumber / 5, + nans: lastNumber / 5, + infinities: 2 * lastNumber / 5 + }); + done(); }); - done(); }); }); - }); }); }); diff --git a/test/acceptance/dataviews/histogram-test.js b/test/acceptance/dataviews/histogram-test.js index 945fc9dd..a78c0de7 100644 --- a/test/acceptance/dataviews/histogram-test.js +++ b/test/acceptance/dataviews/histogram-test.js @@ -6,7 +6,7 @@ var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); var moment = require('moment'); -function createMapConfig(layers, dataviews, analysis) { +function createMapConfig (layers, dataviews, analysis) { return { version: '1.5.0', layers: layers, @@ -15,18 +15,8 @@ function createMapConfig(layers, dataviews, analysis) { }; } -function createMapConfig(layers, dataviews, analysis) { - return { - version: '1.5.0', - layers: layers, - dataviews: dataviews || {}, - analyses: analysis || [] - }; -} - -describe('histogram-dataview', function() { - - afterEach(function(done) { +describe('histogram-dataview', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -37,13 +27,13 @@ describe('histogram-dataview', function() { var mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "2570e105-7b37-40d2-bdf4-1af889598745" + type: 'cartodb', + options: { + source: { + id: '2570e105-7b37-40d2-bdf4-1af889598745' }, - "cartocss": "#points { marker-width: 10; marker-fill: red; }", - "cartocss_version": "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -60,16 +50,16 @@ describe('histogram-dataview', function() { }, [ { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select null::geometry the_geom_webmercator, x from generate_series(0,1000) x" + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'source', + params: { + query: 'select null::geometry the_geom_webmercator, x from generate_series(0,1000) x' } } ] ); - it('should get bins with min >= start and max <= end', function(done) { + it('should get bins with min >= start and max <= end', function (done) { var params = { bins: 3, start: 50, @@ -77,12 +67,12 @@ describe('histogram-dataview', function() { }; this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getDataview('pop_max_histogram', params, function(err, dataview) { + this.testClient.getDataview('pop_max_histogram', params, function (err, dataview) { assert.ok(!err, err); - assert.ok(3 === dataview.bins_count, 'Unexpected bin count: ' + dataview.bins_count); - assert.ok(3 === dataview.bins.length, 'Unexpected number of bins: ' + dataview.bins.length); - dataview.bins.forEach(function(bin) { + assert.ok(dataview.bins_count === 3, 'Unexpected bin count: ' + dataview.bins_count); + assert.ok(dataview.bins.length === 3, 'Unexpected number of bins: ' + dataview.bins.length); + dataview.bins.forEach(function (bin) { assert.ok(bin.min >= params.start, 'bin min < start: ' + JSON.stringify(bin)); assert.ok(bin.max <= params.end, 'bin max > end: ' + JSON.stringify(bin)); }); @@ -90,19 +80,19 @@ describe('histogram-dataview', function() { }); }); - it('should work with min >= start and max <= end, autodetect bins', function(done) { + it('should work with min >= start and max <= end, autodetect bins', function (done) { var params = { start: 50, end: 500 }; this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getDataview('pop_max_histogram', params, function(err, dataview) { + this.testClient.getDataview('pop_max_histogram', params, function (err, dataview) { assert.ok(!err, err); - assert.ok(6 === dataview.bins_count, 'Unexpected bin count: ' + dataview.bins_count); - assert.ok(6 === dataview.bins.length, 'Unexpected number of bins: ' + dataview.bins.length); - dataview.bins.forEach(function(bin) { + assert.ok(dataview.bins_count === 6, 'Unexpected bin count: ' + dataview.bins_count); + assert.ok(dataview.bins.length === 6, 'Unexpected number of bins: ' + dataview.bins.length); + dataview.bins.forEach(function (bin) { assert.ok(bin.min >= params.start, 'bin min < start: ' + JSON.stringify(bin)); assert.ok(bin.max <= params.end, 'bin max > end: ' + JSON.stringify(bin)); }); @@ -110,7 +100,7 @@ describe('histogram-dataview', function() { }); }); - it('should get bin_width right when max > min in filter', function(done) { + it('should get bin_width right when max > min in filter', function (done) { var params = { bins: 10, start: 1e3, @@ -118,12 +108,12 @@ describe('histogram-dataview', function() { }; this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getDataview('pop_max_histogram', params, function(err, dataview) { + this.testClient.getDataview('pop_max_histogram', params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - dataview.bins.forEach(function(bin) { + dataview.bins.forEach(function (bin) { assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -131,7 +121,7 @@ describe('histogram-dataview', function() { }); }); - it('should cast all overridable params to numbers', function(done) { + it('should cast all overridable params to numbers', function (done) { var params = { bins: '256 AS other, (select 256 * 2) AS bins_number--', start: 1e3, @@ -140,20 +130,19 @@ describe('histogram-dataview', function() { }; this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getDataview('pop_max_histogram', params, function(err, res) { + this.testClient.getDataview('pop_max_histogram', params, function (err, res) { assert.ok(!err, err); assert.ok(res.errors); - assert.equal(res.errors.length, 1); + assert.strictEqual(res.errors.length, 1); assert.ok(res.errors[0].match(/Invalid number format for parameter 'bins'/)); done(); }); }); - }); -describe('histogram-dataview for date column type', function() { - afterEach(function(done) { +describe('histogram-dataview for date column type', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -164,13 +153,13 @@ describe('histogram-dataview for date column type', function() { var mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "datetime-histogram-source-week" + type: 'cartodb', + options: { + source: { + id: 'datetime-histogram-source-week' }, - "cartocss": "#points { marker-width: 10; marker-fill: red; }", - "cartocss_version": "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -340,181 +329,181 @@ describe('histogram-dataview for date column type', function() { }, [ { - "id": "datetime-histogram-source-second", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'2007-02-15 01:00:00'::timestamp, '2007-02-15 01:00:57'::timestamp,", - "'0.9 second'::interval", - ") date" + id: 'datetime-histogram-source-second', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'2007-02-15 01:00:00'::timestamp, '2007-02-15 01:00:57'::timestamp,", + "'0.9 second'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-minute", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'2007-02-15 01:00:00'::timestamp, '2007-02-15 02:00:57'::timestamp,", - "'75 second'::interval", - ") date" + id: 'datetime-histogram-source-minute', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'2007-02-15 01:00:00'::timestamp, '2007-02-15 02:00:57'::timestamp,", + "'75 second'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-hour", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'2007-02-15 01:00:00'::timestamp, '2007-02-18 02:00:57'::timestamp,", - "'47 minutes'::interval", - ") date" + id: 'datetime-histogram-source-hour', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'2007-02-15 01:00:00'::timestamp, '2007-02-18 02:00:57'::timestamp,", + "'47 minutes'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-day", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'2007-02-15 01:00:00'::timestamp, '2007-04-18 02:00:57'::timestamp,", - "'24 hours'::interval", - ") date" + id: 'datetime-histogram-source-day', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'2007-02-15 01:00:00'::timestamp, '2007-04-18 02:00:57'::timestamp,", + "'24 hours'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-week", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'2007-02-15 01:00:00'::timestamp, '2008-04-09 01:00:00'::timestamp,", - "'1 day'::interval", - ") date" + id: 'datetime-histogram-source-week', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'2007-02-15 01:00:00'::timestamp, '2008-04-09 01:00:00'::timestamp,", + "'1 day'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-month", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'2007-02-15 01:00:00'::timestamp, '2010-04-09 01:00:00'::timestamp,", - "'30 day'::interval", - ") date" + id: 'datetime-histogram-source-month', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'2007-02-15 01:00:00'::timestamp, '2010-04-09 01:00:00'::timestamp,", + "'30 day'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-quarter", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'2007-02-15 01:00:00'::timestamp, '2020-04-09 01:00:00'::timestamp,", - "'30 day'::interval", - ") date" + id: 'datetime-histogram-source-quarter', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'2007-02-15 01:00:00'::timestamp, '2020-04-09 01:00:00'::timestamp,", + "'30 day'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-year", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'1990-02-15 01:00:00'::timestamp, '2018-04-09 01:00:00'::timestamp,", - "'30 day'::interval", - ") date" + id: 'datetime-histogram-source-year', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'1990-02-15 01:00:00'::timestamp, '2018-04-09 01:00:00'::timestamp,", + "'30 day'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-decade", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'1850-02-15 01:00:00'::timestamp, '2018-04-09 01:00:00'::timestamp,", - "'30 day'::interval", - ") date" + id: 'datetime-histogram-source-decade', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'1850-02-15 01:00:00'::timestamp, '2018-04-09 01:00:00'::timestamp,", + "'30 day'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-century", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'0650-02-15 01:00:00'::timestamp, '1918-04-09 01:00:00'::timestamp,", - "'6 years'::interval", - ") date" + id: 'datetime-histogram-source-century', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'0650-02-15 01:00:00'::timestamp, '1918-04-09 01:00:00'::timestamp,", + "'6 years'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-millennium", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", - "from generate_series(", - "'0005-02-15 01:00:00'::timestamp, '12000-04-09 01:00:00'::timestamp,", - "'72 years'::interval", - ") date" + id: 'datetime-histogram-source-millennium', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', + 'from generate_series(', + "'0005-02-15 01:00:00'::timestamp, '12000-04-09 01:00:00'::timestamp,", + "'72 years'::interval", + ') date' ].join(' ') } }, { - "id": "datetime-histogram-source-tz", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", + id: 'datetime-histogram-source-tz', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', "from generate_series('2007-02-15 01:00:00+00'::timestamptz,", "'2008-04-09 01:00:00+00'::timestamptz, '1 day'::interval", - ") date" + ') date' ].join(' ') } }, { - "id": "date-histogram-source", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date::date AS d", - "from generate_series(", - "'2007-02-15'::date, '2008-04-09'::date, '1 day'::interval", - ") date" + id: 'date-histogram-source', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date::date AS d', + 'from generate_series(', + "'2007-02-15'::date, '2008-04-09'::date, '1 day'::interval", + ') date' ].join(' ') } }, { - "id": "minute-histogram-source-tz", - "type": "source", - "params": { - "query": [ - "select null::geometry the_geom_webmercator, date AS d", + id: 'minute-histogram-source-tz', + type: 'source', + params: { + query: [ + 'select null::geometry the_geom_webmercator, date AS d', "from generate_series('2007-02-15 23:50:00+00'::timestamptz,", "'2007-02-16 00:10:00+00'::timestamptz, '1 minute'::interval", - ") date" + ') date' ].join(' ') } } @@ -530,26 +519,25 @@ describe('histogram-dataview for date column type', function() { }]; dateHistogramsUseCases.forEach(function (test) { - it('should create a date histogram aggregated in months (EDT) ' + test.desc, function (done) { var OFFSET_EDT_IN_MINUTES = -4 * 60; // EDT Eastern Daylight Time (GMT-4) in minutes this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getDataview(test.dataviewId, {}, function(err, dataview) { + this.testClient.getDataview(test.dataviewId, {}, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins.length, 15); + assert.strictEqual(dataview.bins.length, 15); var initialTimestamp = '2007-02-01T00:00:00-04:00'; // EDT midnight var binsStartInMilliseconds = dataview.bins_start * 1000; var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_EDT_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); - dataview.bins.forEach(function(bin, index) { + dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) .utcOffset(OFFSET_EDT_IN_MINUTES) .add(index, 'month') @@ -559,7 +547,7 @@ describe('histogram-dataview for date column type', function() { .utcOffset(OFFSET_EDT_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -576,9 +564,9 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview(test.dataviewId, params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins.length, 61); + assert.strictEqual(dataview.bins.length, 61); dataview.bins.forEach(function (bin) { assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -596,9 +584,9 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview(test.dataviewId, params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins_count, 6); + assert.strictEqual(dataview.bins_count, 6); dataview.bins.forEach(function (bin) { assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -616,7 +604,7 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview(test.dataviewId, params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); done(); @@ -633,16 +621,16 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview(test.dataviewId, params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins.length, 15); + assert.strictEqual(dataview.bins.length, 15); var initialTimestamp = '2007-02-01T00:00:00+02:00'; // CEST midnight var binsStartInMilliseconds = dataview.bins_start * 1000; var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_CEST_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) @@ -654,7 +642,7 @@ describe('histogram-dataview for date column type', function() { .utcOffset(OFFSET_CEST_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -673,16 +661,16 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview(test.dataviewId, params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins.length, 15); + assert.strictEqual(dataview.bins.length, 15); var initialTimestamp = '2007-02-01T00:00:00Z'; // UTC midnight var binsStartInMilliseconds = dataview.bins_start * 1000; var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) @@ -694,7 +682,7 @@ describe('histogram-dataview for date column type', function() { .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -714,16 +702,16 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_second', params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins.length, 57); + assert.strictEqual(dataview.bins.length, 57); var initialTimestamp = '2007-02-15T01:00:00Z'; var binsStartInMilliseconds = dataview.bins_start * 1000; var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) @@ -735,7 +723,7 @@ describe('histogram-dataview for date column type', function() { .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -755,16 +743,16 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview(test.dataviewId, params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins.length, 6); + assert.strictEqual(dataview.bins.length, 6); var initialTimestamp = '2007-01-01T00:00:00Z'; // UTC midnight var binsStartInMilliseconds = dataview.bins_start * 1000; var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) @@ -776,7 +764,7 @@ describe('histogram-dataview for date column type', function() { .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -796,16 +784,16 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_decade', params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins.length, 17); + assert.strictEqual(dataview.bins.length, 17); var initialTimestamp = '1850-01-01T00:00:00Z'; var binsStartInMilliseconds = dataview.bins_start * 1000; var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) @@ -817,7 +805,7 @@ describe('histogram-dataview for date column type', function() { .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -837,16 +825,16 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_century', params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins.length, 14); + assert.strictEqual(dataview.bins.length, 14); var initialTimestamp = '0601-01-01T00:00:00Z'; var binsStartInMilliseconds = dataview.bins_start * 1000; var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) @@ -858,7 +846,7 @@ describe('histogram-dataview for date column type', function() { .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -878,16 +866,16 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_millennium', params, function (err, dataview) { assert.ok(!err, err); - assert.equal(dataview.type, 'histogram'); + assert.strictEqual(dataview.type, 'histogram'); assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width); - assert.equal(dataview.bins.length, 12); + assert.strictEqual(dataview.bins.length, 12); var initialTimestamp = '0001-01-01T00:00:00Z'; var binsStartInMilliseconds = dataview.bins_start * 1000; var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) @@ -899,7 +887,7 @@ describe('histogram-dataview for date column type', function() { .utcOffset(OFFSET_UTC_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -908,9 +896,6 @@ describe('histogram-dataview for date column type', function() { }); }); - - - it('bins_count should be equal to bins length filtered by start and end ' + test.desc, function (done) { var OFFSET_UTC_IN_SECONDS = 0 * 3600; // UTC var params = { @@ -924,10 +909,10 @@ describe('histogram-dataview for date column type', function() { this.testClient.getDataview(test.dataviewId, params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins.length, 6); - assert.equal(dataview.bins_count, 6); - assert.equal(dataview.bins_count, dataview.bins.length); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins.length, 6); + assert.strictEqual(dataview.bins_count, 6); + assert.strictEqual(dataview.bins_count, dataview.bins.length); done(); }); }); @@ -945,9 +930,9 @@ describe('histogram-dataview for date column type', function() { this.testClient.getDataview(test.dataviewId, params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.bins.length, 6); - assert.equal(dataview.bins_count, 7); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.bins.length, 6); + assert.strictEqual(dataview.bins_count, 7); assert.ok(dataview.bins_count > dataview.bins.length); done(); }); @@ -968,7 +953,7 @@ describe('histogram-dataview for date column type', function() { _testClient.getDataview('datetime_histogram_tz', params, function (err, filteredDataview) { assert.ok(!err, err); - assert.deepEqual(dataview, filteredDataview); + assert.deepStrictEqual(dataview, filteredDataview); done(); }); }); @@ -979,8 +964,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_second', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'second'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'second'); done(); }); }); @@ -990,8 +975,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_minute', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'minute'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'minute'); done(); }); }); @@ -1001,8 +986,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_hour', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'hour'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'hour'); done(); }); }); @@ -1012,8 +997,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_day', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'day'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'day'); done(); }); }); @@ -1023,8 +1008,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_week', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'week'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'week'); done(); }); }); @@ -1034,8 +1019,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_month', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'month'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'month'); done(); }); }); @@ -1045,8 +1030,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_quarter', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'quarter'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'quarter'); done(); }); }); @@ -1056,8 +1041,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_year', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'year'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'year'); done(); }); }); @@ -1067,8 +1052,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_decade', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'decade'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'decade'); done(); }); }); @@ -1078,8 +1063,8 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_century', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'century'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'century'); done(); }); }); @@ -1089,28 +1074,25 @@ describe('histogram-dataview for date column type', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('datetime_histogram_automatic_millennium', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'millennium'); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'millennium'); done(); }); }); - - it('should work with dates', function (done) { var params = {}; this.testClient = new TestClient(mapConfig, 1234); this.testClient.getDataview('date_histogram', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.type, 'histogram'); - assert.equal(dataview.aggregation, 'year'); - assert.equal(dataview.bins.length, 2); - assert.equal(dataview.bins_count, 2); + assert.strictEqual(dataview.type, 'histogram'); + assert.strictEqual(dataview.aggregation, 'year'); + assert.strictEqual(dataview.bins.length, 2); + assert.strictEqual(dataview.bins_count, 2); done(); }); }); - it('should not apply offset for a histogram aggregated by minutes', function (done) { var self = this; var params = { @@ -1124,9 +1106,9 @@ describe('histogram-dataview for date column type', function() { self.testClient.getDataview('minute_histogram', params, function (err, dataviewWithOffset) { assert.ifError(err); - assert.notEqual(dataview.offset, dataviewWithOffset.offset); + assert.notStrictEqual(dataview.offset, dataviewWithOffset.offset); dataview.offset = dataviewWithOffset.offset; - assert.deepEqual(dataview, dataviewWithOffset); + assert.deepStrictEqual(dataview, dataviewWithOffset); done(); }); }); @@ -1152,26 +1134,25 @@ describe('histogram-dataview for date column type', function() { self.testClient.getDataview('minute_histogram', paramsWithFilter, function (err, filteredDataview) { assert.ifError(err); - assert.deepEqual(dataview, filteredDataview); + assert.deepStrictEqual(dataview, filteredDataview); self.testClient.getDataview('minute_histogram', paramsWithOffset, - function (err, filteredWithOffsetDataview) { - assert.ifError(err); + function (err, filteredWithOffsetDataview) { + assert.ifError(err); - assert.notEqual(filteredWithOffsetDataview.offset, filteredDataview.offset); - filteredWithOffsetDataview.offset = filteredDataview.offset; - assert.deepEqual(filteredWithOffsetDataview, filteredDataview); - done(); - }); + assert.notStrictEqual(filteredWithOffsetDataview.offset, filteredDataview.offset); + filteredWithOffsetDataview.offset = filteredDataview.offset; + assert.deepStrictEqual(filteredWithOffsetDataview, filteredDataview); + done(); + }); }); }); }); - it('should return an histogram aggregated by days', function (done) { var self = this; var paramsWithDailyAgg = { - aggregation: 'day', + aggregation: 'day' }; // data: from 2007-02-15 23:50:00 to 2007-02-16 00:10:00 @@ -1208,7 +1189,7 @@ describe('histogram-dataview for date column type', function() { self.testClient.getDataview('minute_histogram', paramsWithDailyAgg, function (err, dataview) { assert.ifError(err); - assert.deepEqual(dataview, dataviewWithDailyAggFixture); + assert.deepStrictEqual(dataview, dataviewWithDailyAggFixture); done(); }); }); @@ -1247,16 +1228,14 @@ describe('histogram-dataview for date column type', function() { self.testClient.getDataview('minute_histogram', paramsWithDailyAggAndOffset, function (err, dataview) { assert.ifError(err); - assert.deepEqual(dataview, dataviewWithDailyAggAndOffsetFixture); + assert.deepStrictEqual(dataview, dataviewWithDailyAggAndOffsetFixture); done(); }); }); }); - -describe('histogram-dataview: special float valuer', function() { - - afterEach(function(done) { +describe('histogram-dataview: special float valuer', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -1267,13 +1246,13 @@ describe('histogram-dataview: special float valuer', function() { var mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "a0" + type: 'cartodb', + options: { + source: { + id: 'a0' }, - "cartocss": "#points { marker-width: 10; marker-fill: red; }", - "cartocss_version": "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -1290,10 +1269,10 @@ describe('histogram-dataview: special float valuer', function() { }, [ { - "id": "a0", - "type": "source", - "params": { - "query": [ + id: 'a0', + type: 'source', + params: { + query: [ 'SELECT', ' null::geometry the_geom_webmercator,', ' CASE', @@ -1309,9 +1288,9 @@ describe('histogram-dataview: special float valuer', function() { ] ); - it('should filter infinities out and count them in the summary', function(done) { + it('should filter infinities out and count them in the summary', function (done) { this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getDataview('val_histogram', {}, function(err, dataview) { + this.testClient.getDataview('val_histogram', {}, function (err, dataview) { assert.ok(!err, err); assert.ok(dataview.infinities === (250 + 250)); assert.ok(dataview.nans === 250); @@ -1320,9 +1299,8 @@ describe('histogram-dataview: special float valuer', function() { }); }); -describe('histogram-dates: aggregation input value', function() { - - afterEach(function(done) { +describe('histogram-dates: aggregation input value', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -1333,13 +1311,13 @@ describe('histogram-dates: aggregation input value', function() { var mapConfig = createMapConfig( [ { - type: "cartodb", + type: 'cartodb', options: { source: { - id: "a0" + id: 'a0' }, - cartocss: "#points { marker-width: 10; marker-fill: red; }", - cartocss_version: "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -1373,9 +1351,9 @@ describe('histogram-dates: aggregation input value', function() { query: [ 'select null::geometry the_geom_webmercator, date AS d', 'from generate_series(', - '\'2007-02-15 01:00:00\'::timestamp,', - '\'2008-04-09 01:00:00\'::timestamp,', - ' \'1 day\'::interval', + '\'2007-02-15 01:00:00\'::timestamp,', + '\'2008-04-09 01:00:00\'::timestamp,', + ' \'1 day\'::interval', ') date' ].join(' ') } @@ -1383,7 +1361,7 @@ describe('histogram-dates: aggregation input value', function() { ] ); - it('should fail when aggregation values is not valid while instantiating the map', function(done) { + it('should fail when aggregation values is not valid while instantiating the map', function (done) { this.testClient = new TestClient(mapConfig, 1234); const override = { response: { @@ -1391,10 +1369,10 @@ describe('histogram-dates: aggregation input value', function() { } }; - this.testClient.getDataview('bad_agg_value_histogram', override, function(err, dataviewError) { + this.testClient.getDataview('bad_agg_value_histogram', override, function (err, dataviewError) { assert.ifError(err); - assert.deepEqual(dataviewError, { + assert.deepStrictEqual(dataviewError, { errors: [ 'Invalid aggregation value. Valid ones: auto, second, minute, ' + 'hour, day, week, month, quarter, year, decade, century, millennium' @@ -1413,7 +1391,7 @@ describe('histogram-dates: aggregation input value', function() { }); }); - it('should fail when aggregation values is not valid while fetching dataview result', function(done) { + it('should fail when aggregation values is not valid while fetching dataview result', function (done) { this.testClient = new TestClient(mapConfig, 1234); const override = { aggregation: 'wadus', @@ -1422,10 +1400,10 @@ describe('histogram-dates: aggregation input value', function() { } }; - this.testClient.getDataview('agg_value_histogram', override, function(err, dataviewError) { + this.testClient.getDataview('agg_value_histogram', override, function (err, dataviewError) { assert.ifError(err); - assert.deepEqual(dataviewError, { + assert.deepStrictEqual(dataviewError, { errors: [ 'Invalid aggregation value. Valid ones: auto, second, minute, ' + 'hour, day, week, month, quarter, year, decade, century, millennium' @@ -1445,9 +1423,8 @@ describe('histogram-dates: aggregation input value', function() { }); }); -describe('histogram-dates: timestamp starts at epoch', function() { - - afterEach(function(done) { +describe('histogram-dates: timestamp starts at epoch', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -1458,13 +1435,13 @@ describe('histogram-dates: timestamp starts at epoch', function() { var mapConfig = createMapConfig( [ { - type: "cartodb", + type: 'cartodb', options: { source: { - id: "a0" + id: 'a0' }, - cartocss: "#points { marker-width: 10; marker-fill: red; }", - cartocss_version: "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -1488,9 +1465,9 @@ describe('histogram-dates: timestamp starts at epoch', function() { query: [ 'select null::geometry the_geom_webmercator, date AS d', 'from generate_series(', - '\'1970-01-04 10:00:00\'::timestamp,', - '\'1984-01-04 10:00:00\'::timestamp,', - ' \'1 month\'::interval', + '\'1970-01-04 10:00:00\'::timestamp,', + '\'1984-01-04 10:00:00\'::timestamp,', + ' \'1 month\'::interval', ') date' ].join(' ') } @@ -1498,26 +1475,25 @@ describe('histogram-dates: timestamp starts at epoch', function() { ] ); - it('should work when timestamp_start is epoch (1970-01-01 = 0)', function(done) { + it('should work when timestamp_start is epoch (1970-01-01 = 0)', function (done) { this.testClient = new TestClient(mapConfig, 1234); const override = {}; - this.testClient.getDataview('epoch_start_histogram', override, function(err, dataview) { + this.testClient.getDataview('epoch_start_histogram', override, function (err, dataview) { assert.ifError(err); - const { aggregation, timestamp_start } = dataview; + const { aggregation, timestamp_start: timestampStart } = dataview; - assert.equal(timestamp_start, 0); - assert.equal(aggregation, 'quarter'); + assert.strictEqual(timestampStart, 0); + assert.strictEqual(aggregation, 'quarter'); done(); }); }); }); -describe('histogram-dates: trunc timestamp for each bin respecting user\'s timezone', function() { - - afterEach(function(done) { +describe('histogram-dates: trunc timestamp for each bin respecting user\'s timezone', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -1528,13 +1504,13 @@ describe('histogram-dates: trunc timestamp for each bin respecting user\'s timez var mapConfig = createMapConfig( [ { - type: "cartodb", + type: 'cartodb', options: { source: { - id: "a0" + id: 'a0' }, - cartocss: "#points { marker-width: 10; marker-fill: red; }", - cartocss_version: "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -1568,9 +1544,9 @@ describe('histogram-dates: trunc timestamp for each bin respecting user\'s timez query: [ 'select null::geometry the_geom_webmercator, date AS d', 'from generate_series(', - '\'1970-01-01 00:00:00\'::timestamp,', - '\'1970-01-01 01:59:00\'::timestamp,', - ' \'1 minute\'::interval', + '\'1970-01-01 00:00:00\'::timestamp,', + '\'1970-01-01 01:59:00\'::timestamp,', + ' \'1 minute\'::interval', ') date' ].join(' ') } @@ -1582,9 +1558,9 @@ describe('histogram-dates: trunc timestamp for each bin respecting user\'s timez query: [ 'select null::geometry the_geom_webmercator, date AS d', 'from generate_series(', - '\'1970-01-01 00:00:00\'::timestamptz,', - '\'1970-01-01 01:59:00\'::timestamptz,', - ' \'1 minute\'::interval', + '\'1970-01-01 00:00:00\'::timestamptz,', + '\'1970-01-01 01:59:00\'::timestamptz,', + ' \'1 minute\'::interval', ') date' ].join(' ') } @@ -1601,7 +1577,7 @@ describe('histogram-dates: trunc timestamp for each bin respecting user\'s timez }]; dateHistogramsUseCases.forEach(function (test) { - it('should return histogram with two buckets ' + test.desc , function(done) { + it('should return histogram with two buckets ' + test.desc, function (done) { this.testClient = new TestClient(mapConfig, 1234); const override = { @@ -1609,7 +1585,7 @@ describe('histogram-dates: trunc timestamp for each bin respecting user\'s timez offset: '-3600' }; - this.testClient.getDataview(test.dataviewId, override, function(err, dataview) { + this.testClient.getDataview(test.dataviewId, override, function (err, dataview) { assert.ifError(err); var OFFSET_IN_MINUTES = -1 * 60; // GMT-01 @@ -1618,7 +1594,7 @@ describe('histogram-dates: trunc timestamp for each bin respecting user\'s timez var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) @@ -1630,7 +1606,7 @@ describe('histogram-dates: trunc timestamp for each bin respecting user\'s timez .utcOffset(OFFSET_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); @@ -1641,10 +1617,8 @@ describe('histogram-dates: trunc timestamp for each bin respecting user\'s timez }); }); - -describe('histogram: be able to override with aggregation for histograms instantiated w/o aggregation', function() { - - afterEach(function(done) { +describe('histogram: be able to override with aggregation for histograms instantiated w/o aggregation', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -1655,13 +1629,13 @@ describe('histogram: be able to override with aggregation for histograms instant var mapConfig = createMapConfig( [ { - type: "cartodb", + type: 'cartodb', options: { source: { - id: "a0" + id: 'a0' }, - cartocss: "#points { marker-width: 10; marker-fill: red; }", - cartocss_version: "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -1672,7 +1646,7 @@ describe('histogram: be able to override with aggregation for histograms instant }, type: 'histogram', options: { - column: 'd', + column: 'd' } } }, @@ -1684,9 +1658,9 @@ describe('histogram: be able to override with aggregation for histograms instant query: [ 'select null::geometry the_geom_webmercator, date AS d', 'from generate_series(', - '\'1970-01-01 00:00:00\'::timestamp,', - '\'1970-01-01 01:59:00\'::timestamp,', - ' \'1 minute\'::interval', + '\'1970-01-01 00:00:00\'::timestamp,', + '\'1970-01-01 01:59:00\'::timestamp,', + ' \'1 minute\'::interval', ') date' ].join(' ') } @@ -1694,7 +1668,7 @@ describe('histogram: be able to override with aggregation for histograms instant ] ); - it('should apply aggregation to the histogram', function(done) { + it('should apply aggregation to the histogram', function (done) { this.testClient = new TestClient(mapConfig, 1234); const override = { @@ -1702,7 +1676,7 @@ describe('histogram: be able to override with aggregation for histograms instant offset: '-3600' }; - this.testClient.getDataview('timezone_epoch_histogram', override, function(err, dataview) { + this.testClient.getDataview('timezone_epoch_histogram', override, function (err, dataview) { assert.ifError(err); var OFFSET_IN_MINUTES = -1 * 60; // GMT-01 @@ -1711,7 +1685,7 @@ describe('histogram: be able to override with aggregation for histograms instant var binsStartFormatted = moment.utc(binsStartInMilliseconds) .utcOffset(OFFSET_IN_MINUTES) .format(); - assert.equal(binsStartFormatted, initialTimestamp); + assert.strictEqual(binsStartFormatted, initialTimestamp); dataview.bins.forEach(function (bin, index) { var binTimestampExpected = moment.utc(initialTimestamp) @@ -1723,7 +1697,7 @@ describe('histogram: be able to override with aggregation for histograms instant .utcOffset(OFFSET_IN_MINUTES) .format(); - assert.equal(binTimestampFormatted, binTimestampExpected); + assert.strictEqual(binTimestampFormatted, binTimestampExpected); assert.ok(bin.timestamp <= bin.min, 'bin timestamp < bin min: ' + JSON.stringify(bin)); assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin)); }); diff --git a/test/acceptance/dataviews/overviews-test.js b/test/acceptance/dataviews/overviews-test.js index aa97a28f..f46226a8 100644 --- a/test/acceptance/dataviews/overviews-test.js +++ b/test/acceptance/dataviews/overviews-test.js @@ -5,22 +5,22 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('dataviews using tables without overviews', function() { - - var nonOverviewsMapConfig = { +describe('dataviews using tables without overviews', function () { + var nonOverviewsMapConfig = { version: '1.5.0', analyses: [ - { id: 'data-source', + { + id: 'data-source', type: 'source', params: { - query: 'select * from populated_places_simple_reduced' + query: 'select * from populated_places_simple_reduced' } } ], - dataviews: { + dataviews: { country_places_count: { type: 'formula', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'adm0_a3', operation: 'count' @@ -28,7 +28,7 @@ describe('dataviews using tables without overviews', function() { }, country_categories: { type: 'aggregation', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'adm0_a3', aggregation: 'count' @@ -48,98 +48,95 @@ describe('dataviews using tables without overviews', function() { ] }; - it("should expose a formula", function(done) { + it('should expose a formula', function (done) { var testClient = new TestClient(nonOverviewsMapConfig); - testClient.getDataview('country_places_count', { own_filter: 0 }, function(err, formula_result, headers) { + testClient.getDataview('country_places_count', { own_filter: 0 }, function (err, formulaResult, headers) { if (err) { return done(err); } - assert.deepEqual(formula_result, { operation: 'count', result: 7313, nulls: 0, type: 'formula' }); - assert(getUsesOverviewsFromHeaders(headers) === false); //Overviews logging + assert.deepStrictEqual(formulaResult, { operation: 'count', result: 7313, nulls: 0, type: 'formula' }); + assert(getUsesOverviewsFromHeaders(headers) === false); // Overviews logging testClient.drain(done); }); }); - it("should admit a bbox", function(done) { + it('should admit a bbox', function (done) { var params = { - bbox: "-170,-80,170,80" + bbox: '-170,-80,170,80' }; var testClient = new TestClient(nonOverviewsMapConfig); - testClient.getDataview('country_places_count', params, function(err, formula_result) { + testClient.getDataview('country_places_count', params, function (err, formulaResult) { if (err) { return done(err); } - assert.deepEqual(formula_result, { operation: 'count', result: 7253, nulls: 0, type: 'formula' }); + assert.deepStrictEqual(formulaResult, { operation: 'count', result: 7253, nulls: 0, type: 'formula' }); testClient.drain(done); }); }); - describe('filters', function() { - + describe('filters', function () { describe('category', function () { - - it("should expose a filtered formula", function (done) { + it('should expose a filtered formula', function (done) { var params = { filters: { - dataviews: {country_categories: {accept: ['CAN']}} + dataviews: { country_categories: { accept: ['CAN'] } } } }; var testClient = new TestClient(nonOverviewsMapConfig); - testClient.getDataview('country_places_count', params, function (err, formula_result) { + testClient.getDataview('country_places_count', params, function (err, formulaResult) { if (err) { return done(err); } - assert.deepEqual(formula_result, { operation: 'count', result: 256, nulls: 0, type: 'formula' }); + assert.deepStrictEqual(formulaResult, { operation: 'count', result: 256, nulls: 0, type: 'formula' }); testClient.drain(done); }); }); - it("should expose a filtered formula and admit a bbox", function (done) { + it('should expose a filtered formula and admit a bbox', function (done) { var params = { filters: { - dataviews: {country_categories: {accept: ['CAN']}} + dataviews: { country_categories: { accept: ['CAN'] } } }, - bbox: "-170,-80,170,80" + bbox: '-170,-80,170,80' }; var testClient = new TestClient(nonOverviewsMapConfig); - testClient.getDataview('country_places_count', params, function (err, formula_result) { + testClient.getDataview('country_places_count', params, function (err, formulaResult) { if (err) { return done(err); } - assert.deepEqual(formula_result, { operation: 'count', result: 254, nulls: 0, type: 'formula' }); + assert.deepStrictEqual(formulaResult, { operation: 'count', result: 254, nulls: 0, type: 'formula' }); testClient.drain(done); }); }); }); - }); }); -describe('dataviews using tables with overviews', function() { - - var overviewsMapConfig = { +describe('dataviews using tables with overviews', function () { + var overviewsMapConfig = { version: '1.5.0', analyses: [ - { id: 'data-source', + { + id: 'data-source', type: 'source', params: { - query: 'select * from test_table_overviews' + query: 'select * from test_table_overviews' } }, { id: 'data-source-special-float-values', type: 'source', params: { - query: 'select * from test_special_float_values_table_overviews' + query: 'select * from test_special_float_values_table_overviews' } } ], - dataviews: { + dataviews: { test_sum: { type: 'formula', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'value', operation: 'sum' @@ -147,11 +144,11 @@ describe('dataviews using tables with overviews', function() { }, test_categories: { type: 'aggregation', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'name', aggregation: 'count', - aggregationColumn: 'name', + aggregationColumn: 'name' } }, test_categories_special_values: { @@ -162,12 +159,12 @@ describe('dataviews using tables with overviews', function() { options: { column: 'name', aggregation: 'sum', - aggregationColumn: 'value', + aggregationColumn: 'value' } }, test_histogram: { type: 'histogram', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'value', bins: 2 @@ -175,7 +172,7 @@ describe('dataviews using tables with overviews', function() { }, test_histogram_date: { type: 'histogram', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'updated_at', bins: 2 @@ -193,7 +190,7 @@ describe('dataviews using tables with overviews', function() { }, test_avg: { type: 'formula', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'value', operation: 'avg' @@ -211,7 +208,7 @@ describe('dataviews using tables with overviews', function() { }, test_count: { type: 'formula', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'value', operation: 'count' @@ -219,7 +216,7 @@ describe('dataviews using tables with overviews', function() { }, test_min: { type: 'formula', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'value', operation: 'min' @@ -227,7 +224,7 @@ describe('dataviews using tables with overviews', function() { }, test_max: { type: 'formula', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: { column: 'value', operation: 'max' @@ -258,150 +255,148 @@ describe('dataviews using tables with overviews', function() { ] }; - it("should expose a sum formula", function(done) { + it('should expose a sum formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_sum', { own_filter: 0 }, function(err, formula_result, headers) { + testClient.getDataview('test_sum', { own_filter: 0 }, function (err, formulaResult, headers) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation":"sum", - "result":15, - "infinities": 0, - "nans": 0, - "nulls":0, - "type":"formula" + assert.deepStrictEqual(formulaResult, { + operation: 'sum', + result: 15, + infinities: 0, + nans: 0, + nulls: 0, + type: 'formula' }); - assert.ok(getUsesOverviewsFromHeaders(headers)); //Overviews logging - assert(getDataviewTypeFromHeaders(headers) === 'formula'); //Overviews logging + assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging + assert(getDataviewTypeFromHeaders(headers) === 'formula'); // Overviews logging testClient.drain(done); }); }); - it("should expose an avg formula", function(done) { + it('should expose an avg formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_avg', { own_filter: 0 }, function(err, formula_result, headers) { + testClient.getDataview('test_avg', { own_filter: 0 }, function (err, formulaResult, headers) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation":"avg", - "result":3, - "nulls":0, - "type":"formula", - "infinities": 0, - "nans": 0 + assert.deepStrictEqual(formulaResult, { + operation: 'avg', + result: 3, + nulls: 0, + type: 'formula', + infinities: 0, + nans: 0 }); - assert.ok(getUsesOverviewsFromHeaders(headers)); //Overviews logging - assert(getDataviewTypeFromHeaders(headers) === 'formula'); //Overviews logging + assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging + assert(getDataviewTypeFromHeaders(headers) === 'formula'); // Overviews logging testClient.drain(done); }); }); - it("should expose a count formula", function(done) { + it('should expose a count formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_count', { own_filter: 0 }, function(err, formula_result, headers) { + testClient.getDataview('test_count', { own_filter: 0 }, function (err, formulaResult, headers) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation":"count", - "result":5, - "nulls":0, - "type":"formula", - "infinities": 0, - "nans": 0 + assert.deepStrictEqual(formulaResult, { + operation: 'count', + result: 5, + nulls: 0, + type: 'formula', + infinities: 0, + nans: 0 }); - assert.ok(getUsesOverviewsFromHeaders(headers)); //Overviews logging - assert(getDataviewTypeFromHeaders(headers) === 'formula'); //Overviews logging + assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging + assert(getDataviewTypeFromHeaders(headers) === 'formula'); // Overviews logging testClient.drain(done); }); }); - it("should expose a max formula", function(done) { + it('should expose a max formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_max', { own_filter: 0 }, function(err, formula_result) { + testClient.getDataview('test_max', { own_filter: 0 }, function (err, formulaResult) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation": "max", - "result": 5, - "nulls": 0, - "infinities": 0, - "nans": 0, - "type": "formula" + assert.deepStrictEqual(formulaResult, { + operation: 'max', + result: 5, + nulls: 0, + infinities: 0, + nans: 0, + type: 'formula' }); testClient.drain(done); }); }); - it("should expose a min formula", function(done) { + it('should expose a min formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_min', { own_filter: 0 }, function(err, formula_result) { + testClient.getDataview('test_min', { own_filter: 0 }, function (err, formulaResult) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation": "min", - "result": 1, - "nulls": 0, - "infinities": 0, - "nans": 0, - "type": "formula" + assert.deepStrictEqual(formulaResult, { + operation: 'min', + result: 1, + nulls: 0, + infinities: 0, + nans: 0, + type: 'formula' }); testClient.drain(done); }); }); - it("should admit a bbox", function(done) { + it('should admit a bbox', function (done) { var params = { - bbox: "-170,-80,170,80" + bbox: '-170,-80,170,80' }; var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_sum', params, function(err, formula_result) { + testClient.getDataview('test_sum', params, function (err, formulaResult) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation":"sum", - "result":15, - "nulls":0, - "infinities": 0, - "nans": 0, - "type":"formula" + assert.deepStrictEqual(formulaResult, { + operation: 'sum', + result: 15, + nulls: 0, + infinities: 0, + nans: 0, + type: 'formula' }); testClient.drain(done); }); }); - it("should expose a histogram", function (done) { + it('should expose a histogram', function (done) { var testClient = new TestClient(overviewsMapConfig); testClient.getDataview('test_histogram', function (err, histogram, headers) { if (err) { return done(err); } assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); assert.ok(Array.isArray(histogram.bins)); - assert.ok(getUsesOverviewsFromHeaders(headers)); //Overviews logging - assert(getDataviewTypeFromHeaders(headers) === 'histogram'); //Overviews logging + assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging + assert(getDataviewTypeFromHeaders(headers) === 'histogram'); // Overviews logging testClient.drain(done); }); }); - describe('filters', function() { - + describe('filters', function () { describe('histogram', function () { - - it("should expose a filtered histogram", function (done) { + it('should expose a filtered histogram', function (done) { var params = { filters: { dataviews: { test_histogram: { min: 2 } } @@ -414,14 +409,14 @@ describe('dataviews using tables with overviews', function() { return done(err); } assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); assert.ok(Array.isArray(histogram.bins)); - assert.equal(histogram.bins.length, 4); + assert.strictEqual(histogram.bins.length, 4); testClient.drain(done); }); }); - it("should expose a filtered histogram with no results", function (done) { + it('should expose a filtered histogram with no results', function (done) { var params = { filters: { dataviews: { test_histogram: { max: -1 } } @@ -434,14 +429,14 @@ describe('dataviews using tables with overviews', function() { return done(err); } assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); assert.ok(Array.isArray(histogram.bins)); - assert.equal(histogram.bins.length, 0); + assert.strictEqual(histogram.bins.length, 0); testClient.drain(done); }); }); - it("should expose a filtered date histogram with no results", function (done) { + it('should expose a filtered date histogram with no results', function (done) { // This most likely works because the overviews will pass // the responsibility to the normal dataviews. var params = { @@ -456,157 +451,154 @@ describe('dataviews using tables with overviews', function() { return done(err); } assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); assert.ok(Array.isArray(histogram.bins)); - assert.equal(histogram.bins.length, 0); + assert.strictEqual(histogram.bins.length, 0); testClient.drain(done); }); }); }); describe('category', function () { - var params = { filters: { - dataviews: {test_categories: {accept: ['Hawai']}} + dataviews: { test_categories: { accept: ['Hawai'] } } } }; - it("should expose a filtered sum formula", function (done) { + it('should expose a filtered sum formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_sum', params, function (err, formula_result, headers) { + testClient.getDataview('test_sum', params, function (err, formulaResult, headers) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation":"sum", - "result":1, - "nulls":0, - "infinities": 0, - "nans": 0, - "type":"formula" + assert.deepStrictEqual(formulaResult, { + operation: 'sum', + result: 1, + nulls: 0, + infinities: 0, + nans: 0, + type: 'formula' }); - assert.ok(getUsesOverviewsFromHeaders(headers)); //Overviews logging + assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging testClient.drain(done); }); }); - it("should expose a filtered avg formula", function(done) { + it('should expose a filtered avg formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_avg', params, function(err, formula_result, headers) { + testClient.getDataview('test_avg', params, function (err, formulaResult, headers) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation":"avg", - "result":1, - "nulls":0, - "infinities": 0, - "nans": 0, - "type":"formula" + assert.deepStrictEqual(formulaResult, { + operation: 'avg', + result: 1, + nulls: 0, + infinities: 0, + nans: 0, + type: 'formula' }); - assert.ok(getUsesOverviewsFromHeaders(headers)); //Overviews logging + assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging testClient.drain(done); }); }); - it("should expose a filtered count formula", function(done) { + it('should expose a filtered count formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_count', params, function(err, formula_result, headers) { + testClient.getDataview('test_count', params, function (err, formulaResult, headers) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation":"count", - "result":1, - "infinities": 0, - "nans": 0, - "nulls":0, - "type":"formula" + assert.deepStrictEqual(formulaResult, { + operation: 'count', + result: 1, + infinities: 0, + nans: 0, + nulls: 0, + type: 'formula' }); - assert.ok(getUsesOverviewsFromHeaders(headers)); //Overviews logging + assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging testClient.drain(done); }); }); - it("should expose a filterd max formula", function(done) { + it('should expose a filterd max formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_max', params, function(err, formula_result) { + testClient.getDataview('test_max', params, function (err, formulaResult) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation": "max", - "result": 1, - "nulls": 0, - "infinities": 0, - "nans": 0, - "type": "formula" + assert.deepStrictEqual(formulaResult, { + operation: 'max', + result: 1, + nulls: 0, + infinities: 0, + nans: 0, + type: 'formula' }); testClient.drain(done); }); }); - it("should expose a filterd min formula", function(done) { + it('should expose a filterd min formula', function (done) { var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_min', params, function(err, formula_result) { + testClient.getDataview('test_min', params, function (err, formulaResult) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation": "min", - "result": 1, - "nulls": 0, - "infinities": 0, - "nans": 0, - "type": "formula" + assert.deepStrictEqual(formulaResult, { + operation: 'min', + result: 1, + nulls: 0, + infinities: 0, + nans: 0, + type: 'formula' }); testClient.drain(done); }); }); - it("should expose a filtered sum formula with bbox", function (done) { + it('should expose a filtered sum formula with bbox', function (done) { var bboxparams = { filters: { - dataviews: {test_categories: {accept: ['Hawai']}} + dataviews: { test_categories: { accept: ['Hawai'] } } }, - bbox: "-170,-80,170,80" + bbox: '-170,-80,170,80' }; var testClient = new TestClient(overviewsMapConfig); - testClient.getDataview('test_sum', bboxparams, function (err, formula_result) { + testClient.getDataview('test_sum', bboxparams, function (err, formulaResult) { if (err) { return done(err); } - assert.deepEqual(formula_result, { - "operation":"sum", - "result":1, - "nulls":0, - "infinities": 0, - "nans": 0, - "type":"formula" + assert.deepStrictEqual(formulaResult, { + operation: 'sum', + result: 1, + nulls: 0, + infinities: 0, + nans: 0, + type: 'formula' }); testClient.drain(done); }); }); - - }); describe('aggregation special float values', function () { var params = {}; - it("should expose an aggregation dataview filtering special float values out", function (done) { + it('should expose an aggregation dataview filtering special float values out', function (done) { var testClient = new TestClient(overviewsMapConfig); testClient.getDataview('test_categories_special_values', params, function (err, dataview, headers) { if (err) { return done(err); } - assert.deepEqual(dataview, { + assert.deepStrictEqual(dataview, { aggregation: 'sum', count: 5, nulls: 0, @@ -615,12 +607,12 @@ describe('dataviews using tables with overviews', function() { min: 6, max: 6, categoriesCount: 1, - categories: [ { category: 'Hawai', value: 6, agg: false } ], + categories: [{ category: 'Hawai', value: 6, agg: false }], type: 'aggregation' }); - assert.ok(getUsesOverviewsFromHeaders(headers)); //Overviews logging - assert(getDataviewTypeFromHeaders(headers) === 'aggregation'); //Overviews logging + assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging + assert(getDataviewTypeFromHeaders(headers) === 'aggregation'); // Overviews logging testClient.drain(done); }); @@ -632,7 +624,7 @@ describe('dataviews using tables with overviews', function() { if (err) { return done(err); } - assert.deepEqual(dataview, { + assert.deepStrictEqual(dataview, { bin_width: 0, bins_count: 1, bins_start: 3, @@ -640,7 +632,7 @@ describe('dataviews using tables with overviews', function() { infinities: 1, nans: 1, avg: 3, - bins: [ { bin: 0, min: 3, max: 3, avg: 3, freq: 2 } ], + bins: [{ bin: 0, min: 3, max: 3, avg: 3, freq: 2 }], type: 'histogram' }); testClient.drain(done); @@ -653,7 +645,7 @@ describe('dataviews using tables with overviews', function() { if (err) { return done(err); } - assert.deepEqual(dataview, { + assert.deepStrictEqual(dataview, { operation: 'sum', result: 6, nulls: 0, @@ -666,7 +658,7 @@ describe('dataviews using tables with overviews', function() { }); }); - describe('agreggation validation', function (){ + describe('agreggation validation', function () { const params = { response: { status: 400, @@ -676,21 +668,22 @@ describe('dataviews using tables with overviews', function() { } }; - function createMapConfig(options) { + function createMapConfig (options) { return { version: '1.8.0', analyses: [ - { id: 'data-source', + { + id: 'data-source', type: 'source', params: { query: 'select * from test_table_overviews' } } ], - dataviews: { + dataviews: { test_invalid_aggregation: { type: 'aggregation', - source: {id: 'data-source'}, + source: { id: 'data-source' }, options: options } }, @@ -710,8 +703,8 @@ describe('dataviews using tables with overviews', function() { it('should fail if missing column', function (done) { var options = { - aggregation: "sum", - aggregationColumn: "value" + aggregation: 'sum', + aggregationColumn: 'value' }; var missingColumnMapConfig = createMapConfig(options); @@ -735,8 +728,8 @@ describe('dataviews using tables with overviews', function() { it('should fail if no aggregation operation', function (done) { var options = { - column: "value", - aggregationColumn: "value" + column: 'value', + aggregationColumn: 'value' }; var missingOperationMapConfig = createMapConfig(options); @@ -760,9 +753,9 @@ describe('dataviews using tables with overviews', function() { it('should fail if fake operation', function (done) { var options = { - column: "value", - aggregation: "wadus", - aggregationColumn: "value" + column: 'value', + aggregation: 'wadus', + aggregationColumn: 'value' }; var wrongOperationMapConfig = createMapConfig(options); @@ -786,9 +779,9 @@ describe('dataviews using tables with overviews', function() { it('should fail if invalid operation for overview', function (done) { var options = { - column: "value", - aggregation: "avg", - aggregationColumn: "value" + column: 'value', + aggregation: 'avg', + aggregationColumn: 'value' }; var wrongOperationMapConfig = createMapConfig(options); @@ -812,8 +805,8 @@ describe('dataviews using tables with overviews', function() { it('should fail if no aggregation column when needed', function (done) { var options = { - column: "value", - aggregation: "sum" + column: 'value', + aggregation: 'sum' }; var missingOptionMapConfig = createMapConfig(options); @@ -838,10 +831,10 @@ describe('dataviews using tables with overviews', function() { }); }); -function getUsesOverviewsFromHeaders(headers) { +function getUsesOverviewsFromHeaders (headers) { return headers && headers['x-tiler-profiler'] && JSON.parse(headers['x-tiler-profiler']).usesOverviews; } -function getDataviewTypeFromHeaders(headers) { +function getDataviewTypeFromHeaders (headers) { return headers && headers['x-tiler-profiler'] && JSON.parse(headers['x-tiler-profiler']).dataviewType; } diff --git a/test/acceptance/date-wrapping-test.js b/test/acceptance/date-wrapping-test.js index 85b56111..9f662826 100644 --- a/test/acceptance/date-wrapping-test.js +++ b/test/acceptance/date-wrapping-test.js @@ -1,29 +1,28 @@ 'use strict'; -/* eslint-env mocha */ const assert = require('assert'); const TestClient = require('../support/test-client'); const mapConfigFactory = require('../fixtures/test_mapconfigFactory'); const serverOptions = require('../../lib/server-options'); const usePgMvtRenderer = serverOptions.renderer.mvt.usePostGIS; -const describe_mvt = !usePgMvtRenderer ? describe : describe.skip; +const describeMvt = !usePgMvtRenderer ? describe : describe.skip; -describe_mvt('date-wrapping', () => { +describeMvt('date-wrapping', () => { let testClient; describe('when a map instantiation has one single layer', () => { describe('and the layer has the "dates_as_numbers" option enabled', () => { beforeEach(() => { - const mapConfig = mapConfigFactory.getVectorMapConfig({ layerOptions: [{ dates_as_numbers: true }]}); + const mapConfig = mapConfigFactory.getVectorMapConfig({ layerOptions: [{ dates_as_numbers: true }] }); testClient = new TestClient(mapConfig); }); afterEach(done => testClient.drain(done)); it('should return date columns casted as numbers', done => { - testClient.getTile(0, 0, 0, { format: 'mvt' }, (err, res, mvt) => { + assert.ifError(err); const expected = [ { type: 'Feature', @@ -40,34 +39,31 @@ describe_mvt('date-wrapping', () => { ]; const actual = JSON.parse(mvt.toGeoJSONSync(0)).features; - assert.deepEqual(actual, expected); + assert.deepStrictEqual(actual, expected); done(); }); }); it('should return metadata with casted columns', done => { - - testClient.getLayergroup(function(err, layergroup) { + testClient.getLayergroup(function (err, layergroup) { assert.ifError(err); - assert.deepEqual(layergroup.metadata.layers[0].meta.dates_as_numbers, ['date']); + assert.deepStrictEqual(layergroup.metadata.layers[0].meta.dates_as_numbers, ['date']); done(); }); - }); - }); describe('and the layer has the "dates_as_numbers" option disabled', () => { beforeEach(() => { - const mapConfig = mapConfigFactory.getVectorMapConfig({ layerOptions: [{ dates_as_numbers: false }]}); + const mapConfig = mapConfigFactory.getVectorMapConfig({ layerOptions: [{ dates_as_numbers: false }] }); testClient = new TestClient(mapConfig); }); afterEach(done => testClient.drain(done)); it('should return date columns as dates', done => { - testClient.getTile(0, 0, 0, { format: 'mvt' }, (err, res, mvt) => { + assert.ifError(err); const expected = [ { type: 'Feature', @@ -84,7 +80,7 @@ describe_mvt('date-wrapping', () => { ]; const actual = JSON.parse(mvt.toGeoJSONSync(0)).features; - assert.deepEqual(actual, expected); + assert.deepStrictEqual(actual, expected); done(); }); }); @@ -107,13 +103,14 @@ describe_mvt('date-wrapping', () => { }); it('should return dates as numbers for every layer', done => { - testClient.getLayergroup(function(err, layergroup) { + testClient.getLayergroup(function (err, layergroup) { assert.ifError(err); - assert.deepEqual(layergroup.metadata.layers[0].meta.dates_as_numbers, ['date']); - assert.deepEqual(layergroup.metadata.layers[1].meta.dates_as_numbers, ['date']); + assert.deepStrictEqual(layergroup.metadata.layers[0].meta.dates_as_numbers, ['date']); + assert.deepStrictEqual(layergroup.metadata.layers[1].meta.dates_as_numbers, ['date']); }); testClient.getTile(0, 0, 0, { format: 'mvt' }, (err, res, mvt) => { + assert.ifError(err); const expected0 = [ { type: 'Feature', @@ -145,8 +142,8 @@ describe_mvt('date-wrapping', () => { const actual0 = JSON.parse(mvt.toGeoJSONSync(0)).features; const actual1 = JSON.parse(mvt.toGeoJSONSync(1)).features; - assert.deepEqual(actual0, expected0); - assert.deepEqual(actual1, expected1); + assert.deepStrictEqual(actual0, expected0); + assert.deepStrictEqual(actual1, expected1); done(); }); }); @@ -164,14 +161,15 @@ describe_mvt('date-wrapping', () => { testClient = new TestClient(mapConfig); }); - it('should return dates as numbers only for the layer with the "dates_as_numbers" flag enabled', done => { - testClient.getLayergroup(function(err, layergroup) { + it('should return dates as numbers only for the layer with the "dates_as_numbers" flag enabled', done => { + testClient.getLayergroup(function (err, layergroup) { assert.ifError(err); - assert.deepEqual(layergroup.metadata.layers[0].meta.dates_as_numbers || [], []); - assert.deepEqual(layergroup.metadata.layers[1].meta.dates_as_numbers, ['date']); + assert.deepStrictEqual(layergroup.metadata.layers[0].meta.dates_as_numbers || [], []); + assert.deepStrictEqual(layergroup.metadata.layers[1].meta.dates_as_numbers, ['date']); }); testClient.getTile(0, 0, 0, { format: 'mvt' }, (err, res, mvt) => { + assert.ifError(err); const expected0 = [ { type: 'Feature', @@ -203,8 +201,8 @@ describe_mvt('date-wrapping', () => { const actual0 = JSON.parse(mvt.toGeoJSONSync(0)).features; const actual1 = JSON.parse(mvt.toGeoJSONSync(1)).features; - assert.deepEqual(actual0, expected0); - assert.deepEqual(actual1, expected1); + assert.deepStrictEqual(actual0, expected0); + assert.deepStrictEqual(actual1, expected1); done(); }); }); @@ -222,14 +220,15 @@ describe_mvt('date-wrapping', () => { testClient = new TestClient(mapConfig); }); - it('should return dates as dates for both layers', done => { - testClient.getLayergroup(function(err, layergroup) { + it('should return dates as dates for both layers', done => { + testClient.getLayergroup(function (err, layergroup) { assert.ifError(err); - assert.deepEqual(layergroup.metadata.layers[0].meta.dates_as_numbers || [], []); - assert.deepEqual(layergroup.metadata.layers[1].meta.dates_as_numbers || [], []); + assert.deepStrictEqual(layergroup.metadata.layers[0].meta.dates_as_numbers || [], []); + assert.deepStrictEqual(layergroup.metadata.layers[1].meta.dates_as_numbers || [], []); }); testClient.getTile(0, 0, 0, { format: 'mvt' }, (err, res, mvt) => { + assert.ifError(err); const expected0 = [ { type: 'Feature', @@ -261,8 +260,8 @@ describe_mvt('date-wrapping', () => { const actual0 = JSON.parse(mvt.toGeoJSONSync(0)).features; const actual1 = JSON.parse(mvt.toGeoJSONSync(1)).features; - assert.deepEqual(actual0, expected0); - assert.deepEqual(actual1, expected1); + assert.deepStrictEqual(actual0, expected0); + assert.deepStrictEqual(actual1, expected1); done(); }); }); @@ -285,16 +284,16 @@ describe_mvt('date-wrapping', () => { afterEach(done => testClient.drain(done)); it('should work', done => { - testClient.getLayergroup(function(err, layergroup) { + testClient.getLayergroup(function (err, layergroup) { assert.ifError(err); - assert.deepEqual(layergroup.metadata.layers[0].meta.dates_as_numbers, ['date']); + assert.deepStrictEqual(layergroup.metadata.layers[0].meta.dates_as_numbers, ['date']); done(); }); - }); it('should return correct tiles', done => { testClient.getTile(0, 0, 0, { format: 'mvt' }, (err, res, mvt) => { + assert.ifError(err); const expected = [ { type: 'Feature', @@ -310,10 +309,9 @@ describe_mvt('date-wrapping', () => { } ]; const actual = JSON.parse(mvt.toGeoJSONSync(0)).features; - assert.deepEqual(actual, expected); + assert.deepStrictEqual(actual, expected); done(); }); }); }); - }); diff --git a/test/acceptance/dynamic-styling-named-maps-test.js b/test/acceptance/dynamic-styling-named-maps-test.js index 988b2a0e..48391640 100644 --- a/test/acceptance/dynamic-styling-named-maps-test.js +++ b/test/acceptance/dynamic-styling-named-maps-test.js @@ -7,7 +7,7 @@ var testHelper = require('../support/test-helper'); var CartodbWindshaft = require('../../lib/server'); var serverOptions = require('../../lib/server-options'); -describe('dynamic styling for named maps', function() { +describe('dynamic styling for named maps', function () { var server; before(function () { @@ -16,11 +16,11 @@ describe('dynamic styling for named maps', function() { var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { + afterEach(function (done) { testHelper.deleteRedisKeys(keysToDelete, done); }); @@ -32,11 +32,11 @@ describe('dynamic styling for named maps', function() { auth: { method: 'open' }, placeholders: { color: { - type: "css_color", - default: "Reds" + type: 'css_color', + default: 'Reds' } }, - layergroup: { + layergroup: { version: '1.0.0', layers: [{ options: { @@ -89,7 +89,7 @@ describe('dynamic styling for named maps', function() { it('should instantiate a template applying cartocss dynamicly', function (done) { step( - function postTemplate() { + function postTemplate () { var next = this; assert.response(server, { @@ -102,16 +102,16 @@ describe('dynamic styling for named maps', function() { next(err, res); }); }, - function checkTemplate(err, res) { + function checkTemplate (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200); - assert.deepEqual(JSON.parse(res.body), { + assert.strictEqual(res.statusCode, 200); + assert.deepStrictEqual(JSON.parse(res.body), { template_id: templateId }); return null; }, - function instantiateTemplate(err) { + function instantiateTemplate (err) { assert.ifError(err); var next = this; @@ -128,26 +128,26 @@ describe('dynamic styling for named maps', function() { return next(err, res); }); }, - function checkInstanciation(err, res) { + function checkInstanciation (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200); + assert.strictEqual(res.statusCode, 200); var parsedBody = JSON.parse(res.body); keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; - assert.equal(parsedBody.metadata.layers[0].meta.cartocss, templateParams.styles['0']); - assert.equal( + assert.strictEqual(parsedBody.metadata.layers[0].meta.cartocss, templateParams.styles['0']); + assert.strictEqual( parsedBody.metadata.layers[1].meta.cartocss, template.layergroup.layers[1].options.cartocss ); - assert.equal(parsedBody.metadata.layers[2].meta.cartocss, templateParams.styles['2']); + assert.strictEqual(parsedBody.metadata.layers[2].meta.cartocss, templateParams.styles['2']); return parsedBody.layergroupid; }, - function deleteTemplate(err) { + function deleteTemplate (err) { assert.ifError(err); var next = this; @@ -160,14 +160,14 @@ describe('dynamic styling for named maps', function() { next(err, res); }); }, - function checkDeleteTemplate(err, res) { + function checkDeleteTemplate (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 204); + assert.strictEqual(res.statusCode, 204); assert.ok(!res.body); return null; }, - function finish(err) { + function finish (err) { done(err); } ); diff --git a/test/acceptance/error-middleware-test.js b/test/acceptance/error-middleware-test.js index 88211e09..936c957f 100644 --- a/test/acceptance/error-middleware-test.js +++ b/test/acceptance/error-middleware-test.js @@ -16,10 +16,10 @@ describe('error middleware', function () { const errorHeader = { mainError: { statusCode: 400, - message: "Missing cartocss for layer 0 options", - name: "Error", - label: "ANONYMOUS LAYERGROUP", - type: "layer", + message: 'Missing cartocss for layer 0 options', + name: 'Error', + label: 'ANONYMOUS LAYERGROUP', + type: 'layer' }, moreErrors: [] }; diff --git a/test/acceptance/errors-with-context-test.js b/test/acceptance/errors-with-context-test.js index 4d58b57a..23e09e7a 100644 --- a/test/acceptance/errors-with-context-test.js +++ b/test/acceptance/errors-with-context-test.js @@ -11,7 +11,6 @@ describe('error with context', function () { server = new CartodbWindshaft(serverOptions); }); - var layerOK = { options: { sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, 5e6, 0) as the_geom_webmercator ' + @@ -65,10 +64,10 @@ describe('error with context', function () { assert.ok(Array.isArray(parsedBody.errors_with_context)); var err = parsedBody.errors_with_context[0]; - assert.equal(err.type, 'layer'); - assert.equal(err.subtype, 'query'); + assert.strictEqual(err.type, 'layer'); + assert.strictEqual(err.subtype, 'query'); assert.ok(err.message.indexOf(DB_ERROR_MESSAGE) >= 0); - assert.deepEqual(err.layer, scenario.expectedFailingLayer); + assert.deepStrictEqual(err.layer, scenario.expectedFailingLayer); done(); }); }); diff --git a/test/acceptance/health-check-test.js b/test/acceptance/health-check-test.js index cff4b41e..53ac76f7 100644 --- a/test/acceptance/health-check-test.js +++ b/test/acceptance/health-check-test.js @@ -9,14 +9,13 @@ var CartodbWindshaft = require('../../lib/server'); var serverOptions = require('../../lib/server-options'); describe('health checks', function () { - - function enableHealthConfig() { + function enableHealthConfig () { global.environment.health = { enabled: true }; } - function disableHealthConfig() { + function disableHealthConfig () { global.environment.health = { enabled: false }; @@ -56,49 +55,49 @@ describe('health checks', function () { }); }); - it('error if disabled file exists', function(done) { - var errorMessage = "Maintenance"; + it('error if disabled file exists', function (done) { + var errorMessage = 'Maintenance'; var readFileFn = fs.readFile; - fs.readFile = function(filename, callback) { + fs.readFile = function (filename, callback) { callback(null, errorMessage); }; var server = new CartodbWindshaft(serverOptions); - assert.response(server, healthCheckRequest, RESPONSE_FAIL, function(res, err) { + assert.response(server, healthCheckRequest, RESPONSE_FAIL, function (res, err) { fs.readFile = readFileFn; assert.ok(!err); var parsed = JSON.parse(res.body); assert.ok(parsed.enabled); assert.ok(!parsed.ok); - assert.equal(parsed.err, errorMessage); + assert.strictEqual(parsed.err, errorMessage); done(); }); }); - it('error if disabled file exists but has no content', function(done) { + it('error if disabled file exists but has no content', function (done) { var readFileFn = fs.readFile; - fs.readFile = function(filename, callback) { + fs.readFile = function (filename, callback) { callback(null, ''); }; var server = new CartodbWindshaft(serverOptions); - assert.response(server, healthCheckRequest, RESPONSE_FAIL, function(res, err) { + assert.response(server, healthCheckRequest, RESPONSE_FAIL, function (res, err) { fs.readFile = readFileFn; assert.ok(!err); var parsed = JSON.parse(res.body); assert.ok(parsed.enabled); assert.ok(!parsed.ok); - assert.equal(parsed.err, 'Unknown error'); + assert.strictEqual(parsed.err, 'Unknown error'); done(); }); }); - it('not err if disabled file does not exist', function(done) { + it('not err if disabled file does not exist', function (done) { global.environment.disabled_file = '/tmp/ftreftrgtrccre'; var server = new CartodbWindshaft(serverOptions); @@ -108,11 +107,10 @@ describe('health checks', function () { var parsed = JSON.parse(res.body); - assert.equal(parsed.enabled, true); - assert.equal(parsed.ok, true); + assert.strictEqual(parsed.enabled, true); + assert.strictEqual(parsed.ok, true); done(); }); }); - }); diff --git a/test/acceptance/label-wrap-test.js b/test/acceptance/label-wrap-test.js index 2a968e61..d13ea4e6 100644 --- a/test/acceptance/label-wrap-test.js +++ b/test/acceptance/label-wrap-test.js @@ -48,22 +48,16 @@ describe('CartoCSS wrap', function () { ] }; - - var keysToDelete; - - beforeEach(function () { - keysToDelete = {}; - }); - afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } }); - it("Label should be text-wrapped", function (done) { + it('Label should be text-wrapped', function (done) { this.testClient = new TestClient(mapConfig); this.testClient.getTile(1, 0, 1, { layers: [0] }, (err, res, body) => { + assert.ifError(err); var textWrapPath = './test/fixtures/text_wrap.png'; assert.imageIsSimilarToFile(body, textWrapPath, IMAGE_TOLERANCE, done); }); diff --git a/test/acceptance/layergroup-metadata-test.js b/test/acceptance/layergroup-metadata-test.js index 831a5b8e..1543f230 100644 --- a/test/acceptance/layergroup-metadata-test.js +++ b/test/acceptance/layergroup-metadata-test.js @@ -17,15 +17,15 @@ describe('layergroup metadata', function () { serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; }); - [1234, 'default_public', false].forEach(api_key => { - it(`tiles base urls ${api_key ? `with api key: ${api_key}` : 'without api key'}`, function (done) { + [1234, 'default_public', false].forEach(apiKey => { + it(`tiles base urls ${apiKey ? `with api key: ${apiKey}` : 'without api key'}`, function (done) { const mapConfig = { version: '1.7.0', layers: [ { type: 'cartodb', options: { - sql: 'select * from populated_places_simple_reduced', + sql: 'select * from populated_places_simple_reduced' } } ] @@ -33,7 +33,7 @@ describe('layergroup metadata', function () { const host = `https://localhost.localhost.lan:${global.environment.port}`; - const testClient = new TestClient(mapConfig, api_key); + const testClient = new TestClient(mapConfig, apiKey); testClient.getLayergroup((err, body) => { if (err) { return done(err); @@ -42,15 +42,15 @@ describe('layergroup metadata', function () { let urlLayer = `${host}/api/v1/map/${body.layergroupid}/layer0/{z}/{x}/{y}.mvt`; let urlNoLayer = `${host}/api/v1/map/${body.layergroupid}/{z}/{x}/{y}.mvt`; - if (api_key) { - urlLayer += `?api_key=${api_key}`; - urlNoLayer += `?api_key=${api_key}`; + if (apiKey) { + urlLayer += `?api_key=${apiKey}`; + urlNoLayer += `?api_key=${apiKey}`; } assert.ok(body.layergroupid); - assert.equal(body.metadata.layers[0].tilejson.vector.tiles[0], urlLayer); - assert.equal(body.metadata.tilejson.vector.tiles[0], urlNoLayer); - assert.equal(body.metadata.url.vector.urlTemplate, urlNoLayer); + assert.strictEqual(body.metadata.layers[0].tilejson.vector.tiles[0], urlLayer); + assert.strictEqual(body.metadata.tilejson.vector.tiles[0], urlNoLayer); + assert.strictEqual(body.metadata.url.vector.urlTemplate, urlNoLayer); testClient.drain(done); }); diff --git a/test/acceptance/layers-filters-test.js b/test/acceptance/layers-filters-test.js index 29bfb5ff..06700c34 100644 --- a/test/acceptance/layers-filters-test.js +++ b/test/acceptance/layers-filters-test.js @@ -3,7 +3,7 @@ require('../support/test-helper'); var TestClient = require('../support/test-client'); -describe('layers filters', function() { +describe('layers filters', function () { const type = 'mapnik'; const sql = 'select * from populated_places_simple_reduced'; const cartocss = `#points { @@ -17,11 +17,11 @@ describe('layers filters', function() { marker-fill: red; marker-allow-overlap: true; }`; - const cartocss_version = '3.0.12'; + const cartocssVersion = '3.0.12'; const options = { sql, cartocss, - cartocss_version + cartocss_version: cartocssVersion }; const mapConfig = { @@ -40,7 +40,7 @@ describe('layers filters', function() { ] }; - afterEach(function(done) { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } @@ -52,5 +52,4 @@ describe('layers filters', function() { this.testClient.getTile(0, 0, 0, { layers: layer }, done); }); }); - }); diff --git a/test/acceptance/max-waiting-workers-test.js b/test/acceptance/max-waiting-workers-test.js index 576bd07b..442980a1 100644 --- a/test/acceptance/max-waiting-workers-test.js +++ b/test/acceptance/max-waiting-workers-test.js @@ -64,12 +64,12 @@ function getTiles ({ testClient, layergroupid, coords }) { function getTile ({ testClient, layergroupid, coord }) { return new Promise((resolve, reject) => { - const [ z, x, y ] = coord; + const [z, x, y] = coord; const params = { layergroupid, format: 'png', response: { - status: [ 200, 429 ], + status: [200, 429], headers: { 'Content-Type': /^(image\/png|application\/json; charset=utf-8)$/ } diff --git a/test/acceptance/multilayer-server-test.js b/test/acceptance/multilayer-server-test.js index 2b5558c6..04a281e1 100644 --- a/test/acceptance/multilayer-server-test.js +++ b/test/acceptance/multilayer-server-test.js @@ -13,7 +13,7 @@ var QueryTables = require('cartodb-query-tables').queryTables; var CartodbWindshaft = require('../../lib/server'); var serverOptions = require('../../lib/server-options'); -describe('tests from old api translated to multilayer', function() { +describe('tests from old api translated to multilayer', function () { var server; before(function () { @@ -25,18 +25,18 @@ describe('tests from old api translated to multilayer', function() { var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { + afterEach(function (done) { testHelper.deleteRedisKeys(keysToDelete, done); }); var wadusSql = 'select 1 as cartodb_id, null::geometry as the_geom_webmercator'; var pointSql = "SELECT 'SRID=3857;POINT(0 0)'::geometry as the_geom_webmercator, 1::int as cartodb_id"; - function singleLayergroupConfig(sql, cartocss) { + function singleLayergroupConfig (sql, cartocss) { return { version: '1.0.0', layers: [ @@ -52,7 +52,7 @@ describe('tests from old api translated to multilayer', function() { }; } - function createRequest(layergroup, userHost, apiKey) { + function createRequest (layergroup, userHost, apiKey) { var url = layergroupUrl; if (apiKey) { url += '?api_key=' + apiKey; @@ -68,14 +68,14 @@ describe('tests from old api translated to multilayer', function() { }; } - it("layergroup creation fails if CartoCSS is bogus", function(done) { + it('layergroup creation fails if CartoCSS is bogus', function (done) { var layergroup = singleLayergroupConfig(wadusSql, '#my_table3{'); assert.response(server, createRequest(layergroup), { status: 400 }, - function(res) { + function (res) { var parsed = JSON.parse(res.body); assert.ok(parsed.errors[0].match(/^style0/)); assert.ok(parsed.errors[0].match(/missing closing/)); @@ -84,16 +84,16 @@ describe('tests from old api translated to multilayer', function() { ); }); - it("multiple bad styles returns 400 with all errors", function(done) { + it('multiple bad styles returns 400 with all errors', function (done) { var layergroup = singleLayergroupConfig(wadusSql, '#my_table4{backgxxxxxround-color:#fff;foo:bar}'); assert.response(server, createRequest(layergroup), { status: 400 }, - function(res) { + function (res) { var parsed = JSON.parse(res.body); - assert.equal(parsed.errors.length, 1); + assert.strictEqual(parsed.errors.length, 1); assert.ok(parsed.errors[0].match(/^style0/)); assert.ok(parsed.errors[0].match(/Unrecognized rule: backgxxxxxround-color/)); assert.ok(parsed.errors[0].match(/Unrecognized rule: foo/)); @@ -103,7 +103,7 @@ describe('tests from old api translated to multilayer', function() { }); // Zoom is a special variable - it("Specifying zoom level in CartoCSS does not need a 'zoom' variable in SQL output", function(done) { + it("Specifying zoom level in CartoCSS does not need a 'zoom' variable in SQL output", function (done) { var layergroup = singleLayergroupConfig(pointSql, '#gadm4 [ zoom>=3] { marker-fill:red; }'); assert.response(server, @@ -111,10 +111,10 @@ describe('tests from old api translated to multilayer', function() { { status: 200 }, - function(res) { + function (res) { var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); - assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid); keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; @@ -125,7 +125,7 @@ describe('tests from old api translated to multilayer', function() { }); // See https://github.com/CartoDB/Windshaft-cartodb/issues/88 - it("getting a tile from a user-specific database should return an expected tile", function(done) { + it('getting a tile from a user-specific database should return an expected tile', function (done) { var layergroup = singleLayergroupConfig(pointSql, '#layer { marker-fill:red; }'); var backupDBHost = global.environment.postgres.host; @@ -136,11 +136,10 @@ describe('tests from old api translated to multilayer', function() { { status: 200 }, - function(res) { + function (res) { var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); - assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); - + assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid); keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; keysToDelete['user:cartodb250user:mapviews:global'] = 5; @@ -152,7 +151,7 @@ describe('tests from old api translated to multilayer', function() { }); // See https://github.com/CartoDB/Windshaft-cartodb/issues/89 - it("getting a tile with a user-specific database password", function(done) { + it('getting a tile with a user-specific database password', function (done) { var layergroup = singleLayergroupConfig(pointSql, '#layer { marker-fill:red; }'); var backupDBPass = global.environment.postgres_auth_pass; @@ -163,10 +162,10 @@ describe('tests from old api translated to multilayer', function() { { status: 200 }, - function(res) { + function (res) { var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); - assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid); keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; keysToDelete['user:cartodb250user:mapviews:global'] = 5; @@ -177,12 +176,12 @@ describe('tests from old api translated to multilayer', function() { ); }); - it("creating a layergroup from lzma param", function(done){ + it('creating a layergroup from lzma param', function (done) { var params = { config: JSON.stringify(singleLayergroupConfig(pointSql, '#layer { marker-fill:red; }')) }; - testHelper.lzma_compress_to_base64(JSON.stringify(params), 1, function(err, lzma) { + testHelper.lzma_compress_to_base64(JSON.stringify(params), 1, function (err, lzma) { if (err) { return done(err); } @@ -198,7 +197,7 @@ describe('tests from old api translated to multilayer', function() { { status: 200 }, - function(res) { + function (res) { var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); @@ -211,12 +210,12 @@ describe('tests from old api translated to multilayer', function() { }); }); - it("creating a layergroup from lzma param, invalid json input", function(done) { + it('creating a layergroup from lzma param, invalid json input', function (done) { var params = { config: 'WADUS' }; - testHelper.lzma_compress_to_base64(JSON.stringify(params), 1, function(err, lzma) { + testHelper.lzma_compress_to_base64(JSON.stringify(params), 1, function (err, lzma) { if (err) { return done(err); } @@ -232,10 +231,10 @@ describe('tests from old api translated to multilayer', function() { { status: 400 }, - function(res) { + function (res) { var parsed = JSON.parse(res.body); assert.ok(parsed.errors); - assert.equal(parsed.errors.length, 1); + assert.strictEqual(parsed.errors.length, 1); assert.ok(parsed.errors[0].match(/Unexpected token W/)); done(); @@ -244,14 +243,14 @@ describe('tests from old api translated to multilayer', function() { }); }); - it("uses queries postgresql to figure affected tables in query", function(done) { + it('uses queries postgresql to figure affected tables in query', function (done) { var tableName = 'gadm4'; var expectedCacheChannel = _.template('<%= databaseName %>:public.<%= tableName %>', { - databaseName: _.template(global.environment.postgres_auth_user, {user_id:1}) + '_db', + databaseName: _.template(global.environment.postgres_auth_user, { user_id: 1 }) + '_db', tableName: tableName }); - var layergroup = singleLayergroupConfig('select * from ' + tableName, '#gadm4 { marker-fill: red; }'); + var layergroup = singleLayergroupConfig('select * from ' + tableName, '#gadm4 { marker-fill: red; }'); assert.response(server, { @@ -264,14 +263,14 @@ describe('tests from old api translated to multilayer', function() { { status: 200 }, - function(res) { + function (res) { var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); - assert.ok(res.headers.hasOwnProperty('x-cache-channel')); - assert.equal(res.headers['x-cache-channel'], expectedCacheChannel); + assert.ok(Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel')); + assert.strictEqual(res.headers['x-cache-channel'], expectedCacheChannel); - assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid); keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; @@ -282,14 +281,14 @@ describe('tests from old api translated to multilayer', function() { }); // https://github.com/CartoDB/cartodb-postgresql/issues/86 - it.skip("should not fail with long table names because table name length limit", function(done) { + it.skip('should not fail with long table names because table name length limit', function (done) { var tableName = 'long_table_name_with_enough_chars_to_break_querytables_function'; var expectedCacheChannel = _.template('<%= databaseName %>:public.<%= tableName %>', { - databaseName: _.template(global.environment.postgres_auth_user, {user_id:1}) + '_db', + databaseName: _.template(global.environment.postgres_auth_user, { user_id: 1 }) + '_db', tableName: tableName }); - var layergroup = singleLayergroupConfig('select * from ' + tableName, '#layer { marker-fill: red; }'); + var layergroup = singleLayergroupConfig('select * from ' + tableName, '#layer { marker-fill: red; }'); assert.response(server, { @@ -302,28 +301,27 @@ describe('tests from old api translated to multilayer', function() { { status: 200 }, - function(res) { + function (res) { var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); - assert.ok(res.headers.hasOwnProperty('x-cache-channel')); - assert.equal(res.headers['x-cache-channel'], expectedCacheChannel); + assert.ok(Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel')); + assert.strictEqual(res.headers['x-cache-channel'], expectedCacheChannel); - assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid); done(); } ); }); - it("creates layergroup fails when postgresql queries fail to figure affected tables in query", function(done) { - + it('creates layergroup fails when postgresql queries fail to figure affected tables in query', function (done) { var runQueryFn = PgQueryRunner.prototype.run; - PgQueryRunner.prototype.run = function(username, query, callback) { + PgQueryRunner.prototype.run = function (username, query, callback) { return callback(new Error('fake error message'), []); }; - var layergroup = singleLayergroupConfig('select * from gadm4', '#gadm4 { marker-fill: red; }'); + var layergroup = singleLayergroupConfig('select * from gadm4', '#gadm4 { marker-fill: red; }'); assert.response(server, { @@ -336,21 +334,21 @@ describe('tests from old api translated to multilayer', function() { { status: 400 }, - function(res) { + function (res) { PgQueryRunner.prototype.run = runQueryFn; - assert.ok(!res.headers.hasOwnProperty('x-cache-channel')); + assert.ok(!Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel')); var parsed = JSON.parse(res.body); - assert.deepEqual(parsed.errors, ["fake error message"]); + assert.deepStrictEqual(parsed.errors, ['fake error message']); done(); } ); }); - it("tile requests works when postgresql queries fail to figure affected tables in query", function(done) { - var layergroup = singleLayergroupConfig('select * from gadm4', '#gadm4 { marker-fill: red; }'); + it('tile requests works when postgresql queries fail to figure affected tables in query', function (done) { + var layergroup = singleLayergroupConfig('select * from gadm4', '#gadm4 { marker-fill: red; }'); assert.response(server, { url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify(layergroup)), @@ -362,8 +360,7 @@ describe('tests from old api translated to multilayer', function() { { status: 200 }, - function(res) { - + function (res) { keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; @@ -393,14 +390,13 @@ describe('tests from old api translated to multilayer', function() { { status: 200 }, - function(res) { + function (res) { QueryTables.getQueryMetadataModel = affectedFn; - assert.ok(!res.headers.hasOwnProperty('x-cache-channel')); + assert.ok(!Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel')); done(); } ); } ); }); - }); diff --git a/test/acceptance/multilayer-test.js b/test/acceptance/multilayer-test.js index 10fb4451..a91d5e99 100644 --- a/test/acceptance/multilayer-test.js +++ b/test/acceptance/multilayer-test.js @@ -1,11 +1,12 @@ 'use strict'; -var assert = require('../support/assert'); -var _ = require('underscore'); -var redis = require('redis'); -var step = require('step'); -var strftime = require('strftime'); -var redis_stats_db = 5; +var path = require('path'); +var assert = require('../support/assert'); +var _ = require('underscore'); +var redis = require('redis'); +var step = require('step'); +var strftime = require('strftime'); +var redisStatsDb = 5; var mapnik = require('windshaft').mapnik; var semver = require('semver'); @@ -13,7 +14,7 @@ var semver = require('semver'); var helper = require('../support/test-helper'); var LayergroupToken = require('../../lib/models/layergroup-token'); -var windshaft_fixtures = __dirname + '/../../node_modules/windshaft/test/fixtures'; +var windshaftFixtures = path.join(__dirname, '/../../node_modules/windshaft/test/fixtures'); var IMAGE_EQUALS_TOLERANCE_PER_MIL = 20; var IMAGE_EQUALS_HIGHER_TOLERANCE_PER_MIL = 25; @@ -23,1367 +24,1359 @@ var serverOptions = require('../../lib/server-options'); var QueryTables = require('cartodb-query-tables').queryTables; -['/api/v1/map', '/user/localhost/api/v1/map'].forEach(function(layergroup_url) { +['/api/v1/map', '/user/localhost/api/v1/map'].forEach(function (layergroupUrl) { + var suiteName = 'multilayer:postgres=layergroupUrl=' + layergroupUrl; + describe(suiteName, function () { + var server; -var suiteName = 'multilayer:postgres=layergroup_url=' + layergroup_url; -describe(suiteName, function() { - var server; + before(function () { + server = new CartodbWindshaft(serverOptions); + server.setMaxListeners(0); + }); - before(function () { - server = new CartodbWindshaft(serverOptions); - server.setMaxListeners(0); - }); + var keysToDelete; - var keysToDelete; + beforeEach(function () { + keysToDelete = {}; + }); - beforeEach(function() { - keysToDelete = {}; - }); + afterEach(function (done) { + helper.deleteRedisKeys(keysToDelete, done); + }); - afterEach(function(done) { - helper.deleteRedisKeys(keysToDelete, done); - }); + var cdbQueryTablesFromPostgresEnabledValue = true; - var cdbQueryTablesFromPostgresEnabledValue = true; + var expectedLastUpdatedEpoch = 1234567890123; // this is hard-coded into SQLAPIEmu + var expectedLastUpdated = new Date(expectedLastUpdatedEpoch).toISOString(); - var expected_last_updated_epoch = 1234567890123; // this is hard-coded into SQLAPIEmu - var expected_last_updated = new Date(expected_last_updated_epoch).toISOString(); + var testUser = _.template(global.environment.postgres_auth_user, { user_id: 1 }); + var testDatabase = testUser + '_db'; - var test_user = _.template(global.environment.postgres_auth_user, {user_id:1}); - var test_database = test_user + '_db'; - - it("layergroup with 2 layers, each with its style", function(done) { - - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, 5e6, 0) as the_geom_webmercator' + + it('layergroup with 2 layers, each with its style', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, 5e6, 0) as the_geom_webmercator' + ' from test_table limit 2', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1', - interactivity: 'cartodb_id' - } }, - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, -5e6, 0) as the_geom_webmercator' + + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1', + interactivity: 'cartodb_id' + } + }, + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, -5e6, 0) as the_geom_webmercator' + ' from test_table limit 2 offset 2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id' - } } - ] - }; - - var expected_token; // = "e34dd7e235138a062f8ba7ad051aa3a7"; - 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); - var parsedBody = JSON.parse(res.body); - assert.equal(parsedBody.last_updated, expected_last_updated); - assert.equal(res.headers['x-layergroup-id'], parsedBody.layergroupid); - expected_token = parsedBody.layergroupid; - next(null, res); - }); - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + ':cb0/0/0/0.png', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - - // Check Cache-Control - var cc = res.headers['cache-control']; - assert.equal(cc, 'public,max-age=31536000'); // 1 year - - // Check X-Cache-Channel - cc = res.headers['x-cache-channel']; - assert.ok(cc); - var dbname = test_database; - assert.equal(cc.substring(0, dbname.length), dbname); - if (!cdbQueryTablesFromPostgresEnabledValue) { // only test if it was using the SQL API - var jsonquery = cc.substring(dbname.length + 1); - var sentquery = JSON.parse(jsonquery); - var expectedQuery = [ - layergroup.layers[0].options.sql, ';', - layergroup.layers[1].options.sql - ].join(''); - assert.equal(sentquery.q, 'WITH querytables AS ( SELECT * FROM CDB_QueryTables($windshaft$' + - expectedQuery + - '$windshaft$) as tablenames )' + - ' SELECT (SELECT tablenames FROM querytables), EXTRACT(EPOCH FROM max(updated_at)) as max' + - ' FROM CDB_TableMetadata m' + - ' WHERE m.tabname = any ((SELECT tablenames from querytables)::regclass[])'); - } - - assert.imageBufferIsSimilarToFile(res.body, 'test/fixtures/test_table_0_0_0_multilayer1.png', - IMAGE_EQUALS_HIGHER_TOLERANCE_PER_MIL, function(err/*, similarity*/) { - next(err); - } - ); - }); - }, - // See https://github.com/CartoDB/Windshaft-cartodb/issues/170 - function do_get_tile_nosignature(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + '/localhost@' + expected_token + ':cb0/0/0/0.png', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res) { - assert.equal(res.statusCode, 403, res.statusCode + ':' + res.body); - var parsed = JSON.parse(res.body); - var msg = parsed.errors[0]; - assert.ok(msg.match(/permission denied/i), msg); - next(err); - }); - }, - function do_get_grid_layer0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + '/0/0/0/0.grid.json', - headers: {host: 'localhost' }, - method: 'GET' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile(res.body, 'test/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_grid_layer1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + '/1/0/0/0.grid.json', - headers: {host: 'localhost' }, - method: 'GET' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile(res.body, 'test/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function finish(err) { - keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - done(err); - } - ); - }); - - - describe('server-metadata', function() { - var serverMetadata; - beforeEach(function() { - serverMetadata = global.environment.serverMetadata; - global.environment.serverMetadata = { cdn_url : { http:'test', https: 'tests' } }; - }); - - afterEach(function() { - global.environment.serverMetadata = serverMetadata; - }); - - it("should include serverMedata in the response", function(done) { - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, 5e6, 0) as the_geom_webmercator' + - ' from test_table limit 2', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1' - } } - ] - }; - - step( - function do_create_get() - { - var next = this; - assert.response(server, { - url: layergroup_url + '?config=' + encodeURIComponent(JSON.stringify(layergroup)), - method: 'GET', - headers: {host: 'localhost'} - }, {}, function(res, err) { next(err, res); }); - }, - function do_check_create(err, res) { - var parsed = JSON.parse(res.body); - keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - assert.ok(_.isEqual(parsed.cdn_url, global.environment.serverMetadata.cdn_url)); - done(); - } - ); - }); - - }); - - - it("get creation requests has cache", function(done) { - - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select cartodb_id, the_geom_webmercator from test_table', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1', - interactivity: 'cartodb_id' - } }, - { options: { - sql: 'select cartodb_id, the_geom_webmercator from test_table_2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id' - } } - ] - }; - - var expected_token; - step( - function do_create_get() - { - var next = this; - assert.response(server, { - url: layergroup_url + '?config=' + encodeURIComponent(JSON.stringify(layergroup)), - method: 'GET', - headers: {host: 'localhost'} - }, {}, function(res, err) { next(err, res); }); - }, - function do_check_create(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - expected_token = parsedBody.layergroupid.split(':')[0]; - helper.checkCache(res); - helper.checkSurrogateKey(res, new QueryTables.QueryMetadata([ - {dbname: "test_windshaft_cartodb_user_1_db", table_name: "test_table", schema_name: "public"}, - {dbname: "test_windshaft_cartodb_user_1_db", table_name: "test_table_2", schema_name: "public"}, - ]).key().join(' ')); - - - keysToDelete['map_cfg|' + expected_token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - done(); - } - ); - }); - - it("get creation has no cache if sql is bogus", function(done) { - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select bogus(0,0) as the_geom_webmercator', - cartocss: '#layer { polygon-fill: red; }', - cartocss_version: '2.0.1' - } } - ] - }; - assert.response(server, { - url: layergroup_url + '?config=' + encodeURIComponent(JSON.stringify(layergroup)), - method: 'GET', - headers: {host: 'localhost'} - }, {}, function(res) { - assert.notEqual(res.statusCode, 200); - helper.checkNoCache(res); - done(); - }); - }); - - it("get creation has no cache if cartocss is not valid", function(done) { - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, 5e6, 0) as the_geom_webmercator' + - ' from test_table limit 2', - cartocss: '#layer { invalid-rule:red; }', - cartocss_version: '2.0.1' - } } - ] - }; - assert.response(server, { - url: layergroup_url + '?config=' + encodeURIComponent(JSON.stringify(layergroup)), - method: 'GET', - headers: {host: 'localhost'} - }, {}, function(res) { - assert.notEqual(res.statusCode, 200); - helper.checkNoCache(res); - done(); - }); - }); - - it("layergroup can hold substitution tokens", function(done) { - - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select 1 as cartodb_id, ST_Buffer(!bbox!, -32*greatest(!pixel_width!,!pixel_height!))' + - ' as the_geom_webmercator from test_table limit 1', - cartocss: '#layer { polygon-fill:red; }', - cartocss_version: '2.0.1', - interactivity: 'cartodb_id' - } } - ] - }; - - var expected_token; // = "6d8e4ad5458e2d25cf0eef38e38717a6"; - 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); - var parsedBody = JSON.parse(res.body); - assert.equal(parsedBody.last_updated, expected_last_updated); - if ( expected_token ) { - assert.equal(parsedBody.layergroupid, expected_token + ':' + expected_last_updated_epoch); - } - else { - expected_token = parsedBody.layergroupid.split(':')[0]; - } - next(null, res); - }); - }, - function do_get_tile1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + ':cb10/1/0/0.png', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - - // Check X-Cache-Channel - var cc = res.headers['x-cache-channel']; - assert.ok(cc); - var dbname = test_database; - assert.equal(cc.substring(0, dbname.length), dbname); - if (!cdbQueryTablesFromPostgresEnabledValue) { // only test if it was using the SQL API - var jsonquery = cc.substring(dbname.length + 1); - var sentquery = JSON.parse(jsonquery); - var expectedQuery = layergroup.layers[0].options.sql - .replace(/!bbox!/g, 'ST_MakeEnvelope(0,0,0,0)') - .replace(/!pixel_width!/g, '1') - .replace(/!pixel_height!/g, '1'); - assert.equal(sentquery.q, 'WITH querytables AS ( SELECT * FROM CDB_QueryTables($windshaft$' + - expectedQuery + - '$windshaft$) as tablenames )' + - ' SELECT (SELECT tablenames FROM querytables), EXTRACT(EPOCH FROM max(updated_at)) as max' + - ' FROM CDB_TableMetadata m' + - ' WHERE m.tabname = any ((SELECT tablenames from querytables)::regclass[])'); - } - - var referenceImagePath = 'test/fixtures/test_multilayer_bbox.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, IMAGE_EQUALS_TOLERANCE_PER_MIL, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_tile4(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + ':cb11/4/0/0.png', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - - // Check X-Cache-Channel - var cc = res.headers['x-cache-channel']; - assert.ok(cc); - var dbname = test_database; - assert.equal(cc.substring(0, dbname.length), dbname); - if (!cdbQueryTablesFromPostgresEnabledValue) { // only test if it was using the SQL API - var jsonquery = cc.substring(dbname.length + 1); - var sentquery = JSON.parse(jsonquery); - var expectedQuery = layergroup.layers[0].options.sql - .replace('!bbox!', 'ST_MakeEnvelope(0,0,0,0)') - .replace('!pixel_width!', '1') - .replace('!pixel_height!', '1'); - assert.equal(sentquery.q, 'WITH querytables AS ( SELECT * FROM CDB_QueryTables($windshaft$' + - expectedQuery + - '$windshaft$) as tablenames )' + - ' SELECT (SELECT tablenames FROM querytables), EXTRACT(EPOCH FROM max(updated_at)) as max' + - ' FROM CDB_TableMetadata m' + - ' WHERE m.tabname = any ((SELECT tablenames from querytables)::regclass[])'); - } - - var referenceImagePath = 'test/fixtures/test_multilayer_bbox.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, IMAGE_EQUALS_TOLERANCE_PER_MIL, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_grid1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + '/0/1/0/0.grid.json', - headers: {host: 'localhost' }, - method: 'GET' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile(res.body, 'test/fixtures/test_multilayer_bbox.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_grid4(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + '/0/4/0/0.grid.json', - headers: {host: 'localhost' }, - method: 'GET' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile(res.body, 'test/fixtures/test_multilayer_bbox.grid.json', 2, next); - }); - }, - function finish(err) { - keysToDelete['map_cfg|' + expected_token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - done(err); - } - ); - }); - - it("layergroup creation raises mapviews counter", function(done) { - var layergroup = { - stat_tag: 'random_tag', - version: '1.0.0', - layers: [ - { options: { - sql: 'select 1 as cartodb_id, !pixel_height! as h,' + - ' ST_Buffer(!bbox!, -32*greatest(!pixel_width!,!pixel_height!)) as the_geom_webmercator', - cartocss: '#layer { polygon-fill:red; }', - cartocss_version: '2.0.1' - } } - ] - }; - var statskey = "user:localhost:mapviews"; - var redis_stats_client = redis.createClient(global.environment.redis.port); - var expected_token; // will be set on first post and checked on second - var now = strftime("%Y%m%d", new Date()); - step( - function clean_stats() - { - var next = this; - redis_stats_client.select(redis_stats_db, function(err) { - if ( err ) { - next(err); - } - else { - redis_stats_client.del(statskey+':global', next); - } - }); - }, - function do_post_1(err) - { - assert.ifError(err); - 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); - expected_token = JSON.parse(res.body).layergroupid; - redis_stats_client.zscore(statskey + ":global", now, next); - }); - }, - function check_global_stats_1(err, val) { - assert.ifError(err); - assert.equal(val, 1, "Expected score of " + now + " in " + statskey + ":global to be 1, got " + val); - redis_stats_client.zscore(statskey+':stat_tag:random_tag', now, this); - }, - function check_tag_stats_1_do_post_2(err, val) { - assert.ifError(err); - assert.equal(val, 1, "Expected score of " + now + " in " + statskey + ":stat_tag:" + layergroup.stat_tag + - " to be 1, got " + val); - 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); - assert.equal(JSON.parse(res.body).layergroupid, expected_token); - redis_stats_client.zscore(statskey+':global', now, next); - }); - }, - function check_global_stats_2(err, val) - { - assert.ifError(err); - assert.equal(val, 2, "Expected score of " + now + " in " + statskey + ":global to be 2, got " + val); - redis_stats_client.zscore(statskey+':stat_tag:' + layergroup.stat_tag, now, this); - }, - function check_tag_stats_2(err, val) - { - assert.ifError(err); - assert.equal(val, 2, "Expected score of " + now + " in " + statskey + ":stat_tag:" + layergroup.stat_tag + - " to be 2, got " + val); - return 1; - }, - function finish(err) { - if ( err ) { - return done(err); - } - // strip epoch - expected_token = expected_token.split(':')[0]; - keysToDelete['map_cfg|' + expected_token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - keysToDelete[statskey+':stat_tag:'+layergroup.stat_tag] = 5; - done(); - } - ); - }); - - it("layergroup creation fails if CartoCSS is bogus", function(done) { - var layergroup = { - stat_tag: 'random_tag', - version: '1.0.0', - layers: [ - { options: { - sql: 'select 1 as cartodb_id, !pixel_height! as h,' + - 'ST_Buffer(!bbox!, -32*greatest(!pixel_width!,!pixel_height!)) as the_geom_webmercator', - cartocss: '#layer { polygon-fit:red; }', - cartocss_version: '2.0.1' - } } - ] - }; - 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, 400, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors[0].match(/^style0/)); - assert.ok(parsed.errors[0].match(/Unrecognized rule: polygon-fit/)); - done(); - }); - }); - - // Also tests that server doesn't crash: - // see http://github.com/CartoDB/Windshaft-cartodb/issues/109 - it("layergroup creation fails if sql is bogus", function(done) { - var layergroup = { - stat_tag: 'random_tag', - version: '1.0.0', - layers: [ - { options: { - sql: 'select bogus(0,0) as the_geom_webmercator', - cartocss: '#layer { polygon-fill:red; }', - cartocss_version: '2.0.1' - } } - ] - }; - 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, 400, res.statusCode + ": " + res.body); - var parsed = JSON.parse(res.body); - var msg = parsed.errors[0]; - assert.ok(msg.match(/bogus.*exist/), msg); - helper.checkNoCache(res); - done(); - }); - }); - - it("layergroup with 2 private-table layers", function(done) { - - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select * from test_table_private_1 where cartodb_id=1', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.1.0', - interactivity: 'cartodb_id' - } }, - { options: { - sql: 'select * from test_table_private_1 where cartodb_id=2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.1.0', - interactivity: 'cartodb_id' - } } - ] - }; - - var expected_token; // = "b4ed64d93a411a59f330ab3d798e4009"; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: layergroup_url + '?map_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - assert.equal(parsedBody.last_updated, expected_last_updated); - if ( expected_token ) { - assert.equal(parsedBody.layergroupid, expected_token + ':' + expected_last_updated_epoch); - } - else { - expected_token = parsedBody.layergroupid.split(':')[0]; - } - next(null, res); - }); - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + ':cb0/0/0/0.png?map_key=1234', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - - // Check X-Cache-Channel - var cc = res.headers['x-cache-channel']; - assert.ok(cc); - var dbname = test_database; - assert.equal(cc.substring(0, dbname.length), dbname); - next(err); - }); - }, - function do_get_grid_layer0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + '/0/0/0/0.grid.json?map_key=1234', - headers: {host: 'localhost' }, - method: 'GET' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - next(err); - }); - }, - function do_get_grid_layer1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + '/1/0/0/0.grid.json?map_key=1234', - headers: {host: 'localhost' }, - method: 'GET' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - next(err); - }); - }, - function do_get_tile_unauth(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + ':cb0/0/0/0.png', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res) { - assert.equal(res.statusCode, 403); - var re = new RegExp('permission denied'); - assert.ok(res.body.match(re), 'No "permission denied" error: ' + res.body); - next(err); - }); - }, - function do_get_grid_layer0_unauth(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + '/0/0/0/0.grid.json', - headers: {host: 'localhost' }, - method: 'GET' - }, {}, function(res) { - assert.equal(res.statusCode, 403); - var re = new RegExp('permission denied'); - assert.ok(res.body.match(re), 'No "permission denied" error: ' + res.body); - next(err); - }); - }, - function do_get_grid_layer1_unauth(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + '/1/0/0/0.grid.json', - headers: {host: 'localhost' }, - method: 'GET' - }, {}, function(res) { - assert.equal(res.statusCode, 403); - var re = new RegExp('permission denied'); - assert.ok(res.body.match(re), 'No "permission denied" error: ' + res.body); - next(err); - }); - }, - function finish(err) { - keysToDelete['map_cfg|' + expected_token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - done(err); - } - ); - }); - - // See https://github.com/CartoDB/Windshaft-cartodb/issues/152 - it("x-cache-channel still works for GETs after tiler restart", function(done) { - - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select * from test_table where cartodb_id=1', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.1.0', - interactivity: 'cartodb_id' - } } - ] - }; - - var expected_token; // = "b4ed64d93a411a59f330ab3d798e4009"; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: layergroup_url + '?map_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res, err) { next(err, res); }); - }, - function check_post(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - assert.equal(parsedBody.last_updated, expected_last_updated); - if ( expected_token ) { - assert.equal(parsedBody.layergroupid, expected_token + ':' + expected_last_updated_epoch); - } - else { - expected_token = parsedBody.layergroupid.split(':')[0]; - } - return null; - }, - function do_get0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + ':cb0/0/0/0.png?map_key=1234', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res, err) { next(err, res); }); - }, - function do_check0(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - - // Check X-Cache-Channel - var cc = res.headers['x-cache-channel']; - assert.ok(cc, "Missing X-Cache-Channel"); - var dbname = test_database; - assert.equal(cc.substring(0, dbname.length), dbname); - return null; - }, - function do_restart_server(err/*, res*/) { - assert.ifError(err); - // hack simulating restart... - server = new CartodbWindshaft(serverOptions); - return null; - }, - function do_get1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + ':cb0/0/0/0.png?map_key=1234', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res, err) { next(err, res); }); - }, - function do_check1(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - - // Check X-Cache-Channel - var cc = res.headers['x-cache-channel']; - assert.ok(cc, "Missing X-Cache-Channel on restart"); - var dbname = test_database; - assert.equal(cc.substring(0, dbname.length), dbname); - return null; - }, - function finish(err) { - keysToDelete['map_cfg|' + expected_token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - done(err); - } - ); - }); - - // https://github.com/cartodb/Windshaft-cartodb/issues/81 - it("invalid text-name in CartoCSS", function(done) { - - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select 1 as cartodb_id, 'SRID=3857;POINT(0 0)'::geometry as the_geom_webmercator", - cartocss: '#sample { text-name: cartodb_id; text-face-name: "Dejagnu"; }', - cartocss_version: '2.1.0' - } } - ] - }; - - 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, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.equal(parsed.errors.length, 1); - var errmsg = parsed.errors[0]; - assert.ok(errmsg.match(/text-face-name.*Dejagnu/), parsed.errors.toString()); - done(); - }); - }); - - it("quotes CartoCSS", function(done) { - - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select 'single''quote' as n, 'SRID=3857;POINT(0 0)'::geometry as the_geom_webmercator", - cartocss: '#s [n="single\'quote" ] { marker-fill:red; }', - cartocss_version: '2.1.0' - } }, - { options: { - sql: "select 'double\"quote' as n, 'SRID=3857;POINT(2 0)'::geometry as the_geom_webmercator", - cartocss: '#s [n="double\\"quote" ] { marker-fill:red; }', - cartocss_version: '2.1.0' - } } - ] - }; - - 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.statusCode + ': ' + res.body); - keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - done(); - }); - }); - - // See https://github.com/CartoDB/Windshaft-cartodb/issues/87 - it("exponential notation in CartoCSS filter values", function(done) { - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select .4 as n, 'SRID=3857;POINT(0 0)'::geometry as the_geom_webmercator", - cartocss: '#s [n<=.2e-2] { marker-fill:red; }', - cartocss_version: '2.1.0' - } } - ] - }; - 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.statusCode + ': ' + res.body); - keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - done(); - }); - }); - - // See https://github.com/CartoDB/Windshaft-cartodb/issues/93 - if (semver.satisfies(mapnik.versions.mapnik, '2.3.x')) { - it("accepts unused directives", function(done) { - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: "select 'SRID=3857;POINT(0 0)'::geometry as the_geom_webmercator", - cartocss: '#layer { point-transform:"scale(20)"; }', - cartocss_version: '2.0.1' - } } - ] - }; - var expected_token; // = "e34dd7e235138a062f8ba7ad051aa3a7"; - 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); - var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.equal(parsedBody.layergroupid, expected_token + ':' + expected_last_updated_epoch); - assert.equal(res.headers['x-layergroup-id'], parsedBody.layergroupid); - } - else { - var token_components = parsedBody.layergroupid.split(':'); - expected_token = token_components[0]; - expected_last_updated_epoch = token_components[1]; - } - next(null, res); - }); - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + ':cb0/0/0/0.png', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - assert.imageBufferIsSimilarToFile(res.body, windshaft_fixtures + '/test_default_mapnik_point.png', - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err/*, similarity*/) { - next(err); - } - ); - }); - }, - function finish(err) { - keysToDelete['user:localhost:mapviews:global'] = 5; - keysToDelete['map_cfg|' + expected_token] = 0; - - done(err); - } - ); - }); - } - - // See https://github.com/CartoDB/Windshaft-cartodb/issues/91 - // and https://github.com/CartoDB/Windshaft-cartodb/issues/38 - it("tiles for private tables can be fetched with api_key", function(done) { - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: "select * from test_table_private_1 LIMIT 0", - cartocss: '#layer { marker-fill:red; }', - cartocss_version: '2.0.1' - } } - ] - }; - var expected_token; // = "e34dd7e235138a062f8ba7ad051aa3a7"; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: layergroup_url + '?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { next(null, res); }); - }, - function check_result(err, res) { - assert.ifError(err); - var next = this; - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.equal(parsedBody.layergroupid, expected_token + ':' + expected_last_updated_epoch); - assert.equal(res.headers['x-layergroup-id'], parsedBody.layergroupid); - } - else { - var token_components = parsedBody.layergroupid.split(':'); - expected_token = token_components[0]; - expected_last_updated_epoch = token_components[1]; - } - next(null, res); - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: layergroup_url + "/" + expected_token + ':cb0/0/0/0.png?api_key=1234', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }, {}, function(res) { next(null, res); }); - }, - function check_get_tile(err, res) { - if (err) { - return done(err); - } - assert.equal(res.statusCode, 200, res.body); - keysToDelete['user:localhost:mapviews:global'] = 5; - keysToDelete['map_cfg|' + expected_token] = 0; - done(err); - } - ); - }); - - // SQL strings can be of arbitrary length, when using POST - // See https://github.com/CartoDB/Windshaft-cartodb/issues/111 - it("sql string can be very long", function(done){ - var long_val = 'pretty'; - for (var i=0; i<1024; ++i) { - long_val += ' long'; - } - long_val += ' string'; - var sql = "SELECT "; - for (i=0; i<16; ++i) { - sql += "'" + long_val + "'::text as pretty_long_field_name_" + i + ", "; - } - sql += "cartodb_id, the_geom_webmercator FROM gadm4 g"; - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: sql, - cartocss: '#layer { marker-fill:red; }', - cartocss_version: '2.0.1' - } } - ] - }; - var expected_token; - step( - function do_post() - { - var data = JSON.stringify(layergroup); - assert.ok(data.length > 1024*64); - var next = this; - assert.response(server, { - url: layergroup_url + '?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: data - }, {}, function(res) { next(null, res); }); - }, - function check_result(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - var parsedBody = JSON.parse(res.body); - var token_components = parsedBody.layergroupid.split(':'); - expected_token = token_components[0]; - return null; - }, - function cleanup(err) { - if (err) { - return done(err); - } - keysToDelete['user:localhost:mapviews:global'] = 5; - keysToDelete['map_cfg|' + expected_token] = 0; - - done(err); - } - ); - }); - - // WARN: MapConfig with mapnik layer and no cartocss it's valid since - // vector & raster aggregation project, now we can request MVT format w/o defining styles - // for the layer. - - // See https://github.com/CartoDB/Windshaft-cartodb/issues/133 - it.skip("MapConfig with mapnik layer and no cartocss", function(done) { - - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, 5e6, 0) as the_geom_webmercator' + - ' from test_table limit 2', - interactivity: 'cartodb_id' - } } - ] - }; - - 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, err) { next(err, res); }); - }, - function check_post(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors, 'Missing "errors" in response: ' + JSON.stringify(parsed)); - assert.equal(parsed.errors.length, 1); - var msg = parsed.errors[0]; - assert.equal(msg, 'Missing cartocss for layer 0 options'); - return null; - }, - function finish(err) { - done(err); - } - ); - }); - - if (!cdbQueryTablesFromPostgresEnabledValue) { // only test if it was using the SQL API - // See https://github.com/CartoDB/Windshaft-cartodb/issues/167 - it("lack of response from sql-api will result in a timeout", function(done) { - - var layergroup = { - version: '1.0.0', - layers: [ - { options: { - sql: "select *, 'SQLAPINOANSWER' from test_table", - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.1.0' - } } - ] - }; - - 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, err) { next(err, res); }); - }, - function check_post(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors, 'Missing "errors" in response: ' + JSON.stringify(parsed)); - assert.equal(parsed.errors.length, 1); - var msg = parsed.errors[0]; - assert.ok(msg, /could not fetch source tables/, msg); - return null; - }, - function finish(err) { - done(err); - } - ); - }); - } - - var layergroupTtlRequest = { - url: layergroup_url + '?config=' + encodeURIComponent(JSON.stringify({ - version: '1.0.0', - layers: [ - { options: { - sql: 'select * from test_table limit 2', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1' - } } - ] - })), - method: 'GET', - headers: {host: 'localhost'} - }; - var layergroupTtlResponseExpectation = { - status: 200 - }; - - it("cache control for layergroup default value", function(done) { - global.environment.varnish.layergroupTtl = null; - - var server = new CartodbWindshaft(serverOptions); - - assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation, - function(res) { - assert.equal(res.headers['cache-control'], 'public,max-age=86400,must-revalidate'); - keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - done(); - } - ); - }); - - it("cache control for layergroup uses configuration for max-age", function(done) { - var layergroupTtl = 300; - global.environment.varnish.layergroupTtl = layergroupTtl; - - var server = new CartodbWindshaft(serverOptions); - - assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation, - function(res) { - assert.equal(res.headers['cache-control'], 'public,max-age=' + layergroupTtl + ',must-revalidate'); - keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - done(); - } - ); - }); - - - it("it's not possible to override authorization with a crafted layergroup", function(done) { - - var layergroup = { - version: '1.0.0', - layers: [ - { - options: { - sql: 'select * from test_table_private_1', - cartocss: '#layer { marker-fill:red; }', - cartocss_version: '2.3.0', - interactivity: 'cartodb_id' + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } } + ] + }; + + var expectedToken; // = "e34dd7e235138a062f8ba7ad051aa3a7"; + step( + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + assert.strictEqual(parsedBody.last_updated, expectedLastUpdated); + assert.strictEqual(res.headers['x-layergroup-id'], parsedBody.layergroupid); + expectedToken = parsedBody.layergroupid; + next(null, res); + }); + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + ':cb0/0/0/0.png', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + + // Check Cache-Control + var cc = res.headers['cache-control']; + assert.strictEqual(cc, 'public,max-age=31536000'); // 1 year + + // Check X-Cache-Channel + cc = res.headers['x-cache-channel']; + assert.ok(cc); + var dbname = testDatabase; + assert.strictEqual(cc.substring(0, dbname.length), dbname); + if (!cdbQueryTablesFromPostgresEnabledValue) { // only test if it was using the SQL API + var jsonquery = cc.substring(dbname.length + 1); + var sentquery = JSON.parse(jsonquery); + var expectedQuery = [ + layergroup.layers[0].options.sql, ';', + layergroup.layers[1].options.sql + ].join(''); + assert.strictEqual(sentquery.q, 'WITH querytables AS ( SELECT * FROM CDB_QueryTables($windshaft$' + + expectedQuery + + '$windshaft$) as tablenames )' + + ' SELECT (SELECT tablenames FROM querytables), EXTRACT(EPOCH FROM max(updated_at)) as max' + + ' FROM CDB_TableMetadata m' + + ' WHERE m.tabname = any ((SELECT tablenames from querytables)::regclass[])'); + } + + assert.imageBufferIsSimilarToFile(res.body, 'test/fixtures/test_table_0_0_0_multilayer1.png', + IMAGE_EQUALS_HIGHER_TOLERANCE_PER_MIL, function (err/*, similarity */) { + next(err); + } + ); + }); + }, + // See https://github.com/CartoDB/Windshaft-cartodb/issues/170 + function doGetTileNoSignature (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/localhost@' + expectedToken + ':cb0/0/0/0.png', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 403, res.statusCode + ':' + res.body); + var parsed = JSON.parse(res.body); + var msg = parsed.errors[0]; + assert.ok(msg.match(/permission denied/i), msg); + next(err); + }); + }, + function doGetGridLayer0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + '/0/0/0/0.grid.json', + headers: { host: 'localhost' }, + method: 'GET' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile(res.body, 'test/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetGridLayer1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + '/1/0/0/0.grid.json', + headers: { host: 'localhost' }, + method: 'GET' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile(res.body, 'test/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function finish (err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + done(err); } - ], - template: { - auth: { - method: "open" - }, - name: "open" - } - }; + ); + }); - assert.response( - server, - { - url: '/api/v1/map?signer=localhost', - method: 'POST', - headers: { - host: 'localhost', - 'Content-Type': 'application/json' + describe('server-metadata', function () { + var serverMetadata; + beforeEach(function () { + serverMetadata = global.environment.serverMetadata; + global.environment.serverMetadata = { cdn_url: { http: 'test', https: 'tests' } }; + }); + + afterEach(function () { + global.environment.serverMetadata = serverMetadata; + }); + + it('should include serverMedata in the response', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, 5e6, 0) as the_geom_webmercator' + + ' from test_table limit 2', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1' + } + } + ] + }; + + step( + function doCreateGet () { + var next = this; + assert.response(server, { + url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify(layergroup)), + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res, err) { next(err, res); }); + }, + function doCheckCreate (err, res) { + assert.ifError(err); + var parsed = JSON.parse(res.body); + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + assert.ok(_.isEqual(parsed.cdn_url, global.environment.serverMetadata.cdn_url)); + done(); + } + ); + }); + }); + + it('get creation requests has cache', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select cartodb_id, the_geom_webmercator from test_table', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1', + interactivity: 'cartodb_id' + } + }, + { + options: { + sql: 'select cartodb_id, the_geom_webmercator from test_table_2', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } + } + ] + }; + + var expectedToken; + step( + function doCreateGet () { + var next = this; + assert.response(server, { + url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify(layergroup)), + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res, err) { next(err, res); }); }, - data: JSON.stringify(layergroup) - }, - { - status: 403 - }, - function(res) { - assert.ok(res.body.match(/permission denied for .+?test_table_private_1/)); + function doCheckCreate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + expectedToken = parsedBody.layergroupid.split(':')[0]; + helper.checkCache(res); + helper.checkSurrogateKey(res, new QueryTables.QueryMetadata([ + { dbname: 'test_windshaft_cartodb_user_1_db', table_name: 'test_table', schema_name: 'public' }, + { dbname: 'test_windshaft_cartodb_user_1_db', table_name: 'test_table_2', schema_name: 'public' } + ]).key().join(' ')); + + keysToDelete['map_cfg|' + expectedToken] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(); + } + ); + }); + + it('get creation has no cache if sql is bogus', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select bogus(0,0) as the_geom_webmercator', + cartocss: '#layer { polygon-fill: red; }', + cartocss_version: '2.0.1' + } + } + ] + }; + assert.response(server, { + url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify(layergroup)), + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.notStrictEqual(res.statusCode, 200); + helper.checkNoCache(res); done(); - } - ); - }); + }); + }); - it('should response to empty layers mapconfig', function(done) { - var layergroup = { - layers: [] - }; + it('get creation has no cache if cartocss is not valid', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, 5e6, 0) as the_geom_webmercator' + + ' from test_table limit 2', + cartocss: '#layer { invalid-rule:red; }', + cartocss_version: '2.0.1' + } + } + ] + }; + assert.response(server, { + url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify(layergroup)), + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.notStrictEqual(res.statusCode, 200); + helper.checkNoCache(res); + done(); + }); + }); - assert.response( - server, - { - url: '/api/v1/map', - method: 'POST', - headers: { - host: 'localhost', - 'Content-Type': 'application/json' + it('layergroup can hold substitution tokens', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select 1 as cartodb_id, ST_Buffer(!bbox!, -32*greatest(!pixel_width!,!pixel_height!))' + + ' as the_geom_webmercator from test_table limit 1', + cartocss: '#layer { polygon-fill:red; }', + cartocss_version: '2.0.1', + interactivity: 'cartodb_id' + } + } + ] + }; + + var expectedToken; // = "6d8e4ad5458e2d25cf0eef38e38717a6"; + step( + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + assert.strictEqual(parsedBody.last_updated, expectedLastUpdated); + if (expectedToken) { + assert.strictEqual(parsedBody.layergroupid, expectedToken + ':' + expectedLastUpdatedEpoch); + } else { + expectedToken = parsedBody.layergroupid.split(':')[0]; + } + next(null, res); + }); }, + function doGetTile1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + ':cb10/1/0/0.png', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + + // Check X-Cache-Channel + var cc = res.headers['x-cache-channel']; + assert.ok(cc); + var dbname = testDatabase; + assert.strictEqual(cc.substring(0, dbname.length), dbname); + if (!cdbQueryTablesFromPostgresEnabledValue) { // only test if it was using the SQL API + var jsonquery = cc.substring(dbname.length + 1); + var sentquery = JSON.parse(jsonquery); + var expectedQuery = layergroup.layers[0].options.sql + .replace(/!bbox!/g, 'ST_MakeEnvelope(0,0,0,0)') + .replace(/!pixel_width!/g, '1') + .replace(/!pixel_height!/g, '1'); + assert.strictEqual(sentquery.q, 'WITH querytables AS ( SELECT * FROM CDB_QueryTables($windshaft$' + + expectedQuery + + '$windshaft$) as tablenames )' + + ' SELECT (SELECT tablenames FROM querytables), EXTRACT(EPOCH FROM max(updated_at)) as max' + + ' FROM CDB_TableMetadata m' + + ' WHERE m.tabname = any ((SELECT tablenames from querytables)::regclass[])'); + } + + var referenceImagePath = 'test/fixtures/test_multilayer_bbox.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, IMAGE_EQUALS_TOLERANCE_PER_MIL, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetTile4 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + ':cb11/4/0/0.png', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + + // Check X-Cache-Channel + var cc = res.headers['x-cache-channel']; + assert.ok(cc); + var dbname = testDatabase; + assert.strictEqual(cc.substring(0, dbname.length), dbname); + if (!cdbQueryTablesFromPostgresEnabledValue) { // only test if it was using the SQL API + var jsonquery = cc.substring(dbname.length + 1); + var sentquery = JSON.parse(jsonquery); + var expectedQuery = layergroup.layers[0].options.sql + .replace('!bbox!', 'ST_MakeEnvelope(0,0,0,0)') + .replace('!pixel_width!', '1') + .replace('!pixel_height!', '1'); + assert.strictEqual(sentquery.q, 'WITH querytables AS ( SELECT * FROM CDB_QueryTables($windshaft$' + + expectedQuery + + '$windshaft$) as tablenames )' + + ' SELECT (SELECT tablenames FROM querytables), EXTRACT(EPOCH FROM max(updated_at)) as max' + + ' FROM CDB_TableMetadata m' + + ' WHERE m.tabname = any ((SELECT tablenames from querytables)::regclass[])'); + } + + var referenceImagePath = 'test/fixtures/test_multilayer_bbox.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, IMAGE_EQUALS_TOLERANCE_PER_MIL, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetGrid1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + '/0/1/0/0.grid.json', + headers: { host: 'localhost' }, + method: 'GET' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile(res.body, 'test/fixtures/test_multilayer_bbox.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetGrid4 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + '/0/4/0/0.grid.json', + headers: { host: 'localhost' }, + method: 'GET' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile(res.body, 'test/fixtures/test_multilayer_bbox.grid.json', 2, next); + }); + }, + function finish (err) { + keysToDelete['map_cfg|' + expectedToken] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(err); + } + ); + }); + + it('layergroup creation raises mapviews counter', function (done) { + var layergroup = { + stat_tag: 'random_tag', + version: '1.0.0', + layers: [ + { + options: { + sql: 'select 1 as cartodb_id, !pixel_height! as h,' + + ' ST_Buffer(!bbox!, -32*greatest(!pixel_width!,!pixel_height!)) as the_geom_webmercator', + cartocss: '#layer { polygon-fill:red; }', + cartocss_version: '2.0.1' + } + } + ] + }; + var statskey = 'user:localhost:mapviews'; + var redisStatsClient = redis.createClient(global.environment.redis.port); + var expectedToken; // will be set on first post and checked on second + var now = strftime('%Y%m%d', new Date()); + step( + function cleanStats () { + var next = this; + redisStatsClient.select(redisStatsDb, function (err) { + if (err) { + next(err); + } else { + redisStatsClient.del(statskey + ':global', next); + } + }); + }, + function doPost1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + expectedToken = JSON.parse(res.body).layergroupid; + redisStatsClient.zscore(statskey + ':global', now, next); + }); + }, + function checkGlobalStats1 (err, val) { + assert.ifError(err); + assert.strictEqual(val, '1', 'Expected score of ' + now + ' in ' + statskey + ':global to be 1, got ' + val); + redisStatsClient.zscore(statskey + ':stat_tag:random_tag', now, this); + }, + function checkTagStats1DoPost2 (err, val) { + assert.ifError(err); + assert.strictEqual(val, '1', 'Expected score of ' + now + ' in ' + statskey + ':stat_tag:' + layergroup.stat_tag + + ' to be 1, got ' + val); + var next = this; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(JSON.parse(res.body).layergroupid, expectedToken); + redisStatsClient.zscore(statskey + ':global', now, next); + }); + }, + function checkGlobalStats2 (err, val) { + assert.ifError(err); + assert.strictEqual(val, '2', 'Expected score of ' + now + ' in ' + statskey + ':global to be 2, got ' + val); + redisStatsClient.zscore(statskey + ':stat_tag:' + layergroup.stat_tag, now, this); + }, + function checkTagStats2 (err, val) { + assert.ifError(err); + assert.strictEqual(val, '2', 'Expected score of ' + now + ' in ' + statskey + ':stat_tag:' + layergroup.stat_tag + + ' to be 2, got ' + val); + return 1; + }, + function finish (err) { + if (err) { + return done(err); + } + // strip epoch + expectedToken = expectedToken.split(':')[0]; + keysToDelete['map_cfg|' + expectedToken] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + keysToDelete[statskey + ':stat_tag:' + layergroup.stat_tag] = 5; + done(); + } + ); + }); + + it('layergroup creation fails if CartoCSS is bogus', function (done) { + var layergroup = { + stat_tag: 'random_tag', + version: '1.0.0', + layers: [ + { + options: { + sql: 'select 1 as cartodb_id, !pixel_height! as h,' + + 'ST_Buffer(!bbox!, -32*greatest(!pixel_width!,!pixel_height!)) as the_geom_webmercator', + cartocss: '#layer { polygon-fit:red; }', + cartocss_version: '2.0.1' + } + } + ] + }; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, data: JSON.stringify(layergroup) - }, - { - status: 200 - }, - function(res, err) { - assert.ok(!err); + }, {}, function (res) { + assert.strictEqual(res.statusCode, 400, res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors[0].match(/^style0/)); + assert.ok(parsed.errors[0].match(/Unrecognized rule: polygon-fit/)); + done(); + }); + }); - var parsedBody = JSON.parse(res.body); - assert.ok(parsedBody.layergroupid); + // Also tests that server doesn't crash: + // see http://github.com/CartoDB/Windshaft-cartodb/issues/109 + it('layergroup creation fails if sql is bogus', function (done) { + var layergroup = { + stat_tag: 'random_tag', + version: '1.0.0', + layers: [ + { + options: { + sql: 'select bogus(0,0) as the_geom_webmercator', + cartocss: '#layer { polygon-fill:red; }', + cartocss_version: '2.0.1' + } + } + ] + }; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + var msg = parsed.errors[0]; + assert.ok(msg.match(/bogus.*exist/), msg); + helper.checkNoCache(res); + done(); + }); + }); - keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0; + it('layergroup with 2 private-table layers', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table_private_1 where cartodb_id=1', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.1.0', + interactivity: 'cartodb_id' + } + }, + { + options: { + sql: 'select * from test_table_private_1 where cartodb_id=2', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.1.0', + interactivity: 'cartodb_id' + } + } + ] + }; + + var expectedToken; // = "b4ed64d93a411a59f330ab3d798e4009"; + step( + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl + '?map_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + assert.strictEqual(parsedBody.last_updated, expectedLastUpdated); + if (expectedToken) { + assert.strictEqual(parsedBody.layergroupid, expectedToken + ':' + expectedLastUpdatedEpoch); + } else { + expectedToken = parsedBody.layergroupid.split(':')[0]; + } + next(null, res); + }); + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + ':cb0/0/0/0.png?map_key=1234', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + + // Check X-Cache-Channel + var cc = res.headers['x-cache-channel']; + assert.ok(cc); + var dbname = testDatabase; + assert.strictEqual(cc.substring(0, dbname.length), dbname); + next(err); + }); + }, + function doGetGridLayer0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + '/0/0/0/0.grid.json?map_key=1234', + headers: { host: 'localhost' }, + method: 'GET' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + next(err); + }); + }, + function doGetGridLayer1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + '/1/0/0/0.grid.json?map_key=1234', + headers: { host: 'localhost' }, + method: 'GET' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + next(err); + }); + }, + function doGetTileUnauth (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + ':cb0/0/0/0.png', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 403); + var re = new RegExp('permission denied'); + assert.ok(res.body.match(re), 'No "permission denied" error: ' + res.body); + next(err); + }); + }, + function doGetGridLayer0Unauth (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + '/0/0/0/0.grid.json', + headers: { host: 'localhost' }, + method: 'GET' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 403); + var re = new RegExp('permission denied'); + assert.ok(res.body.match(re), 'No "permission denied" error: ' + res.body); + next(err); + }); + }, + function doGetGridLayer1Unauth (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + '/1/0/0/0.grid.json', + headers: { host: 'localhost' }, + method: 'GET' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 403); + var re = new RegExp('permission denied'); + assert.ok(res.body.match(re), 'No "permission denied" error: ' + res.body); + next(err); + }); + }, + function finish (err) { + keysToDelete['map_cfg|' + expectedToken] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(err); + } + ); + }); + + // See https://github.com/CartoDB/Windshaft-cartodb/issues/152 + it('x-cache-channel still works for GETs after tiler restart', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table where cartodb_id=1', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.1.0', + interactivity: 'cartodb_id' + } + } + ] + }; + + var expectedToken; // = "b4ed64d93a411a59f330ab3d798e4009"; + step( + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl + '?map_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + assert.strictEqual(parsedBody.last_updated, expectedLastUpdated); + if (expectedToken) { + assert.strictEqual(parsedBody.layergroupid, expectedToken + ':' + expectedLastUpdatedEpoch); + } else { + expectedToken = parsedBody.layergroupid.split(':')[0]; + } + return null; + }, + function doGet0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + ':cb0/0/0/0.png?map_key=1234', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res, err) { next(err, res); }); + }, + function doCheck0 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + + // Check X-Cache-Channel + var cc = res.headers['x-cache-channel']; + assert.ok(cc, 'Missing X-Cache-Channel'); + var dbname = testDatabase; + assert.strictEqual(cc.substring(0, dbname.length), dbname); + return null; + }, + function doRestartServer (err/*, res */) { + assert.ifError(err); + // hack simulating restart... + server = new CartodbWindshaft(serverOptions); + return null; + }, + function doGet1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + ':cb0/0/0/0.png?map_key=1234', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res, err) { next(err, res); }); + }, + function doCheck1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + + // Check X-Cache-Channel + var cc = res.headers['x-cache-channel']; + assert.ok(cc, 'Missing X-Cache-Channel on restart'); + var dbname = testDatabase; + assert.strictEqual(cc.substring(0, dbname.length), dbname); + return null; + }, + function finish (err) { + keysToDelete['map_cfg|' + expectedToken] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(err); + } + ); + }); + + // https://github.com/cartodb/Windshaft-cartodb/issues/81 + it('invalid text-name in CartoCSS', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: "select 1 as cartodb_id, 'SRID=3857;POINT(0 0)'::geometry as the_geom_webmercator", + cartocss: '#sample { text-name: cartodb_id; text-face-name: "Dejagnu"; }', + cartocss_version: '2.1.0' + } + } + ] + }; + + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.strictEqual(parsed.errors.length, 1); + var errmsg = parsed.errors[0]; + assert.ok(errmsg.match(/text-face-name.*Dejagnu/), parsed.errors.toString()); + done(); + }); + }); + + it('quotes CartoCSS', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: "select 'single''quote' as n, 'SRID=3857;POINT(0 0)'::geometry as the_geom_webmercator", + cartocss: '#s [n="single\'quote" ] { marker-fill:red; }', + cartocss_version: '2.1.0' + } + }, + { + options: { + sql: "select 'double\"quote' as n, 'SRID=3857;POINT(2 0)'::geometry as the_geom_webmercator", + cartocss: '#s [n="double\\"quote" ] { marker-fill:red; }', + cartocss_version: '2.1.0' + } + } + ] + }; + + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; - done(); + }); + }); + + // See https://github.com/CartoDB/Windshaft-cartodb/issues/87 + it('exponential notation in CartoCSS filter values', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: "select .4 as n, 'SRID=3857;POINT(0 0)'::geometry as the_geom_webmercator", + cartocss: '#s [n<=.2e-2] { marker-fill:red; }', + cartocss_version: '2.1.0' + } + } + ] + }; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + done(); + }); + }); + + // See https://github.com/CartoDB/Windshaft-cartodb/issues/93 + if (semver.satisfies(mapnik.versions.mapnik, '2.3.x')) { + it('accepts unused directives', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: "select 'SRID=3857;POINT(0 0)'::geometry as the_geom_webmercator", + cartocss: '#layer { point-transform:"scale(20)"; }', + cartocss_version: '2.0.1' + } + } + ] + }; + var expectedToken; // = "e34dd7e235138a062f8ba7ad051aa3a7"; + step( + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + if (expectedToken) { + assert.strictEqual(parsedBody.layergroupid, expectedToken + ':' + expectedLastUpdatedEpoch); + assert.strictEqual(res.headers['x-layergroup-id'], parsedBody.layergroupid); + } else { + var tokenComponents = parsedBody.layergroupid.split(':'); + expectedToken = tokenComponents[0]; + expectedLastUpdatedEpoch = tokenComponents[1]; + } + next(null, res); + }); + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + ':cb0/0/0/0.png', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + assert.imageBufferIsSimilarToFile(res.body, windshaftFixtures + '/test_default_mapnik_point.png', + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err/*, similarity */) { + next(err); + } + ); + }); + }, + function finish (err) { + keysToDelete['user:localhost:mapviews:global'] = 5; + keysToDelete['map_cfg|' + expectedToken] = 0; + + done(err); + } + ); + }); + } + + // See https://github.com/CartoDB/Windshaft-cartodb/issues/91 + // and https://github.com/CartoDB/Windshaft-cartodb/issues/38 + it('tiles for private tables can be fetched with api_key', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table_private_1 LIMIT 0', + cartocss: '#layer { marker-fill:red; }', + cartocss_version: '2.0.1' + } + } + ] + }; + var expectedToken; // = "e34dd7e235138a062f8ba7ad051aa3a7"; + step( + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl + '?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { next(null, res); }); + }, + function checkResult (err, res) { + assert.ifError(err); + var next = this; + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsedBody = JSON.parse(res.body); + if (expectedToken) { + assert.strictEqual(parsedBody.layergroupid, expectedToken + ':' + expectedLastUpdatedEpoch); + assert.strictEqual(res.headers['x-layergroup-id'], parsedBody.layergroupid); + } else { + var tokenComponents = parsedBody.layergroupid.split(':'); + expectedToken = tokenComponents[0]; + expectedLastUpdatedEpoch = tokenComponents[1]; + } + next(null, res); + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: layergroupUrl + '/' + expectedToken + ':cb0/0/0/0.png?api_key=1234', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }, {}, function (res) { next(null, res); }); + }, + function checkGetTile (err, res) { + if (err) { + return done(err); + } + assert.strictEqual(res.statusCode, 200, res.body); + keysToDelete['user:localhost:mapviews:global'] = 5; + keysToDelete['map_cfg|' + expectedToken] = 0; + done(err); + } + ); + }); + + // SQL strings can be of arbitrary length, when using POST + // See https://github.com/CartoDB/Windshaft-cartodb/issues/111 + it('sql string can be very long', function (done) { + var longVal = 'pretty'; + for (var i = 0; i < 1024; ++i) { + longVal += ' long'; } - ); + longVal += ' string'; + var sql = 'SELECT '; + for (i = 0; i < 16; ++i) { + sql += "'" + longVal + "'::text as pretty_long_field_name_" + i + ', '; + } + sql += 'cartodb_id, the_geom_webmercator FROM gadm4 g'; + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: sql, + cartocss: '#layer { marker-fill:red; }', + cartocss_version: '2.0.1' + } + } + ] + }; + var expectedToken; + step( + function doPost () { + var data = JSON.stringify(layergroup); + assert.ok(data.length > 1024 * 64); + var next = this; + assert.response(server, { + url: layergroupUrl + '?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: data + }, {}, function (res) { next(null, res); }); + }, + function checkResult (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsedBody = JSON.parse(res.body); + var tokenComponents = parsedBody.layergroupid.split(':'); + expectedToken = tokenComponents[0]; + return null; + }, + function cleanup (err) { + if (err) { + return done(err); + } + keysToDelete['user:localhost:mapviews:global'] = 5; + keysToDelete['map_cfg|' + expectedToken] = 0; + + done(err); + } + ); + }); + + // WARN: MapConfig with mapnik layer and no cartocss it's valid since + // vector & raster aggregation project, now we can request MVT format w/o defining styles + // for the layer. + + // See https://github.com/CartoDB/Windshaft-cartodb/issues/133 + it.skip('MapConfig with mapnik layer and no cartocss', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, 5e6, 0) as the_geom_webmercator' + + ' from test_table limit 2', + interactivity: 'cartodb_id' + } + } + ] + }; + + step( + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors, 'Missing "errors" in response: ' + JSON.stringify(parsed)); + assert.strictEqual(parsed.errors.length, 1); + var msg = parsed.errors[0]; + assert.strictEqual(msg, 'Missing cartocss for layer 0 options'); + return null; + }, + function finish (err) { + done(err); + } + ); + }); + + if (!cdbQueryTablesFromPostgresEnabledValue) { // only test if it was using the SQL API + // See https://github.com/CartoDB/Windshaft-cartodb/issues/167 + it('lack of response from sql-api will result in a timeout', function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: "select *, 'SQLAPINOANSWER' from test_table", + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.1.0' + } + } + ] + }; + + step( + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors, 'Missing "errors" in response: ' + JSON.stringify(parsed)); + assert.strictEqual(parsed.errors.length, 1); + var msg = parsed.errors[0]; + assert.ok(msg, /could not fetch source tables/, msg); + return null; + }, + function finish (err) { + done(err); + } + ); + }); + } + + var layergroupTtlRequest = { + url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify({ + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table limit 2', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1' + } + } + ] + })), + method: 'GET', + headers: { host: 'localhost' } + }; + var layergroupTtlResponseExpectation = { + status: 200 + }; + + it('cache control for layergroup default value', function (done) { + global.environment.varnish.layergroupTtl = null; + + var server = new CartodbWindshaft(serverOptions); + + assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation, + function (res) { + assert.strictEqual(res.headers['cache-control'], 'public,max-age=86400,must-revalidate'); + keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(); + } + ); + }); + + it('cache control for layergroup uses configuration for max-age', function (done) { + var layergroupTtl = 300; + global.environment.varnish.layergroupTtl = layergroupTtl; + + var server = new CartodbWindshaft(serverOptions); + + assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation, + function (res) { + assert.strictEqual(res.headers['cache-control'], 'public,max-age=' + layergroupTtl + ',must-revalidate'); + keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(); + } + ); + }); + + it("it's not possible to override authorization with a crafted layergroup", function (done) { + var layergroup = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table_private_1', + cartocss: '#layer { marker-fill:red; }', + cartocss_version: '2.3.0', + interactivity: 'cartodb_id' + } + } + ], + template: { + auth: { + method: 'open' + }, + name: 'open' + } + }; + + assert.response( + server, + { + url: '/api/v1/map?signer=localhost', + method: 'POST', + headers: { + host: 'localhost', + 'Content-Type': 'application/json' + }, + data: JSON.stringify(layergroup) + }, + { + status: 403 + }, + function (res) { + assert.ok(res.body.match(/permission denied for .+?test_table_private_1/)); + done(); + } + ); + }); + + it('should response to empty layers mapconfig', function (done) { + var layergroup = { + layers: [] + }; + + assert.response( + server, + { + url: '/api/v1/map', + method: 'POST', + headers: { + host: 'localhost', + 'Content-Type': 'application/json' + }, + data: JSON.stringify(layergroup) + }, + { + status: 200 + }, + function (res, err) { + assert.ok(!err); + + var parsedBody = JSON.parse(res.body); + assert.ok(parsedBody.layergroupid); + + keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(); + } + ); + }); }); - -}); - }); diff --git a/test/acceptance/mvt-regressions-test.js b/test/acceptance/mvt-regressions-test.js index 56c7ff0e..fc471061 100644 --- a/test/acceptance/mvt-regressions-test.js +++ b/test/acceptance/mvt-regressions-test.js @@ -18,7 +18,6 @@ const suites = [ ]; describe('mvt regressions', function () { - suites.forEach((suite) => { const { desc, usePostGIS } = suite; @@ -29,7 +28,7 @@ describe('mvt regressions', function () { serverOptions.renderer.mvt.usePostGIS = usePostGIS; }); - after(function (){ + after(function () { serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; }); @@ -66,7 +65,7 @@ describe('mvt regressions', function () { return done(err); } - assert.equal(typeof body.metadata, 'object'); + assert.strictEqual(typeof body.metadata, 'object'); assert.ok(Array.isArray(body.metadata.layers)); body.metadata.layers.forEach(layer => assert.ok(layer.meta.aggregation.mvt)); @@ -85,7 +84,7 @@ describe('MVT Mapnik', function () { serverOptions.renderer.mvt.usePostGIS = false; }); - after(function (){ + after(function () { serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; }); @@ -123,7 +122,7 @@ describe('MVT Mapnik', function () { return _.properties.country === 'Sudan'; })[0]; if (!sudanFeature) { - return reject(new Error(`Missing country='Sudan'`)); + return reject(new Error('Missing country=\'Sudan\'')); } resolve(sudanFeature); @@ -176,5 +175,4 @@ describe('MVT Mapnik', function () { done(); }); }); - }); diff --git a/test/acceptance/mvt-test.js b/test/acceptance/mvt-test.js index 15e28297..91a0a182 100644 --- a/test/acceptance/mvt-test.js +++ b/test/acceptance/mvt-test.js @@ -6,11 +6,11 @@ var assert = require('../support/assert'); var TestClient = require('../support/test-client'); var serverOptions = require('../../lib/server-options'); -function createMapConfig(sql = TestClient.SQL.ONE_POINT) { +function createMapConfig (sql = TestClient.SQL.ONE_POINT) { return { version: '1.6.0', layers: [{ - type: "cartodb", + type: 'cartodb', options: { sql: sql, cartocss: TestClient.CARTOCSS.POINTS, @@ -24,13 +24,13 @@ function createMapConfig(sql = TestClient.SQL.ONE_POINT) { describe('mvt (mapnik)', mvt(false)); describe('mvt (postgis)', mvt(true)); -function mvt(usePostGIS) { +function mvt (usePostGIS) { return function () { const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS; before(function () { serverOptions.renderer.mvt.usePostGIS = usePostGIS; }); - after(function (){ + after(function () { serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; }); @@ -54,7 +54,7 @@ function mvt(usePostGIS) { options: { sql: 'select * from populated_places_simple_reduced limit 10', cartocss: TestClient.CARTOCSS.POINTS, - cartocss_version: '2.3.0', + cartocss_version: '2.3.0' } }] } @@ -70,7 +70,7 @@ function mvt(usePostGIS) { const tileJSON = tile.toJSON(); - assert.equal(tileJSON[0].features.length, 10); + assert.strictEqual(tileJSON[0].features.length, 10); testClient.drain(done); }); @@ -78,8 +78,7 @@ function mvt(usePostGIS) { }); describe('analysis-layers-dataviews-mvt', function () { - - function createMapConfig(layers, dataviews, analysis) { + function createMapConfig (layers, dataviews, analysis) { return { version: '1.5.0', layers: layers, @@ -89,29 +88,29 @@ function mvt(usePostGIS) { } var CARTOCSS = [ - "#points {", - " marker-fill-opacity: 1.0;", - " marker-line-color: #FFF;", - " marker-line-width: 0.5;", - " marker-line-opacity: 1.0;", - " marker-placement: point;", - " marker-type: ellipse;", - " marker-width: 8;", - " marker-fill: red;", - " marker-allow-overlap: true;", - "}" + '#points {', + ' marker-fill-opacity: 1.0;', + ' marker-line-color: #FFF;', + ' marker-line-width: 0.5;', + ' marker-line-opacity: 1.0;', + ' marker-placement: point;', + ' marker-type: ellipse;', + ' marker-width: 8;', + ' marker-fill: red;', + ' marker-allow-overlap: true;', + '}' ].join('\n'); var mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "source": { - "id": "2570e105-7b37-40d2-bdf4-1af889598745" + type: 'cartodb', + options: { + source: { + id: '2570e105-7b37-40d2-bdf4-1af889598745' }, - "cartocss": CARTOCSS, - "cartocss_version": "2.3.0" + cartocss: CARTOCSS, + cartocss_version: '2.3.0' } } ], @@ -128,10 +127,10 @@ function mvt(usePostGIS) { }, [ { - "id": "2570e105-7b37-40d2-bdf4-1af889598745", - "type": "source", - "params": { - "query": "select * from populated_places_simple_reduced" + id: '2570e105-7b37-40d2-bdf4-1af889598745', + type: 'source', + params: { + query: 'select * from populated_places_simple_reduced' } } ] @@ -147,15 +146,13 @@ function mvt(usePostGIS) { assert.ok(Array.isArray(geojsonTile.features)); assert.ok(geojsonTile.features.length > 0); var feature = geojsonTile.features[0]; - assert.ok(feature.properties.hasOwnProperty('pop_max'), 'Missing pop_max property'); + assert.ok(Object.prototype.hasOwnProperty.call(feature.properties, 'pop_max'), 'Missing pop_max property'); testClient.drain(done); }); }); - }); - const testCases = [ { desc: 'should get empty mvt with code 204 (no content)', @@ -197,7 +194,7 @@ function mvt(usePostGIS) { }); describe('overviews', function () { - function createMapConfig(layers, dataviews, analysis) { + function createMapConfig (layers, dataviews, analysis) { return { version: '1.8.0', layers: layers, @@ -210,18 +207,18 @@ function mvt(usePostGIS) { const mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "sql": 'SELECT * FROM test_table_overviews', - "cartocss": TestClient.CARTOCSS.POINTS, - "cartocss_version": "2.3.0" + type: 'cartodb', + options: { + sql: 'SELECT * FROM test_table_overviews', + cartocss: TestClient.CARTOCSS.POINTS, + cartocss_version: '2.3.0' } } ] ); const testClient = new TestClient(mapConfig); - const [ z, x, y ] = [ 0, 0, 0 ]; + const [z, x, y] = [0, 0, 0]; const options = { format: 'mvt' }; testClient.getTile(z, x, y, options, function (err, res, mvt) { @@ -234,11 +231,11 @@ function mvt(usePostGIS) { const feature = geojsonTile.features[0]; - assert.ok(feature.properties.hasOwnProperty('_feature_count'), 'Missing _feature_count property'); - assert.equal(feature.properties.cartodb_id, 1); - assert.equal(feature.properties.name, 'Hawai'); - assert.equal(feature.properties._feature_count, 5); // original table has _feature_count = 1 - assert.equal(feature.properties.value, 3); // original table has value = 1.0 + assert.ok(Object.prototype.hasOwnProperty.call(feature.properties, '_feature_count'), 'Missing _feature_count property'); + assert.strictEqual(feature.properties.cartodb_id, 1); + assert.strictEqual(feature.properties.name, 'Hawai'); + assert.strictEqual(feature.properties._feature_count, 5); // original table has _feature_count = 1 + assert.strictEqual(feature.properties.value, 3); // original table has value = 1.0 testClient.drain(done); }); @@ -248,26 +245,26 @@ function mvt(usePostGIS) { const mapConfig = createMapConfig( [ { - "type": "cartodb", - "options": { - "sql": 'SELECT * FROM test_table_overviews', - "cartocss": TestClient.CARTOCSS.POINTS, - "cartocss_version": "2.3.0" + type: 'cartodb', + options: { + sql: 'SELECT * FROM test_table_overviews', + cartocss: TestClient.CARTOCSS.POINTS, + cartocss_version: '2.3.0' } }, { - "type": "cartodb", - "options": { - "sql": 'SELECT * FROM test_table', - "cartocss": TestClient.CARTOCSS.POINTS, - "cartocss_version": "2.3.0" + type: 'cartodb', + options: { + sql: 'SELECT * FROM test_table', + cartocss: TestClient.CARTOCSS.POINTS, + cartocss_version: '2.3.0' } } ] ); const testClient = new TestClient(mapConfig); - const [ z, x, y ] = [ 0, 0, 0 ]; + const [z, x, y] = [0, 0, 0]; const options = { format: 'mvt' }; testClient.getTile(z, x, y, options, function (err, res, mvt) { @@ -277,12 +274,12 @@ function mvt(usePostGIS) { const tileWithoutOverviews = JSON.parse(mvt.toGeoJSONSync(1)); assert.ok(Array.isArray(tileWithOverviews.features)); - assert.equal(tileWithOverviews.features.length, 1); - assert.equal(tileWithOverviews.features[0].properties._feature_count, 5); + assert.strictEqual(tileWithOverviews.features.length, 1); + assert.strictEqual(tileWithOverviews.features[0].properties._feature_count, 5); assert.ok(Array.isArray(tileWithoutOverviews.features)); - assert.equal(tileWithoutOverviews.features.length, 5); - assert.equal(tileWithoutOverviews.features[0].properties._feature_count, undefined); + assert.strictEqual(tileWithoutOverviews.features.length, 5); + assert.strictEqual(tileWithoutOverviews.features[0].properties._feature_count, undefined); testClient.drain(done); }); diff --git a/test/acceptance/named-layers-test.js b/test/acceptance/named-layers-test.js index a7da4e86..1ea33e31 100644 --- a/test/acceptance/named-layers-test.js +++ b/test/acceptance/named-layers-test.js @@ -1,6 +1,6 @@ 'use strict'; -var test_helper = require('../support/test-helper'); +var testHelper = require('../support/test-helper'); var assert = require('../support/assert'); var CartodbWindshaft = require('../../lib/server'); @@ -13,7 +13,7 @@ var TemplateMaps = require('../../lib/backends/template-maps'); var step = require('step'); -describe('named_layers', function() { +describe('named_layers', function () { var server; before(function () { @@ -45,10 +45,10 @@ describe('named_layers', function() { auth: { method: 'open' }, - "placeholders": { - "color": { - "type": "css_color", - "default": "#cc3300" + placeholders: { + color: { + type: 'css_color', + default: '#cc3300' } }, layergroup: { @@ -69,8 +69,8 @@ describe('named_layers', function() { }, placeholders: { color: { - "type": "css_color", - "default": "#cc3300" + type: 'css_color', + default: '#cc3300' } }, layergroup: { @@ -80,7 +80,6 @@ describe('named_layers', function() { } }; - var namedMapLayer = { type: 'named', options: { @@ -106,50 +105,50 @@ describe('named_layers', function() { var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { - test_helper.deleteRedisKeys(keysToDelete, done); + afterEach(function (done) { + testHelper.deleteRedisKeys(keysToDelete, done); }); - beforeEach(function(done) { + beforeEach(function (done) { global.environment.enabledFeatures.cdbQueryTablesFromPostgres = true; - templateMaps.addTemplate(username, nestedNamedMapTemplate, function(err) { + templateMaps.addTemplate(username, nestedNamedMapTemplate, function (err) { if (err) { return done(err); } - templateMaps.addTemplate(username, tokenAuthTemplate, function(err) { + templateMaps.addTemplate(username, tokenAuthTemplate, function (err) { if (err) { return done(err); } - templateMaps.addTemplate(username, template, function(err) { + templateMaps.addTemplate(username, template, function (err) { return done(err); }); }); }); }); - afterEach(function(done) { + afterEach(function (done) { global.environment.enabledFeatures.cdbQueryTablesFromPostgres = false; - templateMaps.delTemplate(username, nestedNamedMapTemplateName, function(err) { + templateMaps.delTemplate(username, nestedNamedMapTemplateName, function (err) { if (err) { return done(err); } - templateMaps.delTemplate(username, tokenAuthTemplateName, function(err) { + templateMaps.delTemplate(username, tokenAuthTemplateName, function (err) { if (err) { return done(err); } - templateMaps.delTemplate(username, templateName, function(err) { + templateMaps.delTemplate(username, templateName, function (err) { return done(err); }); }); }); }); - it('should fail for non-existing template name', function(done) { - var layergroup = { + it('should fail for non-existing template name', function (done) { + var layergroup = { version: '1.3.0', layers: [ { @@ -162,7 +161,7 @@ describe('named_layers', function() { }; step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(server, { @@ -177,30 +176,29 @@ describe('named_layers', function() { { status: 400 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function checkLayergroup(err, response) { + function checkLayergroup (err, response) { if (err) { throw err; } var parsedBody = JSON.parse(response.body); - assert.deepEqual(parsedBody.errors, ["Template 'nonexistent' of user 'localhost' not found"]); + assert.deepStrictEqual(parsedBody.errors, ["Template 'nonexistent' of user 'localhost' not found"]); return null; }, - function finish(err) { + function finish (err) { done(err); } ); }); - it('should return 403 if not properly authorized', function(done) { - - var layergroup = { + it('should return 403 if not properly authorized', function (done) { + var layergroup = { version: '1.3.0', layers: [ { @@ -215,7 +213,7 @@ describe('named_layers', function() { }; step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(server, { @@ -230,31 +228,29 @@ describe('named_layers', function() { { status: 403 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function checkLayergroup(err, response) { + function checkLayergroup (err, response) { if (err) { throw err; } var parsedBody = JSON.parse(response.body); - assert.deepEqual(parsedBody.errors, [ "Unauthorized 'auth_valid_template' template instantiation" ]); + assert.deepStrictEqual(parsedBody.errors, ["Unauthorized 'auth_valid_template' template instantiation"]); return null; }, - function finish(err) { + function finish (err) { done(err); } ); - }); - it('should return 200 and layergroup if properly authorized', function(done) { - - var layergroup = { + it('should return 200 and layergroup if properly authorized', function (done) { + var layergroup = { version: '1.3.0', layers: [ { @@ -269,7 +265,7 @@ describe('named_layers', function() { }; step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(server, { @@ -284,12 +280,12 @@ describe('named_layers', function() { { status: 200 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function checkLayergroup(err, response) { + function checkLayergroup (err, response) { if (err) { throw err; } @@ -303,16 +299,14 @@ describe('named_layers', function() { return null; }, - function finish(err) { + function finish (err) { done(err); } ); - }); - it('should return 400 for nested named map layers', function(done) { - - var layergroup = { + it('should return 400 for nested named map layers', function (done) { + var layergroup = { version: '1.3.0', layers: [ { @@ -325,7 +319,7 @@ describe('named_layers', function() { }; step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(server, { @@ -340,30 +334,28 @@ describe('named_layers', function() { { status: 400 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function checkLayergroup(err, response) { + function checkLayergroup (err, response) { if (err) { throw err; } var parsedBody = JSON.parse(response.body); - assert.deepEqual(parsedBody.errors, ['Nested named layers are not allowed' ]); + assert.deepStrictEqual(parsedBody.errors, ['Nested named layers are not allowed']); return null; }, - function finish(err) { + function finish (err) { done(err); } ); - }); - it('should return 200 and layergroup with private tables', function(done) { - + it('should return 200 and layergroup with private tables', function (done) { var privateTableTemplateName = 'private_table_template'; var privateTableTemplate = { version: '0.0.1', @@ -385,7 +377,7 @@ describe('named_layers', function() { } }; - var layergroup = { + var layergroup = { version: '1.3.0', layers: [ { @@ -398,10 +390,10 @@ describe('named_layers', function() { }; step( - function createTemplate() { + function createTemplate () { templateMaps.addTemplate(username, privateTableTemplate, this); }, - function createLayergroup(err) { + function createLayergroup (err) { if (err) { throw err; } @@ -420,12 +412,12 @@ describe('named_layers', function() { { status: 200 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function checkLayergroup(err, response) { + function checkLayergroup (err, response) { if (err) { throw err; } @@ -439,7 +431,7 @@ describe('named_layers', function() { return parsedBody.layergroupid; }, - function requestTile(err, layergroupId) { + function requestTile (err, layergroupId) { if (err) { throw err; } @@ -460,63 +452,61 @@ describe('named_layers', function() { 'content-type': 'image/png' } }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function handleTileResponse(err, res) { + function handleTileResponse (err, res) { if (err) { throw err; } - test_helper.checkCache(res); + testHelper.checkCache(res); return true; }, - function deleteTemplate(err) { + function deleteTemplate (err) { var next = this; - templateMaps.delTemplate(username, privateTableTemplateName, function(/*delErr*/) { + templateMaps.delTemplate(username, privateTableTemplateName, function (/* delErr */) { // ignore deletion error next(err); }); }, - function finish(err) { + function finish (err) { done(err); } ); - }); - it('should return 200 and layergroup with private tables and interactivity', function(done) { - + it('should return 200 and layergroup with private tables and interactivity', function (done) { var privateTableTemplateNameInteractivity = 'private_table_template_interactivity'; var privateTableTemplate = { - "version": "0.0.1", - "auth": { - "method": "open" + version: '0.0.1', + auth: { + method: 'open' }, - "name": privateTableTemplateNameInteractivity, - "layergroup": { - "layers": [ + name: privateTableTemplateNameInteractivity, + layergroup: { + layers: [ { - "type": "cartodb", - "options": { - "attributes": { - "columns": [ - "name" + type: 'cartodb', + options: { + attributes: { + columns: [ + 'name' ], - "id": "cartodb_id" + id: 'cartodb_id' }, - "cartocss": "#layer { marker-fill: #cc3300; }", - "cartocss_version": "2.3.0", - "interactivity": "cartodb_id", - "sql": "select * from test_table_private_1" + cartocss: '#layer { marker-fill: #cc3300; }', + cartocss_version: '2.3.0', + interactivity: 'cartodb_id', + sql: 'select * from test_table_private_1' } } ] } }; - var layergroup = { + var layergroup = { version: '1.3.0', layers: [ { @@ -529,10 +519,10 @@ describe('named_layers', function() { }; step( - function createTemplate() { + function createTemplate () { templateMaps.addTemplate(username, privateTableTemplate, this); }, - function createLayergroup(err) { + function createLayergroup (err) { if (err) { throw err; } @@ -551,12 +541,12 @@ describe('named_layers', function() { { status: 200 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function checkLayergroup(err, response) { + function checkLayergroup (err, response) { if (err) { throw err; } @@ -570,7 +560,7 @@ describe('named_layers', function() { return parsedBody.layergroupid; }, - function requestTile(err, layergroupId) { + function requestTile (err, layergroupId) { if (err) { throw err; } @@ -591,35 +581,33 @@ describe('named_layers', function() { 'content-type': 'image/png' } }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function handleTileResponse(err, res) { + function handleTileResponse (err, res) { if (err) { throw err; } - test_helper.checkCache(res); + testHelper.checkCache(res); return true; }, - function deleteTemplate(err) { + function deleteTemplate (err) { var next = this; - templateMaps.delTemplate(username, privateTableTemplateNameInteractivity, function(/*delErr*/) { + templateMaps.delTemplate(username, privateTableTemplateNameInteractivity, function (/* delErr */) { // ignore deletion error next(err); }); }, - function finish(err) { + function finish (err) { done(err); } ); - }); - it('should return 403 when private table is accessed from non named layer', function(done) { - - var layergroup = { + it('should return 403 when private table is accessed from non named layer', function (done) { + var layergroup = { version: '1.3.0', layers: [ { @@ -640,7 +628,7 @@ describe('named_layers', function() { }; step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(server, { @@ -655,12 +643,12 @@ describe('named_layers', function() { { status: 403 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function checkLayergroup(err, response) { + function checkLayergroup (err, response) { if (err) { throw err; } @@ -670,16 +658,14 @@ describe('named_layers', function() { return null; }, - function finish(err) { + function finish (err) { done(err); } ); - }); - it('should return metadata for named layers', function(done) { - - var layergroup = { + it('should return metadata for named layers', function (done) { + var layergroup = { version: '1.3.0', layers: [ { @@ -705,8 +691,8 @@ describe('named_layers', function() { { type: 'torque', options: { - sql: "select * from test_table LIMIT 0", - cartocss: "Map { -torque-frame-count:1; -torque-resolution:1; " + + sql: 'select * from test_table LIMIT 0', + cartocss: 'Map { -torque-frame-count:1; -torque-resolution:1; ' + "-torque-aggregation-function:'count(*)'; -torque-time-attribute:'updated_at'; }" } } @@ -714,7 +700,7 @@ describe('named_layers', function() { }; step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(server, { @@ -729,12 +715,12 @@ describe('named_layers', function() { { status: 200 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function checkLayergroup(err, response) { + function checkLayergroup (err, response) { if (err) { throw err; } @@ -742,27 +728,25 @@ describe('named_layers', function() { var parsedBody = JSON.parse(response.body); assert.ok(parsedBody.metadata); assert.ok(parsedBody.metadata.layers); - assert.equal(parsedBody.metadata.layers.length, 5); - assert.equal(parsedBody.metadata.layers[0].type, 'plain'); - assert.equal(parsedBody.metadata.layers[1].type, 'mapnik'); - assert.equal(parsedBody.metadata.layers[2].type, 'mapnik'); - assert.equal(parsedBody.metadata.layers[3].type, 'mapnik'); - assert.equal(parsedBody.metadata.layers[4].type, 'torque'); + assert.strictEqual(parsedBody.metadata.layers.length, 5); + assert.strictEqual(parsedBody.metadata.layers[0].type, 'plain'); + assert.strictEqual(parsedBody.metadata.layers[1].type, 'mapnik'); + assert.strictEqual(parsedBody.metadata.layers[2].type, 'mapnik'); + assert.strictEqual(parsedBody.metadata.layers[3].type, 'mapnik'); + assert.strictEqual(parsedBody.metadata.layers[4].type, 'torque'); keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; return null; }, - function finish(err) { + function finish (err) { done(err); } ); - }); - it('should work with named tiles', function(done) { - + it('should work with named tiles', function (done) { var namedTilesTemplateName = 'named_tiles_template'; var namedTilesTemplate = { version: '0.0.1', @@ -786,10 +770,10 @@ describe('named_layers', function() { }; step( - function createTemplate() { + function createTemplate () { templateMaps.addTemplate(username, namedTilesTemplate, this); }, - function createLayergroup(err) { + function createLayergroup (err) { if (err) { throw err; } @@ -807,12 +791,12 @@ describe('named_layers', function() { { status: 200 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function checkLayergroup(err, response) { + function checkLayergroup (err, response) { if (err) { throw err; } @@ -821,15 +805,15 @@ describe('named_layers', function() { assert.ok(parsedBody.layergroupid); assert.ok(parsedBody.last_updated); - assert.equal(parsedBody.metadata.layers[0].type, 'mapnik'); - assert.equal(parsedBody.metadata.layers[1].type, 'mapnik'); + assert.strictEqual(parsedBody.metadata.layers[0].type, 'mapnik'); + assert.strictEqual(parsedBody.metadata.layers[1].type, 'mapnik'); keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; return parsedBody.layergroupid; }, - function requestTile(err, layergroupId) { + function requestTile (err, layergroupId) { if (err) { throw err; } @@ -850,29 +834,28 @@ describe('named_layers', function() { 'content-type': 'image/png' } }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function handleTileResponse(err, res) { + function handleTileResponse (err, res) { if (err) { throw err; } - test_helper.checkCache(res); + testHelper.checkCache(res); return true; }, - function deleteTemplate(err) { + function deleteTemplate (err) { var next = this; - templateMaps.delTemplate(username, namedTilesTemplateName, function(/*delErr*/) { + templateMaps.delTemplate(username, namedTilesTemplateName, function (/* delErr */) { // ignore deletion error next(err); }); }, - function finish(err) { + function finish (err) { done(err); } ); - }); }); diff --git a/test/acceptance/named-layers-visibility-test.js b/test/acceptance/named-layers-visibility-test.js index a68314fe..1a717cf8 100644 --- a/test/acceptance/named-layers-visibility-test.js +++ b/test/acceptance/named-layers-visibility-test.js @@ -1,7 +1,7 @@ 'use strict'; var step = require('step'); -var test_helper = require('../support/test-helper'); +var testHelper = require('../support/test-helper'); var assert = require('../support/assert'); var CartodbWindshaft = require('../../lib/server'); @@ -13,7 +13,7 @@ var mapnik = require('windshaft').mapnik; var IMAGE_TOLERANCE = 20; -describe('layers visibility for previews', function() { +describe('layers visibility for previews', function () { var server; before(function () { @@ -52,7 +52,7 @@ describe('layers visibility for previews', function() { }; } - function createTemplate(scenario) { + function createTemplate (scenario) { return { version: '0.0.1', name: scenario.name, @@ -80,12 +80,12 @@ describe('layers visibility for previews', function() { } afterEach(function (done) { - test_helper.deleteRedisKeys({ + testHelper.deleteRedisKeys({ 'user:localhost:mapviews:global': 5 }, done); }); - function previewFixture(version) { + function previewFixture (version) { return './test/fixtures/previews/populated_places_simple_reduced-' + version + '.png'; } @@ -98,64 +98,64 @@ describe('layers visibility for previews', function() { var scenarios = [{ name: 'preview_layers_red', layerPerview: { - '0': true, - '1': false, - 'layer2': false + 0: true, + 1: false, + layer2: false }, layers: threeLayerPointDistintColor }, { name: 'preview_layers_orange', layerPerview: { - '0': false, - '1': true, - 'layer2': false + 0: false, + 1: true, + layer2: false }, layers: threeLayerPointDistintColor }, { name: 'preview_layers_blue', layerPerview: { - '0': false, - '1': false, - 'layer2': true + 0: false, + 1: false, + layer2: true }, layers: threeLayerPointDistintColor }, { name: 'preview_layers_red_orange', layerPerview: { - '0': true, - '1': true, - 'layer2': false + 0: true, + 1: true, + layer2: false }, layers: threeLayerPointDistintColor }, { name: 'preview_layers_red_blue', layerPerview: { - '0': true, - '1': false, - 'layer2': true + 0: true, + 1: false, + layer2: true }, layers: threeLayerPointDistintColor }, { name: 'preview_layers_orange_blue', layerPerview: { - '0': false, - '1': true, - 'layer2': true + 0: false, + 1: true, + layer2: true }, layers: threeLayerPointDistintColor }, { name: 'preview_layers_red_orange_blue', layerPerview: { - '0': true, - '1': true, - 'layer2': true + 0: true, + 1: true, + layer2: true }, layers: threeLayerPointDistintColor }, { name: 'preview_layers_all', layerPerview: {}, layers: threeLayerPointDistintColor - }, { + }, { name: 'preview_layers_undefined', layerPerview: undefined, layers: threeLayerPointDistintColor @@ -195,12 +195,12 @@ describe('layers visibility for previews', function() { assert.ifError(err); var next = this; - var img = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); + var img = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); var previewFixturePath = previewFixture(scenario.name); assert.imageIsSimilarToFile(img, previewFixturePath, IMAGE_TOLERANCE, next); }, - function deleteTemplate(err) { + function deleteTemplate (err) { assert.ifError(err); var next = this; @@ -213,5 +213,4 @@ describe('layers visibility for previews', function() { ); }); }); - }); diff --git a/test/acceptance/named-map-cache-regressions-test.js b/test/acceptance/named-map-cache-regressions-test.js index d8089cf5..8d6c72d5 100644 --- a/test/acceptance/named-map-cache-regressions-test.js +++ b/test/acceptance/named-map-cache-regressions-test.js @@ -165,7 +165,7 @@ describe('named map cache regressions', function () { url: `http://${address}/api/v1/map/named/${templateId}?api_key=${apiKey}`, method: 'DELETE', headers: { - host: 'localhost', + host: 'localhost' } }; diff --git a/test/acceptance/named-maps-authentication-test.js b/test/acceptance/named-maps-authentication-test.js index ac898c5e..848983b2 100644 --- a/test/acceptance/named-maps-authentication-test.js +++ b/test/acceptance/named-maps-authentication-test.js @@ -1,6 +1,6 @@ 'use strict'; -var test_helper = require('../support/test-helper'); +var testHelper = require('../support/test-helper'); var RedisPool = require('redis-mpool'); var querystring = require('querystring'); @@ -11,7 +11,7 @@ var serverOptions = require('../../lib/server-options'); var TemplateMaps = require('../../lib/backends/template-maps'); var NamedMapsCacheEntry = require('../../lib/cache/model/named-maps-entry'); -describe('named maps authentication', function() { +describe('named maps authentication', function () { var server; before(function () { @@ -43,10 +43,10 @@ describe('named maps authentication', function() { auth: { method: 'open' }, - "placeholders": { - "color": { - "type": "css_color", - "default": "#cc3300" + placeholders: { + color: { + type: 'css_color', + default: '#cc3300' } }, layergroup: { @@ -66,8 +66,8 @@ describe('named maps authentication', function() { }, placeholders: { color: { - "type": "css_color", - "default": "#cc3300" + type: 'css_color', + default: '#cc3300' } }, layergroup: { @@ -77,7 +77,6 @@ describe('named maps authentication', function() { } }; - var namedMapLayer = { type: 'named', options: { @@ -133,9 +132,8 @@ describe('named maps authentication', function() { }); }); - function getNamedTile(name, z, x, y, options, callback) { - - var url = '/api/v1/map/named/' + name + '/all/' + [z,x,y].join('/') + '.png'; + function getNamedTile (name, z, x, y, options, callback) { + var url = '/api/v1/map/named/' + name + '/all/' + [z, x, y].join('/') + '.png'; if (options.params) { url = url + '?' + querystring.stringify(options.params); } @@ -163,19 +161,19 @@ describe('named maps authentication', function() { function (res, err) { var img; if (!err && res.headers['content-type'] === 'image/png') { - img = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); + img = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); } return callback(err, res, img); } ); } - describe('tiles', function() { + describe('tiles', function () { it('should return a 404 error for nonexistent template name', function (done) { var nonexistentName = 'nonexistent'; - getNamedTile(nonexistentName, 0, 0, 0, { status: 404 }, function(err, res) { + getNamedTile(nonexistentName, 0, 0, 0, { status: 404 }, function (err, res) { assert.ok(!err); - assert.deepEqual( + assert.deepStrictEqual( JSON.parse(res.body).errors, ["Template '" + nonexistentName + "' of user '" + username + "' not found"] ); @@ -183,28 +181,27 @@ describe('named maps authentication', function() { }); }); - it('should return 403 if not properly authorized', function(done) { - getNamedTile(tokenAuthTemplateName, 0, 0, 0, { status: 403 }, function(err, res) { + it('should return 403 if not properly authorized', function (done) { + getNamedTile(tokenAuthTemplateName, 0, 0, 0, { status: 403 }, function (err, res) { assert.ok(!err); - assert.deepEqual(JSON.parse(res.body).errors, ['Unauthorized template instantiation']); + assert.deepStrictEqual(JSON.parse(res.body).errors, ['Unauthorized template instantiation']); done(); }); }); - it('should return 200 if properly authorized', function(done) { - getNamedTile(tokenAuthTemplateName, 0, 0, 0, { params: { auth_token: 'valid1' } }, function(err, res, img) { - assert.equal(img.width(), 256); - assert.equal(img.height(), 256); + it('should return 200 if properly authorized', function (done) { + getNamedTile(tokenAuthTemplateName, 0, 0, 0, { params: { auth_token: 'valid1' } }, function (err, res, img) { + assert.strictEqual(img.width(), 256); + assert.strictEqual(img.height(), 256); assert.ok(!err); - test_helper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, tokenAuthTemplateName).key()); + testHelper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, tokenAuthTemplateName).key()); done(); }); }); }); - function getStaticMap(name, options, callback) { - + function getStaticMap (name, options, callback) { var url = '/api/v1/map/static/named/' + name + '/640/480.png'; if (options.params) { url = url + '?' + querystring.stringify(options.params); @@ -233,18 +230,18 @@ describe('named maps authentication', function() { function (res, err) { var img; if (!err && res.headers['content-type'] === 'image/png') { - img = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); + img = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); } return callback(err, res, img); } ); } - describe('static maps', function() { + describe('static maps', function () { it('should return a 404 error for nonexistent template name', function (done) { var nonexistentName = 'nonexistent'; - getStaticMap(nonexistentName, { status: 404 }, function(err, res) { + getStaticMap(nonexistentName, { status: 404 }, function (err, res) { assert.ok(!err); - assert.deepEqual( + assert.deepStrictEqual( JSON.parse(res.body).errors, ["Template '" + nonexistentName + "' of user '" + username + "' not found"] ); @@ -252,25 +249,24 @@ describe('named maps authentication', function() { }); }); - it('should return 403 if not properly authorized', function(done) { - getStaticMap(tokenAuthTemplateName, { status: 403 }, function(err, res) { + it('should return 403 if not properly authorized', function (done) { + getStaticMap(tokenAuthTemplateName, { status: 403 }, function (err, res) { assert.ok(!err); - assert.deepEqual(JSON.parse(res.body).errors, ['Unauthorized template instantiation']); + assert.deepStrictEqual(JSON.parse(res.body).errors, ['Unauthorized template instantiation']); done(); }); }); - it('should return 200 if properly authorized', function(done) { - getStaticMap(tokenAuthTemplateName, { params: { auth_token: 'valid1' } }, function(err, res, img) { + it('should return 200 if properly authorized', function (done) { + getStaticMap(tokenAuthTemplateName, { params: { auth_token: 'valid1' } }, function (err, res, img) { assert.ok(!err); - assert.equal(img.width(), 640); - assert.equal(img.height(), 480); + assert.strictEqual(img.width(), 640); + assert.strictEqual(img.height(), 480); - test_helper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, tokenAuthTemplateName).key()); - test_helper.deleteRedisKeys({'user:localhost:mapviews:global': 5}, done); + testHelper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, tokenAuthTemplateName).key()); + testHelper.deleteRedisKeys({ 'user:localhost:mapviews:global': 5 }, done); }); }); }); - }); diff --git a/test/acceptance/named-maps-cache-test.js b/test/acceptance/named-maps-cache-test.js index c369dc0e..1c662991 100644 --- a/test/acceptance/named-maps-cache-test.js +++ b/test/acceptance/named-maps-cache-test.js @@ -8,7 +8,7 @@ var mapnik = require('windshaft').mapnik; var CartodbWindshaft = require('../../lib/server'); var serverOptions = require('../../lib/server-options'); -describe('named maps provider cache', function() { +describe('named maps provider cache', function () { var server; before(function () { @@ -21,7 +21,7 @@ describe('named maps provider cache', function() { var IMAGE_TOLERANCE = 20; - function createTemplate(color) { + function createTemplate (color) { return { version: '0.0.1', name: `${templateName}_${color}`, @@ -30,7 +30,7 @@ describe('named maps provider cache', function() { }, placeholders: { color: { - type: "css_color", + type: 'css_color', default: color } }, @@ -49,13 +49,13 @@ describe('named maps provider cache', function() { }; } - function getNamedTile(templateId, options, callback) { + function getNamedTile (templateId, options, callback) { if (!callback) { callback = options; options = {}; } - var url = '/api/v1/map/named/' + templateId + '/all/' + [0,0,0].join('/') + '.png'; + var url = '/api/v1/map/named/' + templateId + '/all/' + [0, 0, 0].join('/') + '.png'; var requestOptions = { url: url, @@ -78,7 +78,7 @@ describe('named maps provider cache', function() { assert.response(server, requestOptions, expectedResponse, function (res, err) { var img; if (res.statusCode === 200) { - img = mapnik.Image.fromBytes(new Buffer.from(res.body, 'binary')); + img = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); } return callback(err, res, img); }); @@ -113,18 +113,17 @@ describe('named maps provider cache', function() { }); } - function deleteTemplate (templateId, callback) { const deleteTemplateRequest = { url: `/api/v1/map/named/${templateId}?api_key=${apikey}`, method: 'DELETE', headers: { - host: 'localhost', + host: 'localhost' } }; const expectedResponse = { - status: 204, + status: 204 }; assert.response(server, deleteTemplateRequest, expectedResponse, (res, err) => { @@ -132,19 +131,19 @@ describe('named maps provider cache', function() { }); } - function previewFixture(color) { + function previewFixture (color) { return './test/fixtures/provider/populated_places_simple_reduced-' + color + '.png'; } var colors = ['black', 'red', 'green', 'blue']; - colors.forEach(function(color) { + colors.forEach(function (color) { it('should return an image estimating its bounds based on dataset', function (done) { addTemplate(createTemplate(color), function (err, res, template) { if (err) { return done(err); } - getNamedTile(template.template_id, function(err, res, img) { + getNamedTile(template.template_id, function (err, res, img) { assert.ok(!err); assert.imageIsSimilarToFile(img, previewFixture(color), IMAGE_TOLERANCE, (err) => { assert.ifError(err); @@ -165,7 +164,7 @@ describe('named maps provider cache', function() { addTemplate(createTemplate(color), function (err) { assert.ifError(err); - getNamedTile(templateId, function(err, res, img) { + getNamedTile(templateId, function (err, res, img) { assert.ifError(err); assert.imageIsSimilarToFile(img, previewFixture(color), IMAGE_TOLERANCE, function (err) { @@ -174,10 +173,10 @@ describe('named maps provider cache', function() { deleteTemplate(templateId, function (err) { assert.ifError(err); - getNamedTile(templateId, { statusCode: 404 }, function(err, res) { + getNamedTile(templateId, { statusCode: 404 }, function (err, res) { assert.ifError(err); - assert.deepEqual( + assert.deepStrictEqual( JSON.parse(res.body).errors, ["Template 'template_with_color_black' of user 'localhost' not found"] ); diff --git a/test/acceptance/named-maps-static-view-test.js b/test/acceptance/named-maps-static-view-test.js index e6e54195..370f9034 100644 --- a/test/acceptance/named-maps-static-view-test.js +++ b/test/acceptance/named-maps-static-view-test.js @@ -10,7 +10,7 @@ var CartodbWindshaft = require('../../lib/server'); var serverOptions = require('../../lib/server-options'); var TemplateMaps = require('../../lib/backends/template-maps'); -describe('named maps static view', function() { +describe('named maps static view', function () { // configure redis pool instance to use in tests var redisPool = new RedisPool(global.environment.redis); @@ -24,7 +24,7 @@ describe('named maps static view', function() { var PNG_IMAGE_TOLERANCE = 20; var JPG_IMAGE_TOLERANCE = 100; - function createTemplate(view, layers) { + function createTemplate (view, layers) { return { version: '0.0.1', name: templateName, @@ -33,8 +33,8 @@ describe('named maps static view', function() { }, placeholders: { color: { - type: "css_color", - default: "#cc3300" + type: 'css_color', + default: '#cc3300' } }, view: view, @@ -57,7 +57,7 @@ describe('named maps static view', function() { templateMaps.delTemplate(username, templateName, done); }); - function getStaticMap(params, callback) { + function getStaticMap (params, callback) { if (!callback) { callback = params; params = null; @@ -89,13 +89,13 @@ describe('named maps static view', function() { var server = new CartodbWindshaft(serverOptions); assert.response(server, requestOptions, expectedResponse, function (res, err) { - testHelper.deleteRedisKeys({'user:localhost:mapviews:global': 5}, function() { - return callback(err, mapnik.Image.fromBytes(new Buffer(res.body, 'binary'))); + testHelper.deleteRedisKeys({ 'user:localhost:mapviews:global': 5 }, function () { + return callback(err, mapnik.Image.fromBytes(Buffer.from(res.body, 'binary'))); }); }); } - function previewFixture(version, format='png') { + function previewFixture (version, format = 'png') { return './test/fixtures/previews/populated_places_simple_reduced-' + version + '.' + format; } @@ -104,14 +104,12 @@ describe('named maps static view', function() { if (err) { return done(err); } - getStaticMap(function(err, img) { + getStaticMap(function (err, img) { assert.ok(!err); - assert.imageIsSimilarToFile(img, previewFixture('estimated'), PNG_IMAGE_TOLERANCE, err => { + assert.imageIsSimilarToFile(img, previewFixture('estimated'), PNG_IMAGE_TOLERANCE, err => { if (err) { assert.imageIsSimilarToFile(img, previewFixture('estimated-proj5'), PNG_IMAGE_TOLERANCE, done); - } - else - { + } else { done(); } }); @@ -131,7 +129,7 @@ describe('named maps static view', function() { if (err) { return done(err); } - getStaticMap(function(err, img) { + getStaticMap(function (err, img) { assert.ok(!err); assert.imageIsSimilarToFile(img, previewFixture('zoom-center'), PNG_IMAGE_TOLERANCE, done); }); @@ -151,7 +149,7 @@ describe('named maps static view', function() { if (err) { return done(err); } - getStaticMap(function(err, img) { + getStaticMap(function (err, img) { assert.ok(!err); assert.imageIsSimilarToFile(img, previewFixture('bounds'), PNG_IMAGE_TOLERANCE, done); }); @@ -176,7 +174,7 @@ describe('named maps static view', function() { if (err) { return done(err); } - getStaticMap(function(err, img) { + getStaticMap(function (err, img) { assert.ok(!err); assert.imageIsSimilarToFile(img, previewFixture('zoom-center'), PNG_IMAGE_TOLERANCE, done); }); @@ -201,7 +199,7 @@ describe('named maps static view', function() { if (err) { return done(err); } - getStaticMap({ zoom: 3 }, function(err, img) { + getStaticMap({ zoom: 3 }, function (err, img) { assert.ok(!err); assert.imageIsSimilarToFile(img, previewFixture('override-zoom'), PNG_IMAGE_TOLERANCE, done); }); @@ -226,7 +224,7 @@ describe('named maps static view', function() { if (err) { return done(err); } - getStaticMap({ bbox: '0,45,90,45' }, function(err, img) { + getStaticMap({ bbox: '0,45,90,45' }, function (err, img) { assert.ok(!err); assert.imageIsSimilarToFile(img, previewFixture('override-bbox'), PNG_IMAGE_TOLERANCE, done); }); @@ -265,7 +263,7 @@ describe('named maps static view', function() { if (err) { return done(err); } - getStaticMap({ layer: 0 }, function(err, img) { + getStaticMap({ layer: 0 }, function (err, img) { assert.ok(!err); assert.imageIsSimilarToFile(img, previewFixture('bounds'), PNG_IMAGE_TOLERANCE, done); }); @@ -284,10 +282,10 @@ describe('named maps static view', function() { if (err) { return done(err); } - getStaticMap({ format: 'jpeg' }, function(err, img) { + getStaticMap({ format: 'jpeg' }, function (err, img) { assert.ok(!err); assert.imageIsSimilarToFile(img, previewFixture('zoom-center', 'jpeg'), - JPG_IMAGE_TOLERANCE, done, 'jpeg'); + JPG_IMAGE_TOLERANCE, done, 'jpeg'); }); }); }); @@ -308,7 +306,6 @@ describe('named maps static view', function() { var url = `/api/v1/map/static/named/${templateName}/640/480.gif`; - var requestOptions = { url: url, method: 'GET', @@ -330,13 +327,13 @@ describe('named maps static view', function() { assert.response(server, requestOptions, expectedResponse, function (res, err) { assert.ifError(err); - assert.deepEqual( + assert.deepStrictEqual( JSON.parse(res.body), { - errors:['Unsupported image format \"gif\"'], - errors_with_context:[{ + errors: ['Unsupported image format "gif"'], + errors_with_context: [{ type: 'unknown', - message: 'Unsupported image format \"gif\"' + message: 'Unsupported image format "gif"' }] } ); @@ -344,5 +341,4 @@ describe('named maps static view', function() { }); }); }); - }); diff --git a/test/acceptance/named-maps-stats-test.js b/test/acceptance/named-maps-stats-test.js index a41644ba..6ccf112e 100644 --- a/test/acceptance/named-maps-stats-test.js +++ b/test/acceptance/named-maps-stats-test.js @@ -1,6 +1,6 @@ 'use strict'; -var test_helper = require('../support/test-helper'); +var testHelper = require('../support/test-helper'); var RedisPool = require('redis-mpool'); var querystring = require('querystring'); @@ -11,7 +11,7 @@ var serverOptions = require('../../lib/server-options'); var TemplateMaps = require('../../lib/backends/template-maps'); var NamedMapsCacheEntry = require('../../lib/cache/model/named-maps-entry'); -describe('named maps preview stats', function() { +describe('named maps preview stats', function () { var server; before(function () { @@ -34,10 +34,10 @@ describe('named maps preview stats', function() { auth: { method: 'open' }, - "placeholders": { - "color": { - "type": "css_color", - "default": "#cc3300" + placeholders: { + color: { + type: 'css_color', + default: '#cc3300' } }, layergroup: { @@ -55,7 +55,6 @@ describe('named maps preview stats', function() { } }; - beforeEach(function (done) { templateMaps.addTemplate(username, template, done); }); @@ -64,8 +63,7 @@ describe('named maps preview stats', function() { templateMaps.delTemplate(username, templateName, done); }); - function getStaticMap(name, options, callback) { - + function getStaticMap (name, options, callback) { var url = '/api/v1/map/static/named/' + name + '/640/480.png'; if (options.params) { url = url + '?' + querystring.stringify(options.params); @@ -94,24 +92,24 @@ describe('named maps preview stats', function() { function (res, err) { var img; if (!err && res.headers['content-type'] === 'image/png') { - img = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); + img = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); } return callback(err, res, img); } ); } - it('should return 200 if properly authorized', function(done) { - getStaticMap(templateName, { params: { auth_token: 'valid1' } }, function(err, res, img) { + it('should return 200 if properly authorized', function (done) { + getStaticMap(templateName, { params: { auth_token: 'valid1' } }, function (err, res, img) { assert.ok(!err); - assert.equal(img.width(), 640); - assert.equal(img.height(), 480); + assert.strictEqual(img.width(), 640); + assert.strictEqual(img.height(), 480); - test_helper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, templateName).key()); + testHelper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, templateName).key()); var redisKeysToDelete = { 'user:localhost:mapviews:global': 5 }; redisKeysToDelete['user:localhost:mapviews:stat_tag:' + statTag] = 5; - test_helper.deleteRedisKeys(redisKeysToDelete, done); + testHelper.deleteRedisKeys(redisKeysToDelete, done); }); }); }); diff --git a/test/acceptance/overviews-metadata-named-maps-test.js b/test/acceptance/overviews-metadata-named-maps-test.js index 5dc11240..cbab9289 100644 --- a/test/acceptance/overviews-metadata-named-maps-test.js +++ b/test/acceptance/overviews-metadata-named-maps-test.js @@ -1,6 +1,6 @@ 'use strict'; -var test_helper = require('../support/test-helper'); +var testHelper = require('../support/test-helper'); var assert = require('../support/assert'); var CartodbWindshaft = require('../../lib/server'); @@ -14,7 +14,7 @@ var step = require('step'); var windshaft = require('windshaft'); -describe('overviews metadata for named maps', function() { +describe('overviews metadata for named maps', function () { var server; before(function () { @@ -24,7 +24,7 @@ describe('overviews metadata for named maps', function() { // configure redis pool instance to use in tests var redisPool = new RedisPool(global.environment.redis); - var overviews_layer = { + var overviewsLayer = { type: 'cartodb', options: { sql: 'SELECT * FROM test_table_overviews', @@ -33,7 +33,7 @@ describe('overviews metadata for named maps', function() { } }; - var non_overviews_layer = { + var nonOverviewsLayer = { type: 'cartodb', options: { sql: 'SELECT * FROM test_table', @@ -44,12 +44,12 @@ describe('overviews metadata for named maps', function() { var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { - test_helper.deleteRedisKeys(keysToDelete, done); + afterEach(function (done) { + testHelper.deleteRedisKeys(keysToDelete, done); }); var templateId = 'overviews-template-1'; @@ -58,38 +58,37 @@ describe('overviews metadata for named maps', function() { version: '0.0.1', name: templateId, auth: { method: 'open' }, - layergroup: { + layergroup: { version: '1.0.0', - layers: [overviews_layer, non_overviews_layer] + layers: [overviewsLayer, nonOverviewsLayer] } }; - it("should add overviews data to layers", function(done) { + it('should add overviews data to layers', function (done) { step( - function postTemplate() - { - var next = this; + 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); - }); + 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 checkTemplate(err, res) { + function checkTemplate (err, res) { assert.ifError(err); var next = this; - assert.equal(res.statusCode, 200); - assert.deepEqual(JSON.parse(res.body), { + assert.strictEqual(res.statusCode, 200); + assert.deepStrictEqual(JSON.parse(res.body), { template_id: templateId }); next(null); }, - function instantiateTemplate(err) { + function instantiateTemplate (err) { assert.ifError(err); var next = this; @@ -101,17 +100,16 @@ describe('overviews metadata for named maps', function() { 'Content-Type': 'application/json' } }, {}, - function(res, err) { + function (res, err) { return next(err, res); }); - }, - function checkInstanciation(err, res) { + function checkInstanciation (err, res) { assert.ifError(err); var next = this; - assert.equal(res.statusCode, 200); + assert.strictEqual(res.statusCode, 200); var parsedBody = JSON.parse(res.body); @@ -124,36 +122,35 @@ describe('overviews metadata for named maps', function() { next(null, parsedBody.layergroupid); }, - function checkMapconfig(err, layergroupId) - { + function checkMapconfig (err, layergroupId) { assert.ifError(err); var next = this; - var mapStore = new windshaft.storage.MapStore({ + var mapStore = new windshaft.storage.MapStore({ pool: redisPool, expire_time: 500000 }); - mapStore.load(LayergroupToken.parse(layergroupId).token, function(err, mapConfig) { + mapStore.load(LayergroupToken.parse(layergroupId).token, function (err, mapConfig) { assert.ifError(err); - assert.deepEqual(non_overviews_layer, mapConfig._cfg.layers[1]); - assert.equal(mapConfig._cfg.layers[0].type, 'cartodb'); + assert.deepStrictEqual(nonOverviewsLayer, mapConfig._cfg.layers[1]); + assert.strictEqual(mapConfig._cfg.layers[0].type, 'cartodb'); assert.ok(mapConfig._cfg.layers[0].options.query_rewrite_data); - var expected_data = { + var expectedData = { overviews: { test_table_overviews: { - schema: 'public', - 1: { table: '_vovw_1_test_table_overviews' }, - 2: { table: '_vovw_2_test_table_overviews' } - } - } - }; - assert.deepEqual(mapConfig._cfg.layers[0].options.query_rewrite_data, expected_data); + schema: 'public', + 1: { table: '_vovw_1_test_table_overviews' }, + 2: { table: '_vovw_2_test_table_overviews' } + } + } + }; + assert.deepStrictEqual(mapConfig._cfg.layers[0].options.query_rewrite_data, expectedData); }); next(err); }, - function deleteTemplate(err) { + function deleteTemplate (err) { assert.ifError(err); var next = this; @@ -166,23 +163,23 @@ describe('overviews metadata for named maps', function() { next(err, res); }); }, - function checkDeleteTemplate(err, res) { + function checkDeleteTemplate (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 204); + assert.strictEqual(res.statusCode, 204); assert.ok(!res.body); return null; }, - function finish(err) { + function finish (err) { done(err); } ); }); - describe('Overviews Flags', function() { - it("Overviews used", function (done) { + describe('Overviews Flags', function () { + it('Overviews used', function (done) { step( - function postTemplate() { + function postTemplate () { var next = this; assert.response(server, { @@ -194,7 +191,7 @@ describe('overviews metadata for named maps', function() { next(err, res); }); }, - function instantiateTemplate(err) { + function instantiateTemplate (err) { assert.ifError(err); var next = this; @@ -206,12 +203,11 @@ describe('overviews metadata for named maps', function() { 'Content-Type': 'application/json' } }, {}, - function (res, err) { - return next(err, res); - }); - + function (res, err) { + return next(err, res); + }); }, - function checkFlags(err, res) { + function checkFlags (err, res) { assert.ifError(err); var next = this; @@ -224,19 +220,18 @@ describe('overviews metadata for named maps', function() { const headers = JSON.parse(res.headers['x-tiler-profiler']); assert.ok(headers.overviewsAddedToMapconfig); - assert.equal(headers.mapType, 'named'); + assert.strictEqual(headers.mapType, 'named'); next(); }, - function finish(err) { + function finish (err) { done(err); } ); }); - it("Overviews NOT used", function (done) { - + it('Overviews NOT used', function (done) { const nonOverviewsTemplateId = 'non-overviews-template'; var nonOverviewsTemplate = { @@ -245,12 +240,12 @@ describe('overviews metadata for named maps', function() { auth: { method: 'open' }, layergroup: { version: '1.0.0', - layers: [non_overviews_layer] + layers: [nonOverviewsLayer] } }; step( - function postTemplate() { + function postTemplate () { var next = this; assert.response(server, { @@ -262,7 +257,7 @@ describe('overviews metadata for named maps', function() { next(err, res); }); }, - function instantiateTemplate(err) { + function instantiateTemplate (err) { assert.ifError(err); var next = this; @@ -274,12 +269,11 @@ describe('overviews metadata for named maps', function() { 'Content-Type': 'application/json' } }, {}, - function (res, err) { - return next(err, res); - }); - + function (res, err) { + return next(err, res); + }); }, - function checkFlags(err, res) { + function checkFlags (err, res) { assert.ifError(err); var next = this; @@ -291,13 +285,13 @@ describe('overviews metadata for named maps', function() { const headers = JSON.parse(res.headers['x-tiler-profiler']); - assert.equal(headers.overviewsAddedToMapconfig, false); - assert.equal(headers.mapType, 'named'); + assert.strictEqual(headers.overviewsAddedToMapconfig, false); + assert.strictEqual(headers.mapType, 'named'); next(); }, - function finish(err) { + function finish (err) { done(err); } ); diff --git a/test/acceptance/overviews-metadata-test.js b/test/acceptance/overviews-metadata-test.js index 92ab562a..b20e699c 100644 --- a/test/acceptance/overviews-metadata-test.js +++ b/test/acceptance/overviews-metadata-test.js @@ -1,6 +1,6 @@ 'use strict'; -var test_helper = require('../support/test-helper'); +var testHelper = require('../support/test-helper'); var assert = require('../support/assert'); var CartodbWindshaft = require('../../lib/server'); @@ -14,8 +14,7 @@ var step = require('step'); var windshaft = require('windshaft'); - -describe('overviews metadata', function() { +describe('overviews metadata', function () { var server; before(function () { @@ -25,7 +24,7 @@ describe('overviews metadata', function() { // configure redis pool instance to use in tests var redisPool = new RedisPool(global.environment.redis); - var overviews_layer = { + var overviewsLayer = { type: 'cartodb', options: { sql: 'SELECT * FROM test_table_overviews', @@ -34,7 +33,7 @@ describe('overviews metadata', function() { } }; - var non_overviews_layer = { + var nonOverviewsLayer = { type: 'cartodb', options: { sql: 'SELECT * FROM test_table', @@ -45,57 +44,54 @@ describe('overviews metadata', function() { var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { - test_helper.deleteRedisKeys(keysToDelete, done); + afterEach(function (done) { + testHelper.deleteRedisKeys(keysToDelete, done); }); - it("layers with and without overviews", function(done) { - - var layergroup = { + it('layers with and without overviews', function (done) { + var layergroup = { version: '1.0.0', - layers: [overviews_layer, non_overviews_layer] + layers: [overviewsLayer, nonOverviewsLayer] }; - var layergroup_url = '/api/v1/map'; + var layergroupUrl = '/api/v1/map'; - var expected_token; + var expectedToken; 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); + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - assert.equal(res.headers['x-layergroup-id'], parsedBody.layergroupid); - expected_token = parsedBody.layergroupid; - next(null, res); - }); + var parsedBody = JSON.parse(res.body); + assert.strictEqual(res.headers['x-layergroup-id'], parsedBody.layergroupid); + expectedToken = parsedBody.layergroupid; + next(null, res); + }); }, - function do_get_mapconfig(err) - { + function doGetMapconfig (err) { assert.ifError(err); var next = this; - var mapStore = new windshaft.storage.MapStore({ + var mapStore = new windshaft.storage.MapStore({ pool: redisPool, expire_time: 500000 }); - mapStore.load(LayergroupToken.parse(expected_token).token, function(err, mapConfig) { + mapStore.load(LayergroupToken.parse(expectedToken).token, function (err, mapConfig) { assert.ifError(err); - assert.deepEqual(non_overviews_layer, mapConfig._cfg.layers[1]); - assert.equal(mapConfig._cfg.layers[0].type, 'cartodb'); + assert.deepStrictEqual(nonOverviewsLayer, mapConfig._cfg.layers[1]); + assert.strictEqual(mapConfig._cfg.layers[0].type, 'cartodb'); assert.ok(mapConfig._cfg.layers[0].options.query_rewrite_data); - var expected_data = { + var expectedData = { overviews: { test_table_overviews: { schema: 'public', @@ -103,14 +99,14 @@ describe('overviews metadata', function() { 2: { table: '_vovw_2_test_table_overviews' } } } - }; - assert.deepEqual(mapConfig._cfg.layers[0].options.query_rewrite_data, expected_data); - }); + }; + assert.deepStrictEqual(mapConfig._cfg.layers[0].options.query_rewrite_data, expectedData); + }); - next(err); + next(err); }, - function finish(err) { - keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; + function finish (err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; done(err); } @@ -118,75 +114,75 @@ describe('overviews metadata', function() { }); describe('Overviews Flags', function () { - it("Overviews used", function (done) { + it('Overviews used', function (done) { var layergroup = { version: '1.0.0', - layers: [overviews_layer, non_overviews_layer] + layers: [overviewsLayer, nonOverviewsLayer] }; - var layergroup_url = '/api/v1/map'; + var layergroupUrl = '/api/v1/map'; - var expected_token; + var expectedToken; step( - function do_post() { + function doPost () { var next = this; assert.response(server, { - url: layergroup_url, + url: layergroupUrl, method: 'POST', headers: { host: 'localhost', 'Content-Type': 'application/json' }, data: JSON.stringify(layergroup) }, {}, function (res) { - assert.equal(res.statusCode, 200, res.body); + assert.strictEqual(res.statusCode, 200, res.body); const headers = JSON.parse(res.headers['x-tiler-profiler']); assert.ok(headers.overviewsAddedToMapconfig); - assert.equal(headers.mapType, 'anonymous'); + assert.strictEqual(headers.mapType, 'anonymous'); const parsedBody = JSON.parse(res.body); - expected_token = parsedBody.layergroupid; + expectedToken = parsedBody.layergroupid; next(); }); }, - function finish(err) { - keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; + function finish (err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; done(err); } ); }); - it("Overviews NOT used", function (done) { + it('Overviews NOT used', function (done) { var layergroup = { version: '1.0.0', - layers: [non_overviews_layer] + layers: [nonOverviewsLayer] }; - var layergroup_url = '/api/v1/map'; + var layergroupUrl = '/api/v1/map'; - var expected_token; + var expectedToken; step( - function do_post() { + function doPost () { var next = this; assert.response(server, { - url: layergroup_url, + url: layergroupUrl, method: 'POST', headers: { host: 'localhost', 'Content-Type': 'application/json' }, data: JSON.stringify(layergroup) }, {}, function (res) { - assert.equal(res.statusCode, 200, res.body); + assert.strictEqual(res.statusCode, 200, res.body); const headers = JSON.parse(res.headers['x-tiler-profiler']); - assert.equal(headers.overviewsAddedToMapconfig, false); - assert.equal(headers.mapType, 'anonymous'); + assert.strictEqual(headers.overviewsAddedToMapconfig, false); + assert.strictEqual(headers.mapType, 'anonymous'); const parsedBody = JSON.parse(res.body); - expected_token = parsedBody.layergroupid; + expectedToken = parsedBody.layergroupid; next(); }); }, - function finish(err) { - keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; + function finish (err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; done(err); } @@ -195,7 +191,7 @@ describe('overviews metadata', function() { }); }); -describe('overviews metadata with filters', function() { +describe('overviews metadata with filters', function () { var server; before(function () { @@ -207,33 +203,32 @@ describe('overviews metadata with filters', function() { var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { - test_helper.deleteRedisKeys(keysToDelete, done); + afterEach(function (done) { + testHelper.deleteRedisKeys(keysToDelete, done); }); - it("layers with overviews", function(done) { - - var layergroup = { + it('layers with overviews', function (done) { + var layergroup = { version: '1.5.0', layers: [ - { - type: 'cartodb', - options: { - sql: 'SELECT * FROM test_table_overviews', - source: { id: 'with_overviews' }, - cartocss: '#layer { marker-fill: black; }', - cartocss_version: '2.3.0' - } - } + { + type: 'cartodb', + options: { + sql: 'SELECT * FROM test_table_overviews', + source: { id: 'with_overviews' }, + cartocss: '#layer { marker-fill: black; }', + cartocss_version: '2.3.0' + } + } ], - dataviews: { + dataviews: { test_names: { type: 'aggregation', - source: {id: 'with_overviews'}, + source: { id: 'with_overviews' }, options: { column: 'name', aggregation: 'count' @@ -241,10 +236,11 @@ describe('overviews metadata with filters', function() { } }, analyses: [ - { id: 'with_overviews', + { + id: 'with_overviews', type: 'source', params: { - query: 'select * from test_table_overviews' + query: 'select * from test_table_overviews' } } ] @@ -256,40 +252,38 @@ describe('overviews metadata with filters', function() { } }; - var layergroup_url = '/api/v1/map'; + var layergroupUrl = '/api/v1/map'; - var expected_token; + var expectedToken; step( - function do_post() - { - var next = this; - assert.response(server, { - url: layergroup_url + '?filters=' + JSON.stringify(filters), - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - 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; - next(null, res); - }); + function doPost () { + var next = this; + assert.response(server, { + url: layergroupUrl + '?filters=' + JSON.stringify(filters), + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + assert.strictEqual(res.headers['x-layergroup-id'], parsedBody.layergroupid); + expectedToken = parsedBody.layergroupid; + next(null, res); + }); }, - function do_get_mapconfig(err) - { + function doGetMapconfig (err) { assert.ifError(err); var next = this; - var mapStore = new windshaft.storage.MapStore({ + var mapStore = new windshaft.storage.MapStore({ pool: redisPool, expire_time: 500000 }); - mapStore.load(LayergroupToken.parse(expected_token).token, function(err, mapConfig) { + mapStore.load(LayergroupToken.parse(expectedToken).token, function (err, mapConfig) { assert.ifError(err); - assert.equal(mapConfig._cfg.layers[0].type, 'cartodb'); + assert.strictEqual(mapConfig._cfg.layers[0].type, 'cartodb'); assert.ok(mapConfig._cfg.layers[0].options.query_rewrite_data); - var expected_data = { + var expectedData = { overviews: { test_table_overviews: { schema: 'public', @@ -297,18 +291,17 @@ describe('overviews metadata with filters', function() { 2: { table: '_vovw_2_test_table_overviews' } } }, - filters: { test_names: { type: 'category', column: 'name', params: { accept: [ 'Hawai' ] } } }, + filters: { test_names: { type: 'category', column: 'name', params: { accept: ['Hawai'] } } }, unfiltered_query: 'select * from test_table_overviews', filter_stats: { unfiltered_rows: 5, filtered_rows: 1 } - }; - assert.deepEqual(mapConfig._cfg.layers[0].options.query_rewrite_data, expected_data); + }; + assert.deepStrictEqual(mapConfig._cfg.layers[0].options.query_rewrite_data, expectedData); + }); - }); - - next(err); + next(err); }, - function finish(err) { - keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; + function finish (err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; done(err); } diff --git a/test/acceptance/overviews-queries-test.js b/test/acceptance/overviews-queries-test.js index b89b3660..2a15f6a7 100644 --- a/test/acceptance/overviews-queries-test.js +++ b/test/acceptance/overviews-queries-test.js @@ -7,7 +7,7 @@ var cartodbServer = require('../../lib/server'); var ServerOptions = require('./ported/support/ported-server-options'); var testClient = require('./ported/support/test-client'); -describe('overviews_queries', function() { +describe('overviews_queries', function () { var server; before(function () { @@ -17,12 +17,12 @@ describe('overviews_queries', function() { var IMAGE_EQUALS_TOLERANCE_PER_MIL = 2; - after(function() { + after(function () { testHelper.rmdirRecursiveSync(global.environment.millstone.cache_basedir); }); - function imageCompareFn(fixture, done) { - return function(err, tile) { + function imageCompareFn (fixture, done) { + return function (err, tile) { if (err) { return done(err); } @@ -31,39 +31,39 @@ describe('overviews_queries', function() { }; } - it("should not use overview for tables without overviews", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table'), 1, 0, 0, - imageCompareFn('test_table_1_0_0.png', done) - ); + it('should not use overview for tables without overviews', function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table'), 1, 0, 0, + imageCompareFn('test_table_1_0_0.png', done) + ); }); - it("should not use overview for tables without overviews at z=2", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table'), 2, 1, 1, - imageCompareFn('test_table_2_1_1.png', done) - ); + it('should not use overview for tables without overviews at z=2', function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table'), 2, 1, 1, + imageCompareFn('test_table_2_1_1.png', done) + ); }); - it("should not use overview for tables without overviews at z=2", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table'), 3, 3, 3, - imageCompareFn('test_table_3_3_3.png', done) - ); + it('should not use overview for tables without overviews at z=2', function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table'), 3, 3, 3, + imageCompareFn('test_table_3_3_3.png', done) + ); }); - it("should use overview for zoom level 1", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table_overviews'), 1, 0, 0, - imageCompareFn('_vovw_1_test_table_1_0_0.png', done) - ); + it('should use overview for zoom level 1', function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table_overviews'), 1, 0, 0, + imageCompareFn('_vovw_1_test_table_1_0_0.png', done) + ); }); - it("should use overview for zoom level 1", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table_overviews'), 2, 1, 1, - imageCompareFn('_vovw_2_test_table_2_1_1.png', done) - ); + it('should use overview for zoom level 1', function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table_overviews'), 2, 1, 1, + imageCompareFn('_vovw_2_test_table_2_1_1.png', done) + ); }); - it("should not use overview for zoom level 3", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table_overviews'), 3, 3, 3, - imageCompareFn('test_table_3_3_3.png', done) - ); + it('should not use overview for zoom level 3', function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table_overviews'), 3, 3, 3, + imageCompareFn('test_table_3_3_3.png', done) + ); }); }); diff --git a/test/acceptance/ported/attributes-test.js b/test/acceptance/ported/attributes-test.js index 86527e2f..4eb8b0fd 100644 --- a/test/acceptance/ported/attributes-test.js +++ b/test/acceptance/ported/attributes-test.js @@ -8,7 +8,7 @@ var cartodbServer = require('../../../lib/server'); var PortedServerOptions = require('./support/ported-server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('attributes', function() { +describe('attributes', function () { var server; before(function () { @@ -16,46 +16,51 @@ describe('attributes', function() { server.setMaxListeners(0); }); - var test_mapconfig_1 = { + var testMapconfig1 = { version: '1.1.0', layers: [ - { type: 'mapnik', options: { - sql: "select 1 as id, 'SRID=4326;POINT(0 0)'::geometry as the_geom", - cartocss: '#style { }', - cartocss_version: '2.0.1' - } }, - { type: 'mapnik', options: { - sql: "select 1 as i, 6 as n, 'SRID=4326;POINT(0 0)'::geometry as the_geom", - attributes: { id:'i', columns: ['n'] }, - cartocss: '#style { }', - cartocss_version: '2.0.1' - } } + { + type: 'mapnik', + options: { + sql: "select 1 as id, 'SRID=4326;POINT(0 0)'::geometry as the_geom", + cartocss: '#style { }', + cartocss_version: '2.0.1' + } + }, + { + type: 'mapnik', + options: { + sql: "select 1 as i, 6 as n, 'SRID=4326;POINT(0 0)'::geometry as the_geom", + attributes: { id: 'i', columns: ['n'] }, + cartocss: '#style { }', + cartocss_version: '2.0.1' + } + } ] }; - function checkCORSHeaders(res) { - assert.equal( + function checkCORSHeaders (res) { + assert.strictEqual( res.headers['access-control-allow-headers'], 'X-Requested-With, X-Prototype-Version, X-CSRF-Token, Authorization' ); - assert.equal(res.headers['access-control-allow-origin'], '*'); + assert.strictEqual(res.headers['access-control-allow-origin'], '*'); } var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { + afterEach(function (done) { testHelper.deleteRedisKeys(keysToDelete, done); }); - it("can only be fetched from layer having an attributes spec", function(done) { - var expected_token; + it('can only be fetched from layer having an attributes spec', function (done) { + var expectedToken; step( - function do_post() - { + function doPost () { var next = this; assert.response(server, { url: '/api/v1/map', @@ -64,109 +69,103 @@ describe('attributes', function() { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(test_mapconfig_1) - }, {}, function(res, err) { next(err, res); }); + data: JSON.stringify(testMapconfig1) + }, {}, function (res, err) { next(err, res); }); }, - function checkPost(err, res) { + function checkPost (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); // CORS headers should be sent with response // from layergroup creation via POST checkCORSHeaders(res); var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 2}); + if (expectedToken) { + assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 2 }); } else { - expected_token = parsedBody.layergroupid; + expectedToken = parsedBody.layergroupid; } return null; }, - function do_get_attr_0(err) - { + function doGetAttr0 (err) { assert.ifError(err); var next = this; assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/attributes/1', + url: '/api/v1/map/' + expectedToken + '/0/attributes/1', method: 'GET', headers: { host: 'localhost' - }, - }, {}, function(res, err) { next(err, res); }); + } + }, {}, function (res, err) { next(err, res); }); }, - function check_error_0(err, res) { + function checkError0 (err, res) { assert.ifError(err); - assert.equal( + assert.strictEqual( res.statusCode, 400, - res.statusCode + ( res.statusCode !== 200 ? (': ' + res.body) : '' ) + res.statusCode + (res.statusCode !== 200 ? (': ' + res.body) : '') ); var parsed = JSON.parse(res.body); - assert.equal(parsed.errors[0], "Layer 0 has no exposed attributes"); + assert.strictEqual(parsed.errors[0], 'Layer 0 has no exposed attributes'); return null; }, - function do_get_attr_1(err) - { + function doGetAttr1 (err) { assert.ifError(err); var next = this; assert.response(server, { - url: '/api/v1/map/' + expected_token + '/1/attributes/1', + url: '/api/v1/map/' + expectedToken + '/1/attributes/1', method: 'GET', headers: { host: 'localhost' } - }, {}, function(res, err) { next(err, res); }); + }, {}, function (res, err) { next(err, res); }); }, - function check_attr_1(err, res) { + function checkAttr1 (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); var parsed = JSON.parse(res.body); - assert.deepEqual(parsed, {"n":6}); + assert.deepStrictEqual(parsed, { n: 6 }); return null; }, - function do_get_attr_1_404(err) - { + function doGetAttr1404 (err) { assert.ifError(err); var next = this; assert.response(server, { - url: '/api/v1/map/' + expected_token + '/1/attributes/-666', + url: '/api/v1/map/' + expectedToken + '/1/attributes/-666', method: 'GET', headers: { host: 'localhost' } - }, {}, function(res, err) { next(err, res); }); + }, {}, function (res, err) { next(err, res); }); }, - function check_attr_1_404(err, res) { + function checkAttr1404 (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 404, res.statusCode + ': ' + res.body); + assert.strictEqual(res.statusCode, 404, res.statusCode + ': ' + res.body); var parsed = JSON.parse(res.body); assert.ok(parsed.errors); var msg = parsed.errors[0]; - assert.equal(msg, "Multiple features (0) identified by 'i' = -666 in layer 1"); + assert.strictEqual(msg, "Multiple features (0) identified by 'i' = -666 in layer 1"); return null; }, - function finish(err) { - keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; + function finish (err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; - done(err); } ); }); // See https://github.com/CartoDB/Windshaft/issues/131 - it("are checked at map creation time", function(done) { - + it('are checked at map creation time', function (done) { // clone the mapconfig test - var mapconfig = JSON.parse(JSON.stringify(test_mapconfig_1)); + var mapconfig = JSON.parse(JSON.stringify(testMapconfig1)); // append unexistant attribute name mapconfig.layers[1].options.sql = 'SELECT * FROM test_table'; mapconfig.layers[1].options.attributes.id = 'unexistant'; mapconfig.layers[1].options.attributes.columns = ['cartodb_id']; step( - function do_post() - { + function doPost () { var next = this; assert.response(server, { url: '/api/v1/map', @@ -176,30 +175,28 @@ describe('attributes', function() { 'Content-Type': 'application/json' }, data: JSON.stringify(mapconfig) - }, {}, function(res, err) { next(err, res); }); + }, {}, function (res, err) { next(err, res); }); }, - function checkPost(err, res) { + function checkPost (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 404, res.statusCode + ': ' + (res.statusCode===200?'...':res.body)); + assert.strictEqual(res.statusCode, 404, res.statusCode + ': ' + (res.statusCode === 200 ? '...' : res.body)); var parsed = JSON.parse(res.body); assert.ok(parsed.errors); - assert.equal(parsed.errors.length, 1); + assert.strictEqual(parsed.errors.length, 1); var msg = parsed.errors[0]; - assert.equal(msg, 'column "unexistant" does not exist'); + assert.strictEqual(msg, 'column "unexistant" does not exist'); return null; }, - function finish(err) { + function finish (err) { done(err); } ); }); - it("can be used with jsonp", function(done) { - - var expected_token; + it('can be used with jsonp', function (done) { + var expectedToken; step( - function do_post() - { + function doPost () { var next = this; assert.response(server, { url: '/api/v1/map', @@ -208,41 +205,40 @@ describe('attributes', function() { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(test_mapconfig_1) - }, {}, function(res, err) { next(err, res); }); + data: JSON.stringify(testMapconfig1) + }, {}, function (res, err) { next(err, res); }); }, - function checkPost(err, res) { + function checkPost (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); // CORS headers should be sent with response // from layergroup creation via POST checkCORSHeaders(res); var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 2}); + if (expectedToken) { + assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 2 }); } else { - expected_token = parsedBody.layergroupid; + expectedToken = parsedBody.layergroupid; } return null; }, - function do_get_attr_0(err) - { + function doGetAttr0 (err) { assert.ifError(err); var next = this; assert.response(server, { - url: '/api/v1/map/' + expected_token + + url: '/api/v1/map/' + expectedToken + '/0/attributes/1?callback=test', method: 'GET', headers: { host: 'localhost' } - }, {}, function(res, err) { next(err, res); }); + }, {}, function (res, err) { next(err, res); }); }, - function check_error_0(err, res) { + function checkError0 (err, res) { assert.ifError(err); // jsonp errors should be returned with HTTP status 200 - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - assert.equal( + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + assert.strictEqual( res.body, '/**/ typeof test === \'function\' && ' + 'test({"errors":["Layer 0 has no exposed attributes"],' + @@ -252,27 +248,26 @@ describe('attributes', function() { ); return null; }, - function do_get_attr_1(err) - { + function doGetAttr1 (err) { assert.ifError(err); var next = this; assert.response(server, { - url: '/api/v1/map/' + expected_token + '/1/attributes/1', + url: '/api/v1/map/' + expectedToken + '/1/attributes/1', method: 'GET', headers: { host: 'localhost' } - }, {}, function(res, err) { next(err, res); }); + }, {}, function (res, err) { next(err, res); }); }, - function check_attr_1(err, res) { + function checkAttr1 (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); var parsed = JSON.parse(res.body); - assert.deepEqual(parsed, {"n":6}); + assert.deepStrictEqual(parsed, { n: 6 }); return null; }, - function finish(err) { - keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; + function finish (err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; done(err); @@ -284,17 +279,15 @@ describe('attributes', function() { // // Test for http://github.com/CartoDB/Windshaft/issues/130 // - it("database access is read-only", function(done) { - + it('database access is read-only', function (done) { // clone the mapconfig test - var mapconfig = JSON.parse(JSON.stringify(test_mapconfig_1)); + var mapconfig = JSON.parse(JSON.stringify(testMapconfig1)); mapconfig.layers[1].options.sql += ", test_table_inserter(st_setsrid(st_point(0,0),4326),'write') as w"; mapconfig.layers[1].options.attributes.columns.push('w'); step( - function do_post() - { + function doPost () { var next = this; assert.response(server, { url: '/api/v1/map', @@ -304,23 +297,22 @@ describe('attributes', function() { 'Content-Type': 'application/json' }, data: JSON.stringify(mapconfig) - }, {}, function(res, err) { next(err, res); }); + }, {}, function (res, err) { next(err, res); }); }, - function checkPost(err, res) { + function checkPost (err, res) { assert.ifError(err); // TODO: should be 403 Forbidden - assert.equal(res.statusCode, 400, res.statusCode + ': ' + (res.statusCode===200?'...':res.body)); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + (res.statusCode === 200 ? '...' : res.body)); var parsed = JSON.parse(res.body); assert.ok(parsed.errors); - assert.equal(parsed.errors.length, 1); + assert.strictEqual(parsed.errors.length, 1); var msg = parsed.errors[0]; - assert.equal(msg, "cannot execute INSERT in a read-only transaction"); + assert.strictEqual(msg, 'cannot execute INSERT in a read-only transaction'); return null; }, - function finish(err) { + function finish (err) { done(err); } ); }); - }); diff --git a/test/acceptance/ported/blend-filtering-test.js b/test/acceptance/ported/blend-filtering-test.js index 2bb5ca9e..7a5d04e7 100644 --- a/test/acceptance/ported/blend-filtering-test.js +++ b/test/acceptance/ported/blend-filtering-test.js @@ -5,28 +5,32 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var testClient = require('./support/test-client'); var fs = require('fs'); +var path = require('path'); var http = require('http'); -describe('blend layer filtering', function() { - +describe('blend layer filtering', function () { var IMG_TOLERANCE_PER_MIL = 20; var httpRendererResourcesServer; - before(function(done) { + before(function (done) { // Start a server to test external resources - httpRendererResourcesServer = http.createServer( function(request, response) { - var filename = __dirname + '/../../fixtures/http/light_nolabels-1-0-0.png'; - fs.readFile(filename, {encoding: 'binary'}, function(err, file) { + httpRendererResourcesServer = http.createServer(function (request, response) { + var filename = path.join(__dirname, '/../../fixtures/http/light_nolabels-1-0-0.png'); + fs.readFile(filename, { encoding: 'binary' }, function (err, file) { + if (err) { + return done(err); + } + response.writeHead(200); - response.write(file, "binary"); + response.write(file, 'binary'); response.end(); }); }); httpRendererResourcesServer.listen(8033, done); }); - after(function(done) { + after(function (done) { httpRendererResourcesServer.close(done); }); @@ -58,7 +62,7 @@ describe('blend layer filtering', function() { { type: 'torque', options: { - sql: "SELECT * FROM populated_places_simple_reduced", + sql: 'SELECT * FROM populated_places_simple_reduced', cartocss: [ 'Map {', ' buffer-size:0;', @@ -93,8 +97,8 @@ describe('blend layer filtering', function() { { type: 'torque', options: { - sql: "SELECT * FROM populated_places_simple_reduced " + - "where the_geom && ST_MakeEnvelope(-90, 0, 90, 65)", + sql: 'SELECT * FROM populated_places_simple_reduced ' + + 'where the_geom && ST_MakeEnvelope(-90, 0, 90, 65)', cartocss: [ 'Map {', ' buffer-size:0;', @@ -134,11 +138,11 @@ describe('blend layer filtering', function() { [1, 2, 3, 4] ]; - function blendPngFixture(layers) { + function blendPngFixture (layers) { return './test/fixtures/blend/blend-filtering-layers-' + layers.join('.') + '-zxy-1.0.0.png'; } - filteredLayersSuite.forEach(function(filteredLayers) { + filteredLayersSuite.forEach(function (filteredLayers) { var layerFilter = filteredLayers.join(','); var tileRequest = { z: 1, @@ -149,9 +153,10 @@ describe('blend layer filtering', function() { }; it('should filter on ' + layerFilter + '/1/0/0.png', function (done) { - testClient.getTileLayer(mapConfig, tileRequest, function(err, res) { + testClient.getTileLayer(mapConfig, tileRequest, function (err, res) { + assert.ifError(err); assert.imageBufferIsSimilarToFile(res.body, blendPngFixture(filteredLayers), IMG_TOLERANCE_PER_MIL, - function(err) { + function (err) { assert.ok(!err); done(); } diff --git a/test/acceptance/ported/blend-http-fallback-test.js b/test/acceptance/ported/blend-http-fallback-test.js index f2dc1d8b..d9619583 100644 --- a/test/acceptance/ported/blend-http-fallback-test.js +++ b/test/acceptance/ported/blend-http-fallback-test.js @@ -6,27 +6,30 @@ var assert = require('../../support/assert'); var testClient = require('./support/test-client'); var fs = require('fs'); var http = require('http'); +var path = require('path'); -describe('blend http fallback', function() { - +describe('blend http fallback', function () { var IMG_TOLERANCE_PER_MIL = 20; var httpRendererResourcesServer; - before(function(done) { + before(function (done) { // Start a server to test external resources - httpRendererResourcesServer = http.createServer( function(request, response) { + httpRendererResourcesServer = http.createServer(function (request, response) { if (request.url.match(/^\/error404\//)) { response.writeHead(404); response.end(); } else { - var filename = __dirname + '/../../fixtures/http/light_nolabels-1-0-0.png'; + var filename = path.join(__dirname, '/../../fixtures/http/light_nolabels-1-0-0.png'); if (request.url.match(/^\/dark\//)) { - filename = __dirname + '/../../fixtures/http/dark_nolabels-1-0-0.png'; + filename = path.join(__dirname, '/../../fixtures/http/dark_nolabels-1-0-0.png'); } - fs.readFile(filename, {encoding: 'binary'}, function(err, file) { + fs.readFile(filename, { encoding: 'binary' }, function (err, file) { + if (err) { + return done(err); + } response.writeHead(200); - response.write(file, "binary"); + response.write(file, 'binary'); response.end(); }); } @@ -34,7 +37,7 @@ describe('blend http fallback', function() { httpRendererResourcesServer.listen(8033, done); }); - after(function(done) { + after(function (done) { httpRendererResourcesServer.close(done); }); @@ -81,7 +84,7 @@ describe('blend http fallback', function() { }; var filteredLayersSuite = [ - //['all'], // layers displayed: 2 + 4, skipping 3 as it fails + // ['all'], // layers displayed: 2 + 4, skipping 3 as it fails [0, 4], [0, 3], // skips layer 3 as it fails [1, 2], @@ -90,11 +93,11 @@ describe('blend http fallback', function() { [3, 4] ]; - function blendPngFixture(layers) { + function blendPngFixture (layers) { return './test/fixtures/blend/http_fallback/blend-layers-' + layers.join('.') + '-zxy-1.0.0.png'; } - filteredLayersSuite.forEach(function(filteredLayers) { + filteredLayersSuite.forEach(function (filteredLayers) { var layerFilter = filteredLayers.join(','); var tileRequest = { z: 1, @@ -105,9 +108,10 @@ describe('blend http fallback', function() { }; it('should fallback on http error while blending layers ' + layerFilter + '/1/0/0.png', function (done) { - testClient.getTileLayer(mapConfig, tileRequest, function(err, res) { + testClient.getTileLayer(mapConfig, tileRequest, function (err, res) { + assert.ifError(err); assert.imageBufferIsSimilarToFile(res.body, blendPngFixture(filteredLayers), IMG_TOLERANCE_PER_MIL, - function(err) { + function (err) { assert.ok(!err, err); done(); } @@ -116,7 +120,7 @@ describe('blend http fallback', function() { }); }); - it('should keep failing when http layer is requested individually', function(done) { + it('should keep failing when http layer is requested individually', function (done) { var tileRequest = { z: 1, x: 0, @@ -130,11 +134,11 @@ describe('blend http fallback', function() { 'Content-Type': 'application/json; charset=utf-8' } }; - testClient.getTileLayer(mapConfig, tileRequest, expectedResponse, function(err, res) { + testClient.getTileLayer(mapConfig, tileRequest, expectedResponse, function (err, res) { assert.ok(!err); var parsedBody = JSON.parse(res.body); - assert.deepEqual(parsedBody.errors, [ - "Unable to fetch http tile: http://127.0.0.1:8033/error404/1/0/0.png [404]" + assert.deepStrictEqual(parsedBody.errors, [ + 'Unable to fetch http tile: http://127.0.0.1:8033/error404/1/0/0.png [404]' ]); done(); }); diff --git a/test/acceptance/ported/blend-http-timeout-test.js b/test/acceptance/ported/blend-http-timeout-test.js index d71c6868..f904dc57 100644 --- a/test/acceptance/ported/blend-http-timeout-test.js +++ b/test/acceptance/ported/blend-http-timeout-test.js @@ -7,8 +7,9 @@ var testClient = require('./support/test-client'); var serverOptions = require('./support/ported-server-options'); var fs = require('fs'); var http = require('http'); +var path = require('path'); -describe.skip('blend http client timeout', function() { +describe.skip('blend http client timeout', function () { var mapConfig = { version: '1.3.0', layers: [ @@ -36,17 +37,21 @@ describe.skip('blend http client timeout', function() { var slowHttpRendererResourcesServer; - before(function(done) { + before(function (done) { oldHttpRendererTimeout = serverOptions.renderer.http.timeout; serverOptions.renderer.http.timeout = httpRendererTimeout; // Start a server to test external resources - slowHttpRendererResourcesServer = http.createServer( function(request, response) { - setTimeout(function() { - var filename = __dirname + '/../fixtures/http/light_nolabels-1-0-0.png'; - fs.readFile(filename, {encoding: 'binary'}, function(err, file) { + slowHttpRendererResourcesServer = http.createServer(function (request, response) { + setTimeout(function () { + var filename = path.join(__dirname, '/../fixtures/http/light_nolabels-1-0-0.png'); + fs.readFile(filename, { encoding: 'binary' }, function (err, file) { + if (err) { + return done(err); + } + response.writeHead(200); - response.write(file, "binary"); + response.write(file, 'binary'); response.end(); }); }, httpRendererTimeout * 2); @@ -54,30 +59,30 @@ describe.skip('blend http client timeout', function() { slowHttpRendererResourcesServer.listen(8033, done); }); - after(function(done) { + after(function (done) { serverOptions.renderer.http.timeout = oldHttpRendererTimeout; slowHttpRendererResourcesServer.close(done); }); - it('should fail to render when http layer times out', function(done) { + it('should fail to render when http layer times out', function (done) { var options = { statusCode: 400, contentType: 'application/json; charset=utf-8', serverOptions: serverOptions }; - testClient.withLayergroup(mapConfig, options, function(err, requestTile, finish) { + testClient.withLayergroup(mapConfig, options, function (err, requestTile, finish) { + assert.ifError(err); var tileUrl = '/all/0/0/0.png'; - requestTile(tileUrl, options, function(err, res) { + requestTile(tileUrl, options, function (err, res) { assert.ok(!err); var parsedBody = JSON.parse(res.body); assert.ok(parsedBody.errors); assert.ok(parsedBody.errors.length); - assert.equal(parsedBody.errors[0], 'Unable to fetch http tile: http://127.0.0.1:8033/light/0/0/0.png'); - finish(function(finishErr) { + assert.strictEqual(parsedBody.errors[0], 'Unable to fetch http tile: http://127.0.0.1:8033/light/0/0/0.png'); + finish(function (finishErr) { done(err || finishErr); }); }); }); }); - }); diff --git a/test/acceptance/ported/blend-test.js b/test/acceptance/ported/blend-test.js index 269b35fd..b102e776 100644 --- a/test/acceptance/ported/blend-test.js +++ b/test/acceptance/ported/blend-test.js @@ -5,10 +5,10 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var testClient = require('./support/test-client'); -describe('blend png renderer', function() { +describe('blend png renderer', function () { var IMAGE_TOLERANCE_PER_MIL = 20; - function plainTorqueMapConfig(plainColor) { + function plainTorqueMapConfig (plainColor) { return { version: '1.2.0', layers: [ @@ -21,8 +21,8 @@ describe('blend png renderer', function() { { type: 'torque', options: { - sql: "SELECT * FROM populated_places_simple_reduced " + - "where the_geom && ST_MakeEnvelope(-90, 0, 90, 65)", + sql: 'SELECT * FROM populated_places_simple_reduced ' + + 'where the_geom && ST_MakeEnvelope(-90, 0, 90, 65)', cartocss: [ 'Map {', ' buffer-size:0;', @@ -74,17 +74,18 @@ describe('blend png renderer', function() { } ]; - function blendPngFixture(zxy) { + function blendPngFixture (zxy) { return './test/fixtures/blend/blend-plain-torque-' + zxy.join('.') + '.png'; } - testScenarios.forEach(function(testScenario) { + testScenarios.forEach(function (testScenario) { var tileRequest = testScenario.tile; var zxy = [tileRequest.z, tileRequest.x, tileRequest.y]; it('tile all/' + zxy.join('/') + '.png', function (done) { - testClient.getTileLayer(plainTorqueMapConfig(testScenario.plainColor), tileRequest, function(err, res) { + testClient.getTileLayer(plainTorqueMapConfig(testScenario.plainColor), tileRequest, function (err, res) { + assert.ifError(err); assert.imageBufferIsSimilarToFile(res.body, blendPngFixture(zxy), IMAGE_TOLERANCE_PER_MIL, - function(err) { + function (err) { assert.ok(!err); done(); } diff --git a/test/acceptance/ported/external-resources-test.js b/test/acceptance/ported/external-resources-test.js index 6ac05df1..3e834c16 100644 --- a/test/acceptance/ported/external-resources-test.js +++ b/test/acceptance/ported/external-resources-test.js @@ -8,36 +8,36 @@ var PortedServerOptions = require('./support/ported-server-options'); var http = require('http'); var testClient = require('./support/test-client'); var nock = require('nock'); +var path = require('path'); -describe('external resources', function() { - - var res_serv; // resources server - var res_serv_status = { numrequests:0 }; // status of resources server - var res_serv_port; +describe('external resources', function () { + var resServ; // resources server + var resServStatus = { numrequests: 0 }; // status of resources server + var resServPort; var IMAGE_EQUALS_TOLERANCE_PER_MIL = 25; - before(function(done) { + before(function (done) { // Start a server to test external resources - res_serv = http.createServer( function(request, response) { - ++res_serv_status.numrequests; - var filename = __dirname + '/../../fixtures/markers' + request.url; - fs.readFile(filename, "binary", function(err, file) { - if ( err ) { - response.writeHead(404, {'Content-Type': 'text/plain'}); - response.write("404 Not Found\n"); - } else { - response.writeHead(200); - response.write(file, "binary"); - } - response.end(); + resServ = http.createServer(function (request, response) { + ++resServStatus.numrequests; + var filename = path.join(__dirname, '/../../fixtures/markers', request.url); + fs.readFile(filename, 'binary', function (err, file) { + if (err) { + response.writeHead(404, { 'Content-Type': 'text/plain' }); + response.write('404 Not Found\n'); + } else { + response.writeHead(200); + response.write(file, 'binary'); + } + response.end(); }); }); const host = '127.0.0.1'; - const markersServer = res_serv.listen(0); + const markersServer = resServ.listen(0); - res_serv_port = markersServer.address().port; + resServPort = markersServer.address().port; nock.disableNetConnect(); nock.enableNetConnect(host); @@ -45,18 +45,18 @@ describe('external resources', function() { markersServer.on('listening', done); }); - after(function(done) { + after(function (done) { testHelper.rmdirRecursiveSync(global.environment.millstone.cache_basedir); nock.cleanAll(); nock.enableNetConnect(); // Close the resources server - res_serv.close(done); + resServ.close(done); }); - function imageCompareFn(fixture, done) { - return function(err, res) { + function imageCompareFn (fixture, done) { + return function (err, res) { if (err) { return done(err); } @@ -65,18 +65,16 @@ describe('external resources', function() { }; } - it("basic external resource", function(done) { - - var circleStyle = "#test_table_3 { marker-file: url('http://127.0.0.1:" + res_serv_port + + it('basic external resource', function (done) { + var circleStyle = "#test_table_3 { marker-file: url('http://127.0.0.1:" + resServPort + "/circle.svg'); marker-transform:'scale(0.2)'; }"; testClient.getTile(testClient.defaultTableMapConfig('test_table_3', circleStyle), 13, 4011, 3088, imageCompareFn('test_table_13_4011_3088_svg1.png', done)); }); - it("different external resource", function(done) { - - var squareStyle = "#test_table_3 { marker-file: url('http://127.0.0.1:" + res_serv_port + + it('different external resource', function (done) { + var squareStyle = "#test_table_3 { marker-file: url('http://127.0.0.1:" + resServPort + "/square.svg'); marker-transform:'scale(0.2)'; }"; testClient.getTile(testClient.defaultTableMapConfig('test_table_3', squareStyle), 13, 4011, 3088, @@ -84,30 +82,29 @@ describe('external resources', function() { }); // See http://github.com/CartoDB/Windshaft/issues/107 - it("external resources get localized on renderer creation if not locally cached", function(done) { - + it('external resources get localized on renderer creation if not locally cached', function (done) { var options = { serverOptions: PortedServerOptions }; - var externalResourceStyle = "#test_table_3{marker-file: url('http://127.0.0.1:" + res_serv_port + + var externalResourceStyle = "#test_table_3{marker-file: url('http://127.0.0.1:" + resServPort + "/square.svg'); marker-transform:'scale(0.2)'; }"; var externalResourceMapConfig = testClient.defaultTableMapConfig('test_table_3', externalResourceStyle); - testClient.createLayergroup(externalResourceMapConfig, options, function() { - var externalResourceRequestsCount = res_serv_status.numrequests; + testClient.createLayergroup(externalResourceMapConfig, options, function () { + var externalResourceRequestsCount = resServStatus.numrequests; - testClient.createLayergroup(externalResourceMapConfig, options, function() { - assert.equal(res_serv_status.numrequests, externalResourceRequestsCount); + testClient.createLayergroup(externalResourceMapConfig, options, function () { + assert.strictEqual(resServStatus.numrequests, externalResourceRequestsCount); // reset resources cache testHelper.rmdirRecursiveSync(global.environment.millstone.cache_basedir); externalResourceMapConfig = testClient.defaultTableMapConfig('test_table_3 ', externalResourceStyle); - testClient.createLayergroup(externalResourceMapConfig, options, function() { - assert.equal(res_serv_status.numrequests, externalResourceRequestsCount + 1); + testClient.createLayergroup(externalResourceMapConfig, options, function () { + assert.strictEqual(resServStatus.numrequests, externalResourceRequestsCount + 1); done(); }); @@ -115,18 +112,18 @@ describe('external resources', function() { }); }); - it("referencing unexistant external resources returns an error", function(done) { - var url = "http://127.0.0.1:" + res_serv_port + "/notfound.png"; + it('referencing unexistant external resources returns an error', function (done) { + var url = 'http://127.0.0.1:' + resServPort + '/notfound.png'; var style = "#test_table_3{marker-file: url('" + url + "'); marker-transform:'scale(0.2)'; }"; var mapConfig = testClient.defaultTableMapConfig('test_table_3', style); - testClient.createLayergroup(mapConfig, { statusCode: 400 }, function(err, res) { - assert.deepEqual(JSON.parse(res.body).errors, [ + testClient.createLayergroup(mapConfig, { statusCode: 400 }, function (err, res) { + assert.ifError(err); + assert.deepStrictEqual(JSON.parse(res.body).errors, [ "Unable to download '" + url + "' for 'style0' (server returned 404)"] ); done(); }); }); - }); diff --git a/test/acceptance/ported/limits-test.js b/test/acceptance/ported/limits-test.js index 1ee70123..a5b066f2 100644 --- a/test/acceptance/ported/limits-test.js +++ b/test/acceptance/ported/limits-test.js @@ -3,31 +3,31 @@ require('../../support/test-helper'); var fs = require('fs'); +var path = require('path'); var assert = require('../../support/assert'); var testClient = require('./support/test-client'); var serverOptions = require('./support/ported-server-options'); -describe.skip('render limits', function() { - +describe.skip('render limits', function () { var IMAGE_EQUALS_TOLERANCE_PER_MIL = 25; var limitsConfig; var onTileErrorStrategy; - before(function() { + before(function () { limitsConfig = serverOptions.renderer.mapnik.limits; serverOptions.renderer.mapnik.limits = { render: 50, cacheOnTimeout: false }; onTileErrorStrategy = serverOptions.renderer.onTileErrorStrategy; - serverOptions.renderer.onTileErrorStrategy = function(err, tile, headers, stats, format, callback) { + serverOptions.renderer.onTileErrorStrategy = function (err, tile, headers, stats, format, callback) { callback(err, tile, headers, stats); }; }); - after(function() { + after(function () { serverOptions.renderer.mapnik.limits = limitsConfig; serverOptions.renderer.onTileErrorStrategy = onTileErrorStrategy; }); @@ -35,22 +35,25 @@ describe.skip('render limits', function() { var slowQuery = 'select pg_sleep(1), * from test_table limit 2'; var slowQueryMapConfig = testClient.singleLayerMapConfig(slowQuery); - it('slow query/render returns with 400 status', function(done) { + it('slow query/render returns with 400 status', function (done) { var options = { statusCode: 400, serverOptions: serverOptions }; - testClient.createLayergroup(slowQueryMapConfig, options, function(err, res) { - assert.deepEqual(JSON.parse(res.body), { errors: ["Render timed out"] }); + testClient.createLayergroup(slowQueryMapConfig, options, function (err, res) { + assert.ifError(err); + assert.deepStrictEqual(JSON.parse(res.body), { errors: ['Render timed out'] }); done(); }); }); - it('uses onTileErrorStrategy to handle error and modify response', function(done) { - serverOptions.renderer.onTileErrorStrategy = function(err, tile, headers, stats, format, callback) { - var fixture = __dirname + '/../../fixtures/limits/fallback.png'; - fs.readFile(fixture, {encoding: 'binary'}, function(err, img) { - callback(null, img, {'Content-Type': 'image/png'}, {}); + it('uses onTileErrorStrategy to handle error and modify response', function (done) { + serverOptions.renderer.onTileErrorStrategy = function (err, tile, headers, stats, format, callback) { + assert.ifError(err); + var fixture = path.join(__dirname, '/../../fixtures/limits/fallback.png'); + fs.readFile(fixture, { encoding: 'binary' }, function (err, img) { + assert.ifError(err); + callback(null, img, { 'Content-Type': 'image/png' }, {}); }); }; var options = { @@ -58,18 +61,21 @@ describe.skip('render limits', function() { contentType: 'image/png', serverOptions: serverOptions }; - testClient.createLayergroup(slowQueryMapConfig, options, function(err, res) { + testClient.createLayergroup(slowQueryMapConfig, options, function (err, res) { + assert.ifError(err); var parsed = JSON.parse(res.body); assert.ok(parsed.layergroupid); done(); }); }); - it('returns a fallback tile that was modified via onTileErrorStrategy', function(done) { + it('returns a fallback tile that was modified via onTileErrorStrategy', function (done) { var fixtureImage = './test/fixtures/limits/fallback.png'; - serverOptions.renderer.onTileErrorStrategy = function(err, tile, headers, stats, format, callback) { - fs.readFile(fixtureImage, {encoding: null}, function(err, img) { - callback(null, img, {'Content-Type': 'image/png'}, {}); + serverOptions.renderer.onTileErrorStrategy = function (err, tile, headers, stats, format, callback) { + assert.ifError(err); + fs.readFile(fixtureImage, { encoding: null }, function (err, img) { + assert.ifError(err); + callback(null, img, { 'Content-Type': 'image/png' }, {}); }); }; var options = { @@ -77,12 +83,14 @@ describe.skip('render limits', function() { contentType: 'image/png', serverOptions: serverOptions }; - testClient.withLayergroup(slowQueryMapConfig, options, function(err, requestTile, finish) { + testClient.withLayergroup(slowQueryMapConfig, options, function (err, requestTile, finish) { + assert.ifError(err); var tileUrl = '/0/0/0.png'; - requestTile(tileUrl, options, function(err, res) { + requestTile(tileUrl, options, function (err, res) { + assert.ifError(err); assert.imageBufferIsSimilarToFile(res.body, fixtureImage, IMAGE_EQUALS_TOLERANCE_PER_MIL, - function(err) { - finish(function(finishErr) { + function (err) { + finish(function (finishErr) { done(err || finishErr); }); } @@ -90,5 +98,4 @@ describe.skip('render limits', function() { }); }); }); - }); diff --git a/test/acceptance/ported/multilayer-error-cases-test.js b/test/acceptance/ported/multilayer-error-cases-test.js index b4f9a9be..b410faa9 100644 --- a/test/acceptance/ported/multilayer-error-cases-test.js +++ b/test/acceptance/ported/multilayer-error-cases-test.js @@ -9,7 +9,7 @@ var ServerOptions = require('./support/ported-server-options'); var testClient = require('./support/test-client'); var TestClient = require('../../support/test-client'); -describe('multilayer error cases', function() { +describe('multilayer error cases', function () { var server; before(function () { @@ -18,14 +18,14 @@ describe('multilayer error cases', function() { }); // var client = null; - afterEach(function(done) { + afterEach(function (done) { if (this.client) { return this.client.drain(done); } return done(); }); - it("post layergroup with wrong Content-Type", function(done) { + it('post layergroup with wrong Content-Type', function (done) { assert.response(server, { url: '/api/v1/map', method: 'POST', @@ -33,15 +33,15 @@ describe('multilayer error cases', function() { host: 'localhost', 'Content-Type': 'application/x-www-form-urlencoded' } - }, {}, function(res) { - assert.equal(res.statusCode, 400, res.body); + }, {}, function (res) { + assert.strictEqual(res.statusCode, 400, res.body); var parsedBody = JSON.parse(res.body); - assert.deepEqual(parsedBody.errors, ["POST data must be of type application/json"]); + assert.deepStrictEqual(parsedBody.errors, ['POST data must be of type application/json']); done(); }); }); - it("post layergroup with no layers", function(done) { + it('post layergroup with no layers', function (done) { assert.response(server, { url: '/api/v1/map', method: 'POST', @@ -49,15 +49,15 @@ describe('multilayer error cases', function() { host: 'localhost', 'Content-Type': 'application/json' } - }, {}, function(res) { - assert.equal(res.statusCode, 400, res.body); + }, {}, function (res) { + assert.strictEqual(res.statusCode, 400, res.body); var parsedBody = JSON.parse(res.body); - assert.deepEqual(parsedBody.errors, ["Missing layers array from layergroup config"]); + assert.deepStrictEqual(parsedBody.errors, ['Missing layers array from layergroup config']); done(); }); }); - it("post layergroup jsonp errors are returned with 200 status", function(done) { + it('post layergroup jsonp errors are returned with 200 status', function (done) { assert.response(server, { url: '/api/v1/map?callback=test', method: 'POST', @@ -65,9 +65,9 @@ describe('multilayer error cases', function() { host: 'localhost', 'Content-Type': 'application/json' } - }, {}, function(res) { - assert.equal(res.statusCode, 200); - assert.equal( + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200); + assert.strictEqual( res.body, '/**/ typeof test === \'function\' && ' + 'test({"errors":["Missing layers array from layergroup config"],' + @@ -78,15 +78,17 @@ describe('multilayer error cases', function() { }); }); - it("layergroup with no cartocss_version", function(done) { - var layergroup = { + it('layergroup with no cartocss_version', function (done) { + var layergroup = { version: '1.0.0', layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - geom_column: 'the_geom' - } } + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + geom_column: 'the_geom' + } + } ] }; assert.response(server, { @@ -97,188 +99,208 @@ describe('multilayer error cases', function() { 'Content-Type': 'application/json' }, data: JSON.stringify(layergroup) - }, {}, function(res) { - assert.equal(res.statusCode, 400, res.body); + }, {}, function (res) { + assert.strictEqual(res.statusCode, 400, res.body); var parsedBody = JSON.parse(res.body); - assert.deepEqual(parsedBody.errors, ["Missing cartocss_version for layer 0 options"]); + assert.deepStrictEqual(parsedBody.errors, ['Missing cartocss_version for layer 0 options']); done(); }); }); - it("sql/cartocss combination errors", function(done) { - var layergroup = { - version: '1.0.1', - layers: [{ options: { - sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", - cartocss_version: '2.0.2', - cartocss: '#layer [missing=1] { line-width:16; }', - geom_column: 'the_geom' - }}] - }; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { - host: 'localhost', - 'Content-Type': 'application/json' - }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - try { - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - // See http://github.com/CartoDB/Windshaft/issues/159 - var parsed = JSON.parse(res.body); - assert.ok(parsed); - assert.equal(parsed.errors.length, 1); - var error = parsed.errors[0]; - assert.ok(error.match(/column "missing" does not exist/m), error); - // cannot check for error starting with style0 until a new enough mapnik - // is used: https://github.com/mapnik/mapnik/issues/1924 - //assert.ok(error.match(/^style0/), "Error doesn't start with style0: " + error); - // TODO: check which layer introduced the problem ? - done(); - } catch (err) { done(err); } - }); + it('sql/cartocss combination errors', function (done) { + var layergroup = { + version: '1.0.1', + layers: [{ + options: { + sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", + cartocss_version: '2.0.2', + cartocss: '#layer [missing=1] { line-width:16; }', + geom_column: 'the_geom' + } + }] + }; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { + host: 'localhost', + 'Content-Type': 'application/json' + }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + try { + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + // See http://github.com/CartoDB/Windshaft/issues/159 + var parsed = JSON.parse(res.body); + assert.ok(parsed); + assert.strictEqual(parsed.errors.length, 1); + var error = parsed.errors[0]; + assert.ok(error.match(/column "missing" does not exist/m), error); + // cannot check for error starting with style0 until a new enough mapnik + // is used: https://github.com/mapnik/mapnik/issues/1924 + // assert.ok(error.match(/^style0/), "Error doesn't start with style0: " + error); + // TODO: check which layer introduced the problem ? + done(); + } catch (err) { done(err); } + }); }); - it("sql/interactivity combination error", function(done) { - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom", - cartocss_version: '2.0.2', - cartocss: '#layer { line-width:16; }', - interactivity: 'i', - geom_column: 'the_geom' - }}, - { options: { - sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom", - cartocss_version: '2.0.2', - cartocss: '#layer { line-width:16; }', - geom_column: 'the_geom' - }}, - { options: { - sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom", - cartocss_version: '2.0.2', - cartocss: '#layer { line-width:16; }', - interactivity: 'missing', - geom_column: 'the_geom' - }} - ] - }; - this.client = new TestClient(layergroup); - this.client.getLayergroup({ response: { status: 400 } }, function(err, parsed) { - assert.ok(!err, err); - assert.ok(parsed); - assert.equal(parsed.errors.length, 1); - var error = parsed.errors[0]; - assert.ok(error.match(/column "missing" does not exist/m), error); - done(); - }); - }); - - it("blank CartoCSS error", function(done) { - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", - cartocss_version: '2.0.2', - cartocss: '#style { line-width:16 }', - interactivity: 'i', - geom_column: 'the_geom' - }}, - { options: { - sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", - cartocss_version: '2.0.2', - cartocss: '', - interactivity: 'i', - geom_column: 'the_geom' - }} - ] - }; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { - host: 'localhost', - 'Content-Type': 'application/json' - }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - try { - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed); - assert.equal(parsed.errors.length, 1); - var error = parsed.errors[0]; - assert.ok(error.match(/^style1: CartoCSS is empty/), error); - done(); - } catch (err) { done(err); } - }); - }); - - it("Invalid mapnik-geometry-type CartoCSS error", function(done) { - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", - cartocss_version: '2.0.2', - cartocss: '#style [mapnik-geometry-type=bogus] { line-width:16 }', - geom_column: 'the_geom' - }}, - { options: { - sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", - cartocss_version: '2.0.2', - cartocss: '#style [mapnik-geometry-type=bogus] { line-width:16 }', - geom_column: 'the_geom' - }} - ] - }; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { - host: 'localhost', - 'Content-Type': 'application/json' - }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - try { - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed); - assert.equal(parsed.errors.length, 1); - var error = parsed.errors[0]; - // carto-0.9.3 used to say "Failed to parse expression", - // carto-0.9.5 says "not a valid keyword" - assert.ok(error.match(/^style0:.*(Failed|not a valid)/), error); - // TODO: check which layer introduced the problem ? - done(); - } catch (err) { done(err); } - }); - }); - - it("post'ing style with non existent column in filter returns 400 with error", function(done) { - var layergroup = { + it('sql/interactivity combination error', function (done) { + var layergroup = { version: '1.0.1', layers: [ - { options: { - sql: 'select * from test_table limit 1', - cartocss: '#test_table::outline[address="one"], [address="two"] { marker-fill: red; }', - cartocss_version: '2.0.2', - interactivity: [ 'cartodb_id' ], - geom_column: 'the_geom' - } }, - { options: { - sql: 'select * from test_big_poly limit 1', - cartocss: '#test_big_poly { marker-fill:blue }', - cartocss_version: '2.0.2', - interactivity: [ 'cartodb_id' ], - geom_column: 'the_geom' - } } + { + options: { + sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom", + cartocss_version: '2.0.2', + cartocss: '#layer { line-width:16; }', + interactivity: 'i', + geom_column: 'the_geom' + } + }, + { + options: { + sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom", + cartocss_version: '2.0.2', + cartocss: '#layer { line-width:16; }', + geom_column: 'the_geom' + } + }, + { + options: { + sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom", + cartocss_version: '2.0.2', + cartocss: '#layer { line-width:16; }', + interactivity: 'missing', + geom_column: 'the_geom' + } + } + ] + }; + this.client = new TestClient(layergroup); + this.client.getLayergroup({ response: { status: 400 } }, function (err, parsed) { + assert.ok(!err, err); + assert.ok(parsed); + assert.strictEqual(parsed.errors.length, 1); + var error = parsed.errors[0]; + assert.ok(error.match(/column "missing" does not exist/m), error); + done(); + }); + }); + + it('blank CartoCSS error', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", + cartocss_version: '2.0.2', + cartocss: '#style { line-width:16 }', + interactivity: 'i', + geom_column: 'the_geom' + } + }, + { + options: { + sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", + cartocss_version: '2.0.2', + cartocss: '', + interactivity: 'i', + geom_column: 'the_geom' + } + } + ] + }; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { + host: 'localhost', + 'Content-Type': 'application/json' + }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + try { + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed); + assert.strictEqual(parsed.errors.length, 1); + var error = parsed.errors[0]; + assert.ok(error.match(/^style1: CartoCSS is empty/), error); + done(); + } catch (err) { done(err); } + }); + }); + + it('Invalid mapnik-geometry-type CartoCSS error', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", + cartocss_version: '2.0.2', + cartocss: '#style [mapnik-geometry-type=bogus] { line-width:16 }', + geom_column: 'the_geom' + } + }, + { + options: { + sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom", + cartocss_version: '2.0.2', + cartocss: '#style [mapnik-geometry-type=bogus] { line-width:16 }', + geom_column: 'the_geom' + } + } + ] + }; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { + host: 'localhost', + 'Content-Type': 'application/json' + }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + try { + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed); + assert.strictEqual(parsed.errors.length, 1); + var error = parsed.errors[0]; + // carto-0.9.3 used to say "Failed to parse expression", + // carto-0.9.5 says "not a valid keyword" + assert.ok(error.match(/^style0:.*(Failed|not a valid)/), error); + // TODO: check which layer introduced the problem ? + done(); + } catch (err) { done(err); } + }); + }); + + it("post'ing style with non existent column in filter returns 400 with error", function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: 'select * from test_table limit 1', + cartocss: '#test_table::outline[address="one"], [address="two"] { marker-fill: red; }', + cartocss_version: '2.0.2', + interactivity: ['cartodb_id'], + geom_column: 'the_geom' + } + }, + { + options: { + sql: 'select * from test_big_poly limit 1', + cartocss: '#test_big_poly { marker-fill:blue }', + cartocss_version: '2.0.2', + interactivity: ['cartodb_id'], + geom_column: 'the_geom' + } + } ] }; @@ -290,10 +312,10 @@ describe('multilayer error cases', function() { 'Content-Type': 'application/json' }, data: JSON.stringify(layergroup) - }, {}, function(res) { - assert.equal(res.statusCode, 400, res.body); + }, {}, function (res) { + assert.strictEqual(res.statusCode, 400, res.body); var parsed = JSON.parse(res.body); - assert.equal(parsed.errors.length, 1); + assert.strictEqual(parsed.errors.length, 1); var error = parsed.errors[0]; assert.ok(error.match(/column "address" does not exist/m), error); done(); @@ -301,15 +323,16 @@ describe('multilayer error cases', function() { }); // See https://github.com/Vizzuality/Windshaft/issues/31 - it('bogus sql raises 400 status code', function(done) { + it('bogus sql raises 400 status code', function (done) { var bogusSqlMapConfig = testClient.singleLayerMapConfig('BOGUS FROM test_table'); - testClient.createLayergroup(bogusSqlMapConfig, { statusCode: 400 }, function(err, res) { - assert.ok(/syntax error/.test(res.body), "Unexpected error: " + res.body); + testClient.createLayergroup(bogusSqlMapConfig, { statusCode: 400 }, function (err, res) { + assert.ifError(err); + assert.ok(/syntax error/.test(res.body), 'Unexpected error: ' + res.body); done(); }); }); - it('bogus sql raises 200 status code for jsonp', function(done) { + it('bogus sql raises 200 status code for jsonp', function (done) { var bogusSqlMapConfig = testClient.singleLayerMapConfig('bogus'); var options = { method: 'GET', @@ -318,17 +341,18 @@ describe('multilayer error cases', function() { 'Content-Type': 'text/javascript; charset=utf-8' } }; - testClient.createLayergroup(bogusSqlMapConfig, options, function(err, res) { + testClient.createLayergroup(bogusSqlMapConfig, options, function (err, res) { + assert.ifError(err); assert.ok( /^\/\*\*\/ typeof test === 'function' && test\(/.test(res.body), - "Body start expected callback name: " + res.body + 'Body start expected callback name: ' + res.body ); - assert.ok(/syntax error/.test(res.body), "Unexpected error: " + res.body); + assert.ok(/syntax error/.test(res.body), 'Unexpected error: ' + res.body); done(); }); }); - it('query not selecting the_geom raises 200 status code for jsonp instead of 404', function(done) { + it('query not selecting the_geom raises 200 status code for jsonp instead of 404', function (done) { var noGeomMapConfig = testClient.singleLayerMapConfig('select null::geometry the_geom_wadus'); var options = { method: 'GET', @@ -337,25 +361,27 @@ describe('multilayer error cases', function() { 'Content-Type': 'text/javascript; charset=utf-8' } }; - testClient.createLayergroup(noGeomMapConfig, options, function(err, res) { + testClient.createLayergroup(noGeomMapConfig, options, function (err, res) { + assert.ifError(err); assert.ok( /^\/\*\*\/ typeof test === 'function' && test\(/.test(res.body), - "Body start expected callback name: " + res.body + 'Body start expected callback name: ' + res.body ); - assert.ok(/column.*does not exist/.test(res.body), "Unexpected error: " + res.body); + assert.ok(/column.*does not exist/.test(res.body), 'Unexpected error: ' + res.body); done(); }); }); - it("query with no geometry field returns 400 status", function(done){ + it('query with no geometry field returns 400 status', function (done) { var noGeometrySqlMapConfig = testClient.singleLayerMapConfig('SELECT 1'); - testClient.createLayergroup(noGeometrySqlMapConfig, { statusCode: 400 }, function(err, res) { - assert.ok(/column.*does not exist/.test(res.body), "Unexpected error: " + res.body); + testClient.createLayergroup(noGeometrySqlMapConfig, { statusCode: 400 }, function (err, res) { + assert.ifError(err); + assert.ok(/column.*does not exist/.test(res.body), 'Unexpected error: ' + res.body); done(); }); }); - it("bogus style should raise 400 status", function(done){ + it('bogus style should raise 400 status', function (done) { var bogusStyleMapConfig = testClient.defaultTableMapConfig('test_table', '#test_table{xxxxx;}'); testClient.createLayergroup(bogusStyleMapConfig, { method: 'GET', statusCode: 400 }, done); }); @@ -367,52 +393,52 @@ describe('multilayer error cases', function() { } }; - it('should raise 400 error for out of bounds layer index', function(done){ + it('should raise 400 error for out of bounds layer index', function (done) { var mapConfig = testClient.singleLayerMapConfig('select * from test_table', null, null, 'name'); - testClient.getGrid(mapConfig, 1, 13, 4011, 3088, defaultErrorExpectedResponse, function(err, res) { - assert.deepEqual(JSON.parse(res.body).errors, ["Layer '1' not found in layergroup"]); + testClient.getGrid(mapConfig, 1, 13, 4011, 3088, defaultErrorExpectedResponse, function (err, res) { + assert.ifError(err); + assert.deepStrictEqual(JSON.parse(res.body).errors, ["Layer '1' not found in layergroup"]); done(); }); }); - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// // // OPTIONS LAYERGROUP // - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// - it("nonexistent layergroup token error", function(done) { - step( - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/deadbeef/0/0/0/0.grid.json', - method: 'GET', - encoding: 'binary', - headers: { - host: 'localhost' - } - }, {}, function(res, err) { next(err, res); }); - }, - function checkResponse(err, res) { - assert.ifError(err); - // FIXME: should be 404 - assert.equal(res.statusCode, 400, res.statusCode + ':' + res.body); - var parsed = JSON.parse(res.body); - assert.deepEqual(parsed.errors, ["Invalid or nonexistent map configuration token 'deadbeef'"]); - return null; - }, - function finish(err) { - done(err); - } - ); + it('nonexistent layergroup token error', function (done) { + step( + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/deadbeef/0/0/0/0.grid.json', + method: 'GET', + encoding: 'binary', + headers: { + host: 'localhost' + } + }, {}, function (res, err) { next(err, res); }); + }, + function checkResponse (err, res) { + assert.ifError(err); + // FIXME: should be 404 + assert.strictEqual(res.statusCode, 400, res.statusCode + ':' + res.body); + var parsed = JSON.parse(res.body); + assert.deepStrictEqual(parsed.errors, ["Invalid or nonexistent map configuration token 'deadbeef'"]); + return null; + }, + function finish (err) { + done(err); + } + ); }); - it('error 400 on json syntax error', function(done) { - var layergroup = { + it('error 400 on json syntax error', function (done) { + var layergroup = { version: '1.0.1', layers: [ { @@ -427,20 +453,19 @@ describe('multilayer error cases', function() { { url: '/api/v1/map', method: 'POST', - headers: {'Content-Type': 'application/json; charset=utf-8' }, + headers: { 'Content-Type': 'application/json; charset=utf-8' }, data: '{' + JSON.stringify(layergroup) }, { status: 400 }, - function(res) { + function (res) { var parsedBody = JSON.parse(res.body); assert.ok(parsedBody.errors); - assert.equal(parsedBody.errors.length, 1); + assert.strictEqual(parsedBody.errors.length, 1); assert.ok(parsedBody.errors[0].match(/^SyntaxError: Unexpected token {/)); done(); } ); }); - }); diff --git a/test/acceptance/ported/multilayer-interactivity-test.js b/test/acceptance/ported/multilayer-interactivity-test.js index 48e1d007..e1f0b121 100644 --- a/test/acceptance/ported/multilayer-interactivity-test.js +++ b/test/acceptance/ported/multilayer-interactivity-test.js @@ -3,13 +3,13 @@ var testHelper = require('../../support/test-helper'); var assert = require('../../support/assert'); -var _ = require('underscore'); +var _ = require('underscore'); var cartodbServer = require('../../../lib/server'); var getLayerTypeFn = require('windshaft').model.MapConfig.prototype.getType; var PortedServerOptions = require('./support/ported-server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('multilayer interactivity and layers order', function() { +describe('multilayer interactivity and layers order', function () { var server; before(function () { @@ -17,13 +17,13 @@ describe('multilayer interactivity and layers order', function() { server.setMaxListeners(0); }); - function layerType(layer) { + function layerType (layer) { return layer.type || 'undefined'; } - function testInteractivityLayersOrderScenario(testScenario) { - it(testScenario.desc, function(done) { - var layergroup = { + function testInteractivityLayersOrderScenario (testScenario) { + it(testScenario.desc, function (done) { + var layergroup = { version: '1.3.0', layers: testScenario.layers }; @@ -39,16 +39,16 @@ describe('multilayer interactivity and layers order', function() { data: JSON.stringify(layergroup) }, { - //status: 200, don't use status here to have a more meaningful error message + // status: 200, don't use status here to have a more meaningful error message headers: { 'content-type': 'application/json; charset=utf-8' } }, - function(response) { - assert.equal( + function (response) { + assert.strictEqual( response.statusCode, 200, - 'Expected status code 200, got ' + response.statusCode + + 'Expected status code 200, got ' + response.statusCode + '\n\tResponse body: ' + response.body + '\n\tLayer types: ' + layergroup.layers.map(layerType).join(', ') ); @@ -58,21 +58,21 @@ describe('multilayer interactivity and layers order', function() { var layergroupId = layergroupResponse.layergroupid; assert.ok(layergroupId); - assert.equal(layergroupResponse.metadata.layers.length, layergroup.layers.length); + assert.strictEqual(layergroupResponse.metadata.layers.length, layergroup.layers.length); // check layers metadata at least match in number var layersMetadata = layergroupResponse.metadata.layers; - assert.equal(layersMetadata.length, layergroup.layers.length); + assert.strictEqual(layersMetadata.length, layergroup.layers.length); for (var i = 0, len = layersMetadata.length; i < len; i++) { - assert.equal( + assert.strictEqual( getLayerTypeFn(layersMetadata[i].type), getLayerTypeFn(layergroup.layers[i].type) ); } // check torque metadata at least match in number - var torqueLayers = layergroup.layers.filter(function(layer) { return layer.type === 'torque'; }); + var torqueLayers = layergroup.layers.filter(function (layer) { return layer.type === 'torque'; }); if (torqueLayers.length) { - assert.equal(Object.keys(layergroupResponse.metadata.torque).length, torqueLayers.length); + assert.strictEqual(Object.keys(layergroupResponse.metadata.torque).length, torqueLayers.length); } var keysToDelete = { @@ -95,7 +95,7 @@ describe('multilayer interactivity and layers order', function() { type: 'http', options: { urlTemplate: 'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png', - subdomains: ['a','b','c'] + subdomains: ['a', 'b', 'c'] } }; @@ -104,12 +104,12 @@ describe('multilayer interactivity and layers order', function() { options: { sql: "select 1 id, '1970-01-02'::date d, 'POINT(0 0)'::geometry the_geom_webmercator", cartocss: [ - "Map {", - "-torque-frame-count:2;", - "-torque-resolution:3;", - "-torque-time-attribute:d;", - "-torque-aggregation-function:'count(id)';", - "}" + 'Map {', + '-torque-frame-count:2;', + '-torque-resolution:3;', + '-torque-time-attribute:d;', + "-torque-aggregation-function:'count(id)';", + '}' ].join(' '), cartocss_version: '2.0.1' } @@ -362,5 +362,4 @@ describe('multilayer interactivity and layers order', function() { testScenarios.forEach(testInteractivityLayersOrderScenario); chaosScenarios.forEach(testInteractivityLayersOrderScenario); - }); diff --git a/test/acceptance/ported/multilayer-test.js b/test/acceptance/ported/multilayer-test.js index 1ff22011..739f4926 100644 --- a/test/acceptance/ported/multilayer-test.js +++ b/test/acceptance/ported/multilayer-test.js @@ -11,7 +11,7 @@ var cartodbServer = require('../../../lib/server'); var ServerOptions = require('./support/ported-server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('multilayer', function() { +describe('multilayer', function () { var server; before(function () { @@ -20,1235 +20,1233 @@ describe('multilayer', function() { }); mapnik.register_system_fonts(); - var available_system_fonts = _.keys(mapnik.fontFiles()); + var availableSystemFonts = _.keys(mapnik.fontFiles()); var IMAGE_EQUALS_TOLERANCE_PER_MIL = 20; - function checkCORSHeaders(res) { - assert.equal( + function checkCORSHeaders (res) { + assert.strictEqual( res.headers['access-control-allow-headers'], 'X-Requested-With, X-Prototype-Version, X-CSRF-Token, Authorization' ); - assert.equal(res.headers['access-control-allow-origin'], '*'); + assert.strictEqual(res.headers['access-control-allow-origin'], '*'); } // See https://github.com/Vizzuality/Windshaft/issues/70 - it("post layergroup with encoding in content-type", function(done) { - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: 'select the_geom from test_table limit 1', - cartocss: '#layer { marker-fill:red }', - cartocss_version: '2.0.1', - geom_column: 'the_geom' - } } - ] - }; - var expected_token; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json; charset=utf-8' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - expected_token = LayergroupToken.parse(parsedBody.layergroupid).token; - next(); - }); - }, - function finish(err) { - if (err) { - return done(err); + it('post layergroup with encoding in content-type', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: 'select the_geom from test_table limit 1', + cartocss: '#layer { marker-fill:red }', + cartocss_version: '2.0.1', + geom_column: 'the_geom' + } + } + ] + }; + var expectedToken; + step( + function doPost () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json; charset=utf-8' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + expectedToken = LayergroupToken.parse(parsedBody.layergroupid).token; + next(); + }); + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + ); }); // See https://github.com/Vizzuality/Windshaft/issues/71 - it("single layer with multiple css sections", function(done) { - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: 'select st_setsrid(st_makepoint(0, 0), 4326) as the_geom', - cartocss: '#layer { marker-fill:red; } #layer { marker-width:100; }', - cartocss_version: '2.0.1', - geom_column: 'the_geom' - } } - ] - }; - var expected_token; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - expected_token = LayergroupToken.parse(parsedBody.layergroupid).token; - next(); - }); - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - checkCORSHeaders(res); - var referenceImagePath = './test/fixtures/test_bigpoint_red.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, IMAGE_EQUALS_TOLERANCE_PER_MIL, - function(err) { - next(err); - }); - }); - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + it('single layer with multiple css sections', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: 'select st_setsrid(st_makepoint(0, 0), 4326) as the_geom', + cartocss: '#layer { marker-fill:red; } #layer { marker-width:100; }', + cartocss_version: '2.0.1', + geom_column: 'the_geom' + } + } + ] + }; + var expectedToken; + step( + function doPost () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + expectedToken = LayergroupToken.parse(parsedBody.layergroupid).token; + next(); + }); + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + checkCORSHeaders(res); + var referenceImagePath = './test/fixtures/test_bigpoint_red.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, IMAGE_EQUALS_TOLERANCE_PER_MIL, + function (err) { + next(err); + }); + }); + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - it("layergroup with 2 layers, each with its style", function(done) { + it('layergroup with 2 layers, each with its style', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1', + interactivity: ['cartodb_id'], + geom_column: 'the_geom' + } + }, + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, -50, 0) as the_geom from test_table limit 2 offset 2', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: ['cartodb_id'], + geom_column: 'the_geom' + } + } + ] + }; - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1', - interactivity: [ 'cartodb_id' ], - geom_column: 'the_geom' - } }, - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, -50, 0) as the_geom from test_table limit 2 offset 2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: [ 'cartodb_id' ], - geom_column: 'the_geom' - } } - ] - }; - - var expected_token; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - // CORS headers should be sent with response - // from layergroup creation via POST - checkCORSHeaders(res); - var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 2}); - } else { - expected_token = LayergroupToken.parse(parsedBody.layergroupid).token; - } - next(null, res); - }); - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err) { - next(err); - }); - }); - }, - function do_get_grid0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0/0.grid.json', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_grid1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + + var expectedToken; + step( + function doPost () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + // CORS headers should be sent with response + // from layergroup creation via POST + checkCORSHeaders(res); + var parsedBody = JSON.parse(res.body); + if (expectedToken) { + assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 2 }); + } else { + expectedToken = LayergroupToken.parse(parsedBody.layergroupid).token; + } + next(null, res); + }); + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err) { + next(err); + }); + }); + }, + function doGetGrid0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0/0.grid.json', + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetGrid1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/1/0/0/0.grid.json?interactivity=cartodb_id', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - it("layergroup with 2 layers, each with its style, GET method", function(done) { + it('layergroup with 2 layers, each with its style, GET method', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1', + interactivity: ['cartodb_id'], + geom_column: 'the_geom' + } + }, + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, -50, 0) as the_geom from test_table limit 2 offset 2', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: ['cartodb_id'], + geom_column: 'the_geom' + } + } + ] + }; - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1', - interactivity: [ 'cartodb_id' ], - geom_column: 'the_geom' - } }, - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, -50, 0) as the_geom from test_table limit 2 offset 2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: [ 'cartodb_id' ], - geom_column: 'the_geom' - } } - ] - }; - - var expected_token; - step( - function do_get() - { - var next = this; - assert.response(server, { - url: '/api/v1/map?' + querystring.stringify({ - config: JSON.stringify(layergroup) - }), - method: 'GET', - headers: { host: 'localhost', 'Content-Type': 'application/json' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - // CORS headers should be sent with response - // from layergroup creation via GET - // see https://github.com/CartoDB/Windshaft/issues/92 - checkCORSHeaders(res); - var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 2}); - } else { - expected_token = LayergroupToken.parse(parsedBody.layergroupid).token; - } - next(null, res); - }); - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err) { - next(err); - }); - }); - }, - function do_get_grid0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + + var expectedToken; + step( + function doGet () { + var next = this; + assert.response(server, { + url: '/api/v1/map?' + querystring.stringify({ + config: JSON.stringify(layergroup) + }), + method: 'GET', + headers: { host: 'localhost', 'Content-Type': 'application/json' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + // CORS headers should be sent with response + // from layergroup creation via GET + // see https://github.com/CartoDB/Windshaft/issues/92 + checkCORSHeaders(res); + var parsedBody = JSON.parse(res.body); + if (expectedToken) { + assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 2 }); + } else { + expectedToken = LayergroupToken.parse(parsedBody.layergroupid).token; + } + next(null, res); + }); + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err) { + next(err); + }); + }); + }, + function doGetGrid0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0/0.grid.json?interactivity=cartodb_id', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_grid1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetGrid1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/1/0/0/0.grid.json?interactivity=cartodb_id', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - it("layergroup with 2 layers, GET method, JSONP", function(done) { + it('layergroup with 2 layers, GET method, JSONP', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1', + interactivity: ['cartodb_id'], + geom_column: 'the_geom' + } + }, + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, -50, 0) as the_geom from test_table limit 2 offset 2', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: ['cartodb_id'], + geom_column: 'the_geom' + } + } + ] + }; - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1', - interactivity: [ 'cartodb_id' ], - geom_column: 'the_geom' - } }, - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, -50, 0) as the_geom from test_table limit 2 offset 2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: [ 'cartodb_id' ], - geom_column: 'the_geom' - } } - ] - }; + var expectedToken; + step( + function doGetToken () { + var next = this; + assert.response(server, { + url: '/api/v1/map?' + querystring.stringify({ + config: JSON.stringify(layergroup), + callback: 'jsonpTest' + }), + method: 'GET', + headers: { host: 'localhost', 'Content-Type': 'application/json' } + }, {}, function (res, err) { next(err, res); }); + }, + function doCheckToken (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); - var expected_token; - step( - function do_get_token() - { - var next = this; - assert.response(server, { - url: '/api/v1/map?' + querystring.stringify({ - config: JSON.stringify(layergroup), - callback: 'jsonp_test' - }), - method: 'GET', - headers: { host: 'localhost', 'Content-Type': 'application/json' } - }, {}, function(res, err) { next(err, res); }); - }, - function do_check_token(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); + var didRunJsonCallback = false; + /* eslint-disable no-unused-vars, no-eval */ + function jsonpTest (body) { + assert.ok(body.layergroupid); + expectedToken = LayergroupToken.parse(body.layergroupid).token; + assert.ok(body.metadata.layers.length === 2); + assert.ok(body.metadata.layers[0].type === 'mapnik'); + assert.ok(body.metadata.layers[0].meta); + assert.ok(body.metadata.layers[1].type === 'mapnik'); + assert.ok(body.metadata.layers[1].meta); + didRunJsonCallback = true; + } + eval(res.body); + /* eslint-enable */ + assert.ok(didRunJsonCallback); - var didRunJsonCallback = false; - // jshint ignore:start - function jsonp_test(body) { - assert.ok(body.layergroupid); - expected_token = LayergroupToken.parse(body.layergroupid).token; - assert.ok(body.metadata.layers.length === 2); - assert.ok(body.metadata.layers[0].type === 'mapnik'); - assert.ok(body.metadata.layers[0].meta); - assert.ok(body.metadata.layers[1].type === 'mapnik'); - assert.ok(body.metadata.layers[1].meta); - didRunJsonCallback = true; - } - eval(res.body); - // jshint ignore:end - assert.ok(didRunJsonCallback); - - // TODO: check caching headers ! - return null; - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err) { - next(err); - }); - }); - }, - function do_get_grid0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + + // TODO: check caching headers ! + return null; + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err) { + next(err); + }); + }); + }, + function doGetGrid0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0/0.grid.json?interactivity=cartodb_id', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_grid1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetGrid1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/1/0/0/0.grid.json?interactivity=cartodb_id', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - it("layergroup with 3 mixed layers, mapnik torque and attributes", function(done) { - - var layergroup = { - version: '1.1.0', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1', - interactivity: [ 'cartodb_id' ], - geom_column: 'the_geom' - } }, - { options: { - sql: 'select cartodb_id, cartodb_id*10 as n, ST_Translate(the_geom, -50, 0) as the_geom' + + it('layergroup with 3 mixed layers, mapnik torque and attributes', function (done) { + var layergroup = { + version: '1.1.0', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1', + interactivity: ['cartodb_id'], + geom_column: 'the_geom' + } + }, + { + options: { + sql: 'select cartodb_id, cartodb_id*10 as n, ST_Translate(the_geom, -50, 0) as the_geom' + ' from test_table ORDER BY cartodb_id limit 2 offset 2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: [ 'cartodb_id' ], - attributes: { id: 'cartodb_id', columns: ['n'] }, - geom_column: 'the_geom' - } }, - { type: 'torque', options: { - sql: "select cartodb_id, '1970-01-01'::date as d," + - " ST_SnapToGrid(the_geom_webmercator,1e10) as the_geom_webmercator " + - "from test_table WHERE cartodb_id = 4", - cartocss: 'Map { -torque-frame-count:1; -torque-resolution:1; -torque-time-attribute:d; ' + + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: ['cartodb_id'], + attributes: { id: 'cartodb_id', columns: ['n'] }, + geom_column: 'the_geom' + } + }, + { + type: 'torque', + options: { + sql: "select cartodb_id, '1970-01-01'::date as d," + + ' ST_SnapToGrid(the_geom_webmercator,1e10) as the_geom_webmercator ' + + 'from test_table WHERE cartodb_id = 4', + cartocss: 'Map { -torque-frame-count:1; -torque-resolution:1; -torque-time-attribute:d; ' + '-torque-aggregation-function:"count(*)"; } #layer { marker-fill:blue; marker-allow-overlap:true; }' - } } - ] - }; + } + } + ] + }; - var expected_token; - step( - function do_get() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res, err) { - next(err, res); - }); - }, - function check_create(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - expected_token = LayergroupToken.parse(parsed.layergroupid).token; - return null; - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err) { - next(err); - }); - }); - }, - function do_get_grid0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + + var expectedToken; + step( + function doGet () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res, err) { + next(err, res); + }); + }, + function checkCreate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + expectedToken = LayergroupToken.parse(parsed.layergroupid).token; + return null; + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err) { + next(err); + }); + }); + }, + function doGetGrid0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0/0.grid.json?interactivity=cartodb_id', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_grid1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetGrid1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/1/0/0/0.grid.json?interactivity=cartodb_id', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_attr1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/1/attributes/4', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res, err) { - next(err, res); - }); - }, - function do_check_attr1(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - var parsed = JSON.parse(res.body); - assert.deepEqual(parsed, {n:40}); - return null; - }, - function do_get_torque2(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/2/0/0/0.json.torque', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res, err) { next(err, res); }); - }, - function do_check_torque2(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - var parsed = JSON.parse(res.body); - assert.deepEqual(parsed[0].vals__uint8, [1]); - assert.deepEqual(parsed[0].dates__uint16, [0]); - assert.equal(parsed[0].x__uint8, 128); - assert.equal(parsed[0].y__uint8, 128); - return null; - }, - function do_get_torque1(err) - { -// Layer 1 is not a torque layer... -// See https://github.com/CartoDB/Windshaft/issues/136 - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/1/0/0/0.json.torque', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res, err) { next(err, res); }); - }, - function do_check_torque1(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors, res.body); - assert.equal(parsed.errors.length, 1); - var msg = parsed.errors[0]; - assert.ok(msg.match(/Unsupported format json.torque/i), msg); - return null; - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetAttr1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/1/attributes/4', + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res, err) { + next(err, res); + }); + }, + function doCheckAttr1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + var parsed = JSON.parse(res.body); + assert.deepStrictEqual(parsed, { n: 40 }); + return null; + }, + function doGetTorque2 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/2/0/0/0.json.torque', + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res, err) { next(err, res); }); + }, + function doCheckTorque2 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + var parsed = JSON.parse(res.body); + assert.deepStrictEqual(parsed[0].vals__uint8, [1]); + assert.deepStrictEqual(parsed[0].dates__uint16, [0]); + assert.strictEqual(parsed[0].x__uint8, 128); + assert.strictEqual(parsed[0].y__uint8, 128); + return null; + }, + function doGetTorque1 (err) { + // Layer 1 is not a torque layer... + // See https://github.com/CartoDB/Windshaft/issues/136 + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/1/0/0/0.json.torque', + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res, err) { next(err, res); }); + }, + function doCheckTorque1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors, res.body); + assert.strictEqual(parsed.errors.length, 1); + var msg = parsed.errors[0]; + assert.ok(msg.match(/Unsupported format json.torque/i), msg); + return null; + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - it("check that distinct maps result in distinct tiles", function(done) { + it('check that distinct maps result in distinct tiles', function (done) { + var layergroup1 = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1', + interactivity: 'cartodb_id', + geom_column: 'the_geom' + } + } + ] + }; - var layergroup1 = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1', - interactivity: 'cartodb_id', - geom_column: 'the_geom' - } } - ] - }; + var layergroup2 = { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom, -50, 0) as the_geom from test_table limit 2 offset 2', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id', + geom_column: 'the_geom' + } + } + ] + }; - var layergroup2 = { - version: '1.0.0', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom, -50, 0) as the_geom from test_table limit 2 offset 2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id', - geom_column: 'the_geom' - } } - ] - }; - - var token1, token2; - step( - function do_post1() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup1) - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - token1 = LayergroupToken.parse(parsedBody.layergroupid).token; - assert.ok(token1, res.body); - next(null); - }); - }, - function do_post2() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup2) - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - token2 = LayergroupToken.parse(parsedBody.layergroupid).token; - assert.ok(token2); - next(null); - }); - }, - function do_get_tile1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + token1 + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer2.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err) { - next(err); - }); - }); - }, - function do_get_grid1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + token1 + '/0/0/0/0.grid.json?interactivity=cartodb_id', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function do_get_tile2(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + token2 + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer3.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err) { - next(err); - }); - }); - }, - function do_get_grid_layer2(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + token2 + '/0/0/0/0.grid.json?interactivity=cartodb_id', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - assert.utfgridEqualsFile( - res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, - function(err/*, similarity*/) { - next(err); - }); - }); - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + token1] = 0; - keysToDelete['map_cfg|' + token2] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + var token1, token2; + step( + function doPost1 () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup1) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + token1 = LayergroupToken.parse(parsedBody.layergroupid).token; + assert.ok(token1, res.body); + next(null); + }); + }, + function doPost2 () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup2) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + token2 = LayergroupToken.parse(parsedBody.layergroupid).token; + assert.ok(token2); + next(null); + }); + }, + function doGetTile1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + token1 + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer2.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err) { + next(err); + }); + }); + }, + function doGetGrid1 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + token1 + '/0/0/0/0.grid.json?interactivity=cartodb_id', + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer0.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function doGetTile2 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + token2 + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer3.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err) { + next(err); + }); + }); + }, + function doGetGridLayer2 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + token2 + '/0/0/0/0.grid.json?interactivity=cartodb_id', + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + assert.utfgridEqualsFile( + res.body, './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer1.layer1.grid.json', 2, + function (err/*, similarity */) { + next(err); + }); + }); + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + token1] = 0; + keysToDelete['map_cfg|' + token2] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - it("layers are rendered in definition order", function(done) { + it('layers are rendered in definition order', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: "select st_setsrid('LINESTRING(-60 -60,-60 60)'::geometry, 4326) as the_geom", + cartocss_version: '2.0.2', + cartocss: '#layer { line-width:16; line-color:#ff0000; }', + geom_column: 'the_geom' + } + }, + { + options: { + sql: "select st_setsrid('LINESTRING(-100 0,100 0)'::geometry, 4326) as the_geom", + cartocss_version: '2.0.2', + cartocss: '#layer { line-width:16; line-color:#00ff00; }', + geom_column: 'the_geom' + } + }, + { + options: { + sql: "select st_setsrid('LINESTRING(60 -60,60 60)'::geometry, 4326) as the_geom", + cartocss_version: '2.0.2', + cartocss: '#layer { line-width:16; line-color:#0000ff; }', + geom_column: 'the_geom' + } + } + ] + }; - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select st_setsrid('LINESTRING(-60 -60,-60 60)'::geometry, 4326) as the_geom", - cartocss_version: '2.0.2', - cartocss: '#layer { line-width:16; line-color:#ff0000; }', - geom_column: 'the_geom' - } }, - { options: { - sql: "select st_setsrid('LINESTRING(-100 0,100 0)'::geometry, 4326) as the_geom", - cartocss_version: '2.0.2', - cartocss: '#layer { line-width:16; line-color:#00ff00; }', - geom_column: 'the_geom' - } }, - { options: { - sql: "select st_setsrid('LINESTRING(60 -60,60 60)'::geometry, 4326) as the_geom", - cartocss_version: '2.0.2', - cartocss: '#layer { line-width:16; line-color:#0000ff; }', - geom_column: 'the_geom' - } } - ] - }; - - var expected_token; // = "32994445c0a4525432fcd7013bf6524c"; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - try { - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 3}); - } else { - expected_token = LayergroupToken.parse(parsedBody.layergroupid).token; - } - next(null, res); - } catch (err) { next(err); } - }); - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer4.png'; - assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err) { - next(err); - }); - }); - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + var expectedToken; // = "32994445c0a4525432fcd7013bf6524c"; + step( + function doPost () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + try { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + if (expectedToken) { + assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 3 }); + } else { + expectedToken = LayergroupToken.parse(parsedBody.layergroupid).token; + } + next(null, res); + } catch (err) { next(err); } + }); + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + var referenceImagePath = './test/acceptance/ported/fixtures/test_table_0_0_0_multilayer4.png'; + assert.imageBufferIsSimilarToFile(res.body, referenceImagePath, + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err) { + next(err); + }); + }); + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - it("quotes in CartoCSS", function(done) { + it('quotes in CartoCSS', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: "select 'single''quote' as n, 'SRID=4326;POINT(0 0)'::geometry as the_geom", + cartocss: '#s [n="single\'quote" ] { marker-fill:red; }', + cartocss_version: '2.1.0', + geom_column: 'the_geom' + } + }, + { + options: { + sql: "select 'double\"quote' as n, 'SRID=4326;POINT(2 0)'::geometry as the_geom", + cartocss: '#s [n="double\\"quote" ] { marker-fill:red; }', + cartocss_version: '2.1.0', + geom_column: 'the_geom' + } + } + ] + }; - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select 'single''quote' as n, 'SRID=4326;POINT(0 0)'::geometry as the_geom", - cartocss: '#s [n="single\'quote" ] { marker-fill:red; }', - cartocss_version: '2.1.0', - geom_column: 'the_geom' - } }, - { options: { - sql: "select 'double\"quote' as n, 'SRID=4326;POINT(2 0)'::geometry as the_geom", - cartocss: '#s [n="double\\"quote" ] { marker-fill:red; }', - cartocss_version: '2.1.0', - geom_column: 'the_geom' - } } - ] - }; - - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - var expected_token = LayergroupToken.parse(parsed.layergroupid).token; - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - }); + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + var expectedToken = LayergroupToken.parse(parsed.layergroupid).token; + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + }); }); // See https://github.com/CartoDB/Windshaft/issues/90 - it("exponential notation in CartoCSS filter", function(done) { - - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select 1.0 as n, 'SRID=4326;POINT(0 0)'::geometry as the_geom", - cartocss: '#s [n=1e-4 ] { marker-fill:red; }', - cartocss_version: '2.1.0', - geom_column: 'the_geom' - } } - ] - }; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - var expected_token = LayergroupToken.parse(parsed.layergroupid).token; - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - }); + it('exponential notation in CartoCSS filter', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: "select 1.0 as n, 'SRID=4326;POINT(0 0)'::geometry as the_geom", + cartocss: '#s [n=1e-4 ] { marker-fill:red; }', + cartocss_version: '2.1.0', + geom_column: 'the_geom' + } + } + ] + }; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + var expectedToken = LayergroupToken.parse(parsed.layergroupid).token; + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + }); }); // See https://github.com/CartoDB/Windshaft/issues/94 - it("unknown text-face-name", function(done) { + it('unknown text-face-name', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: "select 1.0 as n, 'SRID=4326;POINT(0 0)'::geometry as the_geom", + cartocss: '#s { text-name: [n]; text-face-name: "<%= font %>"; }', + cartocss_version: '2.1.0', + geom_column: 'the_geom' + } + } + ] + }; - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: "select 1.0 as n, 'SRID=4326;POINT(0 0)'::geometry as the_geom", - cartocss: '#s { text-name: [n]; text-face-name: "<%= font %>"; }', - cartocss_version: '2.1.0', - geom_column: 'the_geom' - } } - ] - }; - - var tpl = JSON.stringify(layergroup); - - step( - function doBadPost() { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: _.template(tpl, {font:'bogus'}) - }, function(res) { next(null, res); }); - }, - function checkBadFont(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsedBody = JSON.parse(res.body); - assert.equal(parsedBody.errors.length, 1); - var errmsg = parsedBody.errors[0]; - assert.ok(errmsg.match(/text-face-name.*bogus/), parsedBody.errors.toString()); - //, {"errors":["style0: Failed to find font face 'bogus'"]}); - return null; - }, - function doGoodPost(err) { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: _.template(tpl, {font:available_system_fonts[0]}) - }, function(res) { next(null, res); }); - }, - function checkGoodFont(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - var expected_token = LayergroupToken.parse(parsed.layergroupid).token; - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + var tpl = JSON.stringify(layergroup); + step( + function doBadPost () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: _.template(tpl, { font: 'bogus' }) + }, function (res) { next(null, res); }); + }, + function checkBadFont (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsedBody = JSON.parse(res.body); + assert.strictEqual(parsedBody.errors.length, 1); + var errmsg = parsedBody.errors[0]; + assert.ok(errmsg.match(/text-face-name.*bogus/), parsedBody.errors.toString()); + //, {"errors":["style0: Failed to find font face 'bogus'"]}); + return null; + }, + function doGoodPost (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: _.template(tpl, { font: availableSystemFonts[0] }) + }, function (res) { next(null, res); }); + }, + function checkGoodFont (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + var expectedToken = LayergroupToken.parse(parsed.layergroupid).token; + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// // // OPTIONS LAYERGROUP // - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// - it("geting options on layergroup should return CORS headers", function(done){ + it('geting options on layergroup should return CORS headers', function (done) { const allowHeaders = 'X-Requested-With, X-Prototype-Version, X-CSRF-Token, Authorization, Content-Type'; assert.response(server, { url: '/api/v1/map', method: 'OPTIONS' - },{ + }, { status: 200, // TODO: use checkCORSHeaders() function headers: { - 'Access-Control-Allow-Headers': allowHeaders, - 'Access-Control-Allow-Origin': '*' + 'Access-Control-Allow-Headers': allowHeaders, + 'Access-Control-Allow-Origin': '*' } - }, function() { done(); }); + }, function () { done(); }); }); // See: // - https://github.com/CartoDB/Windshaft/issues/103 // - https://github.com/mapnik/mapnik/issues/2121 // - https://github.com/mapnik/mapnik/issues/764 - it.skip("layergroup with datetime interactivity", function(done) { + it.skip('layergroup with datetime interactivity', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: 'select 1 as i, 2::int2 as n, now() as t, ST_SetSRID(ST_MakePoint(0,0),3857) as the_geom', + cartocss: '#layer { marker-fill:red; }', + cartocss_version: '2.1.1', + interactivity: ['i', 't', 'n'] + } + } + ] + }; - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: 'select 1 as i, 2::int2 as n, now() as t, ST_SetSRID(ST_MakePoint(0,0),3857) as the_geom', - cartocss: '#layer { marker-fill:red; }', - cartocss_version: '2.1.1', - interactivity: [ 'i', 't', 'n' ] - } } - ] - }; - - var expected_token; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { - try { - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 3}); - } else { - expected_token = LayergroupToken.parse(parsedBody.layergroupid).token; - } - next(null, res); - } catch (err) { next(err); } - }); - }, - function do_get_grid0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0/0.grid.json', - method: 'GET', - headers: { host: 'localhost' } - }, {}, function(res) { - next(null, res); - }); - }, - function do_check_grid(err, res) - { - assert.ifError(err); - var next = this; - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - var grid = JSON.parse(res.body); - assert.ok(grid); - assert.ok(grid.hasOwnProperty('data')); - assert.ok(grid.data.hasOwnProperty('1')); - var data = grid.data[1]; - assert.ok(data.hasOwnProperty('n'), "Missing 'n' from grid data keys: " + _.keys(data)); - assert.ok(data.hasOwnProperty('i'), "Missing 'i' from grid data keys: " + _.keys(data)); - assert.ok(data.hasOwnProperty('t'), "Missing 't' from grid data keys: " + _.keys(data)); - next(); - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + expected_token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + var expectedToken; + step( + function doPost () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { + try { + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + if (expectedToken) { + assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 3 }); + } else { + expectedToken = LayergroupToken.parse(parsedBody.layergroupid).token; + } + next(null, res); + } catch (err) { next(err); } + }); + }, + function doGetGrid0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0/0.grid.json', + method: 'GET', + headers: { host: 'localhost' } + }, {}, function (res) { + next(null, res); + }); + }, + function doCheckGrid (err, res) { + assert.ifError(err); + var next = this; + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + var grid = JSON.parse(res.body); + assert.ok(grid); + assert.ok(Object.prototype.hasOwnProperty.call(grid, 'data')); + assert.ok(Object.prototype.hasOwnProperty.call(grid.data, '1')); + var data = grid.data[1]; + assert.ok(Object.prototype.hasOwnProperty.call(data, 'n'), "Missing 'n' from grid data keys: " + _.keys(data)); + assert.ok(Object.prototype.hasOwnProperty.call(data, 'i'), "Missing 'i' from grid data keys: " + _.keys(data)); + assert.ok(Object.prototype.hasOwnProperty.call(data, 't'), "Missing 't' from grid data keys: " + _.keys(data)); + next(); + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + expectedToken] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); // See https://github.com/CartoDB/Windshaft/issues/163 - it.skip("has different token for different database", function(done) { - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: 'select 1 as i, 2::int2 as n, now() as t, ST_SetSRID(ST_MakePoint(0,0),3857) as the_geom', - cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', - cartocss_version: '2.0.1', - geom_column: 'the_geom' - } } - ] - }; + it.skip('has different token for different database', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: 'select 1 as i, 2::int2 as n, now() as t, ST_SetSRID(ST_MakePoint(0,0),3857) as the_geom', + cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }', + cartocss_version: '2.0.1', + geom_column: 'the_geom' + } + } + ] + }; - var token1, token2; - step( - function do_post_1() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res, err) { next(err,res); }); - }, - function check_post_1(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - var parsedBody = JSON.parse(res.body); - token1 = LayergroupToken.parse(parsedBody.layergroupid).token; - return null; - }, - function do_post_2() - { - var next = this; - assert.response(server, { - url: '/database/windshaft_test2/layergroup', - method: 'POST', - headers: { host: 'cartodb250user', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res, err) { next(err,res); }); - }, - function check_post_2(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - var parsedBody = JSON.parse(res.body); - token2 = LayergroupToken.parse(parsedBody.layergroupid).token; - assert.ok(token1 !== token2); - return null; - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + token1] = 0; - keysToDelete['map_cfg|' + token2] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + var token1, token2; + step( + function doPost1 () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsedBody = JSON.parse(res.body); + token1 = LayergroupToken.parse(parsedBody.layergroupid).token; + return null; + }, + function doPost2 () { + var next = this; + assert.response(server, { + url: '/database/windshaft_test2/layergroup', + method: 'POST', + headers: { host: 'cartodb250user', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost2 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsedBody = JSON.parse(res.body); + token2 = LayergroupToken.parse(parsedBody.layergroupid).token; + assert.ok(token1 !== token2); + return null; + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + token1] = 0; + keysToDelete['map_cfg|' + token2] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); // See http://github.com/CartoDB/Windshaft/issues/191 - it("mapnik layer with custom geom_column", function(done) { - var layergroup = { - version: '1.0.1', - layers: [ - { options: { - sql: 'select 1 as i, ST_SetSRID(ST_MakePoint(0,0),4326) as g', - cartocss: '#layer { marker-fill:red; marker-width:100; }', - cartocss_version: '2.0.1', - geom_column: 'g' - } } - ] - }; + it('mapnik layer with custom geom_column', function (done) { + var layergroup = { + version: '1.0.1', + layers: [ + { + options: { + sql: 'select 1 as i, ST_SetSRID(ST_MakePoint(0,0),4326) as g', + cartocss: '#layer { marker-fill:red; marker-width:100; }', + cartocss_version: '2.0.1', + geom_column: 'g' + } + } + ] + }; - var token1; - step( - function do_post_1() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res, err) { next(err,res); }); - }, - function check_post_1(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - var parsedBody = JSON.parse(res.body); - token1 = LayergroupToken.parse(parsedBody.layergroupid).token; - return null; - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + token1 + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res) { - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "image/png"); - checkCORSHeaders(res); - assert.imageBufferIsSimilarToFile(res.body, './test/fixtures/test_bigpoint_red.png', - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err) { - next(err); - }); - }); - }, - function finish(err) { - if (err) { - return done(err); - } - var keysToDelete = {'user:localhost:mapviews:global': 5}; - keysToDelete['map_cfg|' + token1] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + var token1; + step( + function doPost1 () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsedBody = JSON.parse(res.body); + token1 = LayergroupToken.parse(parsedBody.layergroupid).token; + return null; + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + token1 + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + checkCORSHeaders(res); + assert.imageBufferIsSimilarToFile(res.body, './test/fixtures/test_bigpoint_red.png', + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err) { + next(err); + }); + }); + }, + function finish (err) { + if (err) { + return done(err); + } + var keysToDelete = { 'user:localhost:mapviews:global': 5 }; + keysToDelete['map_cfg|' + token1] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - }); diff --git a/test/acceptance/ported/raster-test.js b/test/acceptance/ported/raster-test.js index 313bca02..4d7cf471 100644 --- a/test/acceptance/ported/raster-test.js +++ b/test/acceptance/ported/raster-test.js @@ -1,6 +1,6 @@ 'use strict'; -var testHelper =require('../../support/test-helper'); +var testHelper = require('../../support/test-helper'); var assert = require('../../support/assert'); var step = require('step'); @@ -8,8 +8,7 @@ var cartodbServer = require('../../../lib/server'); var ServerOptions = require('./support/ported-server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('raster', function() { - +describe('raster', function () { var server; before(function () { @@ -17,107 +16,107 @@ describe('raster', function() { server.setMaxListeners(0); }); - function checkCORSHeaders(res) { - assert.equal( + function checkCORSHeaders (res) { + assert.strictEqual( res.headers['access-control-allow-headers'], 'X-Requested-With, X-Prototype-Version, X-CSRF-Token, Authorization' ); - assert.equal(res.headers['access-control-allow-origin'], '*'); + assert.strictEqual(res.headers['access-control-allow-origin'], '*'); } var IMAGE_EQUALS_TOLERANCE_PER_MIL = 2; - it("can render raster for valid mapconfig", function(done) { - var mapconfig = { - version: '1.2.0', - layers: [ - { type: 'mapnik', options: { - sql: "select ST_AsRaster(" + - " ST_MakeEnvelope(-100,-40, 100, 40, 4326), " + + it('can render raster for valid mapconfig', function (done) { + var mapconfig = { + version: '1.2.0', + layers: [ + { + type: 'mapnik', + options: { + sql: 'select ST_AsRaster(' + + ' ST_MakeEnvelope(-100,-40, 100, 40, 4326), ' + " 1.0, -1.0, '8BUI', 127) as rst", - geom_column: 'rst', - geom_type: 'raster', - cartocss: '#layer { raster-opacity:1.0 }', - cartocss_version: '2.0.1' - } } - ] - }; - var expected_token; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(mapconfig) - }, {}, function(res, err) { next(err, res); }); - }, - function checkPost(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - // CORS headers should be sent with response - // from layergroup creation via POST - checkCORSHeaders(res); - var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 2}); - } else { - expected_token = parsedBody.layergroupid; - } - return null; - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { host: 'localhost' } - }, {}, function(res, err) { next(err, res); }); - }, - function check_response(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - assert.deepEqual(res.headers['content-type'], "image/png"); - var next = this; - assert.imageBufferIsSimilarToFile(res.body, - './test/fixtures/raster_gray_rect.png', - IMAGE_EQUALS_TOLERANCE_PER_MIL, function(err) { - try { + geom_column: 'rst', + geom_type: 'raster', + cartocss: '#layer { raster-opacity:1.0 }', + cartocss_version: '2.0.1' + } + } + ] + }; + var expectedToken; + step( + function doPost () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(mapconfig) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost (err, res) { assert.ifError(err); - next(); - } catch (err) { next(err); } - }); - }, - function finish(err) { - if (err) { - return done(err); - } + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + // CORS headers should be sent with response + // from layergroup creation via POST + checkCORSHeaders(res); + var parsedBody = JSON.parse(res.body); + if (expectedToken) { + assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 2 }); + } else { + expectedToken = parsedBody.layergroupid; + } + return null; + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { host: 'localhost' } + }, {}, function (res, err) { next(err, res); }); + }, + function checkResponse (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + assert.deepStrictEqual(res.headers['content-type'], 'image/png'); + var next = this; + assert.imageBufferIsSimilarToFile(res.body, + './test/fixtures/raster_gray_rect.png', + IMAGE_EQUALS_TOLERANCE_PER_MIL, function (err) { + try { + assert.ifError(err); + next(); + } catch (err) { next(err); } + }); + }, + function finish (err) { + if (err) { + return done(err); + } - var keysToDelete = { - 'user:localhost:mapviews:global': 5 - }; - keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; - testHelper.deleteRedisKeys(keysToDelete, done); - } - ); + var keysToDelete = { + 'user:localhost:mapviews:global': 5 + }; + keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0; + testHelper.deleteRedisKeys(keysToDelete, done); + } + ); }); - it("raster geom type does not allow interactivity", function(done) { - - var mapconfig = { + it('raster geom type does not allow interactivity', function (done) { + var mapconfig = { version: '1.2.0', layers: [ { type: 'cartodb', options: { sql: [ - "select 1 id,", - "ST_AsRaster(ST_MakeEnvelope(-100, -40, 100, 40, 4326), 1.0, -1.0, '8BUI', 127) as rst" + 'select 1 id,', + "ST_AsRaster(ST_MakeEnvelope(-100, -40, 100, 40, 4326), 1.0, -1.0, '8BUI', 127) as rst" ].join(' '), geom_column: 'rst', geom_type: 'raster', @@ -142,14 +141,13 @@ describe('raster', function() { { status: 400 }, - function(res, err) { + function (res, err) { assert.ok(!err); checkCORSHeaders(res); var parsedBody = JSON.parse(res.body); - assert.deepEqual(parsedBody.errors, [ 'Mapnik raster layers do not support interactivity' ]); + assert.deepStrictEqual(parsedBody.errors, ['Mapnik raster layers do not support interactivity']); done(); } ); }); - }); diff --git a/test/acceptance/ported/regressions-test.js b/test/acceptance/ported/regressions-test.js index 1533d400..d13addc7 100644 --- a/test/acceptance/ported/regressions-test.js +++ b/test/acceptance/ported/regressions-test.js @@ -5,8 +5,8 @@ var testHelper = require('../../support/test-helper'); var assert = require('../../support/assert'); var testClient = require('./support/test-client'); -describe('regressions', function() { - after(function() { +describe('regressions', function () { + after(function () { testHelper.rmdirRecursiveSync(global.environment.millstone.cache_basedir); }); @@ -15,8 +15,7 @@ describe('regressions', function() { // See http://github.com/CartoDB/Windshaft/issues/130 // [x] Needs a fix on the mapnik side: https://github.com/mapnik/mapnik/pull/2143 // - it("#130 database access is read-only", function(done) { - + it('#130 database access is read-only', function (done) { var writeSqlMapConfig = testClient.singleLayerMapConfig( 'select st_point(0,0) as the_geom, * from test_table_inserter(st_setsrid(st_point(0,0),4326),\'write\')' ); @@ -28,10 +27,11 @@ describe('regressions', function() { } }; - testClient.getTile(writeSqlMapConfig, 0, 0, 0, expectedResponse, function(err, res) { + testClient.getTile(writeSqlMapConfig, 0, 0, 0, expectedResponse, function (err, res) { + assert.ifError(err); var parsedBody = JSON.parse(res.body); assert.ok(parsedBody.errors); - assert.equal(parsedBody.errors.length, 1); + assert.strictEqual(parsedBody.errors.length, 1); assert.ok(parsedBody.errors[0].match(/read-only transaction/), 'read-only error message expected'); done(); }); diff --git a/test/acceptance/ported/retina-test.js b/test/acceptance/ported/retina-test.js index ceca71a9..ac78b85b 100644 --- a/test/acceptance/ported/retina-test.js +++ b/test/acceptance/ported/retina-test.js @@ -9,8 +9,7 @@ var ServerOptions = require('./support/ported-server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('retina support', function() { - +describe('retina support', function () { var layergroupId = null; var server; @@ -21,10 +20,10 @@ describe('retina support', function() { }); var keysToDelete; - beforeEach(function(done) { - keysToDelete = {'user:localhost:mapviews:global': 5}; + beforeEach(function (done) { + keysToDelete = { 'user:localhost:mapviews:global': 5 }; - var retinaSampleMapConfig = { + var retinaSampleMapConfig = { version: '1.2.0', layers: [ { @@ -61,14 +60,12 @@ describe('retina support', function() { ); }); - - afterEach(function(done) { + afterEach(function (done) { keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0; testHelper.deleteRedisKeys(keysToDelete, done); }); - - function testRetinaImage(scaleFactor, responseHead, assertFn) { + function testRetinaImage (scaleFactor, responseHead, assertFn) { assert.response(server, { url: '/api/v1/map/' + layergroupId + '/0/0/0' + scaleFactor + '.png', @@ -83,7 +80,7 @@ describe('retina support', function() { ); } - function testValidImageDimmensions(scaleFactor, imageSize, done) { + function testValidImageDimmensions (scaleFactor, imageSize, done) { testRetinaImage(scaleFactor, { status: 200, @@ -91,32 +88,31 @@ describe('retina support', function() { 'Content-Type': 'image/png' } }, - function(res, err) { + function (res, err) { assert.ok(!err, 'Failed to request 0/0/0' + scaleFactor + '.png tile'); - var image = new mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); + var image = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); - assert.equal(image.width(), imageSize); - assert.equal(image.height(), imageSize); + assert.strictEqual(image.width(), imageSize); + assert.strictEqual(image.height(), imageSize); done(); } ); } - it('image dimensions when scale factor is not defined', function(done) { + it('image dimensions when scale factor is not defined', function (done) { testValidImageDimmensions('', 256, done); }); - it('image dimensions when scale factor = @1x', function(done) { + it('image dimensions when scale factor = @1x', function (done) { testValidImageDimmensions('@1x', 256, done); }); - it('image dimensions when scale factor = @2x', function(done) { + it('image dimensions when scale factor = @2x', function (done) { testValidImageDimmensions('@2x', 512, done); }); - it('error when scale factor is not enabled', function(done) { - + it('error when scale factor is not enabled', function (done) { var scaleFactor = '@4x'; testRetinaImage(scaleFactor, @@ -126,9 +122,9 @@ describe('retina support', function() { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { assert.ok(!err, 'Failed to request 0/0/0' + scaleFactor + '.png tile'); - assert.deepEqual(JSON.parse(res.body).errors, ["Tile with specified resolution not found"]); + assert.deepStrictEqual(JSON.parse(res.body).errors, ['Tile with specified resolution not found']); done(); } diff --git a/test/acceptance/ported/server-gettile-test.js b/test/acceptance/ported/server-gettile-test.js index 1d75a536..52135197 100644 --- a/test/acceptance/ported/server-gettile-test.js +++ b/test/acceptance/ported/server-gettile-test.js @@ -9,7 +9,7 @@ var cartodbServer = require('../../../lib/server'); var ServerOptions = require('./support/ported-server-options'); var testClient = require('./support/test-client'); -describe('server_gettile', function() { +describe('server_gettile', function () { var server; before(function () { @@ -19,12 +19,12 @@ describe('server_gettile', function() { var IMAGE_EQUALS_TOLERANCE_PER_MIL = 25; - after(function() { + after(function () { testHelper.rmdirRecursiveSync(global.environment.millstone.cache_basedir); }); - function imageCompareFn(fixture, done) { - return function(err, res) { + function imageCompareFn (fixture, done) { + return function (err, res) { if (err) { return done(err); } @@ -34,37 +34,40 @@ describe('server_gettile', function() { }; } - - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// // // GET TILE // --{ - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// - it("get'ing a tile with default style should return an expected tile", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table'), 13, 4011, 3088, - imageCompareFn('test_table_13_4011_3088.png', done) - ); + it("get'ing a tile with default style should return an expected tile", function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table'), 13, 4011, 3088, + imageCompareFn('test_table_13_4011_3088.png', done) + ); }); - it("response of get tile can be served by renderer cache", function(done) { + it('response of get tile can be served by renderer cache', function (done) { var tileUrl = '/13/4011/3088.png'; var lastXwc; var mapConfig = testClient.defaultTableMapConfig('test_table'); testClient.withLayergroup(mapConfig, function (err, requestTile, finish) { + assert.ifError(err); requestTile(tileUrl, function (err, res) { + assert.ifError(err); var xwc = parseInt(res.headers['x-windshaft-cache'], 10); assert.ok(xwc); assert.ok(xwc > 0); lastXwc = xwc; requestTile(tileUrl, function (err, res) { + assert.ifError(err); var xwc = parseInt(res.headers['x-windshaft-cache'], 10); assert.ok(xwc); assert.ok(xwc > 0); assert.ok(xwc >= lastXwc); requestTile(tileUrl, { cache_buster: 'wadus' }, function (err, res) { + assert.ifError(err); var xwc = parseInt(res.headers['x-windshaft-cache'], 10); assert.ok(!xwc); @@ -75,22 +78,21 @@ describe('server_gettile', function() { }); }); - it("should not choke when queries end with a semicolon", function(done){ + it('should not choke when queries end with a semicolon', function (done) { testClient.getTile(testClient.singleLayerMapConfig('SELECT * FROM test_table limit 2;'), 0, 0, 0, done); }); - it("should not choke when sql ends with a semicolon and some blanks", function(done){ + it('should not choke when sql ends with a semicolon and some blanks', function (done) { testClient.getTile(testClient.singleLayerMapConfig('SELECT * FROM test_table limit 2; \t\n'), 0, 0, 0, done); }); - it("should not strip quoted semicolons within an sql query", function(done){ + it('should not strip quoted semicolons within an sql query', function (done) { testClient.getTile( testClient.singleLayerMapConfig("SELECT * FROM test_table where name != ';\n'"), 0, 0, 0, done ); }); - it("getting two tiles with same configuration uses renderer cache", function(done) { - + it('getting two tiles with same configuration uses renderer cache', function (done) { var imageFixture = './test/fixtures/test_table_13_4011_3088_styled.png'; var tileUrl = '/13/4011/3088.png'; var mapConfig = testClient.defaultTableMapConfig( @@ -98,26 +100,29 @@ describe('server_gettile', function() { '#test_table{marker-fill: blue;marker-line-color: black;}' ); - function validateLayergroup(res) { + function validateLayergroup (res) { // cache is hit because we create a renderer to validate the map config - assert.ok(!res.headers.hasOwnProperty('x-windshaft-cache'), "Did hit renderer cache on first time"); + assert.ok(!Object.prototype.hasOwnProperty.call(res.headers, 'x-windshaft-cache'), 'Did hit renderer cache on first time'); } - testClient.withLayergroup(mapConfig, validateLayergroup, function(err, requestTile, finish) { - requestTile(tileUrl, function(err, res) { + testClient.withLayergroup(mapConfig, validateLayergroup, function (err, requestTile, finish) { + assert.ifError(err); + requestTile(tileUrl, function (err, res) { + assert.ifError(err); var xwc = parseInt(res.headers['x-windshaft-cache'], 10); assert.ok(!xwc); requestTile(tileUrl, function (err, res) { + assert.ifError(err); assert.ok( - res.headers.hasOwnProperty('x-windshaft-cache'), - "Did not hit renderer cache on second time" + Object.prototype.hasOwnProperty.call(res.headers, 'x-windshaft-cache'), + 'Did not hit renderer cache on second time' ); assert.ok(parseInt(res.headers['x-windshaft-cache'], 10) >= 0); assert.imageBufferIsSimilarToFile(res.body, imageFixture, IMAGE_EQUALS_TOLERANCE_PER_MIL, - function(err) { - finish(function(finishErr) { + function (err) { + finish(function (finishErr) { done(err || finishErr); }); } @@ -127,22 +132,22 @@ describe('server_gettile', function() { }); }); - var test_style_black_200 = "#test_table{marker-fill:black;marker-line-color:black;marker-width:5}"; - var test_style_black_210 = "#test_table{marker-fill:black;marker-line-color:black;marker-width:10}"; + var testStyleBlack200 = '#test_table{marker-fill:black;marker-line-color:black;marker-width:5}'; + var testStyleBlack210 = '#test_table{marker-fill:black;marker-line-color:black;marker-width:10}'; - it("get'ing a tile with url specified 2.0.0 style should return an expected tile", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table', test_style_black_200, '2.0.0'), + it("get'ing a tile with url specified 2.0.0 style should return an expected tile", function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table', testStyleBlack200, '2.0.0'), 13, 4011, 3088, imageCompareFn('test_table_13_4011_3088_styled_black.png', done)); }); - it("get'ing a tile with url specified 2.1.0 style should return an expected tile", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table', test_style_black_210, '2.1.0'), + it("get'ing a tile with url specified 2.1.0 style should return an expected tile", function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table', testStyleBlack210, '2.1.0'), 13, 4011, 3088, imageCompareFn('test_table_13_4011_3088_styled_black.png', done)); }); - if ( semver.satisfies(mapnik.versions.mapnik, '2.3.x') ) { + if (semver.satisfies(mapnik.versions.mapnik, '2.3.x')) { // See http://github.com/CartoDB/Windshaft/issues/99 - it("unused directives are tolerated", function(done){ + it('unused directives are tolerated', function (done) { var style = "#test_table{point-transform: 'scale(100)';}"; var sql = "SELECT 1 as cartodb_id, 'SRID=4326;POINT(0 0)'::geometry as the_geom"; testClient.getTile(testClient.singleLayerMapConfig(sql, style), 0, 0, 0, @@ -151,42 +156,41 @@ describe('server_gettile', function() { } // See http://github.com/CartoDB/Windshaft/issues/100 - var test_strictness = function(done) { + var testStrictness = function (done) { var nonStrictMapConfig = testClient.singleLayerMapConfig( "SELECT 1 as cartodb_id, 'SRID=3857;POINT(666 666)'::geometry as the_geom", "#test_table{point-transform: 'scale(100)';}" ); - testClient.withLayergroup(nonStrictMapConfig, function(err, requestTile, finish) { + testClient.withLayergroup(nonStrictMapConfig, function (err, requestTile, finish) { + assert.ifError(err); var options = { statusCode: 400, contentType: 'application/json; charset=utf-8' }; - requestTile('/0/0/0.png?strict=1', options, function() { + requestTile('/0/0/0.png?strict=1', options, function () { finish(done); }); }); }; - var test_strict_lbl = "unused directives are not tolerated if strict"; - if ( semver.satisfies(mapnik.versions.mapnik, '2.3.x') ) { - // Strictness handling changed in 2.3.x, possibly a bug: see http://github.com/mapnik/mapnik/issues/2301 - it.skip('[skipped due to http://github.com/mapnik/mapnik/issues/2301]' + test_strict_lbl, test_strictness); - } - else if (!semver.satisfies(mapnik.versions.mapnik, '3.0.x')) { - it(test_strict_lbl, test_strictness); + var testStrictLbl = 'unused directives are not tolerated if strict'; + if (semver.satisfies(mapnik.versions.mapnik, '2.3.x')) { + // Strictness handling changed in 2.3.x, possibly a bug: see http://github.com/mapnik/mapnik/issues/2301 + it.skip('[skipped due to http://github.com/mapnik/mapnik/issues/2301]' + testStrictLbl, testStrictness); + } else if (!semver.satisfies(mapnik.versions.mapnik, '3.0.x')) { + it(testStrictLbl, testStrictness); } - if ( semver.satisfies(mapnik.versions.mapnik, '2.3.x') ) { - - it('high cpu regression with mapnik <2.3.x', function(done) { + if (semver.satisfies(mapnik.versions.mapnik, '2.3.x')) { + it('high cpu regression with mapnik <2.3.x', function (done) { var sql = [ "SELECT 'my polygon name here' AS name,", - "st_envelope(st_buffer(st_transform(", - "st_setsrid(st_makepoint(-26.6592894004,49.7990296995),4326),3857),10000000)) AS the_geom", - "FROM generate_series(-6,6) x", - "UNION ALL", + 'st_envelope(st_buffer(st_transform(', + 'st_setsrid(st_makepoint(-26.6592894004,49.7990296995),4326),3857),10000000)) AS the_geom', + 'FROM generate_series(-6,6) x', + 'UNION ALL', "SELECT 'my marker name here' AS name,", - " st_transform(st_setsrid(st_makepoint(49.6042060319,-49.0522997372),4326),3857) AS the_geom", - "FROM generate_series(-6,6) x" + ' st_transform(st_setsrid(st_makepoint(49.6042060319,-49.0522997372),4326),3857) AS the_geom', + 'FROM generate_series(-6,6) x' ].join(' '); var style = [ @@ -219,18 +223,18 @@ describe('server_gettile', function() { }); } // https://github.com/CartoDB/Windshaft-cartodb/issues/316 - it('should return errors with better formatting', function(done) { + it('should return errors with better formatting', function (done) { var mapConfig = { - "version": "1.0.1", - "minzoom": 0, - "maxzoom": 20, - "layers": [ + version: '1.0.1', + minzoom: 0, + maxzoom: 20, + layers: [ { - "type": 'mapnik', - "options": { - "cartocss_version": '2.1.1', - "sql": "SELECT null::geometry AS the_geom", - "cartocss": [ + type: 'mapnik', + options: { + cartocss_version: '2.1.1', + sql: 'SELECT null::geometry AS the_geom', + cartocss: [ '@water: #cdd2d4;', 'Map {', '\tbackground-color: @water;', @@ -241,11 +245,11 @@ describe('server_gettile', function() { } }, { - "type": 'mapnik', - "options": { - "cartocss_version": '2.1.1', - "sql": "SELECT the_geom FROM false_background_zoomed('!scale_denominator!', !bbox!) AS _", - "cartocss": [ + type: 'mapnik', + options: { + cartocss_version: '2.1.1', + sql: "SELECT the_geom FROM false_background_zoomed('!scale_denominator!', !bbox!) AS _", + cartocss: [ '#false_background {', '\tpolygon-fill: @landmass_fill;', '}' @@ -259,11 +263,11 @@ describe('server_gettile', function() { statusCode: 400 }; - testClient.createLayergroup(mapConfig, options, function(err, res, parsedBody) { + testClient.createLayergroup(mapConfig, options, function (err, res, parsedBody) { + assert.ifError(err); assert.ok(parsedBody.errors); // more assertions when errors is populated with better format done(); }); }); - }); diff --git a/test/acceptance/ported/server-png8-format-test.js b/test/acceptance/ported/server-png8-format-test.js index 66a4c820..12376fac 100644 --- a/test/acceptance/ported/server-png8-format-test.js +++ b/test/acceptance/ported/server-png8-format-test.js @@ -5,6 +5,7 @@ var testHelper = require('../../support/test-helper'); var assert = require('../../support/assert'); var _ = require('underscore'); var fs = require('fs'); +var path = require('path'); var cartodbServer = require('../../../lib/server'); var ServerOptions = require('./support/ported-server-options'); @@ -12,7 +13,7 @@ var LayergroupToken = require('../../../lib/models/layergroup-token'); var IMAGE_EQUALS_TOLERANCE_PER_MIL = 85; -describe('server_png8_format', function() { +describe('server_png8_format', function () { var serverPng32; var serverPng8; @@ -32,13 +33,13 @@ describe('server_png8_format', function() { var layergroupId; - before(function(done) { - var testPngFilesDir = __dirname + '/../../results/png'; + before(function (done) { + var testPngFilesDir = path.join(__dirname, '/../../results/png'); fs.readdirSync(testPngFilesDir) - .filter(function(fileName) { + .filter(function (fileName) { return /.*\.png$/.test(fileName); }) - .map(function(fileName) { + .map(function (fileName) { return testPngFilesDir + '/' + fileName; }) .forEach(fs.unlinkSync); @@ -47,22 +48,21 @@ describe('server_png8_format', function() { }); var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = { 'user:localhost:mapviews:global': 5 }; }); - afterEach(function(done) { + afterEach(function (done) { testHelper.deleteRedisKeys(keysToDelete, done); }); - function testOutputForPng32AndPng8(desc, tile, callback) { - + function testOutputForPng32AndPng8 (desc, tile, callback) { var bufferPng32, bufferPng8; - it(desc + '; tile: ' + JSON.stringify(tile), function(done){ + it(desc + '; tile: ' + JSON.stringify(tile), function (done) { assert.response( serverPng32, { @@ -77,14 +77,14 @@ describe('server_png8_format', function() { { status: 200 }, - function(res, err) { + function (res, err) { if (err) { return done(err); } layergroupId = JSON.parse(res.body).layergroupid; - var tilePartialUrl = _.template('/<%= z %>/<%= x %>/<%= y %>.png', tile); + var tilePartialUrl = _.template('/<%= z %>/<%= x %>/<%= y %>.png', tile); var requestPayload = { url: '/api/v1/map/' + layergroupId + tilePartialUrl, @@ -102,16 +102,15 @@ describe('server_png8_format', function() { } }; - assert.response(serverPng32, requestPayload, requestHeaders, function(responsePng32) { - assert.equal(responsePng32.headers['content-type'], "image/png"); + assert.response(serverPng32, requestPayload, requestHeaders, function (responsePng32) { + assert.strictEqual(responsePng32.headers['content-type'], 'image/png'); bufferPng32 = responsePng32.body; - assert.response(serverPng8, requestPayload, requestHeaders, function(responsePng8) { - assert.equal(responsePng8.headers['content-type'], "image/png"); + assert.response(serverPng8, requestPayload, requestHeaders, function (responsePng8) { + assert.strictEqual(responsePng8.headers['content-type'], 'image/png'); bufferPng8 = responsePng8.body; assert.ok(bufferPng8.length < bufferPng32.length); assert.imageBuffersAreSimilar(bufferPng32, bufferPng8, IMAGE_EQUALS_TOLERANCE_PER_MIL, - function(err, imagePaths, similarity) { - + function (err, imagePaths, similarity) { keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0; callback(err, imagePaths, similarity, done); @@ -124,10 +123,9 @@ describe('server_png8_format', function() { }); } - - var currentLevel = 3, - allLevelTiles = [], - maxLevelTile = Math.pow(2, currentLevel); + var currentLevel = 3; + var allLevelTiles = []; + var maxLevelTile = Math.pow(2, currentLevel); for (var i = 0; i < maxLevelTile; i++) { for (var j = 0; j < maxLevelTile; j++) { @@ -139,8 +137,7 @@ describe('server_png8_format', function() { } } - - var layergroup = { + var layergroup = { version: '1.3.0', layers: [ { @@ -148,17 +145,17 @@ describe('server_png8_format', function() { sql: 'SELECT * FROM populated_places_simple_reduced', cartocss: [ '#populated_places_simple_reduced {', - 'marker-fill: #FFCC00;', - 'marker-width: 10;', - 'marker-line-color: #FFF;', - 'marker-line-width: 1.5;', - 'marker-line-opacity: 1;', - 'marker-fill-opacity: 0.9;', - 'marker-comp-op: multiply;', - 'marker-type: ellipse;', - 'marker-placement: point;', - 'marker-allow-overlap: true;', - 'marker-clip: false;', + 'marker-fill: #FFCC00;', + 'marker-width: 10;', + 'marker-line-color: #FFF;', + 'marker-line-width: 1.5;', + 'marker-line-opacity: 1;', + 'marker-fill-opacity: 0.9;', + 'marker-comp-op: multiply;', + 'marker-type: ellipse;', + 'marker-placement: point;', + 'marker-allow-overlap: true;', + 'marker-clip: false;', '}' ].join(' '), cartocss_version: '2.0.1' @@ -167,10 +164,10 @@ describe('server_png8_format', function() { ] }; - var allImagePaths = [], - similarities = []; - allLevelTiles.forEach(function(tile) { - testOutputForPng32AndPng8('intensity visualization', tile, function(err, imagePaths, similarity, done) { + var allImagePaths = []; + var similarities = []; + allLevelTiles.forEach(function (tile) { + testOutputForPng32AndPng8('intensity visualization', tile, function (err, imagePaths, similarity, done) { allImagePaths.push(imagePaths); similarities.push(similarity); var transformPaths = []; diff --git a/test/acceptance/ported/server-test.js b/test/acceptance/ported/server-test.js index 9bd0e7e5..31c25101 100644 --- a/test/acceptance/ported/server-test.js +++ b/test/acceptance/ported/server-test.js @@ -7,7 +7,7 @@ var cartodbServer = require('../../../lib/server'); var ServerOptions = require('./support/ported-server-options'); var testClient = require('./support/test-client'); -describe('server', function() { +describe('server', function () { var server; before(function () { @@ -15,90 +15,92 @@ describe('server', function() { server.setMaxListeners(0); }); - after(function() { + after(function () { testHelper.rmdirRecursiveSync(global.environment.millstone.cache_basedir); }); - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// // // GET INVALID // - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// - it("get call to server returns 200", function(done){ + it('get call to server returns 200', function (done) { assert.response(server, { url: '/', method: 'GET' - },{ + }, { // FIXME: shouldn't this be a 404 ? status: 200 - }, function() { done(); } ); + }, function () { done(); }); }); - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// // // GET VERSION // - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// - it("get /version returns versions", function(done){ + it('get /version returns versions', function (done) { assert.response(server, { url: '/version', method: 'GET' - },{ + }, { status: 200 - }, function(res) { - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('windshaft'), "No 'windshaft' version in " + parsed); - assert.ok(parsed.hasOwnProperty('grainstore'), "No 'grainstore' version in " + parsed); - assert.ok(parsed.hasOwnProperty('node_mapnik'), "No 'node_mapnik' version in " + parsed); - assert.ok(parsed.hasOwnProperty('mapnik'), "No 'mapnik' version in " + parsed); - // TODO: check actual versions ? - done(); + }, function (res) { + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'windshaft'), "No 'windshaft' version in " + parsed); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'grainstore'), "No 'grainstore' version in " + parsed); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'node_mapnik'), "No 'node_mapnik' version in " + parsed); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'mapnik'), "No 'mapnik' version in " + parsed); + // TODO: check actual versions ? + done(); }); }); - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// // // GET GRID // - //////////////////////////////////////////////////////////////////// + /// ///////////////////////////////////////////////////////////////// - it("grid jsonp", function(done){ + it('grid jsonp', function (done) { var mapConfig = testClient.singleLayerMapConfig('select * from test_table', null, null, 'name'); - testClient.getGridJsonp(mapConfig, 0, 13, 4011, 3088, 'jsonp_test', function(err, res) { - assert.equal(res.statusCode, 200, res.body); - assert.deepEqual(res.headers['content-type'], 'text/javascript; charset=utf-8'); + testClient.getGridJsonp(mapConfig, 0, 13, 4011, 3088, 'jsonpTest', function (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + assert.deepStrictEqual(res.headers['content-type'], 'text/javascript; charset=utf-8'); var didRunJsonCallback = false; var response = {}; - // jshint ignore:start - function jsonp_test(body) { + /* eslint-disable no-unused-vars, no-eval */ + function jsonpTest (body) { response = body; didRunJsonCallback = true; } eval(res.body); - // jshint ignore:end + /* eslint-enable */ assert.ok(didRunJsonCallback); assert.utfgridEqualsFile(response, './test/fixtures/test_table_13_4011_3088.grid.json', 2, done); }); }); - it("get'ing a json with default style and single interactivity should return a grid", function(done){ + it("get'ing a json with default style and single interactivity should return a grid", function (done) { var mapConfig = testClient.singleLayerMapConfig('select * from test_table', null, null, 'name'); - testClient.getGrid(mapConfig, 0, 13, 4011, 3088, function(err, res) { - var expected_json = { - "1":{"name":"Hawai"}, - "2":{"name":"El Estocolmo"}, - "3":{"name":"El Rey del Tallarín"}, - "4":{"name":"El Lacón"}, - "5":{"name":"El Pico"} + testClient.getGrid(mapConfig, 0, 13, 4011, 3088, function (err, res) { + assert.ifError(err); + var expectedJson = { + 1: { name: 'Hawai' }, + 2: { name: 'El Estocolmo' }, + 3: { name: 'El Rey del Tallarín' }, + 4: { name: 'El Lacón' }, + 5: { name: 'El Pico' } }; - assert.deepEqual(JSON.parse(res.body).data, expected_json); + assert.deepStrictEqual(JSON.parse(res.body).data, expectedJson); done(); }); }); - it("get'ing a json with default style and no interactivity should return an error", function(done){ + it("get'ing a json with default style and no interactivity should return an error", function (done) { var mapConfig = testClient.singleLayerMapConfig('select * from test_table'); var expectedResponse = { status: 400, @@ -106,13 +108,14 @@ describe('server', function() { 'Content-Type': 'application/json; charset=utf-8' } }; - testClient.getGrid(mapConfig, 0, 13, 4011, 3088, expectedResponse, function(err, res) { - assert.deepEqual(JSON.parse(res.body).errors, ["Tileset has no interactivity"]); + testClient.getGrid(mapConfig, 0, 13, 4011, 3088, expectedResponse, function (err, res) { + assert.ifError(err); + assert.deepStrictEqual(JSON.parse(res.body).errors, ['Tileset has no interactivity']); done(); }); }); - it("get grid jsonp error is returned with 200 status", function(done){ + it('get grid jsonp error is returned with 200 status', function (done) { var mapConfig = testClient.singleLayerMapConfig('select * from test_table'); var expectedResponse = { status: 200, @@ -120,46 +123,50 @@ describe('server', function() { 'Content-Type': 'text/javascript; charset=utf-8' } }; - testClient.getGridJsonp(mapConfig, 0, 13, 4011, 3088, 'test', expectedResponse, function(err, res) { + testClient.getGridJsonp(mapConfig, 0, 13, 4011, 3088, 'test', expectedResponse, function (err, res) { + assert.ifError(err); assert.ok(res.body.match(/"errors":/), 'missing error in response: ' + res.body); done(); }); }); // See http://github.com/Vizzuality/Windshaft/issues/50 - it("get'ing a json with no data should return an empty grid", function(done){ + it("get'ing a json with no data should return an empty grid", function (done) { var query = 'select * from test_table limit 0'; var mapConfig = testClient.singleLayerMapConfig(query, null, null, 'name'); - testClient.getGrid(mapConfig, 0, 13, 4011, 3088, function(err, res) { + testClient.getGrid(mapConfig, 0, 13, 4011, 3088, function (err, res) { + assert.ifError(err); assert.utfgridEqualsFile(res.body, './test/fixtures/test_table_13_4011_3088_empty.grid.json', 2, done); }); }); // Another test for http://github.com/Vizzuality/Windshaft/issues/50 - it("get'ing a json with no data but interactivity should return an empty grid", function(done){ + it("get'ing a json with no data but interactivity should return an empty grid", function (done) { var query = 'SELECT * FROM test_table limit 0'; var mapConfig = testClient.singleLayerMapConfig(query, null, null, 'cartodb_id'); - testClient.getGrid(mapConfig, 0, 13, 4011, 3088, function(err, res) { + testClient.getGrid(mapConfig, 0, 13, 4011, 3088, function (err, res) { + assert.ifError(err); assert.utfgridEqualsFile(res.body, './test/fixtures/test_table_13_4011_3088_empty.grid.json', 2, done); }); }); // See https://github.com/Vizzuality/Windshaft-cartodb/issues/67 - it("get'ing a solid grid while changing interactivity fields", function(done){ + it("get'ing a solid grid while changing interactivity fields", function (done) { var query = 'SELECT * FROM test_big_poly'; - var style211 = "#test_big_poly{polygon-fill:blue;}"; // for solid + var style211 = '#test_big_poly{polygon-fill:blue;}'; // for solid var mapConfigName = testClient.singleLayerMapConfig(query, style211, null, 'name'); - testClient.getGrid(mapConfigName, 0, 3, 2, 2, function(err, res) { - var expected_data = { "1":{"name":"west"} }; - assert.deepEqual(JSON.parse(res.body).data, expected_data); + testClient.getGrid(mapConfigName, 0, 3, 2, 2, function (err, res) { + assert.ifError(err); + var expectedData = { 1: { name: 'west' } }; + assert.deepStrictEqual(JSON.parse(res.body).data, expectedData); var mapConfigCartodbId = testClient.singleLayerMapConfig(query, style211, null, 'cartodb_id'); - testClient.getGrid(mapConfigCartodbId, 0, 3, 2, 2, function(err, res) { - var expected_data = { "1":{"cartodb_id":"1"} }; - assert.deepEqual(JSON.parse(res.body).data, expected_data); + testClient.getGrid(mapConfigCartodbId, 0, 3, 2, 2, function (err, res) { + assert.ifError(err); + var expectedData = { 1: { cartodb_id: 1 } }; + assert.deepStrictEqual(JSON.parse(res.body).data, expectedData); done(); }); }); }); - }); diff --git a/test/acceptance/ported/static-maps-test.js b/test/acceptance/ported/static-maps-test.js index f5458a76..86b6fc65 100644 --- a/test/acceptance/ported/static-maps-test.js +++ b/test/acceptance/ported/static-maps-test.js @@ -6,32 +6,35 @@ var assert = require('../../support/assert'); var testClient = require('./support/test-client'); var http = require('http'); var fs = require('fs'); +var path = require('path'); -describe('static_maps', function() { - +describe('static_maps', function () { var validUrlTemplate = 'http://127.0.0.1:8033/{s}/{z}/{x}/{y}.png'; var invalidUrlTemplate = 'http://127.0.0.1:8033/INVALID/{z}/{x}/{y}.png'; var httpRendererResourcesServer; - before(function(done) { + before(function (done) { // Start a server to test external resources - httpRendererResourcesServer = http.createServer( function(request, response) { - var filename = __dirname + '/../../fixtures/http/basemap.png'; - fs.readFile(filename, {encoding: 'binary'}, function(err, file) { + httpRendererResourcesServer = http.createServer(function (request, response) { + var filename = path.join(__dirname, '/../../fixtures/http/basemap.png'); + fs.readFile(filename, { encoding: 'binary' }, function (err, file) { + if (err) { + return done(err); + } response.writeHead(200); - response.write(file, "binary"); + response.write(file, 'binary'); response.end(); }); }); httpRendererResourcesServer.listen(8033, done); }); - after(function(done) { + after(function (done) { httpRendererResourcesServer.close(done); }); - function staticMapConfig(urlTemplate, cartocss) { + function staticMapConfig (urlTemplate, cartocss) { return { version: '1.2.0', layers: [ @@ -54,21 +57,21 @@ describe('static_maps', function() { }; } - var zoom = 3, - lat = 0, - lon = 0, - width = 400, - height = 300; + var zoom = 3; + var lat = 0; + var lon = 0; + var width = 400; + var height = 300; it('center image', function (done) { var mapConfig = staticMapConfig(validUrlTemplate); - testClient.getStaticCenter(mapConfig, zoom, lat, lon, width, height, function(err, res, image) { + testClient.getStaticCenter(mapConfig, zoom, lat, lon, width, height, function (err, res, image) { if (err) { return done(err); } - assert.equal(image.width(), width); - assert.equal(image.height(), height); + assert.strictEqual(image.width(), width); + assert.strictEqual(image.height(), height); done(); }); @@ -76,58 +79,56 @@ describe('static_maps', function() { it('center image with invalid basemap', function (done) { var mapConfig = staticMapConfig(invalidUrlTemplate); - testClient.getStaticCenter(mapConfig, zoom, lat, lon, width, height, function(err, res, image) { + testClient.getStaticCenter(mapConfig, zoom, lat, lon, width, height, function (err, res, image) { if (err) { return done(err); } - assert.equal(image.width(), width); - assert.equal(image.height(), height); + assert.strictEqual(image.width(), width); + assert.strictEqual(image.height(), height); done(); }); }); - var west = -90, - south = -45, - east = 90, - north = 45, - bbWidth = 640, - bbHeight = 480; + var west = -90; + var south = -45; + var east = 90; + var north = 45; + var bbWidth = 640; + var bbHeight = 480; it('bbox', function (done) { var mapConfig = staticMapConfig(validUrlTemplate); - testClient.getStaticBbox(mapConfig, west, south, east, north, bbWidth, bbHeight, function(err, res, image) { + testClient.getStaticBbox(mapConfig, west, south, east, north, bbWidth, bbHeight, function (err, res, image) { if (err) { return done(err); } - assert.equal(image.width(), bbWidth); - assert.equal(image.height(), bbHeight); + assert.strictEqual(image.width(), bbWidth); + assert.strictEqual(image.height(), bbHeight); done(); }); }); - it('should not fail for coordinates out of range', function (done) { var outOfRangeHeight = 3000; var mapConfig = staticMapConfig(validUrlTemplate); - testClient.getStaticCenter(mapConfig, 1, lat, lon, width, outOfRangeHeight, function(err, res, image) { + testClient.getStaticCenter(mapConfig, 1, lat, lon, width, outOfRangeHeight, function (err, res, image) { if (err) { return done(err); } - assert.equal(image.width(), width); - assert.equal(image.height(), outOfRangeHeight); + assert.strictEqual(image.width(), width); + assert.strictEqual(image.height(), outOfRangeHeight); done(); }); }); - it('should keep failing for other errors', function (done) { - var invalidStyleForZoom = '#layer { marker-fill:red; } #layer[zoom='+zoom+'] { marker-width: [wadus] * 2; }'; + var invalidStyleForZoom = '#layer { marker-fill:red; } #layer[zoom=' + zoom + '] { marker-width: [wadus] * 2; }'; var mapConfig = staticMapConfig(validUrlTemplate, invalidStyleForZoom); var expectedResponse = { statusCode: 400, @@ -135,14 +136,13 @@ describe('static_maps', function() { 'Content-Type': 'application/json; charset=utf-8' } }; - testClient.getStaticCenter(mapConfig, zoom, lat, lon, width, height, expectedResponse, function(err, res) { + testClient.getStaticCenter(mapConfig, zoom, lat, lon, width, height, expectedResponse, function (err, res) { assert.ok(!err); var parsedBody = JSON.parse(res.body); assert.ok(parsedBody.errors); assert.ok(parsedBody.errors.length); - assert.ok(parsedBody.errors[0].match(/column \"wadus\" does not exist/)); + assert.ok(parsedBody.errors[0].match(/column "wadus" does not exist/)); done(); }); }); - }); diff --git a/test/acceptance/ported/support/ported-server-options.js b/test/acceptance/ported/support/ported-server-options.js index a54d08a5..094cbfa6 100644 --- a/test/acceptance/ported/support/ported-server-options.js +++ b/test/acceptance/ported/support/ported-server-options.js @@ -5,8 +5,9 @@ var serverOptions = require('../../../../lib/server-options'); var mapnik = require('windshaft').mapnik; var OverviewsQueryRewriter = require('../../../../lib/utils/overviews-query-rewriter'); var overviewsQueryRewriter = new OverviewsQueryRewriter({ - zoom_level: 'CDB_ZoomFromScale(!scale_denominator!)' + zoom_level: 'CDB_ZoomFromScale(!scale_denominator!)' }); +var path = require('path'); module.exports = _.extend({}, serverOptions, { grainstore: { @@ -21,7 +22,7 @@ module.exports = _.extend({}, serverOptions, { }, renderer: { mapnik: { - poolSize: 4,//require('os').cpus().length, + poolSize: 4, // require('os').cpus().length, poolMaxWaitingClients: 32, metatile: 1, bufferSize: 64, @@ -40,7 +41,7 @@ module.exports = _.extend({}, serverOptions, { whitelist: ['http://127.0.0.1:8033/{s}/{z}/{x}/{y}.png'], fallbackImage: { type: 'fs', - src: __dirname + '/../../test/fixtures/http/basemap.png' + src: path.join(__dirname, '/../../test/fixtures/http/basemap.png') } } }, diff --git a/test/acceptance/ported/support/test-client.js b/test/acceptance/ported/support/test-client.js index e6328527..48a773cf 100644 --- a/test/acceptance/ported/support/test-client.js +++ b/test/acceptance/ported/support/test-client.js @@ -58,7 +58,7 @@ var jsonContentType = 'application/json; charset=utf-8'; var jsContentType = 'text/javascript; charset=utf-8'; var pngContentType = 'image/png'; -function createLayergroup(layergroupConfig, options, callback) { +function createLayergroup (layergroupConfig, options, callback) { if (!callback) { callback = options; options = { @@ -75,25 +75,23 @@ function createLayergroup(layergroupConfig, options, callback) { }; step( - function requestLayergroup() { + function requestLayergroup () { var next = this; var request = layergroupRequest(layergroupConfig, options.method, options.callbackName, options.params); assert.response(serverInstance(options), request, expectedResponse, function (res, err) { next(err, res); }); }, - function validateLayergroup(err, res) { + function validateLayergroup (err, res) { assert.ifError(err); var parsedBody; var layergroupid; if (options.callbackName) { - global[options.callbackName] = function(layergroup) { + global[options.callbackName] = function (layergroup) { layergroupid = layergroup.layergroupid; }; - // jshint ignore:start - eval(res.body); - // jshint ignore:end + eval(res.body); // eslint-disable-line no-eval delete global[options.callbackName]; } else { parsedBody = JSON.parse(res.body); @@ -109,7 +107,7 @@ function createLayergroup(layergroupConfig, options, callback) { }; var redisKey = 'map_cfg|' + layergroupid; keysToDelete[redisKey] = 0; - testHelper.deleteRedisKeys(keysToDelete, function() { + testHelper.deleteRedisKeys(keysToDelete, function () { return callback(err, res, parsedBody); }); } else { @@ -119,7 +117,7 @@ function createLayergroup(layergroupConfig, options, callback) { ); } -function serverInstance(options) { +function serverInstance (options) { if (options.server) { return options.server; } @@ -134,7 +132,7 @@ function serverInstance(options) { return getServer(); } -function layergroupRequest(layergroupConfig, method, callbackName, extraParams) { +function layergroupRequest (layergroupConfig, method, callbackName, extraParams) { method = method || 'POST'; var request = { @@ -165,7 +163,7 @@ function layergroupRequest(layergroupConfig, method, callbackName, extraParams) return request; } -function singleLayerMapConfig(sql, cartocss, cartocssVersion, interactivity) { +function singleLayerMapConfig (sql, cartocss, cartocssVersion, interactivity) { return { version: '1.3.0', layers: [ @@ -183,15 +181,15 @@ function singleLayerMapConfig(sql, cartocss, cartocssVersion, interactivity) { }; } -function defaultTableMapConfig(tableName, cartocss, cartocssVersion, interactivity) { +function defaultTableMapConfig (tableName, cartocss, cartocssVersion, interactivity) { return singleLayerMapConfig(defaultTableQuery(tableName), cartocss, cartocssVersion, interactivity); } -function defaultTableQuery(tableName) { - return _.template('SELECT * FROM <%= tableName %>', {tableName: tableName}); +function defaultTableQuery (tableName) { + return _.template('SELECT * FROM <%= tableName %>', { tableName: tableName }); } -function getStaticBbox(layergroupConfig, west, south, east, north, width, height, expectedResponse, callback) { +function getStaticBbox (layergroupConfig, west, south, east, north, width, height, expectedResponse, callback) { if (!callback) { callback = expectedResponse; expectedResponse = pngContentType; @@ -208,7 +206,7 @@ function getStaticBbox(layergroupConfig, west, south, east, north, width, height return getGeneric(layergroupConfig, url, expectedResponse, callback); } -function getStaticCenter(layergroupConfig, zoom, lat, lon, width, height, expectedResponse, callback) { +function getStaticCenter (layergroupConfig, zoom, lat, lon, width, height, expectedResponse, callback) { if (!callback) { callback = expectedResponse; expectedResponse = pngContentType; @@ -227,7 +225,7 @@ function getStaticCenter(layergroupConfig, zoom, lat, lon, width, height, expect return getGeneric(layergroupConfig, url, expectedResponse, callback); } -function getGrid(layergroupConfig, layer, z, x, y, expectedResponse, callback) { +function getGrid (layergroupConfig, layer, z, x, y, expectedResponse, callback) { if (!callback) { callback = expectedResponse; expectedResponse = jsonContentType; @@ -243,7 +241,7 @@ function getGrid(layergroupConfig, layer, z, x, y, expectedResponse, callback) { return getLayer(layergroupConfig, options, expectedResponse, callback); } -function getGridJsonp(layergroupConfig, layer, z, x, y, jsonpCallbackName, expectedResponse, callback) { +function getGridJsonp (layergroupConfig, layer, z, x, y, jsonpCallbackName, expectedResponse, callback) { if (!callback) { callback = expectedResponse; expectedResponse = jsContentType; @@ -260,7 +258,7 @@ function getGridJsonp(layergroupConfig, layer, z, x, y, jsonpCallbackName, expec return getLayer(layergroupConfig, options, expectedResponse, callback); } -function getTorque(layergroupConfig, layer, z, x, y, expectedResponse, callback) { +function getTorque (layergroupConfig, layer, z, x, y, expectedResponse, callback) { if (!callback) { callback = expectedResponse; expectedResponse = jsonContentType; @@ -276,7 +274,7 @@ function getTorque(layergroupConfig, layer, z, x, y, expectedResponse, callback) return getLayer(layergroupConfig, options, expectedResponse, callback); } -function getTile(layergroupConfig, z, x, y, expectedResponse, callback) { +function getTile (layergroupConfig, z, x, y, expectedResponse, callback) { if (!callback) { callback = expectedResponse; expectedResponse = pngContentType; @@ -291,7 +289,7 @@ function getTile(layergroupConfig, z, x, y, expectedResponse, callback) { return getLayer(layergroupConfig, options, expectedResponse, callback); } -function getTileLayer(layergroupConfig, options, expectedResponse, callback) { +function getTileLayer (layergroupConfig, options, expectedResponse, callback) { if (!callback) { callback = expectedResponse; expectedResponse = pngContentType; @@ -300,11 +298,11 @@ function getTileLayer(layergroupConfig, options, expectedResponse, callback) { return getLayer(layergroupConfig, options, expectedResponse, callback); } -function getLayer(layergroupConfig, options, expectedResponse, callback) { +function getLayer (layergroupConfig, options, expectedResponse, callback) { return getGeneric(layergroupConfig, tileUrlStrategy(options), expectedResponse, callback); } -function tileUrlStrategy(options) { +function tileUrlStrategy (options) { var urlLayerPattern = [ '<%= layer %>', '<%= z %>', @@ -329,7 +327,7 @@ function tileUrlStrategy(options) { return '<%= layergroupid %>/' + urlTemplate(_.defaults(options, { z: 0, x: 0, y: 0, layer: 0 })); } -function getGeneric(layergroupConfig, url, expectedResponse, callback) { +function getGeneric (layergroupConfig, url, expectedResponse, callback) { if (_.isString(expectedResponse)) { expectedResponse = { status: 200, @@ -343,7 +341,7 @@ function getGeneric(layergroupConfig, url, expectedResponse, callback) { var layergroupid = null; step( - function requestLayergroup() { + function requestLayergroup () { var next = this; var request = { url: '/api/v1/map', @@ -364,7 +362,7 @@ function getGeneric(layergroupConfig, url, expectedResponse, callback) { next(err, res); }); }, - function validateLayergroup(err, res) { + function validateLayergroup (err, res) { assert.ok(!err, 'Failed to create layergroup'); var parsedBody = JSON.parse(res.body); @@ -374,7 +372,7 @@ function getGeneric(layergroupConfig, url, expectedResponse, callback) { return res; }, - function requestTile(err, res) { + function requestTile (err, res) { assert.ok(!err, 'Invalid layergroup response: ' + res.body); var next = this; @@ -399,12 +397,12 @@ function getGeneric(layergroupConfig, url, expectedResponse, callback) { next(err, res); }); }, - function validateTile(err, res) { + function validateTile (err, res) { assert.ok(!err, 'Failed to get tile'); var img; if (contentType === pngContentType) { - img = new mapnik.Image.fromBytesSync(new Buffer(res.body, 'binary')); + img = mapnik.Image.fromBytesSync(Buffer.from(res.body, 'binary')); } var keysToDelete = { @@ -412,15 +410,15 @@ function getGeneric(layergroupConfig, url, expectedResponse, callback) { }; var redisKey = 'map_cfg|' + LayergroupToken.parse(layergroupid).token; keysToDelete[redisKey] = 0; - testHelper.deleteRedisKeys(keysToDelete, function() { + testHelper.deleteRedisKeys(keysToDelete, function () { return callback(err, res, img); }); } ); } -function withLayergroup(layergroupConfig, options, callback) { - var validationLayergroupFn = function() {}; +function withLayergroup (layergroupConfig, options, callback) { + var validationLayergroupFn = function () {}; if (!callback) { callback = options; options = {}; @@ -439,14 +437,14 @@ function withLayergroup(layergroupConfig, options, callback) { }; step( - function requestLayergroup() { + function requestLayergroup () { var next = this; var request = layergroupRequest(layergroupConfig, 'POST'); assert.response(serverInstance(options), request, layergroupExpectedResponse, function (res, err) { next(err, res); }); }, - function validateLayergroup(err, res) { + function validateLayergroup (err, res) { assert.ok(!err, 'Failed to request layergroup'); var parsedBody = JSON.parse(res.body); @@ -456,7 +454,7 @@ function withLayergroup(layergroupConfig, options, callback) { validationLayergroupFn(res); - function requestTile(layergroupUrl, options, callback) { + function requestTile (layergroupUrl, options, callback) { if (!callback) { callback = options; options = { @@ -469,17 +467,17 @@ function withLayergroup(layergroupConfig, options, callback) { return `${signer ? `:${signer}@` : ''}`; }; - const cacheTpl = function ({ cache_buster, cacheBuster }) { - return `${cache_buster ? `:${cache_buster}` : `:${cacheBuster}`}`; + const cacheTpl = function ({ cacheBuster }) { + return `${cacheBuster ? `:${cacheBuster}` : ''}`; }; - const urlTpl = function ({layergroupid, cache_buster = null, tile }) { - const { signer, token , cacheBuster } = LayergroupToken.parse(layergroupid); + const urlTpl = function ({ layergroupid, cacheBuster, tile }) { + const { signer, token, cacheBuster: cb } = LayergroupToken.parse(layergroupid); const base = '/api/v1/map/'; - return `${base}${signerTpl({signer})}${token}${cacheTpl({cache_buster, cacheBuster})}${tile}`; + return `${base}${signerTpl({ signer })}${token}${cacheTpl({ cacheBuster: (cacheBuster || cb) })}${tile}`; }; - const finalUrl = urlTpl({ layergroupid, cache_buster: options.cache_buster, tile: layergroupUrl }); + const finalUrl = urlTpl({ layergroupid, cacheBuster: options.cache_buster, tile: layergroupUrl }); var request = { url: finalUrl, @@ -505,7 +503,7 @@ function withLayergroup(layergroupConfig, options, callback) { }); } - function finish(done) { + function finish (done) { var keysToDelete = { 'user:localhost:mapviews:global': 5 }; diff --git a/test/acceptance/ported/torque-boundaries-test.js b/test/acceptance/ported/torque-boundaries-test.js index e4854ac7..0cb1fa25 100644 --- a/test/acceptance/ported/torque-boundaries-test.js +++ b/test/acceptance/ported/torque-boundaries-test.js @@ -8,7 +8,7 @@ var ServerOptions = require('./support/ported-server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('torque boundary points', function() { +describe('torque boundary points', function () { var server; before(function () { @@ -18,11 +18,11 @@ describe('torque boundary points', function() { var layergroupIdToDelete = null; - beforeEach(function() { + beforeEach(function () { layergroupIdToDelete = null; }); - afterEach(function(done) { + afterEach(function (done) { var keysToDelete = { 'user:localhost:mapviews:global': 5 }; @@ -31,51 +31,54 @@ describe('torque boundary points', function() { testHelper.deleteRedisKeys(keysToDelete, done); }); - var boundaryPointsMapConfig = { + var boundaryPointsMapConfig = { version: '1.1.0', layers: [ - { type: 'torque', options: { - sql: "WITH p AS ( " + + { + type: 'torque', + options: { + sql: 'WITH p AS ( ' + " SELECT '1970-01-02'::date as d, " + // r1 is pixel resolution at zoom level 1 // s1 is tile size at zoom level 1 - " 1e-40 as o, 78271.517578125 as r1, 20037508.5 as s1 )" + - " SELECT 1 as i, d, ST_MakePoint(0,0) as ug FROM p" + - " UNION ALL " + - "SELECT 2, d, ST_MakePoint(-o,-o) FROM p" + - " UNION ALL " + - "SELECT 3, d, ST_MakePoint(-o,o) FROM p" + - " UNION ALL " + - "SELECT 4, d, ST_MakePoint(o,-o) FROM p" + - " UNION ALL " + - "SELECT 5, d, ST_MakePoint(o,o) FROM p" + - " UNION ALL " + - "SELECT 6, d, ST_MakePoint(-r1,r1) FROM p" + - " UNION ALL " + - "SELECT 7, d, ST_MakePoint(-r1/2,r1) FROM p" + - " UNION ALL " + - "SELECT 8, d, ST_MakePoint(-r1,-r1) FROM p" + - " UNION ALL " + + ' 1e-40 as o, 78271.517578125 as r1, 20037508.5 as s1 )' + + ' SELECT 1 as i, d, ST_MakePoint(0,0) as ug FROM p' + + ' UNION ALL ' + + 'SELECT 2, d, ST_MakePoint(-o,-o) FROM p' + + ' UNION ALL ' + + 'SELECT 3, d, ST_MakePoint(-o,o) FROM p' + + ' UNION ALL ' + + 'SELECT 4, d, ST_MakePoint(o,-o) FROM p' + + ' UNION ALL ' + + 'SELECT 5, d, ST_MakePoint(o,o) FROM p' + + ' UNION ALL ' + + 'SELECT 6, d, ST_MakePoint(-r1,r1) FROM p' + + ' UNION ALL ' + + 'SELECT 7, d, ST_MakePoint(-r1/2,r1) FROM p' + + ' UNION ALL ' + + 'SELECT 8, d, ST_MakePoint(-r1,-r1) FROM p' + + ' UNION ALL ' + // this is discarded, being on the right boundary - "SELECT 9, d, ST_MakePoint(s1,0) FROM p" + - " UNION ALL " + + 'SELECT 9, d, ST_MakePoint(s1,0) FROM p' + + ' UNION ALL ' + // this is discarded, being on the top boundary - "SELECT 10, d, ST_MakePoint(0,s1) FROM p" + - " UNION ALL " + + 'SELECT 10, d, ST_MakePoint(0,s1) FROM p' + + ' UNION ALL ' + // this is discarded, rounding to the right boundary - "SELECT 11, d, ST_MakePoint(s1-r1/2,0) FROM p" + - " UNION ALL " + + 'SELECT 11, d, ST_MakePoint(s1-r1/2,0) FROM p' + + ' UNION ALL ' + // this is discarded, rounding to the top boundary - "SELECT 12, d, ST_MakePoint(0,s1-r1/2) FROM p", - geom_column: 'ug', - cartocss: 'Map { ' + + 'SELECT 12, d, ST_MakePoint(0,s1-r1/2) FROM p', + geom_column: 'ug', + cartocss: 'Map { ' + '-torque-frame-count:2; ' + '-torque-resolution:1; ' + '-torque-time-attribute:"d"; ' + '-torque-data-aggregation:linear; ' + '-torque-aggregation-function:"count(i)"; }', - cartocss_version: '1.0.1' - } } + cartocss_version: '1.0.1' + } + } ] }; @@ -135,19 +138,19 @@ describe('torque boundary points', function() { { x__uint8: 255, y__uint8: 0, - vals__uint8: [{v: 2, d: 'i=6 (-r1,r1) and i=7(-r1/2,r1)'}], + vals__uint8: [{ v: 2, d: 'i=6 (-r1,r1) and i=7(-r1/2,r1)' }], dates__uint16: [0] }, { x__uint8: 255, y__uint8: 1, - vals__uint8: [{v: 2, d: 'i=1 and i=3'}], + vals__uint8: [{ v: 2, d: 'i=1 and i=3' }], dates__uint16: [0] }, { x__uint8: 255, y__uint8: 255, - vals__uint8: [{v: 2, d: 'i=10 and i=12'}], + vals__uint8: [{ v: 2, d: 'i=10 and i=12' }], dates__uint16: [0] } ] @@ -166,19 +169,19 @@ describe('torque boundary points', function() { { x__uint8: 255, y__uint8: 0, - vals__uint8: [{v: 2, d: 'i=9 and i=11'}], + vals__uint8: [{ v: 2, d: 'i=9 and i=11' }], dates__uint16: [0] }, { x__uint8: 0, y__uint8: 0, - vals__uint8: [{v: 2, d: 'i=1 and i=5'}], + vals__uint8: [{ v: 2, d: 'i=1 and i=5' }], dates__uint16: [0] }, { x__uint8: 0, y__uint8: 255, - vals__uint8: [{v: 2, d: 'i=10 and i=12'}], + vals__uint8: [{ v: 2, d: 'i=10 and i=12' }], dates__uint16: [0] } ] @@ -197,7 +200,7 @@ describe('torque boundary points', function() { { x__uint8: 255, y__uint8: 255, - vals__uint8: [{v: 3, d: 'i=1, i=2 and i=8'}], + vals__uint8: [{ v: 3, d: 'i=1, i=2 and i=8' }], dates__uint16: [0] } ] @@ -235,27 +238,25 @@ describe('torque boundary points', function() { } ]; - tileRequests.forEach(function(tileRequest) { + tileRequests.forEach(function (tileRequest) { // See https://github.com/CartoDB/Windshaft/issues/186 var desc = 'handles ' + tileRequest.desc + '.json.torque\n\n\t' + tileRequest.repr.join('\n\t') + '\n\n'; it(desc, function (done) { - assert.response(server, { url: '/api/v1/map', method: 'POST', headers: { host: 'localhost', 'Content-Type': 'application/json' }, data: JSON.stringify(boundaryPointsMapConfig) }, {}, function (res, err) { - assert.ok(!err, 'Failed to create layergroup'); var parsedBody = JSON.parse(res.body); - var expected_token = parsedBody.layergroupid; - layergroupIdToDelete = expected_token; + var expectedToken = parsedBody.layergroupid; + layergroupIdToDelete = expectedToken; var partialUrl = tileRequest.z + '/' + tileRequest.x + '/' + tileRequest.y; assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/' + partialUrl + '.json.torque', + url: '/api/v1/map/' + expectedToken + '/0/' + partialUrl + '.json.torque', method: 'GET', headers: { host: 'localhost' @@ -263,12 +264,12 @@ describe('torque boundary points', function() { }, {}, function (res, err) { assert.ok(!err, 'Failed to get json'); - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); var parsed = JSON.parse(res.body); /* Order the JSON first by descending x__uint8 and ascending * y__uint8 */ - parsed.sort(function(a,b) { + parsed.sort(function (a, b) { if (a.x__uint8 === b.x__uint8) { return (a.y__uint8 > b.y__uint8); } @@ -276,8 +277,8 @@ describe('torque boundary points', function() { }); var i = 0; - tileRequest.expects.forEach(function(expected) { - assert.equal( + tileRequest.expects.forEach(function (expected) { + assert.strictEqual( parsed[i].x__uint8, expected.x__uint8, parsed[i].x__uint8 + ' == ' + expected.x__uint8 + @@ -286,7 +287,7 @@ describe('torque boundary points', function() { '\nEXPECTED\n--------' + '\n' + JSON.stringify(tileRequest.expects, null, 4) ); - assert.equal( + assert.strictEqual( parsed[i].y__uint8, expected.y__uint8, parsed[i].y__uint8 + ' == ' + expected.y__uint8 + @@ -297,8 +298,8 @@ describe('torque boundary points', function() { ); var j = 0; - expected.vals__uint8.forEach(function(val) { - assert.equal( + expected.vals__uint8.forEach(function (val) { + assert.strictEqual( parsed[i].vals__uint8[j], val.v, 'desc: ' + val.d + @@ -319,7 +320,7 @@ describe('torque boundary points', function() { i++; }); - assert.equal( + assert.strictEqual( parsed.length, tileRequest.expects.length, 'Number of points did not match ' + @@ -336,24 +337,27 @@ describe('torque boundary points', function() { }); }); - it('regression london point', function(done) { - var londonPointMapConfig = { + it('regression london point', function (done) { + var londonPointMapConfig = { version: '1.1.0', layers: [ - { type: 'torque', options: { - sql: "SELECT " + - "1 as i, " + + { + type: 'torque', + options: { + sql: 'SELECT ' + + '1 as i, ' + "'1970-01-02'::date as d, " + - "ST_MakePoint(-11309.9155492599,6715342.44989312) g", - geom_column: 'g', - cartocss: 'Map { ' + + 'ST_MakePoint(-11309.9155492599,6715342.44989312) g', + geom_column: 'g', + cartocss: 'Map { ' + '-torque-frame-count:2; ' + '-torque-resolution:1; ' + '-torque-time-attribute:"d"; ' + '-torque-data-aggregation:linear; ' + '-torque-aggregation-function:"count(i)"; }', - cartocss_version: '1.0.1' - } } + cartocss_version: '1.0.1' + } + } ] }; @@ -369,7 +373,6 @@ describe('torque boundary points', function() { var layergroupId = parsedBody.layergroupid; layergroupIdToDelete = layergroupId; - assert.response(server, { url: '/api/v1/map/' + layergroupId + '/0/2/1/1.json.torque', method: 'GET', @@ -381,7 +384,7 @@ describe('torque boundary points', function() { var parsed = JSON.parse(res.body); - assert.deepEqual(parsed, [{ + assert.deepStrictEqual(parsed, [{ x__uint8: 255, y__uint8: 172, vals__uint8: [1], @@ -393,33 +396,36 @@ describe('torque boundary points', function() { }); }); - it('should consider resolution for least value in query', function(done) { - var londonPointMapConfig = { + it('should consider resolution for least value in query', function (done) { + var londonPointMapConfig = { version: '1.1.0', layers: [ - { type: 'torque', options: { - sql: "" + - "SELECT " + - "0 as i, " + + { + type: 'torque', + options: { + sql: '' + + 'SELECT ' + + '0 as i, ' + "st_transform('0101000020E6100000FABD3AB4B5031C400581A80ECC2F4940'::geometry, 3857) as g " + - "UNION ALL " + - "SELECT " + - "2 as i, " + + 'UNION ALL ' + + 'SELECT ' + + '2 as i, ' + "st_transform('0101000020E61000006739E30EAE031C406625C0C3C72F4940'::geometry, 3857) as g " + - "UNION ALL " + - "SELECT " + - "3 as i, " + + 'UNION ALL ' + + 'SELECT ' + + '3 as i, ' + "st_transform('0101000020E6100000E26DB8A2A7031C40C8BAA5C2C52F4940'::geometry, 3857) as g", - geom_column: 'g', - cartocss: 'Map { ' + + geom_column: 'g', + cartocss: 'Map { ' + '-torque-frame-count:1; ' + '-torque-animation-duration:30;' + '-torque-time-attribute:"i"; ' + '-torque-aggregation-function:"count(i)"; ' + '-torque-resolution:2; ' + '-torque-data-aggregation: cumulative; }', - cartocss_version: '1.0.1' - } } + cartocss_version: '1.0.1' + } + } ] }; @@ -435,7 +441,6 @@ describe('torque boundary points', function() { var layergroupId = parsedBody.layergroupid; layergroupIdToDelete = layergroupId; - assert.response(server, { url: '/api/v1/map/' + layergroupId + '/0/13/4255/2765.json.torque', method: 'GET', @@ -447,7 +452,7 @@ describe('torque boundary points', function() { var parsed = JSON.parse(res.body); - assert.deepEqual(parsed.sort(function(a,b){return a.x__uint8 > b.x__uint8;}), [ + assert.deepStrictEqual(parsed.sort(function (a, b) { return a.x__uint8 > b.x__uint8; }), [ { x__uint8: 47, y__uint8: 127, @@ -465,5 +470,4 @@ describe('torque boundary points', function() { }); }); }); - }); diff --git a/test/acceptance/ported/torque-png-test.js b/test/acceptance/ported/torque-png-test.js index 1b0fed8e..9f972d2d 100644 --- a/test/acceptance/ported/torque-png-test.js +++ b/test/acceptance/ported/torque-png-test.js @@ -5,17 +5,17 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var testClient = require('./support/test-client'); -describe('torque png renderer', function() { +describe('torque png renderer', function () { var IMAGE_TOLERANCE_PER_MIL = 20; - var torquePngPointsMapConfig = { + var torquePngPointsMapConfig = { version: '1.2.0', layers: [ { type: 'torque', options: { - sql: "SELECT * FROM populated_places_simple_reduced where the_geom" + - " && ST_MakeEnvelope(-90, 0, 90, 65)", + sql: 'SELECT * FROM populated_places_simple_reduced where the_geom' + + ' && ST_MakeEnvelope(-90, 0, 90, 65)', cartocss: [ 'Map {', ' buffer-size:0;', @@ -60,19 +60,20 @@ describe('torque png renderer', function() { } ]; - function torquePngFixture(zxy) { + function torquePngFixture (zxy) { return './test/fixtures/torque/populated_places_simple_reduced-' + zxy.join('.') + '.png'; } - tileRequests.forEach(function(tileRequest) { - var z = tileRequest.z, - x = tileRequest.x, - y = tileRequest.y; + tileRequests.forEach(function (tileRequest) { + var z = tileRequest.z; + var x = tileRequest.x; + var y = tileRequest.y; var zxy = [z, x, y]; it('tile ' + zxy.join('/') + '.torque.png', function (done) { - testClient.getTileLayer(torquePngPointsMapConfig, tileRequest, function(err, res) { + testClient.getTileLayer(torquePngPointsMapConfig, tileRequest, function (err, res) { + assert.ifError(err); assert.imageBufferIsSimilarToFile(res.body, torquePngFixture(zxy), IMAGE_TOLERANCE_PER_MIL, - function(err) { + function (err) { assert.ok(!err); done(); } @@ -81,14 +82,13 @@ describe('torque png renderer', function() { }); }); - var mapConfigTorqueOffset = { version: '1.3.0', layers: [ { type: 'torque', options: { - sql: "SELECT * FROM populated_places_simple_reduced", + sql: 'SELECT * FROM populated_places_simple_reduced', cartocss: [ 'Map {', 'buffer-size:0;', @@ -125,21 +125,19 @@ describe('torque png renderer', function() { ] }; - it('torque static map with offset', function(done) { - var w = 600, - h = 400; + it('torque static map with offset', function (done) { + var w = 600; + var h = 400; - testClient.getStaticBbox(mapConfigTorqueOffset, -170, -87, 170, 87, w, h, function(err, res, img) { + testClient.getStaticBbox(mapConfigTorqueOffset, -170, -87, 170, 87, w, h, function (err, res, img) { if (err) { return done(err); } - assert.equal(img.width(), w); - assert.equal(img.height(), h); + assert.strictEqual(img.width(), w); + assert.strictEqual(img.height(), h); done(); }); - }); - }); diff --git a/test/acceptance/ported/torque-test.js b/test/acceptance/ported/torque-test.js index b40650cc..feee249a 100644 --- a/test/acceptance/ported/torque-test.js +++ b/test/acceptance/ported/torque-test.js @@ -10,7 +10,7 @@ var ServerOptions = require('./support/ported-server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('torque', function() { +describe('torque', function () { var server; before(function () { @@ -19,435 +19,437 @@ describe('torque', function() { }); var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { + afterEach(function (done) { testHelper.deleteRedisKeys(keysToDelete, done); }); - function checkCORSHeaders(res) { - assert.equal( + function checkCORSHeaders (res) { + assert.strictEqual( res.headers['access-control-allow-headers'], 'X-Requested-With, X-Prototype-Version, X-CSRF-Token, Authorization' ); - assert.equal(res.headers['access-control-allow-origin'], '*'); + assert.strictEqual(res.headers['access-control-allow-origin'], '*'); } - it("missing required property from torque layer", function(done) { + it('missing required property from torque layer', function (done) { + var layergroup = { + version: '1.1.0', + layers: [ + { + type: 'torque', + options: { + sql: 'select cartodb_id, the_geom from test_table', + geom_column: 'the_geom', + srid: 4326, + cartocss: 'Map { marker-fill:blue; }' + } + } + ] + }; - var layergroup = { - version: '1.1.0', - layers: [ - { type: 'torque', options: { - sql: 'select cartodb_id, the_geom from test_table', - geom_column: 'the_geom', - srid: 4326, - cartocss: 'Map { marker-fill:blue; }' - } } - ] - }; - - step( - function do_post1() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { next(null, res); }); - }, - function checkResponse(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors, parsed); - var error = parsed.errors[0]; - assert.equal(error, - "Missing required property '-torque-frame-count' in torque layer CartoCSS"); - return null; - }, - function do_post2(err) - { - assert.ifError(err); - var next = this; - var css = 'Map { -torque-frame-count: 2; }'; - layergroup.layers[0].options.cartocss = css; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { next(null, res); }); - }, - function checkResponse2(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors, parsed); - var error = parsed.errors[0]; - assert.equal(error, - "Missing required property '-torque-resolution' in torque layer CartoCSS"); - return null; - }, - function do_post3(err) - { - assert.ifError(err); - var next = this; - var css = 'Map { -torque-frame-count: 2; -torque-resolution: 3; }'; - layergroup.layers[0].options.cartocss = css; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { next(null, res); }); - }, - function checkResponse3(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors, parsed); - var error = parsed.errors[0]; - assert.equal(error, - "Missing required property '-torque-aggregation-function' in torque layer CartoCSS"); - return null; - }, - function finish(err) { - done(err); - } - ); + step( + function doPost1 () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { next(null, res); }); + }, + function checkResponse (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors, parsed); + var error = parsed.errors[0]; + assert.strictEqual(error, + "Missing required property '-torque-frame-count' in torque layer CartoCSS"); + return null; + }, + function doPost2 (err) { + assert.ifError(err); + var next = this; + var css = 'Map { -torque-frame-count: 2; }'; + layergroup.layers[0].options.cartocss = css; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { next(null, res); }); + }, + function checkResponse2 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors, parsed); + var error = parsed.errors[0]; + assert.strictEqual(error, + "Missing required property '-torque-resolution' in torque layer CartoCSS"); + return null; + }, + function doPost3 (err) { + assert.ifError(err); + var next = this; + var css = 'Map { -torque-frame-count: 2; -torque-resolution: 3; }'; + layergroup.layers[0].options.cartocss = css; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { next(null, res); }); + }, + function checkResponse3 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors, parsed); + var error = parsed.errors[0]; + assert.strictEqual(error, + "Missing required property '-torque-aggregation-function' in torque layer CartoCSS"); + return null; + }, + function finish (err) { + done(err); + } + ); }); // See http://github.com/CartoDB/Windshaft/issues/150 - it.skip("unquoted property in torque layer", function(done) { - - var layergroup = { - version: '1.1.0', - layers: [ - { type: 'torque', options: { - sql: 'select updated_at as d, cartodb_id as id, the_geom from test_table', - geom_column: 'the_geom', - srid: 4326, - cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:"d"; ' + + it.skip('unquoted property in torque layer', function (done) { + var layergroup = { + version: '1.1.0', + layers: [ + { + type: 'torque', + options: { + sql: 'select updated_at as d, cartodb_id as id, the_geom from test_table', + geom_column: 'the_geom', + srid: 4326, + cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:"d"; ' + '-torque-aggregation-function:count(id); }' - } } - ] - }; - step( - function do_post1() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function(res) { next(null, res); }); - }, - function checkResponse(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors, parsed); - var error = parsed.errors[0]; - assert.equal(error, "Something meaningful here"); - return null; - }, - function finish(err) { - done(err); - } - ); + } + } + ] + }; + step( + function doPost1 () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { next(null, res); }); + }, + function checkResponse (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors, parsed); + var error = parsed.errors[0]; + assert.strictEqual(error, 'Something meaningful here'); + return null; + }, + function finish (err) { + done(err); + } + ); }); - it("can render tile for valid mapconfig", function(done) { - - var mapconfig = { - version: '1.1.0', - layers: [ - { type: 'torque', options: { - sql: "select 1 as id, '1970-01-02'::date as d, 'POINT(0 0)'::geometry as the_geom UNION ALL select 2, " + + it('can render tile for valid mapconfig', function (done) { + var mapconfig = { + version: '1.1.0', + layers: [ + { + type: 'torque', + options: { + sql: "select 1 as id, '1970-01-02'::date as d, 'POINT(0 0)'::geometry as the_geom UNION ALL select 2, " + "'1970-01-01'::date, 'POINT(1 1)'::geometry", - geom_column: 'the_geom', - cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' + + geom_column: 'the_geom', + cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' + '-torque-aggregation-function:\'count(id)\'; }', - cartocss_version: '2.0.1' - } } - ] - }; + cartocss_version: '2.0.1' + } + } + ] + }; - var expected_token; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(mapconfig) - }, {}, function(res, err) { next(err, res); }); - }, - function checkPost(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - // CORS headers should be sent with response - // from layergroup creation via POST - checkCORSHeaders(res); - var parsedBody = JSON.parse(res.body); - if ( expected_token ) { - assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 2}); - } else { - expected_token = parsedBody.layergroupid; - } - var meta = parsedBody.metadata; - assert.ok(!_.isUndefined(meta), - 'No metadata in torque MapConfig creation response: ' + res.body); - var tm = meta.torque; - assert.ok(tm, - 'No "torque" in metadata:' + JSON.stringify(meta)); - var tm0 = tm[0]; - assert.ok(tm0, - 'No layer 0 in "torque" in metadata:' + JSON.stringify(tm)); - var expectedTorqueMetadata = {"start":0,"end":86400000,"data_steps":2,"column_type":"date"}; - Object.keys(expectedTorqueMetadata).forEach(function(k) { - assert.equal(tm0[k], expectedTorqueMetadata[k]); - assert.equal(meta.layers[0].meta[k], expectedTorqueMetadata[k]); - }); - return null; - }, - function do_get_tile(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0.png', - method: 'GET', - encoding: 'binary', - headers: { - host: 'localhost' - } - }, {}, function(res, err) { next(err, res); }); - }, - function check_mapnik_error_1(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ( res.statusCode !== 200 ? (': ' + res.body) : '' )); - var parsed = JSON.parse(res.body); - assert.equal(parsed.errors.length, 1); - assert.equal(parsed.errors[0], "No 'mapnik' layers in MapConfig"); - return null; - }, - function do_get_grid0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0/0.grid.json', - method: 'GET', - headers: { - host: 'localhost' - } - }, {}, function(res, err) { next(err, res); }); - }, - function check_mapnik_error_2(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ( res.statusCode !== 200 ? (': ' + res.body) : '' )); - var parsed = JSON.parse(res.body); - assert.equal(parsed.errors.length, 1); - assert.equal(parsed.errors[0], "Unsupported format grid.json"); - return null; - }, - function do_get_torque0(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0/0.json.torque', - method: 'GET', - headers: { - host: 'localhost' - } - }, {}, function(res, err) { next(err, res); }); - }, - function check_torque0_response(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - var tile_content = [{"x__uint8":43,"y__uint8":43,"vals__uint8":[1,1],"dates__uint16":[0,1]}]; - var parsed = JSON.parse(res.body); - assert.deepEqual(tile_content, parsed); - return null; - }, - function do_get_torque0_1(err) - { - assert.ifError(err); - var next = this; - assert.response(server, { - url: '/api/v1/map/' + expected_token + '/0/0/0/0.torque.json', - method: 'GET', - headers: { - host: 'localhost' - } - }, {}, function(res, err) { next(err, res); }); - }, - function check_torque0_response_1(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - var tile_content = [{"x__uint8":43,"y__uint8":43,"vals__uint8":[1,1],"dates__uint16":[0,1]}]; - var parsed = JSON.parse(res.body); - assert.deepEqual(tile_content, parsed); - return null; - }, - function finish(err) { - keysToDelete['map_cfg|' + LayergroupToken.parse(expected_token).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - done(err); - } - ); + var expectedToken; + step( + function doPost () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(mapconfig) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + // CORS headers should be sent with response + // from layergroup creation via POST + checkCORSHeaders(res); + var parsedBody = JSON.parse(res.body); + if (expectedToken) { + assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 2 }); + } else { + expectedToken = parsedBody.layergroupid; + } + var meta = parsedBody.metadata; + assert.ok(!_.isUndefined(meta), + 'No metadata in torque MapConfig creation response: ' + res.body); + var tm = meta.torque; + assert.ok(tm, + 'No "torque" in metadata:' + JSON.stringify(meta)); + var tm0 = tm[0]; + assert.ok(tm0, + 'No layer 0 in "torque" in metadata:' + JSON.stringify(tm)); + var expectedTorqueMetadata = { start: 0, end: 86400000, data_steps: 2, column_type: 'date' }; + Object.keys(expectedTorqueMetadata).forEach(function (k) { + assert.strictEqual(tm0[k], expectedTorqueMetadata[k]); + assert.strictEqual(meta.layers[0].meta[k], expectedTorqueMetadata[k]); + }); + return null; + }, + function doGetTile (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0.png', + method: 'GET', + encoding: 'binary', + headers: { + host: 'localhost' + } + }, {}, function (res, err) { next(err, res); }); + }, + function checkMapnikError1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + (res.statusCode !== 200 ? (': ' + res.body) : '')); + var parsed = JSON.parse(res.body); + assert.strictEqual(parsed.errors.length, 1); + assert.strictEqual(parsed.errors[0], "No 'mapnik' layers in MapConfig"); + return null; + }, + function doGetGrid0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0/0.grid.json', + method: 'GET', + headers: { + host: 'localhost' + } + }, {}, function (res, err) { next(err, res); }); + }, + function checkMapnikError2 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + (res.statusCode !== 200 ? (': ' + res.body) : '')); + var parsed = JSON.parse(res.body); + assert.strictEqual(parsed.errors.length, 1); + assert.strictEqual(parsed.errors[0], 'Unsupported format grid.json'); + return null; + }, + function doGetTorque0 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0/0.json.torque', + method: 'GET', + headers: { + host: 'localhost' + } + }, {}, function (res, err) { next(err, res); }); + }, + function checkTorque0Response (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + var tileContent = [{ x__uint8: 43, y__uint8: 43, vals__uint8: [1, 1], dates__uint16: [0, 1] }]; + var parsed = JSON.parse(res.body); + assert.deepStrictEqual(tileContent, parsed); + return null; + }, + function doGetTorque01 (err) { + assert.ifError(err); + var next = this; + assert.response(server, { + url: '/api/v1/map/' + expectedToken + '/0/0/0/0.torque.json', + method: 'GET', + headers: { + host: 'localhost' + } + }, {}, function (res, err) { next(err, res); }); + }, + function checkTorque0Response1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + var tileContent = [{ x__uint8: 43, y__uint8: 43, vals__uint8: [1, 1], dates__uint16: [0, 1] }]; + var parsed = JSON.parse(res.body); + assert.deepStrictEqual(tileContent, parsed); + return null; + }, + function finish (err) { + keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + done(err); + } + ); }); // Test that you cannot write to the database from a torque tile request // // Test for http://github.com/CartoDB/Windshaft/issues/130 // - it("database access is read-only", function(done) { - var mapconfig = { - version: '1.1.0', - layers: [ - { type: 'torque', options: { - sql: "select 'SRID=3857;POINT(0 0)'::geometry as g, now() as d,* from " + + it('database access is read-only', function (done) { + var mapconfig = { + version: '1.1.0', + layers: [ + { + type: 'torque', + options: { + sql: "select 'SRID=3857;POINT(0 0)'::geometry as g, now() as d,* from " + "test_table_inserter(st_setsrid(st_point(0,0),4326),'write')", - geom_column: 'g', - cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' + + geom_column: 'g', + cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' + '-torque-aggregation-function:\'count(*)\'; }', - cartocss_version: '2.0.1' - } } - ] - }; - step( - function do_post() - { - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(mapconfig) - }, {}, function(res, err) { next(err, res); }); - }, - function checkPost(err, res) { - assert.ifError(err); - // TODO: should be 403 Forbidden - assert.equal(res.statusCode, 400, res.statusCode + ': ' + (res.statusCode===200?'...':res.body)); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors); - assert.equal(parsed.errors.length, 1); - var msg = parsed.errors[0]; - assert.equal(msg, "TorqueRenderer: cannot execute INSERT in a read-only transaction"); - return null; - }, - function finish(err) { - done(err); - } - ); - + cartocss_version: '2.0.1' + } + } + ] + }; + step( + function doPost () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(mapconfig) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost (err, res) { + assert.ifError(err); + // TODO: should be 403 Forbidden + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + (res.statusCode === 200 ? '...' : res.body)); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors); + assert.strictEqual(parsed.errors.length, 1); + var msg = parsed.errors[0]; + assert.strictEqual(msg, 'TorqueRenderer: cannot execute INSERT in a read-only transaction'); + return null; + }, + function finish (err) { + done(err); + } + ); }); // See http://github.com/CartoDB/Windshaft/issues/164 - it("gives a 500 on database connection refused", function(done) { - - var mapconfig = { - version: '1.1.0', - layers: [ - { type: 'torque', options: { - sql: "select 1 as id, '1970-01-03'::date as d, 'POINT(0 0)'::geometry as the_geom UNION ALL select 2, " + + it('gives a 500 on database connection refused', function (done) { + var mapconfig = { + version: '1.1.0', + layers: [ + { + type: 'torque', + options: { + sql: "select 1 as id, '1970-01-03'::date as d, 'POINT(0 0)'::geometry as the_geom UNION ALL select 2, " + "'1970-01-01'::date, 'POINT(1 1)'::geometry", - geom_column: 'the_geom', - cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' + + geom_column: 'the_geom', + cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' + '-torque-aggregation-function:\'count(id)\'; }', - cartocss_version: '2.0.1' - } } - ] - }; + cartocss_version: '2.0.1' + } + } + ] + }; - let defautlPort = global.environment.postgres.port; + const defautlPort = global.environment.postgres.port; - step( - function do_post() - { - var next = this; - global.environment.postgres.port = 54777; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(mapconfig) - }, {}, function(res, err) { next(err, res); }); - }, - function checkPost(err, res) { - assert.ifError(err); + step( + function doPost () { + var next = this; + global.environment.postgres.port = 54777; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(mapconfig) + }, {}, function (res, err) { next(err, res); }); + }, + function checkPost (err, res) { + assert.ifError(err); - global.environment.postgres.port = defautlPort; + global.environment.postgres.port = defautlPort; - assert.equal(res.statusCode, 500, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors, parsed); - var error = parsed.errors[0]; - assert.equal(error, "TorqueRenderer: cannot connect to the database"); - return null; - }, - function finish(err) { - done(err); - } - ); + assert.strictEqual(res.statusCode, 500, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors, parsed); + var error = parsed.errors[0]; + assert.strictEqual(error, 'TorqueRenderer: cannot connect to the database'); + return null; + }, + function finish (err) { + done(err); + } + ); }); - it("checks types for torque-specific styles", function(done) { - var wrongStyle = ["Map {", - "-torque-frame-count:512;", - "-torque-animation-duration:30;", - "-torque-time-attribute:'cartodb_id';", - "-torque-aggregation-function:count(cartodb_id);", //unquoted aggregation function - "-torque-resolution:4;", - "-torque-data-aggregation:linear;", - "}"].join(" "); - var layergroup = { - version: '1.1.0', - layers: [ - { type: 'torque', options: { - sql: 'select cartodb_id, the_geom from test_table', - geom_column: 'the_geom', - srid: 4326, - cartocss: wrongStyle - } } - ] - }; + it('checks types for torque-specific styles', function (done) { + var wrongStyle = ['Map {', + '-torque-frame-count:512;', + '-torque-animation-duration:30;', + "-torque-time-attribute:'cartodb_id';", + '-torque-aggregation-function:count(cartodb_id);', // unquoted aggregation function + '-torque-resolution:4;', + '-torque-data-aggregation:linear;', + '}'].join(' '); + var layergroup = { + version: '1.1.0', + layers: [ + { + type: 'torque', + options: { + sql: 'select cartodb_id, the_geom from test_table', + geom_column: 'the_geom', + srid: 4326, + cartocss: wrongStyle + } + } + ] + }; - step( - function request(){ - var next = this; - assert.response(server, { - url: '/api/v1/map', - method: 'POST', - headers: { host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(layergroup) - }, {}, function (res) { next(null, res); }); - }, - function checkResponse(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.errors, parsed); - var error = parsed.errors[0]; - assert.equal(error, - "Unexpected type for property '-torque-aggregation-function', expected string"); - done(); - return null; - } - ); - }); + step( + function request () { + var next = this; + assert.response(server, { + url: '/api/v1/map', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(layergroup) + }, {}, function (res) { next(null, res); }); + }, + function checkResponse (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.errors, parsed); + var error = parsed.errors[0]; + assert.strictEqual(error, + "Unexpected type for property '-torque-aggregation-function', expected string"); + done(); + return null; + } + ); + }); }); diff --git a/test/acceptance/ported/torque-zero-zero-test.js b/test/acceptance/ported/torque-zero-zero-test.js index 9b76183e..3c144c77 100644 --- a/test/acceptance/ported/torque-zero-zero-test.js +++ b/test/acceptance/ported/torque-zero-zero-test.js @@ -5,7 +5,7 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var testClient = require('./support/test-client'); -describe('torque tiles at 0,0 point', function() { +describe('torque tiles at 0,0 point', function () { /* Tiles are represented as in: @@ -22,35 +22,34 @@ describe('torque tiles at 0,0 point', function() { x: 3, y: 3, expects: [], - expects_fixed: [{"x__uint8":1,"y__uint8":0,"vals__uint8":[1],"dates__uint16":[0]}] + expects_fixed: [{ x__uint8: 1, y__uint8: 0, vals__uint8: [1], dates__uint16: [0] }] }, { what: 'tr', x: 4, y: 3, expects: [], - expects_fixed: [{"x__uint8":0,"y__uint8":0,"vals__uint8":[1],"dates__uint16":[0]}] + expects_fixed: [{ x__uint8: 0, y__uint8: 0, vals__uint8: [1], dates__uint16: [0] }] }, { what: 'bl', x: 3, y: 4, - expects: [{"x__uint8":1,"y__uint8":1,"vals__uint8":[1],"dates__uint16":[0]}] + expects: [{ x__uint8: 1, y__uint8: 1, vals__uint8: [1], dates__uint16: [0] }] }, { what: 'br', x: 4, y: 4, - expects: [{"x__uint8":0,"y__uint8":1,"vals__uint8":[1],"dates__uint16":[0]}] + expects: [{ x__uint8: 0, y__uint8: 1, vals__uint8: [1], dates__uint16: [0] }] } ]; - tiles.forEach(function(tile) { - it(tile.what, function(done) { - + tiles.forEach(function (tile) { + it(tile.what, function (done) { var query = 'select 1 cartodb_id,' + ' ST_Transform(ST_SetSRID(ST_MakePoint(0, 0), 4326), 3857) the_geom_webmercator'; - var mapConfig = { + var mapConfig = { version: '1.3.0', layers: [ { @@ -77,17 +76,16 @@ describe('torque tiles at 0,0 point', function() { ] }; - testClient.getTorque(mapConfig, 0, 3, tile.x, tile.y, function(err, res) { + testClient.getTorque(mapConfig, 0, 3, tile.x, tile.y, function (err, res) { assert.ok(!err, err); try { - assert.deepEqual(JSON.parse(res.body), tile.expects); + assert.deepStrictEqual(JSON.parse(res.body), tile.expects); } catch (ex) { // With Proj 5.1 this bug has been fixed and the point appears in all tiles - assert.deepEqual(JSON.parse(res.body), tile.expects_fixed); + assert.deepStrictEqual(JSON.parse(res.body), tile.expects_fixed); } done(); }); }); }); - }); diff --git a/test/acceptance/ported/wrap-test.js b/test/acceptance/ported/wrap-test.js index cafa2ea3..107156a8 100644 --- a/test/acceptance/ported/wrap-test.js +++ b/test/acceptance/ported/wrap-test.js @@ -5,11 +5,11 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var testClient = require('./support/test-client'); -describe('wrap x coordinate', function() { - describe('renders correct tile', function() { +describe('wrap x coordinate', function () { + describe('renders correct tile', function () { var IMG_TOLERANCE_PER_MIL = 20; - function plainTorqueMapConfig(plainColor) { + function plainTorqueMapConfig (plainColor) { return { version: '1.2.0', layers: [ @@ -22,8 +22,8 @@ describe('wrap x coordinate', function() { { type: 'torque', options: { - sql: "SELECT * FROM populated_places_simple_reduced " + - "where the_geom && ST_MakeEnvelope(-90, 0, 90, 65)", + sql: 'SELECT * FROM populated_places_simple_reduced ' + + 'where the_geom && ST_MakeEnvelope(-90, 0, 90, 65)', cartocss: [ 'Map {', ' buffer-size:0;', @@ -85,18 +85,19 @@ describe('wrap x coordinate', function() { } ]; - function blendPngFixture(zxy) { + function blendPngFixture (zxy) { return './test/fixtures/blend/blend-plain-torque-' + zxy.join('.') + '.png'; } - testScenarios.forEach(function(testScenario) { + testScenarios.forEach(function (testScenario) { var tileRequest = testScenario.tile; var zxy = [tileRequest.z, tileRequest.x, tileRequest.y]; var fixtureZxy = [testScenario.fixture.z, testScenario.fixture.x, testScenario.fixture.y]; it('tile all/' + zxy.join('/') + '.png', function (done) { - testClient.getTileLayer(plainTorqueMapConfig(testScenario.plainColor), tileRequest, function(err, res) { + testClient.getTileLayer(plainTorqueMapConfig(testScenario.plainColor), tileRequest, function (err, res) { + assert.ifError(err); assert.imageBufferIsSimilarToFile(res.body, blendPngFixture(fixtureZxy), IMG_TOLERANCE_PER_MIL, - function(err) { + function (err) { assert.ok(!err); done(); } @@ -106,16 +107,15 @@ describe('wrap x coordinate', function() { }); }); - describe('mapnik', function() { - it("can get a tile with negative x coordinate", function(done){ - testClient.getTile(testClient.defaultTableMapConfig('test_table'), 2, -2, 1, function(err, res, img) { + describe('mapnik', function () { + it('can get a tile with negative x coordinate', function (done) { + testClient.getTile(testClient.defaultTableMapConfig('test_table'), 2, -2, 1, function (err, res, img) { assert.ok(!err); assert.ok(img); - assert.equal(img.width(), 256); - assert.equal(img.height(), 256); + assert.strictEqual(img.width(), 256); + assert.strictEqual(img.height(), 256); done(); }); }); }); - }); diff --git a/test/acceptance/rate-limit-test.js b/test/acceptance/rate-limit-test.js index 4560fd57..dc5d0cad 100644 --- a/test/acceptance/rate-limit-test.js +++ b/test/acceptance/rate-limit-test.js @@ -16,7 +16,7 @@ let userLimitsApi; let rateLimit; let redisClient; let testClient; -let keysToDelete = ['user:localhost:mapviews:global']; +const keysToDelete = ['user:localhost:mapviews:global']; const user = 'localhost'; let layergroupid; @@ -71,8 +71,7 @@ const createMapConfig = ({ } }); - -function setLimit(count, period, burst, endpoint = RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS) { +function setLimit (count, period, burst, endpoint = RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS) { redisClient.SELECT(8, err => { if (err) { return; @@ -86,13 +85,13 @@ function setLimit(count, period, burst, endpoint = RATE_LIMIT_ENDPOINTS_GROUPS.A }); } -function getReqAndRes() { +function getReqAndRes () { return { req: {}, res: { headers: {}, - set(headers, value) { - if(typeof headers === 'object') { + set (headers, value) { + if (typeof headers === 'object') { this.headers = headers; } else { this.headers[headers] = value; @@ -106,7 +105,7 @@ function getReqAndRes() { } function assertGetLayergroupRequest (status, limit, remaining, reset, retry, done) { - let response = { + const response = { status, headers: { 'Content-Type': 'application/json; charset=utf-8', @@ -116,7 +115,7 @@ function assertGetLayergroupRequest (status, limit, remaining, reset, retry, don } }; - if(retry) { + if (retry) { response.headers['Retry-After'] = retry; } @@ -131,27 +130,27 @@ function assertGetLayergroupRequest (status, limit, remaining, reset, retry, don function assertRateLimitRequest (status, limit, remaining, reset, retry, done) { const { req, res } = getReqAndRes(); rateLimit(req, res, function (err) { - let expectedHeaders = { - "Carto-Rate-Limit-Limit": limit, - "Carto-Rate-Limit-Remaining": remaining, - "Carto-Rate-Limit-Reset": reset + const expectedHeaders = { + 'Carto-Rate-Limit-Limit': limit, + 'Carto-Rate-Limit-Remaining': remaining, + 'Carto-Rate-Limit-Reset': reset }; - if(retry) { + if (retry) { expectedHeaders['Retry-After'] = retry; } - assert.deepEqual(res.headers, expectedHeaders); + assert.deepStrictEqual(res.headers, expectedHeaders); - if(status === 200) { + if (status === 200) { assert.ifError(err); } else { assert.ok(err); - assert.equal(err.message, 'You are over platform\'s limits: too many requests.' + + assert.strictEqual(err.message, 'You are over platform\'s limits: too many requests.' + ' Please contact us to know more details'); - assert.equal(err.http_status, 429); - assert.equal(err.type, 'limit'); - assert.equal(err.subtype, 'rate-limit'); + assert.strictEqual(err.http_status, 429); + assert.strictEqual(err.type, 'limit'); + assert.strictEqual(err.subtype, 'rate-limit'); } if (done) { @@ -160,8 +159,8 @@ function assertRateLimitRequest (status, limit, remaining, reset, retry, done) { }); } -describe('rate limit', function() { - before(function() { +describe('rate limit', function () { + before(function () { global.environment.enabledFeatures.rateLimitsEnabled = true; global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = true; @@ -169,13 +168,13 @@ describe('rate limit', function() { testClient = new TestClient(createMapConfig(), 1234); }); - after(function() { + after(function () { global.environment.enabledFeatures.rateLimitsEnabled = false; global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = false; }); - afterEach(function(done) { - keysToDelete.forEach( key => { + afterEach(function (done) { + keysToDelete.forEach(key => { redisClient.del(key); }); @@ -198,23 +197,21 @@ describe('rate limit', function() { assertGetLayergroupRequest(200, '2', '1', '1', null, done); }); - it("1 req/sec: 2 req/seg should be limited", function(done) { + it('1 req/sec: 2 req/seg should be limited', function (done) { const count = 1; const period = 1; const burst = 1; setLimit(count, period, burst); assertGetLayergroupRequest(200, '2', '1', '1'); - setTimeout( () => assertGetLayergroupRequest(200, '2', '0', '1'), 250); - setTimeout( () => assertGetLayergroupRequest(429, '2', '0', '1', '1'), 500); - setTimeout( () => assertGetLayergroupRequest(429, '2', '0', '1', '1'), 750); - setTimeout( () => assertGetLayergroupRequest(429, '2', '0', '1', '1'), 950); - setTimeout( () => assertGetLayergroupRequest(200, '2', '0', '1', null, done), 1050); + setTimeout(() => assertGetLayergroupRequest(200, '2', '0', '1'), 250); + setTimeout(() => assertGetLayergroupRequest(429, '2', '0', '1', '1'), 500); + setTimeout(() => assertGetLayergroupRequest(429, '2', '0', '1', '1'), 750); + setTimeout(() => assertGetLayergroupRequest(429, '2', '0', '1', '1'), 950); + setTimeout(() => assertGetLayergroupRequest(200, '2', '0', '1', null, done), 1050); }); - }); - describe('rate limit middleware', function () { before(function (done) { global.environment.enabledFeatures.rateLimitsEnabled = true; @@ -232,7 +229,6 @@ describe('rate limit middleware', function () { redisClient = redis.createClient(global.environment.redis.port); testClient = new TestClient(createMapConfig(), 1234); - const count = 1; const period = 1; const burst = 0; @@ -250,41 +246,39 @@ describe('rate limit middleware', function () { }); }); - it("1 req/sec: 2 req/seg should be limited", function (done) { + it('1 req/sec: 2 req/seg should be limited', function (done) { assertRateLimitRequest(200, 1, 0, 1); - setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 1), 250); - setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 1), 500); - setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 1), 750); - setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 1), 950); - setTimeout( () => assertRateLimitRequest(200, 1, 0, 1, null, done), 1050); + setTimeout(() => assertRateLimitRequest(429, 1, 0, 0, 1), 250); + setTimeout(() => assertRateLimitRequest(429, 1, 0, 0, 1), 500); + setTimeout(() => assertRateLimitRequest(429, 1, 0, 0, 1), 750); + setTimeout(() => assertRateLimitRequest(429, 1, 0, 0, 1), 950); + setTimeout(() => assertRateLimitRequest(200, 1, 0, 1, null, done), 1050); }); - it("1 req/sec: 2 req/seg should be limited, removing SHA script from Redis", function (done) { + it('1 req/sec: 2 req/seg should be limited, removing SHA script from Redis', function (done) { userLimitsApi.metadataBackend.redisCmd( 8, 'SCRIPT', ['FLUSH'], function () { assertRateLimitRequest(200, 1, 0, 1); - setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 1), 500); - setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 1), 500); - setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 1), 750); - setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 1), 950); - setTimeout( () => assertRateLimitRequest(200, 1, 0, 1, null, done), 1050); + setTimeout(() => assertRateLimitRequest(429, 1, 0, 0, 1), 500); + setTimeout(() => assertRateLimitRequest(429, 1, 0, 0, 1), 500); + setTimeout(() => assertRateLimitRequest(429, 1, 0, 0, 1), 750); + setTimeout(() => assertRateLimitRequest(429, 1, 0, 0, 1), 950); + setTimeout(() => assertRateLimitRequest(200, 1, 0, 1, null, done), 1050); } ); }); }); - const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS; describe('rate limit and vector tiles (mapnik)', () => rateLimitAndVectorTilesTest(false)); describe('rate limit and vector tiles (postgis)', () => rateLimitAndVectorTilesTest(true)); -function rateLimitAndVectorTilesTest(usePostGIS) { - - before(function() { +function rateLimitAndVectorTilesTest (usePostGIS) { + before(function () { serverOptions.renderer.mvt.usePostGIS = usePostGIS; }); @@ -292,7 +286,7 @@ function rateLimitAndVectorTilesTest(usePostGIS) { serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; }); - before(function(done) { + before(function (done) { global.environment.enabledFeatures.rateLimitsEnabled = true; global.environment.enabledFeatures.rateLimitsByEndpoint.tile = true; @@ -303,7 +297,7 @@ function rateLimitAndVectorTilesTest(usePostGIS) { setLimit(count, period, burst, RATE_LIMIT_ENDPOINTS_GROUPS.TILE); testClient = new TestClient(createMapConfig(), 1234); - testClient.getLayergroup({status: 200}, (err, res) => { + testClient.getLayergroup({ status: 200 }, (err, res) => { assert.ifError(err); layergroupid = res.layergroupid; @@ -312,13 +306,13 @@ function rateLimitAndVectorTilesTest(usePostGIS) { }); }); - after(function() { + after(function () { global.environment.enabledFeatures.rateLimitsEnabled = false; global.environment.enabledFeatures.rateLimitsByEndpoint.tile = false; }); - afterEach(function(done) { - keysToDelete.forEach( key => { + afterEach(function (done) { + keysToDelete.forEach(key => { redisClient.del(key); }); @@ -334,11 +328,11 @@ function rateLimitAndVectorTilesTest(usePostGIS) { it('mvt rate limited', function (done) { const tileParams = (status, limit, remaining, reset, retry, contentType) => { - let headers = { - "Content-Type": contentType, - "Carto-Rate-Limit-Limit": limit, - "Carto-Rate-Limit-Remaining": remaining, - "Carto-Rate-Limit-Reset": reset + const headers = { + 'Content-Type': contentType, + 'Carto-Rate-Limit-Limit': limit, + 'Carto-Rate-Limit-Remaining': remaining, + 'Carto-Rate-Limit-Reset': reset }; if (retry) { @@ -348,7 +342,7 @@ function rateLimitAndVectorTilesTest(usePostGIS) { return { layergroupid: layergroupid, format: 'mvt', - response: {status, headers} + response: { status, headers } }; }; @@ -364,15 +358,14 @@ function rateLimitAndVectorTilesTest(usePostGIS) { assert.ifError(err); var tileJSON = tile.toJSON(); - assert.equal(Array.isArray(tileJSON), true); - assert.equal(tileJSON.length, 2); - assert.equal(tileJSON[0].name, 'errorTileSquareLayer'); - assert.equal(tileJSON[1].name, 'errorTileStripesLayer'); + assert.strictEqual(Array.isArray(tileJSON), true); + assert.strictEqual(tileJSON.length, 2); + assert.strictEqual(tileJSON[0].name, 'errorTileSquareLayer'); + assert.strictEqual(tileJSON[1].name, 'errorTileStripesLayer'); done(); } ); }); - }); } diff --git a/test/acceptance/regressions-test.js b/test/acceptance/regressions-test.js index 8ac63a83..b777d729 100644 --- a/test/acceptance/regressions-test.js +++ b/test/acceptance/regressions-test.js @@ -8,8 +8,7 @@ const LayergroupToken = require('../../lib/models/layergroup-token'); const CartodbWindshaft = require('../../lib/server'); const serverOptions = require('../../lib/server-options'); -describe('regressions', function() { - +describe('regressions', function () { var ERROR_RESPONSE = { status: 400, headers: { @@ -17,15 +16,15 @@ describe('regressions', function() { } }; - it('should expose a nice error when missing sql option', function(done) { + it('should expose a nice error when missing sql option', function (done) { var mapConfig = { version: '1.5.0', layers: [ { - "type": "cartodb", - "options": { - "cartocss": '#polygons { polygon-fill: red; }', - "cartocss_version": "2.3.0" + type: 'cartodb', + options: { + cartocss: '#polygons { polygon-fill: red; }', + cartocss_version: '2.3.0' } } ] @@ -33,11 +32,11 @@ describe('regressions', function() { var testClient = new TestClient(mapConfig, 1234); - testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroupResult) { + testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) { assert.ok(!err, err); - assert.equal(layergroupResult.errors.length, 1); - assert.equal(layergroupResult.errors[0], 'Missing sql for layer 0 options'); + assert.strictEqual(layergroupResult.errors.length, 1); + assert.strictEqual(layergroupResult.errors[0], 'Missing sql for layer 0 options'); testClient.drain(done); }); @@ -71,7 +70,7 @@ describe('regressions', function() { }, data: JSON.stringify(layergroup) }, - function(res, err) { + function (res, err) { if (err) { return done(err); } @@ -112,7 +111,7 @@ describe('regressions', function() { const conn = testClient.getDBConnection(); - const sql = `select CDB_TableMetadataTouch('test_table_localhost_regular1'::regclass)`; + const sql = 'select CDB_TableMetadataTouch(\'test_table_localhost_regular1\'::regclass)'; conn.query(sql, (err) => { if (err) { @@ -129,7 +128,7 @@ describe('regressions', function() { const timestampA = parseInt(cacheBusterA, 10); const timestampB = parseInt(cacheBusterB, 10); - assert.notEqual(timestampA, timestampB); + assert.notStrictEqual(timestampA, timestampB); assert.ok(timestampA < timestampB, `timestampA: ${timestampA} > timestampB:${timestampB}`); testClient.drain(done); @@ -206,9 +205,9 @@ describe('regressions', function() { testClient.getDataview('country_places_count', params, (err, dataview) => { assert.ifError(err); - assert.equal(dataview.type, 'aggregation'); - assert.equal(dataview.categories.length, 1); - assert.deepEqual(dataview.categories[0], { value: 256, category: 'CAN', agg: false }); + assert.strictEqual(dataview.type, 'aggregation'); + assert.strictEqual(dataview.categories.length, 1); + assert.deepStrictEqual(dataview.categories[0], { value: 256, category: 'CAN', agg: false }); testClient.drain(done); }); diff --git a/test/acceptance/server-test.js b/test/acceptance/server-test.js index 976066a7..aa010b56 100644 --- a/test/acceptance/server-test.js +++ b/test/acceptance/server-test.js @@ -2,15 +2,14 @@ require('../support/test-helper'); -var assert = require('../support/assert'); +var assert = require('../support/assert'); var querystring = require('querystring'); -var step = require('step'); +var step = require('step'); var CartodbWindshaft = require('../../lib/server'); var serverOptions = require('../../lib/server-options'); - -describe('server', function() { +describe('server', function () { var server; before(function () { @@ -19,47 +18,47 @@ describe('server', function() { }); // TODO: I guess this should be a 404 instead... - it("get call to server returns 200", function(done){ - step( - function doGet() { - var next = this; - assert.response(server, { - url: '/', - method: 'GET' - },{}, function(res, err) { next(err,res); }); - }, - function doCheck(err, res) { - assert.ifError(err); - assert.ok(res.statusCode, 200); - var cc = res.headers['x-cache-channel']; - assert.ok(!cc); - return null; - }, - function finish(err) { - done(err); - } - ); + it('get call to server returns 200', function (done) { + step( + function doGet () { + var next = this; + assert.response(server, { + url: '/', + method: 'GET' + }, {}, function (res, err) { next(err, res); }); + }, + function doCheck (err, res) { + assert.ifError(err); + assert.ok(res.statusCode, 200); + var cc = res.headers['x-cache-channel']; + assert.ok(!cc); + return null; + }, + function finish (err) { + done(err); + } + ); }); - it("get call to server returns 200", function(done){ + it('get call to server returns 200', function (done) { assert.response(server, { url: '/version', method: 'GET' - },{ - status: 200 - }, function(res) { - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('windshaft_cartodb'), "No 'windshaft_cartodb' version in " + parsed); - assert.ok(parsed.hasOwnProperty('windshaft'), "No 'windshaft' version in " + parsed); - assert.ok(parsed.hasOwnProperty('grainstore'), "No 'grainstore' version in " + parsed); - assert.ok(parsed.hasOwnProperty('node_mapnik'), "No 'node_mapnik' version in " + parsed); - assert.ok(parsed.hasOwnProperty('mapnik'), "No 'mapnik' version in " + parsed); - done(); + }, { + status: 200 + }, function (res) { + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'windshaft_cartodb'), "No 'windshaft_cartodb' version in " + parsed); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'windshaft'), "No 'windshaft' version in " + parsed); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'grainstore'), "No 'grainstore' version in " + parsed); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'node_mapnik'), "No 'node_mapnik' version in " + parsed); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'mapnik'), "No 'mapnik' version in " + parsed); + done(); }); }); }); -describe('server old_api', function() { +describe('server old_api', function () { var server; before(function () { @@ -68,16 +67,16 @@ describe('server old_api', function() { }); // See https://github.com/CartoDB/Windshaft-cartodb/issues/115 - it.skip("get'ing tile with not-strictly-valid style", function(done) { - var style = querystring.stringify({style: '#test_table{line-color:black}}', style_version: '2.0.0'}); + it.skip("get'ing tile with not-strictly-valid style", function (done) { + var style = querystring.stringify({ style: '#test_table{line-color:black}}', style_version: '2.0.0' }); assert.response(server, { - headers: {host: 'localhost'}, + headers: { host: 'localhost' }, url: '/tiles/test_table/0/0/0.png?' + style, // madrid method: 'GET', encoding: 'binary' - },{}, function(res){ - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - done(); + }, {}, function (res) { + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + done(); }); }); }); diff --git a/test/acceptance/special-numeric-values-test.js b/test/acceptance/special-numeric-values-test.js index 0ac183fd..0e11bdc9 100644 --- a/test/acceptance/special-numeric-values-test.js +++ b/test/acceptance/special-numeric-values-test.js @@ -5,9 +5,8 @@ require('../support/test-helper'); var assert = require('../support/assert'); var TestClient = require('../support/test-client'); -describe('special numeric values', function() { - - afterEach(function(done) { +describe('special numeric values', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -17,7 +16,7 @@ describe('special numeric values', function() { var ATTRIBUTES_LAYER = 1; - function createMapConfig(sql, id, columns) { + function createMapConfig (sql, id, columns) { return { version: '1.6.0', layers: [ @@ -41,7 +40,7 @@ describe('special numeric values', function() { cartocss_version: '2.0.1' } } - ] + ] }; } @@ -63,9 +62,9 @@ describe('special numeric values', function() { this.testClient = new TestClient(mapConfig, 1234); this.testClient.getFeatureAttributes(featureId, ATTRIBUTES_LAYER, {}, function (err, attributes) { assert.ifError(err); - assert.equal(attributes.infinity, 'Infinity'); - assert.equal(attributes._infinity, '-Infinity'); - assert.equal(attributes.nan, 'NaN'); + assert.strictEqual(attributes.infinity, 'Infinity'); + assert.strictEqual(attributes._infinity, '-Infinity'); + assert.strictEqual(attributes.nan, 'NaN'); done(); }); }); diff --git a/test/acceptance/sql-wrap-test.js b/test/acceptance/sql-wrap-test.js index 87eb705f..fcf48fe7 100644 --- a/test/acceptance/sql-wrap-test.js +++ b/test/acceptance/sql-wrap-test.js @@ -5,9 +5,8 @@ require('../support/test-helper'); var assert = require('../support/assert'); var TestClient = require('../support/test-client'); -describe('sql-wrap', function() { - - afterEach(function(done) { +describe('sql-wrap', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -15,40 +14,39 @@ describe('sql-wrap', function() { } }); - it('should use sql_wrap from layer options', function(done) { + it('should use sql_wrap from layer options', function (done) { var mapConfig = { version: '1.5.0', layers: [ { - "type": "cartodb", - "options": { - "sql": "SELECT * FROM populated_places_simple_reduced", - "sql_wrap": "SELECT * FROM (<%= sql %>) _w WHERE adm0_a3 = 'USA'", - "cartocss": [ - "#points {", - " marker-fill-opacity: 1;", - " marker-line-color: #FFF;", - " marker-line-width: 0.5;", - " marker-line-opacity: 1;", - " marker-placement: point;", - " marker-type: ellipse;", - " marker-width: 8;", - " marker-fill: red;", - " marker-allow-overlap: true;", - "}" + type: 'cartodb', + options: { + sql: 'SELECT * FROM populated_places_simple_reduced', + sql_wrap: "SELECT * FROM (<%= sql %>) _w WHERE adm0_a3 = 'USA'", + cartocss: [ + '#points {', + ' marker-fill-opacity: 1;', + ' marker-line-color: #FFF;', + ' marker-line-width: 0.5;', + ' marker-line-opacity: 1;', + ' marker-placement: point;', + ' marker-type: ellipse;', + ' marker-width: 8;', + ' marker-fill: red;', + ' marker-allow-overlap: true;', + '}' ].join('\n'), - "cartocss_version": "2.3.0" + cartocss_version: '2.3.0' } } ] }; this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getTile(0, 0, 0, function(err, tile, img) { + this.testClient.getTile(0, 0, 0, function (err, tile, img) { assert.ok(!err, err); var fixtureImg = './test/fixtures/sql-wrap-usa-filter.png'; assert.imageIsSimilarToFile(img, fixtureImg, 20, done); }); }); - }); diff --git a/test/acceptance/stats/mapnik-stats-layergroup-test.js b/test/acceptance/stats/mapnik-stats-layergroup-test.js index 0071a3ae..ead01881 100644 --- a/test/acceptance/stats/mapnik-stats-layergroup-test.js +++ b/test/acceptance/stats/mapnik-stats-layergroup-test.js @@ -17,97 +17,97 @@ const suites = [ } ]; -suites.forEach(({desc, usePostGIS}) => { -describe(`[${desc}] Create mapnik layergroup`, function() { - const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS; +suites.forEach(({ desc, usePostGIS }) => { + describe(`[${desc}] Create mapnik layergroup`, function () { + const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS; - before(function() { - serverOptions.renderer.mvt.usePostGIS = usePostGIS; - this.layerStatsConfig = global.environment.enabledFeatures.layerStats; - global.environment.enabledFeatures.layerStats = true; - }); + before(function () { + serverOptions.renderer.mvt.usePostGIS = usePostGIS; + this.layerStatsConfig = global.environment.enabledFeatures.layerStats; + global.environment.enabledFeatures.layerStats = true; + }); - after(function() { - serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; - global.environment.enabledFeatures.layerStats = this.layerStatsConfig; - }); + after(function () { + serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; + global.environment.enabledFeatures.layerStats = this.layerStatsConfig; + }); - var cartocssVersion = '2.3.0'; - var cartocss = '#layer { line-width:16; }'; + var cartocssVersion = '2.3.0'; + var cartocss = '#layer { line-width:16; }'; - var mapnikLayer1 = { - type: 'mapnik', - options: { - sql: 'select * from test_table limit 1', - cartocss_version: cartocssVersion, - cartocss: cartocss - } - }; + var mapnikLayer1 = { + type: 'mapnik', + options: { + sql: 'select * from test_table limit 1', + cartocss_version: cartocssVersion, + cartocss: cartocss + } + }; - var mapnikLayer2 = { - type: 'mapnik', - options: { - sql: 'select * from test_table_2 limit 2', - cartocss_version: cartocssVersion, - cartocss: cartocss - } - }; + var mapnikLayer2 = { + type: 'mapnik', + options: { + sql: 'select * from test_table_2 limit 2', + cartocss_version: cartocssVersion, + cartocss: cartocss + } + }; - var mapnikLayer3 = { - type: 'mapnik', - options: { - sql: 'select * from test_table_3 limit 3', - cartocss_version: cartocssVersion, - cartocss: cartocss - } - }; + var mapnikLayer3 = { + type: 'mapnik', + options: { + sql: 'select * from test_table_3 limit 3', + cartocss_version: cartocssVersion, + cartocss: cartocss + } + }; - var mapnikLayer4 = { - type: 'mapnik', - options: { - sql: [ - 'select t1.cartodb_id, t1.the_geom, t1.the_geom_webmercator, t2.address', - ' from test_table t1, test_table_2 t2', - ' where t1.cartodb_id = t2.cartodb_id' - ].join(''), - cartocss_version: cartocssVersion, - cartocss: cartocss - } - }; + var mapnikLayer4 = { + type: 'mapnik', + options: { + sql: [ + 'select t1.cartodb_id, t1.the_geom, t1.the_geom_webmercator, t2.address', + ' from test_table t1, test_table_2 t2', + ' where t1.cartodb_id = t2.cartodb_id' + ].join(''), + cartocss_version: cartocssVersion, + cartocss: cartocss + } + }; - var mapnikLayer100 = { - type: 'mapnik', - options: { - sql: [ - 'SELECT * FROM test_table_100' - ].join(''), - cartocss_version: cartocssVersion, - cartocss: cartocss - } - }; + var mapnikLayer100 = { + type: 'mapnik', + options: { + sql: [ + 'SELECT * FROM test_table_100' + ].join(''), + cartocss_version: cartocssVersion, + cartocss: cartocss + } + }; - var httpLayer = { - type: 'http', - options: { - urlTemplate: 'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png', - subdomains: ['a','b','c'] - } - }; + var httpLayer = { + type: 'http', + options: { + urlTemplate: 'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'] + } + }; - var mapnikLayerGeomColumn = { - type: 'mapnik', - options: { - sql: 'select *, the_geom as my_geom from test_table_3 limit 2', - geom_column: 'my_geom', - cartocss_version: cartocssVersion, - cartocss: cartocss - } - }; + var mapnikLayerGeomColumn = { + type: 'mapnik', + options: { + sql: 'select *, the_geom as my_geom from test_table_3 limit 2', + geom_column: 'my_geom', + cartocss_version: cartocssVersion, + cartocss: cartocss + } + }; - var mapnikLayerNullCats = { - type: 'mapnik', - options: { - sql: ` + var mapnikLayerNullCats = { + type: 'mapnik', + options: { + sql: ` WITH geom AS ( SELECT 'SRID=4326;POINT(0 0)'::geometry AS the_geom, @@ -119,544 +119,542 @@ describe(`[${desc}] Create mapnik layergroup`, function() { UNION SELECT 2 AS cartodb_id, NULL::text As cat, geom.* FROM geom `, - cartocss_version: cartocssVersion, - cartocss: cartocss + cartocss_version: cartocssVersion, + cartocss: cartocss + } + }; + + function mapnikBasicLayerId (index) { + return 'layer' + index; } - }; - - function mapnikBasicLayerId(index) { - return 'layer' + index; - } - function typeLayerId(type, index) { - return type + '-' + mapnikBasicLayerId(index); - } - - it('with one mapnik layer should response with meta-stats for that layer', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - mapnikLayer1 - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 1); - testClient.drain(done); - }); - }); - - it('with two mapnik layer should response with meta-stats for every layer', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - mapnikLayer1, - mapnikLayer2 - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 1); - assert.equal(layergroup.metadata.layers[1].id, mapnikBasicLayerId(1)); - assert.equal(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 2); - testClient.drain(done); - }); - }); - - it('with three mapnik layer should response with meta-stats for every layer', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - mapnikLayer1, - mapnikLayer2, - mapnikLayer3 - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 1); - assert.equal(layergroup.metadata.layers[1].id, mapnikBasicLayerId(1)); - assert.equal(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 2); - assert.equal(layergroup.metadata.layers[2].id, mapnikBasicLayerId(2)); - assert.equal(layergroup.metadata.layers[2].meta.stats.estimatedFeatureCount, 3); - testClient.drain(done); - }); - }); - - it('with one mapnik layer (sql with join) should response with meta-stats for that layer', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - mapnikLayer4 - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); - testClient.drain(done); - }); - }); - - it('with two mapnik layer (sql with join) should response with meta-stats for every layer', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - mapnikLayer4, - mapnikLayer4 - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); - assert.equal(layergroup.metadata.layers[1].id, mapnikBasicLayerId(1)); - assert.equal(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 5); - testClient.drain(done); - }); - }); - - it('with two mapnik layer (with & without join) should response with meta-stats for every layer', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - mapnikLayer3, - mapnikLayer4 - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 3); - assert.ok(!layergroup.metadata.layers[0].meta.stats[1]); - assert.equal(layergroup.metadata.layers[1].id, mapnikBasicLayerId(1)); - assert.equal(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 5); - assert.ok(!layergroup.metadata.layers[2]); - testClient.drain(done); - }); - }); - - it('with mapnik and layer and httplayer should response with layer metadata with same order', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - mapnikLayer1, - httpLayer - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].type, 'mapnik'); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 1); - assert.equal(layergroup.metadata.layers[1].id, typeLayerId('http', 0)); - assert.equal(layergroup.metadata.layers[1].type, 'http'); - testClient.drain(done); - }); - }); - - it('with httpLayer and mapnik layer should response with layer metadata with same order', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - httpLayer, - mapnikLayer1 - ] - }); - - testClient.getLayergroup(function (err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, typeLayerId('http', 0)); - assert.equal(layergroup.metadata.layers[0].type, 'http'); - assert.ok(!layergroup.metadata.layers[0].meta.cartocss); - assert.equal(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 1); - assert.equal(layergroup.metadata.layers[1].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[1].type, 'mapnik'); - assert.equal(layergroup.metadata.layers[1].meta.cartocss, cartocss); - testClient.drain(done); - }); - }); - - it('should work with different geom_column', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - mapnikLayerGeomColumn - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - // we don't care about stats here as is an aliased column - assert.ok(layergroup.metadata.layers[0].meta.stats.hasOwnProperty('estimatedFeatureCount')); - testClient.drain(done); - }); - }); - - it('should not include the stats part if the FF is disabled', function(done) { - global.environment.enabledFeatures.layerStats = false; - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - httpLayer, - mapnikLayer1, - httpLayer - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, typeLayerId('http', 0)); - assert.equal(layergroup.metadata.layers[0].type, 'http'); - assert.equal(layergroup.metadata.layers[1].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[1].type, 'mapnik'); - assert.ok(!layergroup.metadata.layers[1].meta.hasOwnProperty('stats')); - assert.equal(layergroup.metadata.layers[2].id, typeLayerId('http', 1)); - assert.equal(layergroup.metadata.layers[2].type, 'http'); - global.environment.enabledFeatures.layerStats = true; - testClient.drain(done); - }); - }); - - function layerWithMetadata(layer, metadata) { - return Object.assign(layer, { - options: Object.assign(layer.options, { metadata }) - }); - } - - it('should provide columns as optional metadata', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayer4, { - columns: true - }) - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); - const expectedColumns = { - cartodb_id: { type: 'number' }, - the_geom: { type: 'geometry' }, - the_geom_webmercator: { type: 'geometry' }, - address: { type: 'string' } - }; - assert.deepEqual(layergroup.metadata.layers[0].meta.stats.columns, expectedColumns); - testClient.drain(done); - }); - }); - - // metadata categories are ordered only partially by descending frequency; - // this orders them completely to avoid ambiguities when comparing - function withSortedCategories(columns) { - function catOrder(a, b) { - if (a.frequency !== b.frequency) { - return b.frequency - a.frequency; - } - if (a.category < b.category) { - return -1; - } - if (a.category > b.category) { - return +1; - } - return 0; + function typeLayerId (type, index) { + return type + '-' + mapnikBasicLayerId(index); } - let sorted = {}; - Object.keys(columns).forEach(name => { - let data = columns[name]; - if (data.hasOwnProperty('categories')) { - data = Object.assign(data, { categories: data.categories.sort(catOrder)}); - } - sorted[name] = data; - }); - return sorted; - } - it('should provide column stats as optional metadata', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayer4, { - columnStats: true - }) - ] + it('with one mapnik layer should response with meta-stats for that layer', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + mapnikLayer1 + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 1); + testClient.drain(done); + }); }); - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); - const expectedColumns = { - cartodb_id: { - type: 'number', - avg: 3, - max: 5, - min: 1, - sum: 15 - }, - the_geom: { type: 'geometry' }, - the_geom_webmercator: { type: 'geometry' }, - address: { - type: 'string', - categories: [ - { - category: "Calle de la Palma 72, Madrid, Spain", - frequency: 1 - }, - { - category: "Calle de PĂ©rez GaldĂłs 9, Madrid, Spain", - frequency: 1 - }, - { - category: "Calle Divino Pastor 12, Madrid, Spain", - frequency: 1 - }, - { - category: "Manuel Fernández y González 8, Madrid, Spain", - frequency: 1 - }, - { - category: "Plaza Conde de Toreno 2, Madrid, Spain", - frequency: 1 - } - ] + it('with two mapnik layer should response with meta-stats for every layer', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + mapnikLayer1, + mapnikLayer2 + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 1); + assert.strictEqual(layergroup.metadata.layers[1].id, mapnikBasicLayerId(1)); + assert.strictEqual(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 2); + testClient.drain(done); + }); + }); + + it('with three mapnik layer should response with meta-stats for every layer', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + mapnikLayer1, + mapnikLayer2, + mapnikLayer3 + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 1); + assert.strictEqual(layergroup.metadata.layers[1].id, mapnikBasicLayerId(1)); + assert.strictEqual(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 2); + assert.strictEqual(layergroup.metadata.layers[2].id, mapnikBasicLayerId(2)); + assert.strictEqual(layergroup.metadata.layers[2].meta.stats.estimatedFeatureCount, 3); + testClient.drain(done); + }); + }); + + it('with one mapnik layer (sql with join) should response with meta-stats for that layer', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + mapnikLayer4 + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); + testClient.drain(done); + }); + }); + + it('with two mapnik layer (sql with join) should response with meta-stats for every layer', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + mapnikLayer4, + mapnikLayer4 + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); + assert.strictEqual(layergroup.metadata.layers[1].id, mapnikBasicLayerId(1)); + assert.strictEqual(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 5); + testClient.drain(done); + }); + }); + + it('with two mapnik layer (with & without join) should response with meta-stats for every layer', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + mapnikLayer3, + mapnikLayer4 + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 3); + assert.ok(!layergroup.metadata.layers[0].meta.stats[1]); + assert.strictEqual(layergroup.metadata.layers[1].id, mapnikBasicLayerId(1)); + assert.strictEqual(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 5); + assert.ok(!layergroup.metadata.layers[2]); + testClient.drain(done); + }); + }); + + it('with mapnik and layer and httplayer should response with layer metadata with same order', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + mapnikLayer1, + httpLayer + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].type, 'mapnik'); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 1); + assert.strictEqual(layergroup.metadata.layers[1].id, typeLayerId('http', 0)); + assert.strictEqual(layergroup.metadata.layers[1].type, 'http'); + testClient.drain(done); + }); + }); + + it('with httpLayer and mapnik layer should response with layer metadata with same order', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + httpLayer, + mapnikLayer1 + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, typeLayerId('http', 0)); + assert.strictEqual(layergroup.metadata.layers[0].type, 'http'); + assert.ok(!layergroup.metadata.layers[0].meta.cartocss); + assert.strictEqual(layergroup.metadata.layers[1].meta.stats.estimatedFeatureCount, 1); + assert.strictEqual(layergroup.metadata.layers[1].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[1].type, 'mapnik'); + assert.strictEqual(layergroup.metadata.layers[1].meta.cartocss, cartocss); + testClient.drain(done); + }); + }); + + it('should work with different geom_column', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + mapnikLayerGeomColumn + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + // we don't care about stats here as is an aliased column + assert.ok(Object.prototype.hasOwnProperty.call(layergroup.metadata.layers[0].meta.stats, 'estimatedFeatureCount')); + testClient.drain(done); + }); + }); + + it('should not include the stats part if the FF is disabled', function (done) { + global.environment.enabledFeatures.layerStats = false; + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + httpLayer, + mapnikLayer1, + httpLayer + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, typeLayerId('http', 0)); + assert.strictEqual(layergroup.metadata.layers[0].type, 'http'); + assert.strictEqual(layergroup.metadata.layers[1].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[1].type, 'mapnik'); + assert.ok(!Object.prototype.hasOwnProperty.call(layergroup.metadata.layers[1].meta, 'stats')); + assert.strictEqual(layergroup.metadata.layers[2].id, typeLayerId('http', 1)); + assert.strictEqual(layergroup.metadata.layers[2].type, 'http'); + global.environment.enabledFeatures.layerStats = true; + testClient.drain(done); + }); + }); + + function layerWithMetadata (layer, metadata) { + return Object.assign(layer, { + options: Object.assign(layer.options, { metadata }) + }); + } + + it('should provide columns as optional metadata', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayer4, { + columns: true + }) + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); + const expectedColumns = { + cartodb_id: { type: 'number' }, + the_geom: { type: 'geometry' }, + the_geom_webmercator: { type: 'geometry' }, + address: { type: 'string' } + }; + assert.deepStrictEqual(layergroup.metadata.layers[0].meta.stats.columns, expectedColumns); + testClient.drain(done); + }); + }); + + // metadata categories are ordered only partially by descending frequency; + // this orders them completely to avoid ambiguities when comparing + function withSortedCategories (columns) { + function catOrder (a, b) { + if (a.frequency !== b.frequency) { + return b.frequency - a.frequency; } - }; - assert.deepEqual( - withSortedCategories(layergroup.metadata.layers[0].meta.stats.columns), - withSortedCategories(expectedColumns) - ); - testClient.drain(done); - }); - }); + if (a.category < b.category) { + return -1; + } + if (a.category > b.category) { + return +1; + } + return 0; + } + const sorted = {}; + Object.keys(columns).forEach(name => { + let data = columns[name]; + if (Object.prototype.hasOwnProperty.call(data, 'categories')) { + data = Object.assign(data, { categories: data.categories.sort(catOrder) }); + } + sorted[name] = data; + }); + return sorted; + } - it('should limit the number of categories as requested', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayer4, { - columnStats: { topCategories: 2 } - }) - ] - }); + it('should provide column stats as optional metadata', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayer4, { + columnStats: true + }) + ] + }); - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - const columnsMetadata = layergroup.metadata.layers[0].meta.stats.columns; - assert.equal(columnsMetadata.address.categories.length, 2); - testClient.drain(done); - }); - }); - - it('should include null categories if requested', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayerNullCats, { - columnStats: { includeNulls: true } - }) - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - const columnsMetadata = layergroup.metadata.layers[0].meta.stats.columns; - assert.equal(columnsMetadata.cat.categories.length, 3); - testClient.drain(done); - }); - }); - - it('should not include null categories if not requested', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayerNullCats, { - columnStats: { includeNulls: false } - }) - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - const columnsMetadata = layergroup.metadata.layers[0].meta.stats.columns; - assert.equal(columnsMetadata.cat.categories.length, 2); - testClient.drain(done); - }); - }); - - it('should provide row count as optional metadata', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayer4, { - featureCount: true - }) - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); - assert.equal(layergroup.metadata.layers[0].meta.stats.featureCount, 5); - testClient.drain(done); - }); - }); - - it('should provide geometry type as optional metadata', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayer4, { - geometryType: true - }) - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); - assert.equal(layergroup.metadata.layers[0].meta.stats.geometryType, 'ST_Point'); - testClient.drain(done); - }); - }); - - it(`should not fail "TypeError: ... 'geom_type' of undefined" for empty results`, function(done) { - var testClient = new TestClient({ - version: '1.8.0', - layers: [ - { - type: 'mapnik', - options: { - sql: 'select * from test_table where false', - metadata: { - geometryType: true - } + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); + const expectedColumns = { + cartodb_id: { + type: 'number', + avg: 3, + max: 5, + min: 1, + sum: 15 + }, + the_geom: { type: 'geometry' }, + the_geom_webmercator: { type: 'geometry' }, + address: { + type: 'string', + categories: [ + { + category: 'Calle de la Palma 72, Madrid, Spain', + frequency: 1 + }, + { + category: 'Calle de PĂ©rez GaldĂłs 9, Madrid, Spain', + frequency: 1 + }, + { + category: 'Calle Divino Pastor 12, Madrid, Spain', + frequency: 1 + }, + { + category: 'Manuel Fernández y González 8, Madrid, Spain', + frequency: 1 + }, + { + category: 'Plaza Conde de Toreno 2, Madrid, Spain', + frequency: 1 + } + ] } - } - ] + }; + assert.deepStrictEqual( + withSortedCategories(layergroup.metadata.layers[0].meta.stats.columns), + withSortedCategories(expectedColumns) + ); + testClient.drain(done); + }); }); - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.geometryType, undefined); - testClient.drain(done); - }); - }); + it('should limit the number of categories as requested', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayer4, { + columnStats: { topCategories: 2 } + }) + ] + }); - it('should provide a sample as optional metadata', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayer100, { - sample: { num_rows: 30 } - }) - ] + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + const columnsMetadata = layergroup.metadata.layers[0].meta.stats.columns; + assert.strictEqual(columnsMetadata.address.categories.length, 2); + testClient.drain(done); + }); }); - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 100); - assert(layergroup.metadata.layers[0].meta.stats.sample.length > 0); - const expectedCols = [ 'cartodb_id', 'value', 'the_geom', 'the_geom_webmercator' ].sort(); - assert.deepEqual(Object.keys(layergroup.metadata.layers[0].meta.stats.sample[0]).sort(), expectedCols); - testClient.drain(done); - }); - }); + it('should include null categories if requested', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayerNullCats, { + columnStats: { includeNulls: true } + }) + ] + }); - it('should not provide a sample when the source table is empty', function (done) { - var testClient = new TestClient({ - version: "1.4.0", - layers: [ - { - type: "mapnik", - options: { - sql: "SELECT * FROM test_table_100 limit 0", - cartocss_version: "2.3.0", - cartocss: "#layer { line-width:16; }", - metadata: { - sample: { - num_rows: 30 + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + const columnsMetadata = layergroup.metadata.layers[0].meta.stats.columns; + assert.strictEqual(columnsMetadata.cat.categories.length, 3); + testClient.drain(done); + }); + }); + + it('should not include null categories if not requested', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayerNullCats, { + columnStats: { includeNulls: false } + }) + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + const columnsMetadata = layergroup.metadata.layers[0].meta.stats.columns; + assert.strictEqual(columnsMetadata.cat.categories.length, 2); + testClient.drain(done); + }); + }); + + it('should provide row count as optional metadata', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayer4, { + featureCount: true + }) + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.featureCount, 5); + testClient.drain(done); + }); + }); + + it('should provide geometry type as optional metadata', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayer4, { + geometryType: true + }) + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.geometryType, 'ST_Point'); + testClient.drain(done); + }); + }); + + it('should not fail "TypeError: ... \'geom_type\' of undefined" for empty results', function (done) { + var testClient = new TestClient({ + version: '1.8.0', + layers: [ + { + type: 'mapnik', + options: { + sql: 'select * from test_table where false', + metadata: { + geometryType: true } } } - } - ] + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.geometryType, undefined); + testClient.drain(done); + }); }); - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.deepStrictEqual(layergroup.metadata.layers[0].meta.stats.sample, {}); - testClient.drain(done); - }); - }); + it('should provide a sample as optional metadata', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayer100, { + sample: { num_rows: 30 } + }) + ] + }); - it('can specify sample columns', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayer100, { - sample: { - num_rows: 30, - include_columns: [ 'cartodb_id', 'the_geom' ] + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 100); + assert(layergroup.metadata.layers[0].meta.stats.sample.length > 0); + const expectedCols = ['cartodb_id', 'value', 'the_geom', 'the_geom_webmercator'].sort(); + assert.deepStrictEqual(Object.keys(layergroup.metadata.layers[0].meta.stats.sample[0]).sort(), expectedCols); + testClient.drain(done); + }); + }); + + it('should not provide a sample when the source table is empty', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + { + type: 'mapnik', + options: { + sql: 'SELECT * FROM test_table_100 limit 0', + cartocss_version: '2.3.0', + cartocss: '#layer { line-width:16; }', + metadata: { + sample: { + num_rows: 30 + } + } + } } - }) - ] + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.deepStrictEqual(layergroup.metadata.layers[0].meta.stats.sample, {}); + testClient.drain(done); + }); }); - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 100); - assert(layergroup.metadata.layers[0].meta.stats.sample.length > 0); - const expectedCols = [ 'cartodb_id', 'the_geom' ].sort(); - assert.deepEqual(Object.keys(layergroup.metadata.layers[0].meta.stats.sample[0]).sort(), expectedCols); - testClient.drain(done); + it('can specify sample columns', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayer100, { + sample: { + num_rows: 30, + include_columns: ['cartodb_id', 'the_geom'] + } + }) + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 100); + assert(layergroup.metadata.layers[0].meta.stats.sample.length > 0); + const expectedCols = ['cartodb_id', 'the_geom'].sort(); + assert.deepStrictEqual(Object.keys(layergroup.metadata.layers[0].meta.stats.sample[0]).sort(), expectedCols); + testClient.drain(done); + }); + }); + + it('should only provide requested optional metadata', function (done) { + var testClient = new TestClient({ + version: '1.4.0', + layers: [ + layerWithMetadata(mapnikLayer4, { + geometryType: true, + featureCount: true + }) + ] + }); + + testClient.getLayergroup(function (err, layergroup) { + assert.ifError(err); + assert.strictEqual(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.geometryType, 'ST_Point'); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.featureCount, 5); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.sample, undefined); + assert.strictEqual(layergroup.metadata.layers[0].meta.stats.columns, undefined); + testClient.drain(done); + }); }); }); - - - it('should only provide requested optional metadata', function(done) { - var testClient = new TestClient({ - version: '1.4.0', - layers: [ - layerWithMetadata(mapnikLayer4, { - geometryType: true, - featureCount: true - }) - ] - }); - - testClient.getLayergroup(function(err, layergroup) { - assert.ifError(err); - assert.equal(layergroup.metadata.layers[0].id, mapnikBasicLayerId(0)); - assert.equal(layergroup.metadata.layers[0].meta.stats.estimatedFeatureCount, 5); - assert.equal(layergroup.metadata.layers[0].meta.stats.geometryType, 'ST_Point'); - assert.equal(layergroup.metadata.layers[0].meta.stats.featureCount, 5); - assert.equal(layergroup.metadata.layers[0].meta.stats.sample, undefined); - assert.equal(layergroup.metadata.layers[0].meta.stats.columns, undefined); - testClient.drain(done); - }); - }); - -}); }); diff --git a/test/acceptance/stats/multilayer-stats-test.js b/test/acceptance/stats/multilayer-stats-test.js index 17b3fe14..20a1a499 100644 --- a/test/acceptance/stats/multilayer-stats-test.js +++ b/test/acceptance/stats/multilayer-stats-test.js @@ -5,8 +5,7 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('multilayer stats disabled', function() { - +describe('multilayer stats disabled', function () { before(function () { this.layerMetadataConfig = global.environment.enabledFeatures.layerMetadata; this.layerStatsConfig = global.environment.enabledFeatures.layerStats; @@ -19,18 +18,16 @@ describe('multilayer stats disabled', function() { global.environment.enabledFeatures.layerStats = this.layerStatsConfig; }); - - function testLayerMetadataStats(testScenario) { - - it(testScenario.desc, function(done) { - var mapConfig = { + function testLayerMetadataStats (testScenario) { + it(testScenario.desc, function (done) { + var mapConfig = { version: '1.3.0', layers: testScenario.layers }; var testClient = new TestClient(mapConfig); - testClient.getLayergroup(function(err, layergroup) { + testClient.getLayergroup(function (err, layergroup) { assert.ifError(err); layergroup.metadata.layers.forEach(function (layer) { if (layer.type !== 'torque' && layer.type !== 'mapnik') { @@ -41,9 +38,9 @@ describe('multilayer stats disabled', function() { } else { assert.ok('cartocss' in layer.meta); // check torque metadata at least match in number - var torqueLayers = mapConfig.layers.filter(function(layer) { return layer.type === 'torque'; }); + var torqueLayers = mapConfig.layers.filter(function (layer) { return layer.type === 'torque'; }); if (torqueLayers.length) { - assert.equal(Object.keys(layergroup.metadata.torque).length, torqueLayers.length); + assert.strictEqual(Object.keys(layergroup.metadata.torque).length, torqueLayers.length); } } }); @@ -64,7 +61,7 @@ describe('multilayer stats disabled', function() { type: 'http', options: { urlTemplate: 'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png', - subdomains: ['a','b','c'] + subdomains: ['a', 'b', 'c'] } }; @@ -73,12 +70,12 @@ describe('multilayer stats disabled', function() { options: { sql: "select 1 id, '1970-01-02'::date d, 'POINT(0 0)'::geometry the_geom_webmercator", cartocss: [ - "Map {", - "-torque-frame-count:2;", - "-torque-resolution:3;", - "-torque-time-attribute:d;", - "-torque-aggregation-function:'count(id)';", - "}" + 'Map {', + '-torque-frame-count:2;', + '-torque-resolution:3;', + '-torque-time-attribute:d;', + "-torque-aggregation-function:'count(id)';", + '}' ].join(' '), cartocss_version: '2.0.1' } @@ -223,5 +220,4 @@ describe('multilayer stats disabled', function() { ]; testScenarios.forEach(testLayerMetadataStats); - }); diff --git a/test/acceptance/templates-test.js b/test/acceptance/templates-test.js index b9c36b63..a18b1507 100644 --- a/test/acceptance/templates-test.js +++ b/test/acceptance/templates-test.js @@ -1,13 +1,13 @@ 'use strict'; -var assert = require('../support/assert'); -var _ = require('underscore'); -var redis = require('redis'); -var step = require('step'); -var strftime = require('strftime'); +var assert = require('../support/assert'); +var _ = require('underscore'); +var redis = require('redis'); +var step = require('step'); +var strftime = require('strftime'); var QueryTables = require('cartodb-query-tables').queryTables; var NamedMapsCacheEntry = require('../../lib/cache/model/named-maps-entry'); -var redis_stats_db = 5; +var redisStatsDb = 5; // Pollute the PG environment to make sure // configuration settings are always enforced @@ -15,6 +15,7 @@ var redis_stats_db = 5; process.env.PGPORT = '666'; process.env.PGHOST = 'fake'; +var path = require('path'); var fs = require('fs'); var http = require('http'); @@ -25,7 +26,7 @@ var serverOptions = require('../../lib/server-options'); var LayergroupToken = require('../../lib/models/layergroup-token'); -describe('template_api', function() { +describe('template_api', function () { var server; before(function () { @@ -36,1752 +37,1707 @@ describe('template_api', function() { }); var httpRendererResourcesServer; - before(function(done) { + before(function (done) { // Start a server to test external resources - httpRendererResourcesServer = http.createServer( function(request, response) { - var filename = __dirname + '/../fixtures/http/light_nolabels-1-0-0.png'; - fs.readFile(filename, {encoding: 'binary'}, function(err, file) { + httpRendererResourcesServer = http.createServer(function (request, response) { + var filename = path.join(__dirname, '/../fixtures/http/light_nolabels-1-0-0.png'); + fs.readFile(filename, { encoding: 'binary' }, function (err, file) { + if (err) { + return done(); + } response.writeHead(200); - response.write(file, "binary"); + response.write(file, 'binary'); response.end(); }); }); httpRendererResourcesServer.listen(8033, done); }); - after(function(done) { + after(function (done) { httpRendererResourcesServer.close(done); }); var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { + afterEach(function (done) { helper.deleteRedisKeys(keysToDelete, done); }); - var template_acceptance1 = { + var templateAcceptance1 = { version: '0.0.1', name: 'acceptance1', auth: { method: 'open' }, - layergroup: { - version: '1.0.0', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, -5e6, 0) as the_geom_webmercator' + + layergroup: { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, -5e6, 0) as the_geom_webmercator' + ' from test_table limit 2 offset 2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id' - } } - ] + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } + } + ] } }; - function makeTemplate(templateName) { + function makeTemplate (templateName) { return { version: '0.0.1', name: templateName || 'acceptance1', auth: { method: 'open' }, - layergroup: { + layergroup: { version: '1.0.0', - layers: [ - { options: { - sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, -5e6, 0) as the_geom_webmercator' + + layers: [ + { + options: { + sql: 'select cartodb_id, ST_Translate(the_geom_webmercator, -5e6, 0) as the_geom_webmercator' + ' from test_table limit 2 offset 2', - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id' - } } + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } + } ] } }; } - function extendDefaultsTemplate(template) { - return _.extend({}, template, {auth: {method: 'open'}, placeholders: {}}); + function extendDefaultsTemplate (template) { + return _.extend({}, template, { auth: { method: 'open' }, placeholders: {} }); } - it("can add template, returning id", function(done) { + it('can add template, returning id', function (done) { + var expectedTplId = 'acceptance1'; + var postRequest1 = { + url: '/api/v1/map/named', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptance1) + }; + step( + function postUnauthenticated () { + var next = this; + assert.response(server, postRequest1, {}, + function (res) { next(null, res); }); + }, + function postTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), res.body); + err = parsed.errors[0]; + assert.ok(err.match(/only.*authenticated.*user/i), + 'Unexpected error response: ' + err); + postRequest1.url += '?api_key=1234'; + var next = this; + assert.response(server, postRequest1, {}, + function (res) { next(null, res); }); + }, + function rePostTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsedBody = JSON.parse(res.body); + var expectedBody = { template_id: expectedTplId }; + assert.deepStrictEqual(parsedBody, expectedBody); - var expected_tpl_id = "acceptance1"; - var post_request_1 = { - url: '/api/v1/map/named', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance1) - }; - step( - function postUnauthenticated() - { - var next = this; - assert.response(server, post_request_1, {}, - function(res) { next(null, res); }); - }, - function postTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 403); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), res.body); - err = parsed.errors[0]; - assert.ok(err.match(/only.*authenticated.*user/i), - 'Unexpected error response: ' + err); - post_request_1.url += '?api_key=1234'; - var next = this; - assert.response(server, post_request_1, {}, - function(res) { next(null, res); }); - }, - function rePostTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsedBody = JSON.parse(res.body); - var expectedBody = { template_id: expected_tpl_id }; - assert.deepEqual(parsedBody, expectedBody); + keysToDelete['map_tpl|localhost'] = 0; - keysToDelete['map_tpl|localhost'] = 0; + var next = this; + assert.response(server, postRequest1, {}, + function (res) { next(null, res); }); + }, + function checkFailure (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.body); + var parsedBody = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsedBody, 'errors'), res.body); + assert.ok(parsedBody.errors[0].match(/already exists/i), + 'Unexpected error for pre-existing template name: ' + parsedBody.errors); - var next = this; - assert.response(server, post_request_1, {}, - function(res) { next(null, res); }); - }, - function checkFailure(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.body); - var parsedBody = JSON.parse(res.body); - assert.ok(parsedBody.hasOwnProperty('errors'), res.body); - assert.ok(parsedBody.errors[0].match(/already exists/i), - 'Unexpected error for pre-existing template name: ' + parsedBody.errors); - - done(); - } - ); + done(); + } + ); }); // See https://github.com/CartoDB/Windshaft-cartodb/issues/128 - it("cannot create template with auth='token' and no valid tokens", function(done) { - var tpl_id; - step( - function postTemplate1() - { - // clone the valid one, and give it another name - var broken_template = JSON.parse(JSON.stringify(template_acceptance1)); - broken_template.name = 'broken1'; - // Set auth='token' and specify no tokens - broken_template.auth.method = 'token'; - delete broken_template.auth.tokens; - var post_request_1 = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(broken_template) - }; - var next = this; - assert.response(server, post_request_1, {}, - function(res) { next(null, res); }); - }, - function checkFailure1(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.body); - var parsedBody = JSON.parse(res.body); - assert.ok(parsedBody.hasOwnProperty('errors'), res.body); - var re = /invalid.*authentication.*missing/i; - assert.ok(parsedBody.errors[0].match(re), - 'Error for invalid authentication does not match ' + re + ': ' + parsedBody.errors); - return null; - }, - function postTemplate2(err) - { - assert.ifError(err); - // clone the valid one and rename it - var broken_template = JSON.parse(JSON.stringify(template_acceptance1)); - broken_template.name = 'broken1'; - // Set auth='token' and specify no tokens - broken_template.auth.method = 'token'; - broken_template.auth.tokens = []; - var post_request_1 = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(broken_template) - }; - var next = this; - assert.response(server, post_request_1, {}, - function(res) { next(null, res); }); - }, - function checkFailure2(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.body); - var parsedBody = JSON.parse(res.body); - assert.ok(parsedBody.hasOwnProperty('errors'), res.body); - var re = new RegExp(/invalid.*authentication.*missing/i); - assert.ok(parsedBody.errors[0].match(re), - 'Error for invalid authentication does not match ' + re + ': ' + parsedBody.errors); - return null; - }, - function postTemplateValid(err) - { - assert.ifError(err); - // clone the valid one and rename it - var broken_template = JSON.parse(JSON.stringify(template_acceptance1)); - broken_template.name = 'broken1'; - var post_request_1 = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(broken_template) - }; - var next = this; - assert.response(server, post_request_1, {}, - function(res) { next(null, res); }); - }, - function putTemplateInvalid(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - // clone the valid one and rename it - var broken_template = JSON.parse(JSON.stringify(template_acceptance1)); - broken_template.name = 'broken1'; - // Set auth='token' and specify no tokens - broken_template.auth.method = 'token'; - broken_template.auth.tokens = []; - var put_request_1 = { - url: '/api/v1/map/named/' + tpl_id + '/?api_key=1234', - method: 'PUT', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(broken_template) - }; - var next = this; - assert.response(server, put_request_1, {}, - function(res) { next(null, res); }); - }, - function deleteTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ": " + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - var re = /invalid.*authentication.*missing/i; - assert.ok(parsed.errors[0].match(re), - 'Error for invalid authentication on PUT does not match ' + + it("cannot create template with auth='token' and no valid tokens", function (done) { + var tplId; + step( + function postTemplate1 () { + // clone the valid one, and give it another name + var brokenTemplate = JSON.parse(JSON.stringify(templateAcceptance1)); + brokenTemplate.name = 'broken1'; + // Set auth='token' and specify no tokens + brokenTemplate.auth.method = 'token'; + delete brokenTemplate.auth.tokens; + var postRequest1 = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(brokenTemplate) + }; + var next = this; + assert.response(server, postRequest1, {}, + function (res) { next(null, res); }); + }, + function checkFailure1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.body); + var parsedBody = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsedBody, 'errors'), res.body); + var re = /invalid.*authentication.*missing/i; + assert.ok(parsedBody.errors[0].match(re), + 'Error for invalid authentication does not match ' + re + ': ' + parsedBody.errors); + return null; + }, + function postTemplate2 (err) { + assert.ifError(err); + // clone the valid one and rename it + var brokenTemplate = JSON.parse(JSON.stringify(templateAcceptance1)); + brokenTemplate.name = 'broken1'; + // Set auth='token' and specify no tokens + brokenTemplate.auth.method = 'token'; + brokenTemplate.auth.tokens = []; + var postRequest1 = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(brokenTemplate) + }; + var next = this; + assert.response(server, postRequest1, {}, + function (res) { next(null, res); }); + }, + function checkFailure2 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.body); + var parsedBody = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsedBody, 'errors'), res.body); + var re = new RegExp(/invalid.*authentication.*missing/i); + assert.ok(parsedBody.errors[0].match(re), + 'Error for invalid authentication does not match ' + re + ': ' + parsedBody.errors); + return null; + }, + function postTemplateValid (err) { + assert.ifError(err); + // clone the valid one and rename it + var brokenTemplate = JSON.parse(JSON.stringify(templateAcceptance1)); + brokenTemplate.name = 'broken1'; + var postRequest1 = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(brokenTemplate) + }; + var next = this; + assert.response(server, postRequest1, {}, + function (res) { next(null, res); }); + }, + function putTemplateInvalid (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + // clone the valid one and rename it + var brokenTemplate = JSON.parse(JSON.stringify(templateAcceptance1)); + brokenTemplate.name = 'broken1'; + // Set auth='token' and specify no tokens + brokenTemplate.auth.method = 'token'; + brokenTemplate.auth.tokens = []; + var putRequest1 = { + url: '/api/v1/map/named/' + tplId + '/?api_key=1234', + method: 'PUT', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(brokenTemplate) + }; + var next = this; + assert.response(server, putRequest1, {}, + function (res) { next(null, res); }); + }, + function deleteTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + var re = /invalid.*authentication.*missing/i; + assert.ok(parsed.errors[0].match(re), + 'Error for invalid authentication on PUT does not match ' + re + ': ' + parsed.errors); - var del_request = { - url: '/api/v1/map/named/' + tpl_id + '?api_key=1234', - method: 'DELETE', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, del_request, {}, - function(res, err) { next(err, res); }); - }, - function checkDelete(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 204, res.statusCode + ': ' + res.body); - assert.ok(!res.body, 'Unexpected body in DELETE /template response'); + var delRequest = { + url: '/api/v1/map/named/' + tplId + '?api_key=1234', + method: 'DELETE', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, delRequest, {}, + function (res, err) { next(err, res); }); + }, + function checkDelete (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 204, res.statusCode + ': ' + res.body); + assert.ok(!res.body, 'Unexpected body in DELETE /template response'); - done(); - } - ); + done(); + } + ); }); - it("instance endpoint should return CORS headers", function(done){ - step(function postTemplate1() { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost.localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance1) - }; - assert.response(server, post_request, {}, function(res) { next(null, res); }); + it('instance endpoint should return CORS headers', function (done) { + step(function postTemplate1 () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost.localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptance1) + }; + assert.response(server, postRequest, {}, function (res) { next(null, res); }); }, - function testCORS() { + function testCORS () { const allowHeaders = 'X-Requested-With, X-Prototype-Version, X-CSRF-Token, Authorization, Content-Type'; assert.response(server, { url: '/api/v1/map/named/acceptance1', method: 'OPTIONS' - },{ + }, { status: 200, headers: { 'Access-Control-Allow-Headers': allowHeaders, 'Access-Control-Allow-Origin': '*' } - }, function() { done(); }); - }); + }, function () { done(); }); + }); }); - describe('server-metadata', function() { + describe('server-metadata', function () { var serverMetadata; - beforeEach(function() { + beforeEach(function () { serverMetadata = global.environment.serverMetadata; - global.environment.serverMetadata = { cdn_url : { http:'test', https: 'tests' } }; + global.environment.serverMetadata = { cdn_url: { http: 'test', https: 'tests' } }; }); - afterEach(function() { + afterEach(function () { global.environment.serverMetadata = serverMetadata; }); + it('instance endpoint should return server metadata', function (done) { + var tmpl = _.clone(templateAcceptance1); + tmpl.name = 'rambotemplate2'; - it("instance endpoint should return server metadata", function(done){ - var tmpl = _.clone(template_acceptance1); - tmpl.name = "rambotemplate2"; - - step(function postTemplate1() { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(tmpl) - }; - assert.response(server, post_request, {}, function(res) { - next(null, res); - }); + step(function postTemplate1 () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(tmpl) + }; + assert.response(server, postRequest, {}, function (res) { + next(null, res); + }); }, - function testCORS() { - var next = this; - assert.response(server, { - url: '/api/v1/map/named/' + tmpl.name, - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' } - },{ - status: 200 - }, function(res) { - var parsed = JSON.parse(res.body); - keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - assert.ok(_.isEqual(parsed.cdn_url, global.environment.serverMetadata.cdn_url)); - next(null); - }); + function testCORS () { + var next = this; + assert.response(server, { + url: '/api/v1/map/named/' + tmpl.name, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' } + }, { + status: 200 + }, function (res) { + var parsed = JSON.parse(res.body); + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + assert.ok(_.isEqual(parsed.cdn_url, global.environment.serverMetadata.cdn_url)); + next(null); + }); }, - function deleteTemplate(err) { + function deleteTemplate (err) { assert.ifError(err); - var del_request = { - url: '/api/v1/map/named/' + tmpl.name + '?api_key=1234', - method: 'DELETE', - headers: {host: 'localhost', 'Content-Type': 'application/json' } - }; - assert.response(server, del_request, {}, function() { - done(); - }); + var delRequest = { + url: '/api/v1/map/named/' + tmpl.name + '?api_key=1234', + method: 'DELETE', + headers: { host: 'localhost', 'Content-Type': 'application/json' } + }; + assert.response(server, delRequest, {}, function () { + done(); + }); } - ); + ); }); }); + it('can list templates', function (done) { + var tplid1, tplid2; + step( + function postTemplate1 () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptance1) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function postTemplate2 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplid1 = parsed.template_id; + var next = this; + var backupName = templateAcceptance1.name; + templateAcceptance1.name += '_new'; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptance1) + }; + templateAcceptance1.name = backupName; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function litsTemplatesUnauthenticated (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplid2 = parsed.template_id; + var next = this; + var getRequest = { + url: '/api/v1/map/named', + method: 'GET', + headers: { host: 'localhost' } + }; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function litsTemplates (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + 'Missing error from response: ' + res.body); + err = parsed.errors[0]; + assert.ok(err.match(/authenticated user/), err); + var next = this; + var getRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'GET', + headers: { host: 'localhost' } + }; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkList (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_ids'), + "Missing 'template_ids' from response body: " + res.body); + var ids = parsed.template_ids; + assert.strictEqual(ids.length, 2); + assert.ok(ids.indexOf(tplid1) !== -1, + 'Missing "' + tplid1 + "' from list response: " + ids.join(',')); + assert.ok(ids.indexOf(tplid2) !== -1, + 'Missing "' + tplid2 + "' from list response: " + ids.join(',')); - it("can list templates", function(done) { + keysToDelete['map_tpl|localhost'] = 0; - var tplid1, tplid2; - step( - function postTemplate1() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance1) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function postTemplate2(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tplid1 = parsed.template_id; - - var next = this; - var backup_name = template_acceptance1.name; - template_acceptance1.name += '_new'; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance1) - }; - template_acceptance1.name = backup_name; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function litsTemplatesUnauthenticated(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tplid2 = parsed.template_id; - var next = this; - var get_request = { - url: '/api/v1/map/named', - method: 'GET', - headers: {host: 'localhost'} - }; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function litsTemplates(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 403, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - 'Missing error from response: ' + res.body); - err = parsed.errors[0]; - assert.ok(err.match(/authenticated user/), err); - var next = this; - var get_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'GET', - headers: {host: 'localhost'} - }; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkList(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_ids'), - "Missing 'template_ids' from response body: " + res.body); - var ids = parsed.template_ids; - assert.equal(ids.length, 2); - assert.ok(ids.indexOf(tplid1) !== -1, - 'Missing "' + tplid1 + "' from list response: " + ids.join(',')); - assert.ok(ids.indexOf(tplid2) !== -1, - 'Missing "' + tplid2 + "' from list response: " + ids.join(',')); - - keysToDelete['map_tpl|localhost'] = 0; - - done(); - } - ); + done(); + } + ); }); - it("can update template", function(done) { + it('can update template', function (done) { + var tplId; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(makeTemplate()) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function putMisnamedTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var backupName = templateAcceptance1.name; + templateAcceptance1.name = 'changed_name'; + var putRequest = { + url: '/api/v1/map/named/' + tplId + '/?api_key=1234', + method: 'PUT', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptance1) + }; + templateAcceptance1.name = backupName; + var next = this; + assert.response(server, putRequest, {}, + function (res) { next(null, res); }); + }, + function putUnexistentTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsedBody = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsedBody, 'errors'), res.body); + assert.ok(parsedBody.errors[0].match(/cannot update name/i), + 'Unexpected error for invalid update: ' + parsedBody.errors); + var putRequest = { + url: '/api/v1/map/named/unexistent/?api_key=1234', + method: 'PUT', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(makeTemplate()) + }; + var next = this; + assert.response(server, putRequest, {}, + function (res) { next(null, res); }); + }, + function putValidTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + res.body); + var parsedBody = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsedBody, 'errors'), res.body); + assert.ok(parsedBody.errors[0].match(/cannot update name/i), + 'Unexpected error for invalid update: ' + parsedBody.errors); + var putRequest = { + url: '/api/v1/map/named/' + tplId + '/?api_key=1234', + method: 'PUT', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(makeTemplate()) + }; + var next = this; + assert.response(server, putRequest, {}, + function (res) { next(null, res); }); + }, + function checkValidUpate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + assert.strictEqual(tplId, parsed.template_id); - var tpl_id; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(makeTemplate()) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function putMisnamedTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var backup_name = template_acceptance1.name; - template_acceptance1.name = 'changed_name'; - var put_request = { - url: '/api/v1/map/named/' + tpl_id + '/?api_key=1234', - method: 'PUT', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance1) - }; - template_acceptance1.name = backup_name; - var next = this; - assert.response(server, put_request, {}, - function(res) { next(null, res); }); - }, - function putUnexistentTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ": " + res.body); - var parsedBody = JSON.parse(res.body); - assert.ok(parsedBody.hasOwnProperty('errors'), res.body); - assert.ok(parsedBody.errors[0].match(/cannot update name/i), - 'Unexpected error for invalid update: ' + parsedBody.errors); - var put_request = { - url: '/api/v1/map/named/unexistent/?api_key=1234', - method: 'PUT', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(makeTemplate()) - }; - var next = this; - assert.response(server, put_request, {}, - function(res) { next(null, res); }); - }, - function putValidTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 400, res.statusCode + ": " + res.body); - var parsedBody = JSON.parse(res.body); - assert.ok(parsedBody.hasOwnProperty('errors'), res.body); - assert.ok(parsedBody.errors[0].match(/cannot update name/i), - 'Unexpected error for invalid update: ' + parsedBody.errors); - var put_request = { - url: '/api/v1/map/named/' + tpl_id + '/?api_key=1234', - method: 'PUT', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(makeTemplate()) - }; - var next = this; - assert.response(server, put_request, {}, - function(res) { next(null, res); }); - }, - function checkValidUpate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ": " + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - assert.equal(tpl_id, parsed.template_id); + keysToDelete['map_tpl|localhost'] = 0; - keysToDelete['map_tpl|localhost'] = 0; - - done(); - } - ); + done(); + } + ); }); - it("can get a template by id", function(done) { + it('can get a template by id', function (done) { + var tplId; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(makeTemplate()) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function getTemplateUnauthorized (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var getRequest = { + url: '/api/v1/map/named/' + tplId, + method: 'GET', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function getTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, res.statusCode + ': ' + res.body); + var parsedBody = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsedBody, 'errors'), res.body); + assert.ok(parsedBody.errors[0].match(/only.*authenticated.*user/i), + 'Unexpected error for unauthenticated template get: ' + parsedBody.errors); + var getRequest = { + url: '/api/v1/map/named/' + tplId + '?api_key=1234', + method: 'GET', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkReturnTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template'), + "Missing 'template' from response body: " + res.body); + assert.deepStrictEqual(extendDefaultsTemplate(makeTemplate()), parsed.template); - var tpl_id; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(makeTemplate()) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function getTemplateUnauthorized(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var get_request = { - url: '/api/v1/map/named/' + tpl_id, - method: 'GET', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function getTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 403, res.statusCode + ": " + res.body); - var parsedBody = JSON.parse(res.body); - assert.ok(parsedBody.hasOwnProperty('errors'), res.body); - assert.ok(parsedBody.errors[0].match(/only.*authenticated.*user/i), - 'Unexpected error for unauthenticated template get: ' + parsedBody.errors); - var get_request = { - url: '/api/v1/map/named/' + tpl_id + '?api_key=1234', - method: 'GET', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkReturnTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ": " + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template'), - "Missing 'template' from response body: " + res.body); - assert.deepEqual(extendDefaultsTemplate(makeTemplate()), parsed.template); + keysToDelete['map_tpl|localhost'] = 0; - keysToDelete['map_tpl|localhost'] = 0; - - done(); - } - ); + done(); + } + ); }); - it("can delete a template by id", function(done) { + it('can delete a template by id', function (done) { + var tplId; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(makeTemplate()) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function getTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var getRequest = { + url: '/api/v1/map/named/' + tplId + '?api_key=1234', + method: 'GET', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function deleteTemplateUnauthorized (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template'), + "Missing 'template' from response body: " + res.body); + assert.deepStrictEqual(extendDefaultsTemplate(makeTemplate()), parsed.template); + var delRequest = { + url: '/api/v1/map/named/' + tplId, + method: 'DELETE', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, delRequest, {}, + function (res) { next(null, res); }); + }, + function deleteTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/only.*authenticated.*user/i), + 'Unexpected error for unauthenticated template get: ' + parsed.errors); + var delRequest = { + url: '/api/v1/map/named/' + tplId + '?api_key=1234', + method: 'DELETE', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, delRequest, {}, + function (res) { next(null, res); }); + }, + function getMissingTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 204, res.statusCode + ': ' + res.body); + assert.ok(!res.body, 'Unexpected body in DELETE /template response'); + var getRequest = { + url: '/api/v1/map/named/' + tplId + '?api_key=1234', + method: 'GET', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkGetFailure (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 404, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/cannot find/i), + 'Unexpected error for missing template: ' + parsed.errors); - var tpl_id; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(makeTemplate()) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function getTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var get_request = { - url: '/api/v1/map/named/' + tpl_id + '?api_key=1234', - method: 'GET', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function deleteTemplateUnauthorized(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ": " + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template'), - "Missing 'template' from response body: " + res.body); - assert.deepEqual(extendDefaultsTemplate(makeTemplate()), parsed.template); - var del_request = { - url: '/api/v1/map/named/' + tpl_id, - method: 'DELETE', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, del_request, {}, - function(res) { next(null, res); }); - }, - function deleteTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 403, res.statusCode + ": " + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/only.*authenticated.*user/i), - 'Unexpected error for unauthenticated template get: ' + parsed.errors); - var del_request = { - url: '/api/v1/map/named/' + tpl_id + '?api_key=1234', - method: 'DELETE', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, del_request, {}, - function(res) { next(null, res); }); - }, - function getMissingTemplate(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 204, res.statusCode + ': ' + res.body); - assert.ok(!res.body, 'Unexpected body in DELETE /template response'); - var get_request = { - url: '/api/v1/map/named/' + tpl_id + '?api_key=1234', - method: 'GET', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkGetFailure(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 404, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/cannot find/i), - 'Unexpected error for missing template: ' + parsed.errors); - - done(); - } - ); + done(); + } + ); }); - it("can instanciate a template by id wadus", function(done) { + it('can instanciate a template by id wadus', function (done) { + // This map fetches data from a private table + var templateAcceptance2 = { + version: '0.0.1', + name: 'acceptance1', + auth: { method: 'token', valid_tokens: ['valid1', 'valid2'] }, + layergroup: { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table_private_1 LIMIT 0', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } + } + ] + } + }; - // This map fetches data from a private table - var template_acceptance2 = { - version: '0.0.1', - name: 'acceptance1', - auth: { method: 'token', valid_tokens: ['valid1','valid2'] }, - layergroup: { - version: '1.0.0', - layers: [ - { options: { - sql: "select * from test_table_private_1 LIMIT 0", - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id' - } } - ] - } - }; + var templateParams = {}; - var template_params = {}; + var tplId; + var layergroupid; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptance2) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateNoAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var postRequest = { + url: '/api/v1/map/named/' + tplId, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + // See https://github.com/CartoDB/Windshaft-cartodb/issues/173 + function instanciateForeignDB (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, + 'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/unauthorized/i), + 'Unexpected error for unauthorized instance : ' + parsed.errors); + var postRequest = { + url: '/api/v1/map/named/' + tplId + '?auth_token=valid2', + method: 'POST', + headers: { host: 'foreign', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 404, res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/not found/i), 'Unexpected error for forbidden instance : ' + parsed.errors); + var postRequest = { + url: '/api/v1/map/named/' + tplId + '?auth_token=valid2', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function fetchTileNoAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Instantiating template: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'layergroupid'), + "Missing 'layergroupid' from response body: " + res.body); + layergroupid = parsed.layergroupid; + assert.ok(layergroupid.match(/^localhost@/), + 'Returned layergroupid does not start with signer name: ' + layergroupid); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'last_updated'), + "Missing 'last_updated' from response body: " + res.body); - var tpl_id; - var layergroupid; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance2) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateNoAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var post_request = { - url: '/api/v1/map/named/' + tpl_id, - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - // See https://github.com/CartoDB/Windshaft-cartodb/issues/173 - function instanciateForeignDB(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 403, - 'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/unauthorized/i), - 'Unexpected error for unauthorized instance : ' + parsed.errors); - var post_request = { - url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2', - method: 'POST', - headers: {host: 'foreign', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 404, res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/not found/i), 'Unexpected error for forbidden instance : ' + parsed.errors); - var post_request = { - url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function fetchTileNoAuth(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - 'Instantiating template: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('layergroupid'), - "Missing 'layergroupid' from response body: " + res.body); - layergroupid = parsed.layergroupid; - assert.ok(layergroupid.match(/^localhost@/), - "Returned layergroupid does not start with signer name: " + layergroupid); - assert.ok(parsed.hasOwnProperty('last_updated'), - "Missing 'last_updated' from response body: " + res.body); + keysToDelete['user:localhost:mapviews:global'] = 5; + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + // TODO: check value of last_updated ? + var getRequest = { + url: '/api/v1/map/' + layergroupid + ':cb0/0/0/0.png', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function fetchTileAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, + 'Fetching tile with no auth: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/permission denied/i), + 'Unexpected error for unauthorized instance (expected /permission denied/): ' + parsed.errors); + var getRequest = { + url: '/api/v1/map/' + layergroupid + '/0/0/0.png?auth_token=valid1', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkTile (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body); + assert.strictEqual(res.headers['content-type'], 'image/png'); + return null; + }, + // See https://github.com/CartoDB/Windshaft-cartodb/issues/172 + function fetchTileForeignSignature (err) { + assert.ifError(err); + var foreignsigned = layergroupid.replace(/[^@]*@/, 'foreign@'); + var getRequest = { + url: '/api/v1/map/' + foreignsigned + '/0/0/0.png?auth_token=valid1', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkForeignSignerError (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, + 'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/cannot use/i), + 'Unexpected error for unauthorized instance (expected /cannot use/): ' + parsed.errors); + return null; + }, + function deleteTemplate (err) { + assert.ifError(err); + var delRequest = { + url: '/api/v1/map/named/' + tplId + '?api_key=1234', + method: 'DELETE', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, delRequest, {}, + function (res) { next(null, res); }); + }, + function fetchTileDeleted (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 204, + 'Deleting template: ' + res.statusCode + ':' + res.body); + var getRequest = { + url: '/api/v1/map/' + layergroupid + '/0/0/0.png?auth_token=valid1', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkTileAvailable (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, 'Tile should be accessible'); + assert.strictEqual(res.headers['content-type'], 'image/png'); - // TODO: check value of last_updated ? - var get_request = { - url: '/api/v1/map/' + layergroupid + ':cb0/0/0/0.png', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function fetchTileAuth(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 403, - 'Fetching tile with no auth: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/permission denied/i), - 'Unexpected error for unauthorized instance (expected /permission denied/): ' + parsed.errors); - var get_request = { - url: '/api/v1/map/' + layergroupid + '/0/0/0.png?auth_token=valid1', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkTile(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - 'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body); - assert.equal(res.headers['content-type'], "image/png"); - return null; - }, - // See https://github.com/CartoDB/Windshaft-cartodb/issues/172 - function fetchTileForeignSignature(err) { - assert.ifError(err); - var foreignsigned = layergroupid.replace(/[^@]*@/, 'foreign@'); - var get_request = { - url: '/api/v1/map/' + foreignsigned + '/0/0/0.png?auth_token=valid1', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkForeignSignerError(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 403, - 'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/cannot use/i), - 'Unexpected error for unauthorized instance (expected /cannot use/): ' + parsed.errors); - return null; - }, - function deleteTemplate(err) - { - assert.ifError(err); - var del_request = { - url: '/api/v1/map/named/' + tpl_id + '?api_key=1234', - method: 'DELETE', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, del_request, {}, - function(res) { next(null, res); }); - }, - function fetchTileDeleted(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 204, - 'Deleting template: ' + res.statusCode + ':' + res.body); - var get_request = { - url: '/api/v1/map/' + layergroupid + '/0/0/0.png?auth_token=valid1', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkTileAvailable(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, 'Tile should be accessible'); - assert.equal(res.headers['content-type'], "image/png"); - - done(); - } - ); + done(); + } + ); }); - it("can instanciate a template with torque layer by id", function(done) { - - // This map fetches data from a private table - var template = { - version: '0.0.1', - name: 'acceptance1', - auth: { method: 'token', valid_tokens: ['valid1','valid2'] }, - layergroup: { - version: '1.1.0', - layers: [ - { type: 'torque', options: { - sql: "select * from test_table_private_1 LIMIT 0", - cartocss: "Map { -torque-frame-count:1; -torque-resolution:1; " + + it('can instanciate a template with torque layer by id', function (done) { + // This map fetches data from a private table + var template = { + version: '0.0.1', + name: 'acceptance1', + auth: { method: 'token', valid_tokens: ['valid1', 'valid2'] }, + layergroup: { + version: '1.1.0', + layers: [ + { + type: 'torque', + options: { + sql: 'select * from test_table_private_1 LIMIT 0', + cartocss: 'Map { -torque-frame-count:1; -torque-resolution:1; ' + "-torque-aggregation-function:'count(*)'; -torque-time-attribute:'updated_at'; }" - } } - ] - } - }; + } + } + ] + } + }; - var template_params = {}; + var templateParams = {}; - var tpl_id; - var layergroupid; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateNoAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var post_request = { - url: '/api/v1/map/named/' + tpl_id, - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 403, - 'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/unauthorized/i), - 'Unexpected error for unauthorized instance : ' + parsed.errors); - var post_request = { - url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function fetchTileNoAuth(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - 'Instantiating template: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('layergroupid'), - "Missing 'layergroupid' from response body: " + res.body); - layergroupid = parsed.layergroupid; - assert.ok(layergroupid.match(/^localhost@/), - "Returned layergroupid does not start with signer name: " + layergroupid); - assert.ok(parsed.hasOwnProperty('last_updated'), - "Missing 'last_updated' from response body: " + res.body); + var tplId; + var layergroupid; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(template) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateNoAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var postRequest = { + url: '/api/v1/map/named/' + tplId, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, + 'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/unauthorized/i), + 'Unexpected error for unauthorized instance : ' + parsed.errors); + var postRequest = { + url: '/api/v1/map/named/' + tplId + '?auth_token=valid2', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function fetchTileNoAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Instantiating template: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'layergroupid'), + "Missing 'layergroupid' from response body: " + res.body); + layergroupid = parsed.layergroupid; + assert.ok(layergroupid.match(/^localhost@/), + 'Returned layergroupid does not start with signer name: ' + layergroupid); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'last_updated'), + "Missing 'last_updated' from response body: " + res.body); - keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; - // TODO: check value of last_updated ? - var get_request = { - url: '/api/v1/map/' + layergroupid + ':cb0/0/0/0/0.json.torque', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function fetchTileAuth(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 403, - 'Fetching tile with no auth: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/permission denied/i), - 'Unexpected error for unauthorized instance (expected /permission denied): ' + parsed.errors); - var get_request = { - url: '/api/v1/map/' + layergroupid + ':cb1/0/0/0/0.json.torque?auth_token=valid1', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkTile_fetchOnRestart(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - '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.equal(cc, expectedCC); - // hack simulating restart... - // FIXME: we need a better way to reset cache while running tests - server.layergroupAffectedTablesCache.cache.reset(); // need to clean channel cache - var get_request = { - url: '/api/v1/map/' + layergroupid + ':cb1/0/0/0/1.json.torque?auth_token=valid1', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkCacheChannel(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - '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.equal(cc, expectedCC); - return null; - }, - function deleteTemplate(err) - { - assert.ifError(err); - var del_request = { - url: '/api/v1/map/named/' + tpl_id + '?api_key=1234', - method: 'DELETE', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, del_request, {}, - function(res) { next(null, res); }); - }, - function fetchTileDeleted(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 204, - 'Deleting template: ' + res.statusCode + ':' + res.body); - var get_request = { - url: '/api/v1/map/' + layergroupid + ':cb2/0/0/0/0.json.torque?auth_token=valid1', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkTorqueTileAvailable(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, 'Torque tile should be accessible'); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); + // TODO: check value of last_updated ? + var getRequest = { + url: '/api/v1/map/' + layergroupid + ':cb0/0/0/0/0.json.torque', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function fetchTileAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, + 'Fetching tile with no auth: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/permission denied/i), + 'Unexpected error for unauthorized instance (expected /permission denied): ' + parsed.errors); + var getRequest = { + url: '/api/v1/map/' + layergroupid + ':cb1/0/0/0/0.json.torque?auth_token=valid1', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkTileFetchOnRestart (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body); + assert.strictEqual(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.strictEqual(cc, expectedCC); + // hack simulating restart... + // FIXME: we need a better way to reset cache while running tests + server.layergroupAffectedTablesCache.cache.reset(); // need to clean channel cache + var getRequest = { + url: '/api/v1/map/' + layergroupid + ':cb1/0/0/0/1.json.torque?auth_token=valid1', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkCacheChannel (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body); + assert.strictEqual(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.strictEqual(cc, expectedCC); + return null; + }, + function deleteTemplate (err) { + assert.ifError(err); + var delRequest = { + url: '/api/v1/map/named/' + tplId + '?api_key=1234', + method: 'DELETE', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, delRequest, {}, + function (res) { next(null, res); }); + }, + function fetchTileDeleted (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 204, + 'Deleting template: ' + res.statusCode + ':' + res.body); + var getRequest = { + url: '/api/v1/map/' + layergroupid + ':cb2/0/0/0/0.json.torque?auth_token=valid1', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkTorqueTileAvailable (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, 'Torque tile should be accessible'); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); - done(); - } - ); + done(); + } + ); }); - it("can instanciate a template with attribute service by id", function(done) { + it('can instanciate a template with attribute service by id', function (done) { + // This map fetches data from a private table + var template = { + version: '0.0.1', + name: 'acceptance1', + auth: { method: 'token', valid_tokens: ['valid1', 'valid2'] }, + layergroup: { + version: '1.1.0', + layers: [ + { + options: { + sql: 'select * from test_table_private_1 where cartodb_id in ( 5,6 )', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + attributes: { id: 'cartodb_id', columns: ['name', 'address'] } + } + } + ] + } + }; - // This map fetches data from a private table - var template = { - version: '0.0.1', - name: 'acceptance1', - auth: { method: 'token', valid_tokens: ['valid1','valid2'] }, - layergroup: { - version: '1.1.0', - layers: [ - { options: { - sql: "select * from test_table_private_1 where cartodb_id in ( 5,6 )", - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - attributes: { id:'cartodb_id', columns: ['name', 'address'] } - } } - ] - } - }; + var templateParams = {}; - var template_params = {}; + var tplId; + var layergroupid; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(template) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateNoAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var postRequest = { + url: '/api/v1/map/named/' + tplId, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, + 'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/unauthorized/i), + 'Unexpected error for unauthorized instance : ' + parsed.errors); + var postRequest = { + url: '/api/v1/map/named/' + tplId + '?auth_token=valid2', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function fetchAttributeNoAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Instantiating template: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'layergroupid'), + "Missing 'layergroupid' from response body: " + res.body); + layergroupid = parsed.layergroupid; + assert.ok(layergroupid.match(/^localhost@/), + 'Returned layergroupid does not start with signer name: ' + layergroupid); + assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'last_updated'), + "Missing 'last_updated' from response body: " + res.body); - var tpl_id; - var layergroupid; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateNoAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var post_request = { - url: '/api/v1/map/named/' + tpl_id, - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 403, - 'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/unauthorized/i), - 'Unexpected error for unauthorized instance : ' + parsed.errors); - var post_request = { - url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function fetchAttributeNoAuth(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - 'Instantiating template: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('layergroupid'), - "Missing 'layergroupid' from response body: " + res.body); - layergroupid = parsed.layergroupid; - assert.ok(layergroupid.match(/^localhost@/), - "Returned layergroupid does not start with signer name: " + layergroupid); - assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); - assert.ok(parsed.hasOwnProperty('last_updated'), - "Missing 'last_updated' from response body: " + res.body); + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; - keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; + // TODO: check value of last_updated ? + var getRequest = { + url: '/api/v1/map/' + layergroupid + ':cb0/0/attributes/5', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function fetchAttributeAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 403, + 'Fetching tile with no auth: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'), + "Missing 'errors' from response body: " + res.body); + assert.ok(parsed.errors[0].match(/permission denied/i), + 'Unexpected error for unauthorized getAttributes (expected /permission denied/): ' + parsed.errors); + var getRequest = { + url: '/api/v1/map/' + layergroupid + ':cb1/0/attributes/5?auth_token=valid2', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkAttribute (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Unexpected error for authorized getAttributes: ' + res.statusCode + ' -- ' + res.body); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); + return null; + }, + function deleteTemplate (err) { + assert.ifError(err); + var delRequest = { + url: '/api/v1/map/named/' + tplId + '?api_key=1234', + method: 'DELETE', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, delRequest, {}, + function (res) { next(null, res); }); + }, + function fetchAttrDeleted (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 204, + 'Deleting template: ' + res.statusCode + ':' + res.body); + var getRequest = { + url: '/api/v1/map/' + layergroupid + ':cb2/0/attributes/5?auth_token=valid2', + method: 'GET', + headers: { host: 'localhost' }, + encoding: 'binary' + }; + var next = this; + assert.response(server, getRequest, {}, + function (res) { next(null, res); }); + }, + function checkLayerAttributesAvailable (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, 'Layer attributes should be accessible'); + assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8'); - // TODO: check value of last_updated ? - var get_request = { - url: '/api/v1/map/' + layergroupid + ':cb0/0/attributes/5', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function fetchAttributeAuth(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 403, - 'Fetching tile with no auth: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('errors'), - "Missing 'errors' from response body: " + res.body); - assert.ok(parsed.errors[0].match(/permission denied/i), - 'Unexpected error for unauthorized getAttributes (expected /permission denied/): ' + parsed.errors); - var get_request = { - url: '/api/v1/map/' + layergroupid + ':cb1/0/attributes/5?auth_token=valid2', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkAttribute(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - 'Unexpected error for authorized getAttributes: ' + res.statusCode + ' -- ' + res.body); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - return null; - }, - function deleteTemplate(err) - { - assert.ifError(err); - var del_request = { - url: '/api/v1/map/named/' + tpl_id + '?api_key=1234', - method: 'DELETE', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, del_request, {}, - function(res) { next(null, res); }); - }, - function fetchAttrDeleted(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 204, - 'Deleting template: ' + res.statusCode + ':' + res.body); - var get_request = { - url: '/api/v1/map/' + layergroupid + ':cb2/0/attributes/5?auth_token=valid2', - method: 'GET', - headers: {host: 'localhost' }, - encoding: 'binary' - }; - var next = this; - assert.response(server, get_request, {}, - function(res) { next(null, res); }); - }, - function checkLayerAttributesAvailable(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, 'Layer attributes should be accessible'); - assert.equal(res.headers['content-type'], "application/json; charset=utf-8"); - - done(); - } - ); + done(); + } + ); }); - it("can instanciate a template by id with open auth", function(done) { + it('can instanciate a template by id with open auth', function (done) { + // This map fetches data from a private table + var templateAcceptanceOpen = { + version: '0.0.1', + name: 'acceptance_open', + auth: { method: 'open' }, + layergroup: { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table_private_1 LIMIT 0', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } + } + ] + } + }; - // This map fetches data from a private table - var template_acceptance_open = { - version: '0.0.1', - name: 'acceptance_open', - auth: { method: 'open' }, - layergroup: { + var templateParams = {}; + + var tplId; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptanceOpen) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateNoAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var postRequest = { + url: '/api/v1/map/named/' + tplId, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + helper.checkNoCache(res); + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body); + + keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; + keysToDelete['map_tpl|localhost'] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(); + } + ); + }); + + it('can instanciate a template using jsonp', function (done) { + // This map fetches data from a private table + var templateAcceptanceOpen = { + version: '0.0.1', + name: 'acceptance_open_jsonp', + auth: { method: 'open' }, + layergroup: { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table_private_1 LIMIT 0', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } + } + ] + } + }; + + var tplId; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptanceOpen) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateNoAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var postRequest = { + url: '/api/v1/map/named/' + tplId + '/jsonp?callback=jsonTest', + method: 'GET', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function checkInstanciation (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + // See https://github.com/CartoDB/Windshaft-cartodb/issues/176 + helper.checkCache(res); + var expectedSurrogateKey = [ + new QueryTables.QueryMetadata([{ + dbname: 'test_windshaft_cartodb_user_1_db', + schema_name: 'public', + table_name: 'test_table_private_1' + }]).key(), + new NamedMapsCacheEntry('localhost', templateAcceptanceOpen.name).key() + ].join(' '); + helper.checkSurrogateKey(res, expectedSurrogateKey); + + /* eslint-disable no-unused-vars, no-eval */ + function jsonTest (body) { + keysToDelete['map_cfg|' + LayergroupToken.parse(body.layergroupid).token] = 0; + } + eval(res.body); + /* eslint-enable */ + + keysToDelete['map_tpl|localhost'] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + return null; + }, + function finish (err) { + done(err); + } + ); + }); + + it('can instanciate a template using jsonp with params', function (done) { + // This map fetches data from a private table + var templateAcceptanceOpen = { + version: '0.0.1', + name: 'acceptance_open_jsonp_params', + auth: { method: 'open' }, + placeholders: { + color: { type: 'css_color', default: 'red' } + }, + layergroup: { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table_private_1 LIMIT 0', + cartocss: '#layer { marker-fill: <%= color %>; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } + } + ] + } + }; + + var tplId; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptanceOpen) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instanciateNoAuth (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var postRequest = { + url: '/api/v1/map/named/' + tplId + '/jsonp?callback=jsonTest&config=' + JSON.stringify({ color: 'blue' }), + method: 'GET', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function checkInstanciation (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body); + // See https://github.com/CartoDB/Windshaft-cartodb/issues/176 + helper.checkCache(res); + var expectedSurrogateKey = [ + new QueryTables.QueryMetadata([{ + dbname: 'test_windshaft_cartodb_user_1_db', + schema_name: 'public', + table_name: 'test_table_private_1' + }]).key(), + new NamedMapsCacheEntry('localhost', templateAcceptanceOpen.name).key() + ].join(' '); + helper.checkSurrogateKey(res, expectedSurrogateKey); + + /* eslint-disable no-unused-vars, no-eval */ + function jsonTest (body) { + keysToDelete['map_cfg|' + LayergroupToken.parse(body.layergroupid).token] = 0; + } + eval(res.body); + /* eslint-enable */ + + keysToDelete['map_tpl|localhost'] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(); + } + ); + }); + + it('template instantiation raises mapviews counter', function (done) { + var layergroup = { + stat_tag: 'random_tag', version: '1.0.0', layers: [ - { options: { - sql: "select * from test_table_private_1 LIMIT 0", - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id' - } } - ] - } - }; - - var template_params = {}; - - var tpl_id; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance_open) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateNoAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var post_request = { - url: '/api/v1/map/named/' + tpl_id, - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - helper.checkNoCache(res); - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, - 'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body); - - keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0; - keysToDelete['map_tpl|localhost'] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - done(); - } - ); - }); - - it("can instanciate a template using jsonp", function(done) { - - // This map fetches data from a private table - var template_acceptance_open = { - version: '0.0.1', - name: 'acceptance_open_jsonp', - auth: { method: 'open' }, - layergroup: { - version: '1.0.0', - layers: [ - { options: { - sql: "select * from test_table_private_1 LIMIT 0", - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id' - } } - ] - } - }; - - var tpl_id; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance_open) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateNoAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var post_request = { - url: '/api/v1/map/named/' + tpl_id + "/jsonp?callback=json_test", - method: 'GET', - headers: {host: 'localhost' } - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function checkInstanciation(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - // See https://github.com/CartoDB/Windshaft-cartodb/issues/176 - helper.checkCache(res); - var expectedSurrogateKey = [ - new QueryTables.QueryMetadata([{dbname: 'test_windshaft_cartodb_user_1_db', schema_name: 'public', - table_name: 'test_table_private_1'}]).key(), - new NamedMapsCacheEntry('localhost', template_acceptance_open.name).key() - ].join(' '); - helper.checkSurrogateKey(res, expectedSurrogateKey); - - // jshint ignore:start - function json_test(body) { - keysToDelete['map_cfg|' + LayergroupToken.parse(body.layergroupid).token] = 0; - } - eval(res.body); - // jshint ignore:end - keysToDelete['map_tpl|localhost'] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - return null; - }, - function finish(err) { - done(err); - } - ); - }); - - it("can instanciate a template using jsonp with params", function(done) { - - // This map fetches data from a private table - var template_acceptance_open = { - version: '0.0.1', - name: 'acceptance_open_jsonp_params', - auth: { method: 'open' }, - placeholders: { - color: { type: "css_color", default: "red" } - }, - layergroup: { - version: '1.0.0', - layers: [ - { options: { - sql: "select * from test_table_private_1 LIMIT 0", - cartocss: '#layer { marker-fill: <%= color %>; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id' - } } - ] - } - }; - - var tpl_id; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance_open) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instanciateNoAuth(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var post_request = { - url: '/api/v1/map/named/' + tpl_id + "/jsonp?callback=json_test&config=" + JSON.stringify({color:'blue'}), - method: 'GET', - headers: {host: 'localhost' } - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function checkInstanciation(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); - // See https://github.com/CartoDB/Windshaft-cartodb/issues/176 - helper.checkCache(res); - var expectedSurrogateKey = [ - new QueryTables.QueryMetadata([{dbname: 'test_windshaft_cartodb_user_1_db', schema_name: 'public', - table_name: 'test_table_private_1'}]).key(), - new NamedMapsCacheEntry('localhost', template_acceptance_open.name).key() - ].join(' '); - helper.checkSurrogateKey(res, expectedSurrogateKey); - - // jshint ignore:start - function json_test(body) { - keysToDelete['map_cfg|' + LayergroupToken.parse(body.layergroupid).token] = 0; - } - eval(res.body); - // jshint ignore:end - keysToDelete['map_tpl|localhost'] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - done(); - } - ); - }); - - it("template instantiation raises mapviews counter", function(done) { - var layergroup = { - stat_tag: 'random_tag', - version: '1.0.0', - layers: [ - { options: { - sql: 'select 1 as cartodb_id, !pixel_height! as h,' + + { + options: { + sql: 'select 1 as cartodb_id, !pixel_height! as h,' + ' ST_Buffer(!bbox!, -32*greatest(!pixel_width!,!pixel_height!)) as the_geom_webmercator', - cartocss: '#layer { polygon-fill:red; }', - cartocss_version: '2.0.1' - } } - ] - }; - var template = { - version: '0.0.1', - name: 'stat_gathering', - auth: { method: 'open' }, - layergroup: layergroup - }; - var statskey = "user:localhost:mapviews"; - var redis_stats_client = redis.createClient(global.environment.redis.port); - var template_id; // will be set on template post - var now = strftime("%Y%m%d", new Date()); - var errors = []; - step( - function clean_stats() - { - var next = this; - redis_stats_client.select(redis_stats_db, function(err) { - if ( err ) { - next(err); - } - else { - redis_stats_client.del(statskey+':global', next); - } - }); - }, - function do_post_tempate(err) - { - assert.ifError(err); - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instantiateTemplate(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - template_id = JSON.parse(res.body).template_id; - var post_request = { - url: '/api/v1/map/named/' + template_id, - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify({}) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function check_global_stats(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - 'Instantiating template: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('layergroupid'), - "Missing 'layergroupid' from response body: " + res.body); - keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; - redis_stats_client.ZSCORE(statskey + ":global", now, this); - }, - function check_tag_stats(err, val) { - assert.ifError(err); - assert.equal(val, 1, "Expected score of " + now + " in " + statskey + ":global to be 1, got " + val); - redis_stats_client.ZSCORE(statskey+':stat_tag:random_tag', now, this); - }, - function check_tag_stats_value(err, val) { - assert.ifError(err); - assert.equal(val, 1, "Expected score of " + now + " in " + statskey + ":stat_tag:" + layergroup.stat_tag + - " to be 1, got " + val); - return null; - }, - function deleteTemplate(err) - { - assert.ifError(err); - var del_request = { - url: '/api/v1/map/named/' + template_id + '?api_key=1234', - method: 'DELETE', - headers: {host: 'localhost'} - }; - var next = this; - assert.response(server, del_request, {}, - function(res) { next(null, res); }); - }, - function cleanup_stats(err, res) { - if (err) { - return done(err); - } - assert.equal(res.statusCode, 204, res.statusCode + ': ' + res.body); - if ( err ) { - errors.push('' + err); - } - - keysToDelete['user:localhost:mapviews:global'] = 5; - keysToDelete[statskey+':stat_tag:'+layergroup.stat_tag] = 5; - - done(); - } - ); - }); - - it("instance map token changes with templates certificate changes", function(done) { - - // This map fetches data from a private table - var template_acceptance2 = { - version: '0.0.1', - name: 'acceptance2', - auth: { method: 'token', valid_tokens: ['valid1','valid2'] }, - layergroup: { - version: '1.0.0', - layers: [ - { options: { - sql: "select * from test_table_private_1 LIMIT 0", - cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', - cartocss_version: '2.0.2', - interactivity: 'cartodb_id' - } } + cartocss: '#layer { polygon-fill:red; }', + cartocss_version: '2.0.1' + } + } ] - } - }; + }; + var template = { + version: '0.0.1', + name: 'stat_gathering', + auth: { method: 'open' }, + layergroup: layergroup + }; + var statskey = 'user:localhost:mapviews'; + var redisStatsClient = redis.createClient(global.environment.redis.port); + var templateId; // will be set on template post + var now = strftime('%Y%m%d', new Date()); + var errors = []; + step( + function cleanStats () { + var next = this; + redisStatsClient.select(redisStatsDb, function (err) { + if (err) { + next(err); + } else { + redisStatsClient.del(statskey + ':global', next); + } + }); + }, + function doPostTempate (err) { + assert.ifError(err); + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(template) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instantiateTemplate (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + templateId = JSON.parse(res.body).template_id; + var postRequest = { + url: '/api/v1/map/named/' + templateId, + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify({}) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function checkGlobalStats (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Instantiating template: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'layergroupid'), + "Missing 'layergroupid' from response body: " + res.body); + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + redisStatsClient.ZSCORE(statskey + ':global', now, this); + }, + function checkTagStats (err, val) { + assert.ifError(err); + assert.strictEqual(val, '1', 'Expected score of ' + now + ' in ' + statskey + ':global to be 1, got ' + val); + redisStatsClient.ZSCORE(statskey + ':stat_tag:random_tag', now, this); + }, + function checkTagStatsValue (err, val) { + assert.ifError(err); + assert.equal(val, '1', 'Expected score of ' + now + ' in ' + statskey + ':stat_tag:' + layergroup.stat_tag + + ' to be 1, got ' + val); + return null; + }, + function deleteTemplate (err) { + assert.ifError(err); + var delRequest = { + url: '/api/v1/map/named/' + templateId + '?api_key=1234', + method: 'DELETE', + headers: { host: 'localhost' } + }; + var next = this; + assert.response(server, delRequest, {}, + function (res) { next(null, res); }); + }, + function cleanupStats (err, res) { + if (err) { + return done(err); + } + assert.strictEqual(res.statusCode, 204, res.statusCode + ': ' + res.body); + if (err) { + errors.push('' + err); + } - var template_params = {}; + keysToDelete['user:localhost:mapviews:global'] = 5; + keysToDelete[statskey + ':stat_tag:' + layergroup.stat_tag] = 5; - var tpl_id; - var layergroupid; - step( - function postTemplate() - { - var next = this; - var post_request = { - url: '/api/v1/map/named?api_key=1234', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_acceptance2) - }; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instance1(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - tpl_id = parsed.template_id; - var post_request = { - url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - var next = this; - assert.response(server, post_request, {}, - function(res, err) { next(err, res); }); - }, - function checkInstance1(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - 'Instantiating template: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('layergroupid'), - "Missing 'layergroupid' from response body: " + res.body); - layergroupid = parsed.layergroupid; - helper.checkSurrogateKey(res, new NamedMapsCacheEntry('localhost', template_acceptance2.name).key()); - - keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; - return null; - }, - function updateTemplate(err) - { - assert.ifError(err); - // clone the valid one and rename it - var changedTemplate = JSON.parse(JSON.stringify(template_acceptance2)); - changedTemplate.auth.method = 'open'; - var post_request = { - url: '/api/v1/map/named/' + tpl_id + '/?api_key=1234', - method: 'PUT', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(changedTemplate) - }; - var next = this; - assert.response(server, post_request, {}, - function(res) { next(null, res); }); - }, - function instance2(err, res) - { - assert.ifError(err); - assert.equal(res.statusCode, 200, res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), - "Missing 'template_id' from response body: " + res.body); - assert.equal(tpl_id, parsed.template_id); - var post_request = { - url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2', - method: 'POST', - headers: {host: 'localhost', 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) - }; - var next = this; - assert.response(server, post_request, {}, - function(res, err) { next(err, res); }); - }, - function checkInstance2(err, res) { - assert.ifError(err); - assert.equal(res.statusCode, 200, - 'Instantiating template: ' + res.statusCode + ': ' + res.body); - var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('layergroupid'), - "Missing 'layergroupid' from response body: " + res.body); - assert.ok(layergroupid !== parsed.layergroupid); - helper.checkSurrogateKey(res, new NamedMapsCacheEntry('localhost', template_acceptance2.name).key()); - - keysToDelete['map_tpl|localhost'] = 0; - keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; - keysToDelete['user:localhost:mapviews:global'] = 5; - - done(); - } - ); + done(); + } + ); }); + it('instance map token changes with templates certificate changes', function (done) { + // This map fetches data from a private table + var templateAcceptance2 = { + version: '0.0.1', + name: 'acceptance2', + auth: { method: 'token', valid_tokens: ['valid1', 'valid2'] }, + layergroup: { + version: '1.0.0', + layers: [ + { + options: { + sql: 'select * from test_table_private_1 LIMIT 0', + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } + } + ] + } + }; - it("can use an http layer", function(done) { + var templateParams = {}; + var tplId; + var layergroupid; + step( + function postTemplate () { + var next = this; + var postRequest = { + url: '/api/v1/map/named?api_key=1234', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateAcceptance2) + }; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instance1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + tplId = parsed.template_id; + var postRequest = { + url: '/api/v1/map/named/' + tplId + '?auth_token=valid2', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res, err) { next(err, res); }); + }, + function checkInstance1 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Instantiating template: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'layergroupid'), + "Missing 'layergroupid' from response body: " + res.body); + layergroupid = parsed.layergroupid; + helper.checkSurrogateKey(res, new NamedMapsCacheEntry('localhost', templateAcceptance2.name).key()); + + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + return null; + }, + function updateTemplate (err) { + assert.ifError(err); + // clone the valid one and rename it + var changedTemplate = JSON.parse(JSON.stringify(templateAcceptance2)); + changedTemplate.auth.method = 'open'; + var postRequest = { + url: '/api/v1/map/named/' + tplId + '/?api_key=1234', + method: 'PUT', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(changedTemplate) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res) { next(null, res); }); + }, + function instance2 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), + "Missing 'template_id' from response body: " + res.body); + assert.strictEqual(tplId, parsed.template_id); + var postRequest = { + url: '/api/v1/map/named/' + tplId + '?auth_token=valid2', + method: 'POST', + headers: { host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(templateParams) + }; + var next = this; + assert.response(server, postRequest, {}, + function (res, err) { next(err, res); }); + }, + function checkInstance2 (err, res) { + assert.ifError(err); + assert.strictEqual(res.statusCode, 200, + 'Instantiating template: ' + res.statusCode + ': ' + res.body); + var parsed = JSON.parse(res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'layergroupid'), + "Missing 'layergroupid' from response body: " + res.body); + assert.ok(layergroupid !== parsed.layergroupid); + helper.checkSurrogateKey(res, new NamedMapsCacheEntry('localhost', templateAcceptance2.name).key()); + + keysToDelete['map_tpl|localhost'] = 0; + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + keysToDelete['user:localhost:mapviews:global'] = 5; + + done(); + } + ); + }); + + it('can use an http layer', function (done) { var username = 'localhost'; var httpTemplateName = 'acceptance_http'; - var httpTemplate = { + var httpTemplate = { version: '0.0.1', name: httpTemplateName, - layergroup: { + layergroup: { version: '1.3.0', layers: [ { - type: "http", + type: 'http', options: { - urlTemplate: "http://127.0.0.1:8033/{s}/{z}/{x}/{y}.png", + urlTemplate: 'http://127.0.0.1:8033/{s}/{z}/{x}/{y}.png', subdomains: [ - "a", - "b", - "c" + 'a', + 'b', + 'c' ] } }, { type: 'cartodb', options: { - sql: "select * from test_table_private_1", + sql: 'select * from test_table_private_1', cartocss: '#layer { marker-fill:blue; }', cartocss_version: '2.0.2', interactivity: 'cartodb_id' @@ -1791,13 +1747,12 @@ describe('template_api', function() { } }; - var template_params = {}; + var templateParams = {}; var expectedTemplateId = httpTemplateName; var layergroupid; step( - function createTemplate() - { + function createTemplate () { var next = this; assert.response( server, @@ -1813,16 +1768,16 @@ describe('template_api', function() { { status: 200 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function instantiateTemplate(err, res) { + function instantiateTemplate (err, res) { if (err) { throw err; } - assert.deepEqual(JSON.parse(res.body), { template_id: expectedTemplateId }); + assert.deepStrictEqual(JSON.parse(res.body), { template_id: expectedTemplateId }); var next = this; assert.response( server, @@ -1833,24 +1788,24 @@ describe('template_api', function() { host: username, 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) + data: JSON.stringify(templateParams) }, { status: 200 }, - function(res) { + function (res) { next(null, res); } ); }, - function fetchTile(err, res) { + function fetchTile (err, res) { if (err) { throw err; } var parsed = JSON.parse(res.body); assert.ok( - parsed.hasOwnProperty('layergroupid'), "Missing 'layergroupid' from response body: " + res.body); + Object.prototype.hasOwnProperty.call(parsed, 'layergroupid'), "Missing 'layergroupid' from response body: " + res.body); layergroupid = parsed.layergroupid; keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; @@ -1870,19 +1825,19 @@ describe('template_api', function() { { status: 200 }, - function(res) { + function (res) { next(null, res); } ); }, - function checkTile(err, res) { + function checkTile (err, res) { if (err) { throw err; } - assert.equal(res.headers['content-type'], "image/png"); + assert.strictEqual(res.headers['content-type'], 'image/png'); return null; }, - function deleteTemplate(err) { + function deleteTemplate (err) { if (err) { throw err; } @@ -1899,23 +1854,23 @@ describe('template_api', function() { { status: 204 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function finish(err) { + function finish (err) { done(err); } ); }); - describe('named map nonexistent tokens', function() { + describe('named map nonexistent tokens', function () { var username = 'localhost'; var templateHash = 'deadbeef'; var nonexistentToken = 'wadus'; - function request(token) { + function request (token) { return { url: '/api/v1/map/' + token + '/all/0/0/0.png', method: 'GET', @@ -1933,20 +1888,19 @@ describe('template_api', function() { status: 400 }; - function checkTileFn(done) { - return function checkTile(res, err) { + function checkTileFn (done) { + return function checkTile (res, err) { if (err) { return done(err); } - assert.deepEqual(JSON.parse(res.body).errors, + assert.deepStrictEqual(JSON.parse(res.body).errors, ["Invalid or nonexistent map configuration token '" + nonexistentToken + "'"]); done(); }; } - it("returns an error for named map nonexistent tokens", function(done) { - + it('returns an error for named map nonexistent tokens', function (done) { var nonexistentNamedMapToken = username + '@' + templateHash + '@' + nonexistentToken; assert.response( @@ -1957,8 +1911,7 @@ describe('template_api', function() { ); }); - it("returns an error for named map nonexistent tokens without template hash", function(done) { - + it('returns an error for named map nonexistent tokens without template hash', function (done) { var nonexistentNamedMapToken = username + '@' + nonexistentToken; assert.response( @@ -1968,23 +1921,21 @@ describe('template_api', function() { checkTileFn(done) ); }); - }); var torqueParamsScenarios = [ { templateParams: {}, - expectedTile: [{"x__uint8":125,"y__uint8":159,"vals__uint8":[2],"dates__uint16":[0]}] + expectedTile: [{ x__uint8: 125, y__uint8: 159, vals__uint8: [2], dates__uint16: [0] }] }, { templateParams: { namesFilter: "'Hawai'" }, - expectedTile: [{"x__uint8":125,"y__uint8":159,"vals__uint8":[1],"dates__uint16":[0]}] + expectedTile: [{ x__uint8: 125, y__uint8: 159, vals__uint8: [1], dates__uint16: [0] }] } ]; - torqueParamsScenarios.forEach(function(scenario) { - it("can instantiate with torque layer and params=" + JSON.stringify(scenario.templateParams), function(done) { - - var torqueParamsTemplate = { + torqueParamsScenarios.forEach(function (scenario) { + it('can instantiate with torque layer and params=' + JSON.stringify(scenario.templateParams), function (done) { + var torqueParamsTemplate = { version: '0.0.1', name: 'acceptance_torque_params', auth: { @@ -1992,18 +1943,18 @@ describe('template_api', function() { }, placeholders: { namesFilter: { - "type": "sql_ident", - "default": "'Hawai', 'El Estocolmo'" + type: 'sql_ident', + default: "'Hawai', 'El Estocolmo'" } }, - layergroup: { + layergroup: { version: '1.4.0', layers: [ { type: 'torque', options: { - sql: "select * from test_table_private_1 where name in (<%= namesFilter %>)", - cartocss: "Map { -torque-frame-count:1; -torque-resolution:1; " + + sql: 'select * from test_table_private_1 where name in (<%= namesFilter %>)', + cartocss: 'Map { -torque-frame-count:1; -torque-resolution:1; ' + "-torque-aggregation-function:'count(*)'; -torque-time-attribute:'cartodb_id'; }", cartocss_version: '2.0.2' } @@ -2014,7 +1965,7 @@ describe('template_api', function() { var layergroupIdToDelete; step( - function createTemplate() { + function createTemplate () { var next = this; var createTemplateRequest = { url: '/api/v1/map/named?api_key=1234', @@ -2031,15 +1982,15 @@ describe('template_api', function() { { status: 200 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function instantiateTemplate(err, res) { + function instantiateTemplate (err, res) { assert.ifError(err); var parsed = JSON.parse(res.body); - assert.ok(parsed.hasOwnProperty('template_id'), "Missing 'template_id' from response: " + res.body); + assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'template_id'), "Missing 'template_id' from response: " + res.body); var templateId = parsed.template_id; var instantiatePostRequest = { url: '/api/v1/map/named/' + templateId, @@ -2057,12 +2008,12 @@ describe('template_api', function() { { status: 200 }, - function(res, err) { + function (res, err) { return next(err, res); } ); }, - function requestTile(err, res) { + function requestTile (err, res) { assert.ifError(err); var layergroupId = JSON.parse(res.body).layergroupid; @@ -2082,12 +2033,12 @@ describe('template_api', function() { { status: 200 }, - function(res, err) { + function (res, err) { return next(err, res); } ); }, - function validateTileAndFinish(err, res) { + function validateTileAndFinish (err, res) { if (err) { return done(err); } @@ -2096,7 +2047,7 @@ describe('template_api', function() { keysToDelete['map_tpl|localhost'] = 0; keysToDelete['user:localhost:mapviews:global'] = 5; - assert.deepEqual( + assert.deepStrictEqual( JSON.parse(res.body), scenario.expectedTile ); @@ -2106,5 +2057,4 @@ describe('template_api', function() { ); }); }); - }); diff --git a/test/acceptance/tilejson-test.js b/test/acceptance/tilejson-test.js index 1c0ea21b..70aece24 100644 --- a/test/acceptance/tilejson-test.js +++ b/test/acceptance/tilejson-test.js @@ -11,9 +11,8 @@ const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS; describe('tilejson via mapnik renderer', () => tileJsonSuite(false)); describe('tilejson via postgis renderer', () => tileJsonSuite(true)); -function tileJsonSuite(usePostGIS) { - - before(function() { +function tileJsonSuite (usePostGIS) { + before(function () { serverOptions.renderer.mvt.usePostGIS = usePostGIS; }); @@ -21,8 +20,8 @@ function tileJsonSuite(usePostGIS) { serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; }); - function tilejsonValidation(tilejson, shouldHaveGrid = false) { - assert.equal(tilejson.tilejson, '2.2.0'); + function tilejsonValidation (tilejson, shouldHaveGrid = false) { + assert.strictEqual(tilejson.tilejson, '2.2.0'); assert.ok(Array.isArray(tilejson.tiles), JSON.stringify(tilejson)); assert.ok(tilejson.tiles.length > 0); @@ -31,21 +30,22 @@ function tileJsonSuite(usePostGIS) { assert.ok(Array.isArray(tilejson.grids)); assert.ok(tilejson.grids.length > 0); } - } const sql = 'SELECT * FROM populated_places_simple_reduced'; const cartocss = TestClient.CARTOCSS.POINTS; - const cartocss_version = '3.0.12'; + const cartocssVersion = '3.0.12'; const RASTER_LAYER = { options: { - sql, cartocss, cartocss_version + sql, cartocss, cartocss_version: cartocssVersion } }; const RASTER_INTERACTIVITY_LAYER = { options: { - sql, cartocss, cartocss_version, + sql, + cartocss, + cartocss_version: cartocssVersion, interactivity: ['cartodb_id'] } }; @@ -61,26 +61,26 @@ function tileJsonSuite(usePostGIS) { } }; - function mapConfig(layers) { + function mapConfig (layers) { return { version: '1.7.0', layers: Array.isArray(layers) ? layers : [layers] }; } - describe('per layer', function() { - it('should expose raster + vector tilejson for raster layers', function(done) { + describe('per layer', function () { + it('should expose raster + vector tilejson for raster layers', function (done) { var testClient = new TestClient(mapConfig(RASTER_LAYER)); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); const metadata = layergroupResult.metadata; assert.ok(metadata); - assert.equal(metadata.layers.length, 1); + assert.strictEqual(metadata.layers.length, 1); const layer = metadata.layers[0]; - assert.deepEqual(Object.keys(layer.tilejson), ['vector', 'raster']); + assert.deepStrictEqual(Object.keys(layer.tilejson), ['vector', 'raster']); Object.keys(layer.tilejson).forEach(k => { tilejsonValidation(layer.tilejson[k]); @@ -90,18 +90,18 @@ function tileJsonSuite(usePostGIS) { }); }); - it('should expose just the vector tilejson vector only layers', function(done) { + it('should expose just the vector tilejson vector only layers', function (done) { var testClient = new TestClient(mapConfig(VECTOR_LAYER)); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); const metadata = layergroupResult.metadata; assert.ok(metadata); - assert.equal(metadata.layers.length, 1); + assert.strictEqual(metadata.layers.length, 1); const layer = metadata.layers[0]; - assert.deepEqual(Object.keys(layer.tilejson), ['vector']); + assert.deepStrictEqual(Object.keys(layer.tilejson), ['vector']); Object.keys(layer.tilejson).forEach(k => { tilejsonValidation(layer.tilejson[k]); @@ -111,18 +111,18 @@ function tileJsonSuite(usePostGIS) { }); }); - it('should expose just the raster tilejson plain layers', function(done) { + it('should expose just the raster tilejson plain layers', function (done) { var testClient = new TestClient(mapConfig(PLAIN_LAYER)); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); const metadata = layergroupResult.metadata; assert.ok(metadata); - assert.equal(metadata.layers.length, 1); + assert.strictEqual(metadata.layers.length, 1); const layer = metadata.layers[0]; - assert.deepEqual(Object.keys(layer.tilejson), ['raster']); + assert.deepStrictEqual(Object.keys(layer.tilejson), ['raster']); Object.keys(layer.tilejson).forEach(k => { tilejsonValidation(layer.tilejson[k]); @@ -132,18 +132,18 @@ function tileJsonSuite(usePostGIS) { }); }); - it('should expose grids for the raster layer with interactivity', function(done) { + it('should expose grids for the raster layer with interactivity', function (done) { var testClient = new TestClient(mapConfig(RASTER_INTERACTIVITY_LAYER)); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); const metadata = layergroupResult.metadata; assert.ok(metadata); - assert.equal(metadata.layers.length, 1); + assert.strictEqual(metadata.layers.length, 1); const layer = metadata.layers[0]; - assert.deepEqual(Object.keys(layer.tilejson), ['vector', 'raster']); + assert.deepStrictEqual(Object.keys(layer.tilejson), ['vector', 'raster']); tilejsonValidation(layer.tilejson.vector); tilejsonValidation(layer.tilejson.raster, true); @@ -152,21 +152,21 @@ function tileJsonSuite(usePostGIS) { }); }); - it('should work with several layers', function(done) { + it('should work with several layers', function (done) { var testClient = new TestClient(mapConfig([RASTER_LAYER, RASTER_INTERACTIVITY_LAYER])); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); const metadata = layergroupResult.metadata; assert.ok(metadata); - assert.equal(metadata.layers.length, 2); + assert.strictEqual(metadata.layers.length, 2); - assert.deepEqual(Object.keys(metadata.layers[0].tilejson), ['vector', 'raster']); + assert.deepStrictEqual(Object.keys(metadata.layers[0].tilejson), ['vector', 'raster']); tilejsonValidation(metadata.layers[0].tilejson.vector); tilejsonValidation(metadata.layers[0].tilejson.raster); - assert.deepEqual(Object.keys(metadata.layers[1].tilejson), ['vector', 'raster']); + assert.deepStrictEqual(Object.keys(metadata.layers[1].tilejson), ['vector', 'raster']); tilejsonValidation(metadata.layers[1].tilejson.vector); tilejsonValidation(metadata.layers[1].tilejson.raster, true); @@ -175,25 +175,24 @@ function tileJsonSuite(usePostGIS) { }); }); - describe('root tilejson', function() { - - it('should expose just the `vector` tilejson and URL when for vector only mapnik layers', function(done) { + describe('root tilejson', function () { + it('should expose just the `vector` tilejson and URL when for vector only mapnik layers', function (done) { var testClient = new TestClient(mapConfig(VECTOR_LAYER)); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); const metadata = layergroupResult.metadata; assert.ok(metadata); const tilejson = metadata.tilejson; - assert.deepEqual(Object.keys(tilejson), ['vector']); + assert.deepStrictEqual(Object.keys(tilejson), ['vector']); Object.keys(tilejson).forEach(k => { tilejsonValidation(tilejson[k]); }); const url = metadata.url; - assert.deepEqual(Object.keys(url), ['vector']); + assert.deepStrictEqual(Object.keys(url), ['vector']); assert.ok(url.vector.urlTemplate); assert.ok(url.vector.subdomains); @@ -202,23 +201,23 @@ function tileJsonSuite(usePostGIS) { }); }); - it('should expose just the `vector` and `raster` tilejson and urls for mapnik layers', function(done) { + it('should expose just the `vector` and `raster` tilejson and urls for mapnik layers', function (done) { var testClient = new TestClient(mapConfig(RASTER_LAYER)); - testClient.getLayergroup(function(err, layergroupResult) { + testClient.getLayergroup(function (err, layergroupResult) { assert.ok(!err, err); const metadata = layergroupResult.metadata; assert.ok(metadata); const tilejson = metadata.tilejson; - assert.deepEqual(Object.keys(tilejson), ['vector', 'raster']); + assert.deepStrictEqual(Object.keys(tilejson), ['vector', 'raster']); Object.keys(tilejson).forEach(k => { tilejsonValidation(tilejson[k]); }); const url = metadata.url; - assert.deepEqual(Object.keys(url), ['vector', 'raster']); + assert.deepStrictEqual(Object.keys(url), ['vector', 'raster']); assert.ok(url.vector.urlTemplate); assert.ok(url.vector.subdomains); @@ -229,6 +228,5 @@ function tileJsonSuite(usePostGIS) { testClient.drain(done); }); }); - }); } diff --git a/test/acceptance/turbo-carto/anonymous-maps-test.js b/test/acceptance/turbo-carto/anonymous-maps-test.js index 80680192..201b0875 100644 --- a/test/acceptance/turbo-carto/anonymous-maps-test.js +++ b/test/acceptance/turbo-carto/anonymous-maps-test.js @@ -5,22 +5,22 @@ var TestClient = require('../../support/test-client'); var IMAGE_TOLERANCE_PER_MIL = 20; -function imageCompareFn(fixture, done) { - return function(err, res, image) { +function imageCompareFn (fixture, done) { + return function (err, res, image) { assert.ok(!err, err); assert.imageIsSimilarToFile(image, './test/fixtures/' + fixture, IMAGE_TOLERANCE_PER_MIL, done); }; } -function makeMapconfig(cartocss) { +function makeMapconfig (cartocss) { return { - "version": "1.4.0", - "layers": [ + version: '1.4.0', + layers: [ { - "type": 'mapnik', - "options": { - "cartocss_version": '2.3.0', - "sql": [ + type: 'mapnik', + options: { + cartocss_version: '2.3.0', + sql: [ 'SELECT test_table.*, _prices.price FROM test_table JOIN (' + ' SELECT 1 AS cartodb_id, 10.00 AS price', ' UNION ALL', @@ -33,14 +33,14 @@ function makeMapconfig(cartocss) { ' SELECT 5, 21.00', ') _prices ON _prices.cartodb_id = test_table.cartodb_id' ].join('\n'), - "cartocss": cartocss + cartocss: cartocss } } ] }; } -describe('turbo-carto for anonymous maps', function() { +describe('turbo-carto for anonymous maps', function () { describe('parsing ramp function with colorbrewer for greens and mapnik renderer', function () { beforeEach(function () { var turboCartocss = '#layer { marker-fill: ramp([price], colorbrewer(Greens)); }'; @@ -56,15 +56,15 @@ describe('turbo-carto for anonymous maps', function() { this.testClient.getTile(13, 4011, 3088, imageCompareFn(fixturePath, done)); }); - it('should work for different char case in quantification names', function(done) { + it('should work for different char case in quantification names', function (done) { this.testClient = new TestClient( makeMapconfig('#layer { marker-fill: ramp([price], colorbrewer(Greens, 3), jeNkS); }') ); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('layergroupid')); - assert.ok(!layergroup.hasOwnProperty('errors')); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid')); + assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors')); done(); }); @@ -94,8 +94,8 @@ describe('turbo-carto for anonymous maps', function() { { type: 'torque', options: { - sql: "SELECT * FROM populated_places_simple_reduced where the_geom" + - " && ST_MakeEnvelope(-90, 0, 90, 65)", + sql: 'SELECT * FROM populated_places_simple_reduced where the_geom' + + ' && ST_MakeEnvelope(-90, 0, 90, 65)', cartocss: [ 'Map {', ' buffer-size:0;', diff --git a/test/acceptance/turbo-carto/error-cases-test.js b/test/acceptance/turbo-carto/error-cases-test.js index 5b7df33c..b4bdeafe 100644 --- a/test/acceptance/turbo-carto/error-cases-test.js +++ b/test/acceptance/turbo-carto/error-cases-test.js @@ -5,35 +5,35 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -function makeMapconfig(markerWidth, markerFill) { +function makeMapconfig (markerWidth, markerFill) { return { - "version": "1.4.0", - "layers": [ + version: '1.4.0', + layers: [ { - "type": 'mapnik', - "options": { - "cartocss_version": '2.3.0', - "sql": 'SELECT * FROM populated_places_simple_reduced', - "cartocss": createCartocss(markerWidth, markerFill) + type: 'mapnik', + options: { + cartocss_version: '2.3.0', + sql: 'SELECT * FROM populated_places_simple_reduced', + cartocss: createCartocss(markerWidth, markerFill) } } ] }; } -function createCartocss(markerWidth, markerFill) { +function createCartocss (markerWidth, markerFill) { return [ - "#populated_places_simple_reduced {", - " marker-fill-opacity: 0.9;", - " marker-line-color: #FFF;", - " marker-line-width: 1;", - " marker-line-opacity: 1;", - " marker-placement: point;", - " marker-type: ellipse;", - " marker-allow-overlap: true;", - " marker-width: " + (markerWidth || '10') + ";", - " marker-fill: " + (markerFill || 'red') + ";", - "}" + '#populated_places_simple_reduced {', + ' marker-fill-opacity: 0.9;', + ' marker-line-color: #FFF;', + ' marker-line-width: 1;', + ' marker-line-opacity: 1;', + ' marker-placement: point;', + ' marker-type: ellipse;', + ' marker-allow-overlap: true;', + ' marker-width: ' + (markerWidth || '10') + ';', + ' marker-fill: ' + (markerFill || 'red') + ';', + '}' ].join('\n'); } @@ -44,20 +44,20 @@ var ERROR_RESPONSE = { } }; -describe('turbo-carto error cases', function() { +describe('turbo-carto error cases', function () { afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } }); - it('should return invalid number of ramp error', function(done) { + it('should return invalid number of ramp error', function (done) { this.testClient = new TestClient(makeMapconfig('ramp([pop_max], 8, 96, 3, (8,24,96,128))')); - this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroup) { + this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('errors')); - assert.equal(layergroup.errors.length, 1); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'errors')); + assert.strictEqual(layergroup.errors.length, 1); assert.ok(layergroup.errors[0].match(/^Failed\sto\sprocess/), layergroup.errors[0]); assert.ok(layergroup.errors[0].match(/invalid\sramp\slength/i), layergroup.errors[0]); @@ -65,13 +65,13 @@ describe('turbo-carto error cases', function() { }); }); - it('should return invalid column from datasource', function(done) { + it('should return invalid column from datasource', function (done) { this.testClient = new TestClient(makeMapconfig(null, 'ramp([wadus_column], (red, green, blue))')); - this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroup) { + this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('errors')); - assert.equal(layergroup.errors.length, 1); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'errors')); + assert.strictEqual(layergroup.errors.length, 1); assert.ok(layergroup.errors[0].match(/^Failed\sto\sprocess/)); assert.ok(layergroup.errors[0].match(/unable\sto\scompute\sramp/i)); assert.ok(layergroup.errors[0].match(/wadus_column/)); @@ -80,28 +80,28 @@ describe('turbo-carto error cases', function() { }); }); - it('should return invalid method from datasource', function(done) { + it('should return invalid method from datasource', function (done) { this.testClient = new TestClient(makeMapconfig(null, 'ramp([wadus_column], (red, green, blue), wadusmethod)')); - this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroup) { + this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('errors')); - assert.equal(layergroup.errors.length, 1); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'errors')); + assert.strictEqual(layergroup.errors.length, 1); assert.ok(layergroup.errors[0].match(/^Failed\sto\sprocess/)); assert.ok(layergroup.errors[0].match(/unable\sto\scompute\sramp/i)); - assert.ok(layergroup.errors[0].match(/invalid\smethod\s\"wadusmethod\"/i)); + assert.ok(layergroup.errors[0].match(/invalid\smethod\s"wadusmethod"/i)); done(); }); }); - it('should fail by falling back to normal carto parser', function(done) { + it('should fail by falling back to normal carto parser', function (done) { this.testClient = new TestClient(makeMapconfig('ramp([price], (8,24,96), (8,24,96));//(red, green, blue))')); - this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroup) { + this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('errors')); - assert.equal(layergroup.errors.length, 1); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'errors')); + assert.strictEqual(layergroup.errors.length, 1); assert.ok(!layergroup.errors[0].match(/^Failed\sto\sprocess/)); assert.ok(layergroup.errors[0].match(/invalid\scode/i)); @@ -109,25 +109,25 @@ describe('turbo-carto error cases', function() { }); }); - it('turbo-carto: should return error invalid column from datasource with some context', function(done) { + it('turbo-carto: should return error invalid column from datasource with some context', function (done) { this.testClient = new TestClient(makeMapconfig(null, 'ramp([wadus_column], (red, green, blue))')); - this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroup) { + this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('errors')); - assert.equal(layergroup.errors_with_context.length, 1); - assert.equal(layergroup.errors_with_context[0].type, 'layer'); - assert.equal(layergroup.errors_with_context[0].subtype, 'turbo-carto'); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'errors')); + assert.strictEqual(layergroup.errors_with_context.length, 1); + assert.strictEqual(layergroup.errors_with_context[0].type, 'layer'); + assert.strictEqual(layergroup.errors_with_context[0].subtype, 'turbo-carto'); assert.ok(layergroup.errors_with_context[0].message.match(/^Failed\sto\sprocess/)); assert.ok(layergroup.errors_with_context[0].message.match(/unable\sto\scompute\sramp/i)); assert.ok(layergroup.errors_with_context[0].message.match(/wadus_column/)); - assert.equal(layergroup.errors_with_context[0].layer.id, 'layer0'); - assert.equal(layergroup.errors_with_context[0].layer.index, 0); - assert.equal(layergroup.errors_with_context[0].layer.type, 'mapnik'); + assert.strictEqual(layergroup.errors_with_context[0].layer.id, 'layer0'); + assert.strictEqual(layergroup.errors_with_context[0].layer.index, 0); + assert.strictEqual(layergroup.errors_with_context[0].layer.type, 'mapnik'); - assert.equal(layergroup.errors_with_context[0].layer.context.selector, '#populated_places_simple_reduced'); - assert.deepEqual(layergroup.errors_with_context[0].layer.context.source, { + assert.strictEqual(layergroup.errors_with_context[0].layer.context.selector, '#populated_places_simple_reduced'); + assert.deepStrictEqual(layergroup.errors_with_context[0].layer.context.source, { start: { line: 10, column: 3 @@ -141,50 +141,49 @@ describe('turbo-carto error cases', function() { }); }); - it('should return multiple errors', function(done) { - + it('should return multiple errors', function (done) { var multipleErrorsMapConfig = { - "version": "1.4.0", - "layers": [ + version: '1.4.0', + layers: [ { - "type": 'mapnik', - "options": { - "cartocss_version": '2.3.0', - "sql": 'SELECT * FROM populated_places_simple_reduced', - "cartocss": createCartocss(null, 'ramp([wadus_column], (red, green, blue))') + type: 'mapnik', + options: { + cartocss_version: '2.3.0', + sql: 'SELECT * FROM populated_places_simple_reduced', + cartocss: createCartocss(null, 'ramp([wadus_column], (red, green, blue))') } }, { - "type": 'mapnik', - "options": { - "cartocss_version": '2.3.0', - "sql": 'SELECT * FROM populated_places_simple_reduced', - "cartocss": createCartocss('ramp([invalid_column], (red, green, blue))') + type: 'mapnik', + options: { + cartocss_version: '2.3.0', + sql: 'SELECT * FROM populated_places_simple_reduced', + cartocss: createCartocss('ramp([invalid_column], (red, green, blue))') } } ] }; this.testClient = new TestClient(multipleErrorsMapConfig); - this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function(err, layergroup) { + this.testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('errors')); - assert.equal(layergroup.errors_with_context.length, 2); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'errors')); + assert.strictEqual(layergroup.errors_with_context.length, 2); - assert.equal(layergroup.errors_with_context[0].type, 'layer'); - assert.equal(layergroup.errors_with_context[0].subtype, 'turbo-carto'); + assert.strictEqual(layergroup.errors_with_context[0].type, 'layer'); + assert.strictEqual(layergroup.errors_with_context[0].subtype, 'turbo-carto'); assert.ok(layergroup.errors_with_context[0].message.match(/^Failed\sto\sprocess/)); assert.ok(layergroup.errors_with_context[0].message.match(/unable\sto\scompute\sramp/i)); assert.ok(layergroup.errors_with_context[0].message.match(/wadus_column/)); - assert.equal(layergroup.errors_with_context[0].layer.id, 'layer0'); + assert.strictEqual(layergroup.errors_with_context[0].layer.id, 'layer0'); - assert.equal(layergroup.errors_with_context[1].type, 'layer'); - assert.equal(layergroup.errors_with_context[1].subtype, 'turbo-carto'); + assert.strictEqual(layergroup.errors_with_context[1].type, 'layer'); + assert.strictEqual(layergroup.errors_with_context[1].subtype, 'turbo-carto'); assert.ok(layergroup.errors_with_context[1].message.match(/^Failed\sto\sprocess/)); assert.ok(layergroup.errors_with_context[1].message.match(/unable\sto\scompute\sramp/i)); assert.ok(layergroup.errors_with_context[1].message.match(/invalid_column/)); - assert.equal(layergroup.errors_with_context[1].layer.id, 'layer1'); + assert.strictEqual(layergroup.errors_with_context[1].layer.id, 'layer1'); done(); }); diff --git a/test/acceptance/turbo-carto/named-maps-test.js b/test/acceptance/turbo-carto/named-maps-test.js index c8e389a8..f8d05532 100644 --- a/test/acceptance/turbo-carto/named-maps-test.js +++ b/test/acceptance/turbo-carto/named-maps-test.js @@ -9,7 +9,7 @@ var serverOptions = require('../../../lib/server-options'); var mapnik = require('windshaft').mapnik; var IMAGE_TOLERANCE_PER_MIL = 10; -describe('turbo-carto for named maps', function() { +describe('turbo-carto for named maps', function () { var server; before(function () { @@ -18,25 +18,25 @@ describe('turbo-carto for named maps', function() { var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { + afterEach(function (done) { testHelper.deleteRedisKeys(keysToDelete, done); }); var templateId = 'turbo-carto-template-1'; - function template(table) { + function template (table) { return { version: '0.0.1', name: templateId, auth: { method: 'open' }, placeholders: { color: { - type: "css_color", - default: "Reds" + type: 'css_color', + default: 'Reds' } }, layergroup: { @@ -85,10 +85,10 @@ describe('turbo-carto for named maps', function() { } ]; - scenarios.forEach(function(scenario) { + scenarios.forEach(function (scenario) { it('should create a template with turbo-carto parsed properly: ' + scenario.desc, function (done) { step( - function postTemplate() { + function postTemplate () { var next = this; assert.response(server, { @@ -101,16 +101,16 @@ describe('turbo-carto for named maps', function() { next(err, res); }); }, - function checkTemplate(err, res) { + function checkTemplate (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200); - assert.deepEqual(JSON.parse(res.body), { + assert.strictEqual(res.statusCode, 200); + assert.deepStrictEqual(JSON.parse(res.body), { template_id: templateId }); return null; }, - function instantiateTemplateWithReds(err) { + function instantiateTemplateWithReds (err) { assert.ifError(err); var next = this; @@ -123,14 +123,14 @@ describe('turbo-carto for named maps', function() { }, data: JSON.stringify(templateParamsReds) }, {}, - function(res, err) { + function (res, err) { return next(err, res); }); }, - function checkInstanciationWithReds(err, res) { + function checkInstanciationWithReds (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200); + assert.strictEqual(res.statusCode, 200); var parsedBody = JSON.parse(res.body); @@ -142,7 +142,7 @@ describe('turbo-carto for named maps', function() { return parsedBody.layergroupid; }, - function requestTileReds(err, layergroupId) { + function requestTileReds (err, layergroupId) { assert.ifError(err); var next = this; @@ -153,24 +153,24 @@ describe('turbo-carto for named maps', function() { headers: { host: 'localhost' }, encoding: 'binary' }, {}, - function(res, err) { + function (res, err) { next(err, res); }); }, - function checkTileReds(err, res) { + function checkTileReds (err, res) { assert.ifError(err); var next = this; - assert.equal(res.statusCode, 200); - assert.equal(res.headers['content-type'], 'image/png'); + assert.strictEqual(res.statusCode, 200); + assert.strictEqual(res.headers['content-type'], 'image/png'); var fixturePath = './test/fixtures/turbo-carto-named-maps-reds.png'; - var image = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); + var image = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, next); }, - function instantiateTemplateWithBlues(err) { + function instantiateTemplateWithBlues (err) { assert.ifError(err); var next = this; @@ -183,13 +183,13 @@ describe('turbo-carto for named maps', function() { }, data: JSON.stringify(templateParamsBlues) }, {}, - function(res, err) { + function (res, err) { return next(err, res); }); }, - function checkInstanciationWithBlues(err, res) { + function checkInstanciationWithBlues (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 200); + assert.strictEqual(res.statusCode, 200); var parsedBody = JSON.parse(res.body); @@ -201,7 +201,7 @@ describe('turbo-carto for named maps', function() { return parsedBody.layergroupid; }, - function requestTileBlues(err, layergroupId) { + function requestTileBlues (err, layergroupId) { assert.ifError(err); var next = this; @@ -212,24 +212,24 @@ describe('turbo-carto for named maps', function() { headers: { host: 'localhost' }, encoding: 'binary' }, {}, - function(res, err) { + function (res, err) { next(err, res); }); }, - function checkTileBlues(err, res) { + function checkTileBlues (err, res) { assert.ifError(err); var next = this; - assert.equal(res.statusCode, 200); - assert.equal(res.headers['content-type'], 'image/png'); + assert.strictEqual(res.statusCode, 200); + assert.strictEqual(res.headers['content-type'], 'image/png'); var fixturePath = './test/fixtures/turbo-carto-named-maps-blues.png'; - var image = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); + var image = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, next); }, - function deleteTemplate(err) { + function deleteTemplate (err) { assert.ifError(err); var next = this; @@ -242,14 +242,14 @@ describe('turbo-carto for named maps', function() { next(err, res); }); }, - function checkDeleteTemplate(err, res) { + function checkDeleteTemplate (err, res) { assert.ifError(err); - assert.equal(res.statusCode, 204); + assert.strictEqual(res.statusCode, 204); assert.ok(!res.body); return null; }, - function finish(err) { + function finish (err) { done(err); } ); diff --git a/test/acceptance/turbo-carto/regressions-test.js b/test/acceptance/turbo-carto/regressions-test.js index 66769da1..e36dc2e1 100644 --- a/test/acceptance/turbo-carto/regressions-test.js +++ b/test/acceptance/turbo-carto/regressions-test.js @@ -5,24 +5,23 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -function makeMapconfig(sql, cartocss) { +function makeMapconfig (sql, cartocss) { return { - "version": "1.4.0", - "layers": [ + version: '1.4.0', + layers: [ { - "type": 'mapnik', - "options": { - "cartocss_version": '2.3.0', - "sql": sql, - "cartocss": cartocss + type: 'mapnik', + options: { + cartocss_version: '2.3.0', + sql: sql, + cartocss: cartocss } } ] }; } -describe('turbo-carto regressions', function() { - +describe('turbo-carto regressions', function () { afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); @@ -31,103 +30,103 @@ describe('turbo-carto regressions', function() { } }); - it('should accept // comments', function(done) { + it('should accept // comments', function (done) { var cartocss = [ - "/** simple visualization */", - "", - "Map {", - " buffer-size: 256;", - "}", - "", - "#county_points_with_population{", - " marker-fill-opacity: 0.1;", - " marker-line-color:#FFFFFF;//#CF1C90;", - " marker-line-width: 0;", - " marker-line-opacity: 0.3;", - " marker-placement: point;", - " marker-type: ellipse;", - " //marker-comp-op: overlay;", - " marker-width: [cartodb_id];", - " [zoom=5]{marker-width: [cartodb_id]*2;}", - " [zoom=6]{marker-width: [cartodb_id]*4;}", - " marker-fill: #000000;", - " marker-allow-overlap: true;", - " ", - "", - "}" + '/** simple visualization */', + '', + 'Map {', + ' buffer-size: 256;', + '}', + '', + '#county_points_with_population{', + ' marker-fill-opacity: 0.1;', + ' marker-line-color:#FFFFFF;//#CF1C90;', + ' marker-line-width: 0;', + ' marker-line-opacity: 0.3;', + ' marker-placement: point;', + ' marker-type: ellipse;', + ' //marker-comp-op: overlay;', + ' marker-width: [cartodb_id];', + ' [zoom=5]{marker-width: [cartodb_id]*2;}', + ' [zoom=6]{marker-width: [cartodb_id]*4;}', + ' marker-fill: #000000;', + ' marker-allow-overlap: true;', + ' ', + '', + '}' ].join('\n'); this.testClient = new TestClient(makeMapconfig('SELECT * FROM populated_places_simple_reduced', cartocss)); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('layergroupid')); - assert.ok(!layergroup.hasOwnProperty('errors')); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid')); + assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors')); done(); }); }); - it('should fail for private tables', function(done) { + it('should fail for private tables', function (done) { var cartocss = [ - "#private_table {", - " marker-placement: point;", - " marker-allow-overlap: true;", - " marker-line-width: 0;", - " marker-fill-opacity: 1.0;", - " marker-width: ramp([cartodb_id], 10, 20);", - " marker-fill: red;", - "}" + '#private_table {', + ' marker-placement: point;', + ' marker-allow-overlap: true;', + ' marker-line-width: 0;', + ' marker-fill-opacity: 1.0;', + ' marker-width: ramp([cartodb_id], 10, 20);', + ' marker-fill: red;', + '}' ].join('\n'); this.testClient = new TestClient(makeMapconfig('SELECT * FROM test_table_private_1', cartocss)); - this.testClient.getLayergroup({ response: TestClient.RESPONSE.ERROR }, function(err, layergroup) { + this.testClient.getLayergroup({ response: TestClient.RESPONSE.ERROR }, function (err, layergroup) { assert.ok(!err, err); - assert.ok(!layergroup.hasOwnProperty('layergroupid')); - assert.ok(layergroup.hasOwnProperty('errors')); + assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid')); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'errors')); var turboCartoError = layergroup.errors_with_context[0]; assert.ok(turboCartoError); - assert.equal(turboCartoError.type, 'layer'); + assert.strictEqual(turboCartoError.type, 'layer'); assert.ok(turboCartoError.message.match(/permission\sdenied\sfor\s.+?test_table_private_1/)); done(); }); }); - it('should work for private tables with api key', function(done) { + it('should work for private tables with api key', function (done) { var cartocss = [ - "#private_table {", - " marker-placement: point;", - " marker-allow-overlap: true;", - " marker-line-width: 0;", - " marker-fill-opacity: 1.0;", - " marker-width: ramp([cartodb_id], 10, 20);", - " marker-fill: red;", - "}" + '#private_table {', + ' marker-placement: point;', + ' marker-allow-overlap: true;', + ' marker-line-width: 0;', + ' marker-fill-opacity: 1.0;', + ' marker-width: ramp([cartodb_id], 10, 20);', + ' marker-fill: red;', + '}' ].join('\n'); this.testClient = new TestClient(makeMapconfig('SELECT * FROM test_table_private_1', cartocss), 1234); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('layergroupid')); - assert.ok(!layergroup.hasOwnProperty('errors')); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid')); + assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors')); done(); }); }); - it('should work with mapnik substitution tokens', function(done) { + it('should work with mapnik substitution tokens', function (done) { var cartocss = [ - "#layer {", - " line-width: 2;", - " line-color: #3B3B58;", - " line-opacity: 1;", - " polygon-opacity: 0.7;", - " polygon-fill: ramp([points_count], (#E5F5F9,#99D8C9,#2CA25F))", - "}" + '#layer {', + ' line-width: 2;', + ' line-color: #3B3B58;', + ' line-opacity: 1;', + ' polygon-opacity: 0.7;', + ' polygon-fill: ramp([points_count], (#E5F5F9,#99D8C9,#2CA25F))', + '}' ].join('\n'); var sql = [ @@ -148,25 +147,25 @@ describe('turbo-carto regressions', function() { ].join('\n'); this.testClient = new TestClient(makeMapconfig(sql, cartocss)); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('layergroupid')); - assert.ok(!layergroup.hasOwnProperty('errors')); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid')); + assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors')); done(); }); }); - it('should work with mapnik substitution tokens and analyses', function(done) { + it('should work with mapnik substitution tokens and analyses', function (done) { var cartocss = [ - "#layer {", - " line-width: 2;", - " line-color: #3B3B58;", - " line-opacity: 1;", - " polygon-opacity: 0.7;", - " polygon-fill: ramp([points_count], (#E5F5F9,#99D8C9,#2CA25F))", - "}" + '#layer {', + ' line-width: 2;', + ' line-color: #3B3B58;', + ' line-opacity: 1;', + ' polygon-opacity: 0.7;', + ' polygon-fill: ramp([points_count], (#E5F5F9,#99D8C9,#2CA25F))', + '}' ].join('\n'); var sqlWrap = [ @@ -187,44 +186,43 @@ describe('turbo-carto regressions', function() { ].join('\n'); var mapConfig = { - "version": "1.5.0", - "layers": [ + version: '1.5.0', + layers: [ { - "type": 'mapnik', - "options": { - "cartocss_version": '2.3.0', - "source": { - "id": "head" + type: 'mapnik', + options: { + cartocss_version: '2.3.0', + source: { + id: 'head' }, sql_wrap: sqlWrap, - "cartocss": cartocss + cartocss: cartocss } } ], - "analyses": [ + analyses: [ { - "id": "head", - "type": "source", - "params": { - "query": "SELECT * FROM populated_places_simple_reduced" + id: 'head', + type: 'source', + params: { + query: 'SELECT * FROM populated_places_simple_reduced' } } ] }; this.testClient = new TestClient(mapConfig, 1234); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('layergroupid')); - assert.ok(!layergroup.hasOwnProperty('errors')); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid')); + assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors')); done(); }); }); - describe('empty datasource results', function() { - + describe('empty datasource results', function () { afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); @@ -233,37 +231,37 @@ describe('turbo-carto regressions', function() { } }); - function emptyResultMapConfig(markerFillRule) { + function emptyResultMapConfig (markerFillRule) { var cartocss = [ - "#county_points_with_population {", - " marker-placement: point;", - " marker-allow-overlap: true;", - " marker-fill-opacity: 1.0;", - " marker-fill: " + markerFillRule + ';', - " marker-line-width: 0;", - "}" + '#county_points_with_population {', + ' marker-placement: point;', + ' marker-allow-overlap: true;', + ' marker-fill-opacity: 1.0;', + ' marker-fill: ' + markerFillRule + ';', + ' marker-line-width: 0;', + '}' ].join('\n'); return { - "version": "1.5.0", - "layers": [ + version: '1.5.0', + layers: [ { - "type": 'mapnik', - "options": { - "cartocss_version": '2.3.0', - "source": { - "id": "head" + type: 'mapnik', + options: { + cartocss_version: '2.3.0', + source: { + id: 'head' }, - "cartocss": cartocss + cartocss: cartocss } } ], - "analyses": [ + analyses: [ { - "id": "head", - "type": "source", - "params": { - "query": "SELECT * FROM populated_places_simple_reduced limit 0" + id: 'head', + type: 'source', + params: { + query: 'SELECT * FROM populated_places_simple_reduced limit 0' } } ] @@ -272,16 +270,16 @@ describe('turbo-carto regressions', function() { var methods = ['quantiles', 'equal', 'jenks', 'headtails', 'category']; - methods.forEach(function(method) { - it('should work for "' + method+ '" method', function(done) { + methods.forEach(function (method) { + it('should work for "' + method + '" method', function (done) { var makerFillRule = 'ramp([pop_max], (#E5F5F9,#99D8C9,#2CA25F), ' + method + ')'; this.testClient = new TestClient(emptyResultMapConfig(makerFillRule), 1234); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('layergroupid')); - assert.ok(!layergroup.hasOwnProperty('errors')); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid')); + assert.ok(!Object.prototype.hasOwnProperty.call(layergroup, 'errors')); done(); }); @@ -293,9 +291,9 @@ describe('turbo-carto regressions', function() { { desc: 'numeric datasource', cartocss: [ - "#points {", - " marker-fill: ramp([scalerank], colorbrewer(Reds), category);", - "}" + '#points {', + ' marker-fill: ramp([scalerank], colorbrewer(Reds), category);', + '}' ].join('\n'), expected: [ '#points {', @@ -312,15 +310,15 @@ describe('turbo-carto regressions', function() { ' [ scalerank = 10 ] {', ' marker-fill: #a50f15', ' }', - '}', + '}' ].join('\n') }, { desc: 'string datasource', cartocss: [ - "#points {", - " marker-fill: ramp([adm0name], colorbrewer(Reds), category);", - "}" + '#points {', + ' marker-fill: ramp([adm0name], colorbrewer(Reds), category);', + '}' ].join('\n'), expected: [ '#points {', @@ -337,15 +335,15 @@ describe('turbo-carto regressions', function() { ' [ adm0name = "Canada" ] {', ' marker-fill: #a50f15', ' }', - '}', + '}' ].join('\n') }, { desc: 'numeric manual', cartocss: [ - "#points {", - " marker-fill: ramp([scalerank], colorbrewer(Reds), (-1, 6, 8, 4, 10), category);", - "}" + '#points {', + ' marker-fill: ramp([scalerank], colorbrewer(Reds), (-1, 6, 8, 4, 10), category);', + '}' ].join('\n'), expected: [ '#points {', @@ -362,20 +360,20 @@ describe('turbo-carto regressions', function() { ' [ scalerank = 10 ] {', ' marker-fill: #a50f15', ' }', - '}', + '}' ].join('\n') } ]; - scenarios.forEach(function(scenario) { - it('category ramps should use original type: ' + scenario.desc, function(done) { + scenarios.forEach(function (scenario) { + it('category ramps should use original type: ' + scenario.desc, function (done) { var mapConfig = makeMapconfig('SELECT * FROM populated_places_simple_reduced', scenario.cartocss); this.testClient = new TestClient(mapConfig); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ok(!err, err); - assert.ok(layergroup.hasOwnProperty('layergroupid')); - assert.deepEqual(layergroup.metadata.layers[0].meta.cartocss, scenario.expected); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid')); + assert.deepStrictEqual(layergroup.metadata.layers[0].meta.cartocss, scenario.expected); done(); }); @@ -403,7 +401,7 @@ describe('turbo-carto regressions', function() { }, value: 1 } - ], + ] }, { numBuckets: 2, @@ -424,7 +422,7 @@ describe('turbo-carto regressions', function() { }, value: 20 } - ], + ] }, { numBuckets: 3, @@ -453,8 +451,8 @@ describe('turbo-carto regressions', function() { }, value: 20 } - ], - }, + ] + } ]; scenarios.forEach(function (scenario) { @@ -466,28 +464,28 @@ describe('turbo-carto regressions', function() { const rule = layergroup.metadata.layers[0].meta.cartocss_meta.rules[0]; assert.ok(!err, err); - assert.equal(rule.buckets.length, scenario.numBuckets); - assert.deepEqual(rule.buckets, scenario.bucketResponse); + assert.strictEqual(rule.buckets.length, scenario.numBuckets); + assert.deepStrictEqual(rule.buckets, scenario.bucketResponse); done(); }); }); }); - function makeMapconfig({numQuantiles = 1}) { + function makeMapconfig ({ numQuantiles = 1 }) { return { - "version": "1.4.0", - "layers": [ + version: '1.4.0', + layers: [ { - "type": 'mapnik', - "options": { - "cartocss_version": '2.3.0', - "sql": 'SELECT * FROM populated_places_simple_reduced', - "cartocss": `#layer {\n + type: 'mapnik', + options: { + cartocss_version: '2.3.0', + sql: 'SELECT * FROM populated_places_simple_reduced', + cartocss: `#layer {\n marker-width: ramp([labelrank], range(1, 20), quantiles(${numQuantiles}));\n marker-fill: #EE4D5A;\n marker-fill-opacity: 0.9;\n marker-allow-overlap: true;\n marker-line-width: 1;\n - marker-line-color: #FFFFFF;\n marker-line-opacity: 1;\n}`, + marker-line-color: #FFFFFF;\n marker-line-opacity: 1;\n}` } } ] diff --git a/test/acceptance/user-database-timeout-limit-test.js b/test/acceptance/user-database-timeout-limit-test.js index 747ef2c2..c1e86b46 100644 --- a/test/acceptance/user-database-timeout-limit-test.js +++ b/test/acceptance/user-database-timeout-limit-test.js @@ -82,15 +82,15 @@ const createMapConfig = ({ } }); -const db_limit_error_message = 'You are over platform\'s limits: SQL query timeout error.' + +const dbLimitErrorMessage = 'You are over platform\'s limits: SQL query timeout error.' + ' Refactor your query before running again or contact CARTO support for more details.'; const DATASOURCE_TIMEOUT_ERROR = { - errors: [db_limit_error_message], + errors: [dbLimitErrorMessage], errors_with_context: [{ type: 'limit', subtype: 'datasource', - message: db_limit_error_message + message: dbLimitErrorMessage }] }; @@ -124,7 +124,7 @@ describe('user database timeout limit', function () { this.testClient.getDataview('count', params, (err, timeoutError) => { assert.ifError(err); - assert.deepEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); + assert.deepStrictEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); done(); }); @@ -157,12 +157,13 @@ describe('user database timeout limit', function () { }; this.testClient.getLayergroup({ response: expectedResponse }, (err, timeoutError) => { - assert.deepEqual(timeoutError, { - errors: [db_limit_error_message ], + assert.ifError(err); + assert.deepStrictEqual(timeoutError, { + errors: [dbLimitErrorMessage], errors_with_context: [{ type: 'limit', subtype: 'datasource', - message: db_limit_error_message, + message: dbLimitErrorMessage, layer: { id: 'layer0', index: 0, type: 'mapnik' } }] }); @@ -221,7 +222,7 @@ describe('user database timeout limit', function () { const params = { layergroupid: this.layergroupid, format: 'png', - layers: [ 0 ] + layers: [0] }; this.testClient.getTile(0, 0, 0, params, (err, res, tile) => { @@ -305,7 +306,7 @@ describe('user database timeout limit', function () { const params = { layergroupid: this.layergroupid, format: 'png', - layers: [ 0 ], + layers: [0], response: { status: 429, headers: { @@ -317,7 +318,7 @@ describe('user database timeout limit', function () { this.testClient.getTile(0, 0, 0, params, (err, res, timeoutError) => { assert.ifError(err); - assert.deepEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); + assert.deepStrictEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); done(); }); @@ -343,7 +344,7 @@ describe('user database timeout limit', function () { this.testClient.getStaticCenter(params, (err, res, timeoutError) => { assert.ifError(err); - assert.deepEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); + assert.deepStrictEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); done(); }); @@ -379,12 +380,13 @@ describe('user database timeout limit', function () { }; this.testClient.getLayergroup({ response: expectedResponse }, (err, timeoutError) => { - assert.deepEqual(timeoutError, { - errors: [ db_limit_error_message ], + assert.ifError(err); + assert.deepStrictEqual(timeoutError, { + errors: [dbLimitErrorMessage], errors_with_context: [{ type: 'limit', subtype: 'datasource', - message: db_limit_error_message, + message: dbLimitErrorMessage, layer: { id: 'layer0', index: 0, type: 'mapnik' } }] }); @@ -397,7 +399,7 @@ describe('user database timeout limit', function () { describe('fetching vector tiles via mapnik renderer', () => testFetchingVectorTiles(false)); describe('fetching vector tiles via postgis renderer', () => testFetchingVectorTiles(true)); - function testFetchingVectorTiles(usePostGIS) { + function testFetchingVectorTiles (usePostGIS) { const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS; before(function () { @@ -408,7 +410,6 @@ describe('user database timeout limit', function () { serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; }); - beforeEach(function (done) { const mapconfig = createMapConfig(); this.testClient = new TestClient(mapconfig, 1234); @@ -447,7 +448,7 @@ describe('user database timeout limit', function () { const params = { layergroupid: this.layergroupid, format: 'mvt', - layers: [ 0 ], + layers: [0], response: { status: 429, headers: { @@ -460,20 +461,18 @@ describe('user database timeout limit', function () { assert.ifError(err); var tileJSON = tile.toJSON(); - assert.equal(Array.isArray(tileJSON), true); - assert.equal(tileJSON.length, 2); - assert.equal(tileJSON[0].name, 'errorTileSquareLayer'); - assert.equal(tileJSON[1].name, 'errorTileStripesLayer'); + assert.strictEqual(Array.isArray(tileJSON), true); + assert.strictEqual(tileJSON.length, 2); + assert.strictEqual(tileJSON[0].name, 'errorTileSquareLayer'); + assert.strictEqual(tileJSON[1].name, 'errorTileStripesLayer'); done(); }); - }); }); } }); - describe('interactivity', function () { describe('while validating in layergroup creation', function () { beforeEach(function (done) { @@ -500,12 +499,13 @@ describe('user database timeout limit', function () { }; this.testClient.getLayergroup({ response: expectedResponse }, (err, timeoutError) => { - assert.deepEqual(timeoutError, { - errors: [ db_limit_error_message ], + assert.ifError(err); + assert.deepStrictEqual(timeoutError, { + errors: [dbLimitErrorMessage], errors_with_context: [{ type: 'limit', subtype: 'datasource', - message: db_limit_error_message, + message: dbLimitErrorMessage, layer: { id: 'layer0', index: 0, type: 'mapnik' } }] }); @@ -566,7 +566,7 @@ describe('user database timeout limit', function () { this.testClient.getTile(0, 0, 0, params, (err, res, timeoutError) => { assert.ifError(err); - assert.deepEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); + assert.deepStrictEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); done(); }); @@ -604,12 +604,13 @@ describe('user database timeout limit', function () { }; this.testClient.getLayergroup({ response: expectedResponse }, (err, timeoutError) => { - assert.deepEqual(timeoutError, { - errors: [db_limit_error_message], + assert.ifError(err); + assert.deepStrictEqual(timeoutError, { + errors: [dbLimitErrorMessage], errors_with_context: [{ type: 'limit', subtype: 'datasource', - message: db_limit_error_message, + message: dbLimitErrorMessage, layer: { id: 'torque-layer0', index: 0, type: 'torque' } }] }); @@ -661,7 +662,7 @@ describe('user database timeout limit', function () { const params = { layergroupid: this.layergroupid, format: 'torque.json', - layers: [ 0 ], + layers: [0], response: { status: 429, headers: { @@ -673,7 +674,7 @@ describe('user database timeout limit', function () { this.testClient.getTile(0, 0, 0, params, (err, res, timeoutError) => { assert.ifError(err); - assert.deepEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); + assert.deepStrictEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); done(); }); @@ -683,7 +684,7 @@ describe('user database timeout limit', function () { const params = { layergroupid: this.layergroupid, format: 'torque.png', - layers: [ 0 ], + layers: [0], response: { status: 429, headers: { @@ -695,7 +696,7 @@ describe('user database timeout limit', function () { this.testClient.getTile(0, 0, 0, params, (err, res, attributes) => { assert.ifError(err); - assert.deepEqual(attributes, DATASOURCE_TIMEOUT_ERROR); + assert.deepStrictEqual(attributes, DATASOURCE_TIMEOUT_ERROR); done(); }); @@ -710,7 +711,7 @@ describe('user database timeout limit', function () { const mapconfig = createMapConfig({ attributes: { id: 'cartodb_id', - columns: [ 'val' ] + columns: ['val'] } }); this.testClient = new TestClient(mapconfig, 1234); @@ -735,12 +736,13 @@ describe('user database timeout limit', function () { }; this.testClient.getLayergroup({ response: expectedResponse }, (err, timeoutError) => { - assert.deepEqual(timeoutError, { - errors: [db_limit_error_message], + assert.ifError(err); + assert.deepStrictEqual(timeoutError, { + errors: [dbLimitErrorMessage], errors_with_context: [{ type: 'limit', subtype: 'datasource', - message: db_limit_error_message, + message: dbLimitErrorMessage, layer: { id: 'layer0', index: 0, @@ -759,7 +761,7 @@ describe('user database timeout limit', function () { const mapconfig = createMapConfig({ attributes: { id: 'cartodb_id', - columns: [ 'val' ] + columns: ['val'] } }); @@ -812,7 +814,7 @@ describe('user database timeout limit', function () { this.testClient.getAttributes(params, (err, res, timeoutError) => { assert.ifError(err); - assert.deepEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); + assert.deepStrictEqual(timeoutError, DATASOURCE_TIMEOUT_ERROR); done(); }); diff --git a/test/acceptance/user-render-timeout-limit-test.js b/test/acceptance/user-render-timeout-limit-test.js index 37083752..a9de3c96 100644 --- a/test/acceptance/user-render-timeout-limit-test.js +++ b/test/acceptance/user-render-timeout-limit-test.js @@ -100,16 +100,16 @@ describe('user render timeout limit', function () { this.testClient.getLayergroup({ response: expectedResponse }, (err, timeoutError) => { assert.ifError(err); - assert.deepEqual(timeoutError, { + assert.deepStrictEqual(timeoutError, { errors: [renderTimeoutErrorMessage], errors_with_context: [{ type: 'limit', subtype: 'render', message: renderTimeoutErrorMessage, layer: { - id: "layer0", + id: 'layer0', index: 0, - type: "mapnik" + type: 'mapnik' } }] }); @@ -166,7 +166,7 @@ describe('user render timeout limit', function () { }); }); - describe('with onTileErrorStrategy DISABLED', function() { + describe('with onTileErrorStrategy DISABLED', function () { var onTileErrorStrategy; beforeEach(function (done) { @@ -210,7 +210,7 @@ describe('user render timeout limit', function () { this.testClient.getTile(0, 0, 0, params, (err, res, timeoutError) => { assert.ifError(err); - assert.deepEqual(timeoutError, { + assert.deepStrictEqual(timeoutError, { errors: [renderTimeoutErrorMessage], errors_with_context: [{ type: 'limit', @@ -269,10 +269,10 @@ describe('user render timeout limit', function () { assert.ifError(err); var tileJSON = tile.toJSON(); - assert.equal(Array.isArray(tileJSON), true); - assert.equal(tileJSON.length, 2); - assert.equal(tileJSON[0].name, 'errorTileSquareLayer'); - assert.equal(tileJSON[1].name, 'errorTileStripesLayer'); + assert.strictEqual(Array.isArray(tileJSON), true); + assert.strictEqual(tileJSON.length, 2); + assert.strictEqual(tileJSON[0].name, 'errorTileSquareLayer'); + assert.strictEqual(tileJSON[1].name, 'errorTileStripesLayer'); done(); }); @@ -318,7 +318,7 @@ describe('user render timeout limit', function () { this.testClient.getTile(0, 0, 0, params, (err, res, tile) => { assert.ifError(err); - assert.deepEqual(tile, { + assert.deepStrictEqual(tile, { errors: [renderTimeoutErrorMessage], errors_with_context: [{ type: 'limit', @@ -384,7 +384,7 @@ describe('user render timeout limit', function () { }); }); - describe('with onTileErrorStrategy DISABLED', function() { + describe('with onTileErrorStrategy DISABLED', function () { var onTileErrorStrategy; beforeEach(function (done) { @@ -434,7 +434,7 @@ describe('user render timeout limit', function () { this.testClient.getStaticCenter(params, function (err, res, timeoutError) { assert.ifError(err); - assert.deepEqual(timeoutError, { + assert.deepStrictEqual(timeoutError, { errors: [renderTimeoutErrorMessage], errors_with_context: [{ type: 'limit', diff --git a/test/acceptance/vector-layergroup-test.js b/test/acceptance/vector-layergroup-test.js index 47fdf1be..504fbf66 100644 --- a/test/acceptance/vector-layergroup-test.js +++ b/test/acceptance/vector-layergroup-test.js @@ -6,7 +6,6 @@ const assert = require('../support/assert'); const TestClient = require('../support/test-client'); const serverOptions = require('../../lib/server-options'); - const POINTS_SQL_1 = ` select st_setsrid(st_makepoint(x*10, x*10), 4326) as the_geom, @@ -44,27 +43,27 @@ function createVectorLayergroup () { } const INCOMPATIBLE_LAYERS_ERROR = { - "errors": [ - "The `mapnik` or `cartodb` layers must be consistent:" + - " `cartocss` option is either present or voided in all layers. Mixing is not allowed." + errors: [ + 'The `mapnik` or `cartodb` layers must be consistent:' + + ' `cartocss` option is either present or voided in all layers. Mixing is not allowed.' ], - "errors_with_context":[ + errors_with_context: [ { - "type":"mapconfig", - "message": "The `mapnik` or `cartodb` layers must be consistent:" + - " `cartocss` option is either present or voided in all layers. Mixing is not allowed." + type: 'mapconfig', + message: 'The `mapnik` or `cartodb` layers must be consistent:' + + ' `cartocss` option is either present or voided in all layers. Mixing is not allowed.' } ] }; const INVALID_FORMAT_ERROR = { - "errors": [ + errors: [ "Unsupported format: 'cartocss' option is missing for png" ], - "errors_with_context":[ + errors_with_context: [ { - "type": "tile", - "message": "Unsupported format: 'cartocss' option is missing for png" + type: 'tile', + message: "Unsupported format: 'cartocss' option is missing for png" } ] }; @@ -90,7 +89,7 @@ suites.forEach((suite) => { serverOptions.renderer.mvt.usePostGIS = usePostGIS; }); - after(function (){ + after(function () { serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS; }); @@ -110,22 +109,22 @@ suites.forEach((suite) => { return done(err); } - assert.equal(tile.tileSize, 4096); - assert.equal(tile.z, 0); - assert.equal(tile.x, 0); - assert.equal(tile.y, 0); + assert.strictEqual(tile.tileSize, 4096); + assert.strictEqual(tile.z, 0); + assert.strictEqual(tile.x, 0); + assert.strictEqual(tile.y, 0); const layer0 = JSON.parse(tile.toGeoJSONSync(0)); - assert.equal(layer0.name, 'layer0'); - assert.equal(layer0.features[0].type, 'Feature'); - assert.equal(layer0.features[0].geometry.type, 'Point'); + assert.strictEqual(layer0.name, 'layer0'); + assert.strictEqual(layer0.features[0].type, 'Feature'); + assert.strictEqual(layer0.features[0].geometry.type, 'Point'); const layer1 = JSON.parse(tile.toGeoJSONSync(1)); - assert.equal(layer1.name, 'layer1'); - assert.equal(layer1.features[0].type, 'Feature'); - assert.equal(layer1.features[0].geometry.type, 'Point'); + assert.strictEqual(layer1.name, 'layer1'); + assert.strictEqual(layer1.features[0].type, 'Feature'); + assert.strictEqual(layer1.features[0].geometry.type, 'Point'); done(); }); }); @@ -136,16 +135,16 @@ suites.forEach((suite) => { return done(err); } - assert.equal(tile.tileSize, 4096); - assert.equal(tile.z, 0); - assert.equal(tile.x, 0); - assert.equal(tile.y, 0); + assert.strictEqual(tile.tileSize, 4096); + assert.strictEqual(tile.z, 0); + assert.strictEqual(tile.x, 0); + assert.strictEqual(tile.y, 0); const layer = JSON.parse(tile.toGeoJSONSync(0)); - assert.equal(layer.name, 'layer0'); - assert.equal(layer.features[0].type, 'Feature'); - assert.equal(layer.features[0].geometry.type, 'Point'); + assert.strictEqual(layer.name, 'layer0'); + assert.strictEqual(layer.features[0].type, 'Feature'); + assert.strictEqual(layer.features[0].geometry.type, 'Point'); done(); }); @@ -157,16 +156,16 @@ suites.forEach((suite) => { return done(err); } - assert.equal(tile.tileSize, 4096); - assert.equal(tile.z, 0); - assert.equal(tile.x, 0); - assert.equal(tile.y, 0); + assert.strictEqual(tile.tileSize, 4096); + assert.strictEqual(tile.z, 0); + assert.strictEqual(tile.x, 0); + assert.strictEqual(tile.y, 0); const layer = JSON.parse(tile.toGeoJSONSync(0)); - assert.equal(layer.name, 'layer1'); - assert.equal(layer.features[0].type, 'Feature'); - assert.equal(layer.features[0].geometry.type, 'Point'); + assert.strictEqual(layer.name, 'layer1'); + assert.strictEqual(layer.features[0].type, 'Feature'); + assert.strictEqual(layer.features[0].geometry.type, 'Point'); done(); }); @@ -188,7 +187,7 @@ suites.forEach((suite) => { return done(err); } - assert.deepEqual(body, INVALID_FORMAT_ERROR); + assert.deepStrictEqual(body, INVALID_FORMAT_ERROR); done(); }); }); @@ -201,7 +200,7 @@ suites.forEach((suite) => { } }; - const cartocss = `#layer0 { marker-fill: red; marker-width: 10; }`; + const cartocss = '#layer0 { marker-fill: red; marker-width: 10; }'; const cartocssVersion = '2.3.0'; this.testClient.mapConfig.layers[0].options.cartocss = cartocss; @@ -212,7 +211,7 @@ suites.forEach((suite) => { return done(err); } - assert.deepEqual(body, INCOMPATIBLE_LAYERS_ERROR); + assert.deepStrictEqual(body, INCOMPATIBLE_LAYERS_ERROR); done(); }); diff --git a/test/acceptance/widgets/aggregation-test.js b/test/acceptance/widgets/aggregation-test.js index dbca2c82..80218f53 100644 --- a/test/acceptance/widgets/aggregation-test.js +++ b/test/acceptance/widgets/aggregation-test.js @@ -5,9 +5,8 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('aggregation widgets', function() { - - var aggregationMapConfig = { +describe('aggregation widgets', function () { + var aggregationMapConfig = { version: '1.5.0', layers: [ { @@ -30,30 +29,28 @@ describe('aggregation widgets', function() { ] }; - it("should expose an aggregation", function(done) { + it('should expose an aggregation', function (done) { var testClient = new TestClient(aggregationMapConfig); - testClient.getWidget('country_places_count', { own_filter: 0 }, function(err, res) { + testClient.getWidget('country_places_count', { own_filter: 0 }, function (err, res) { if (err) { return done(err); } var aggregation = JSON.parse(res.body); - assert.equal(aggregation.categories.length, 6); - assert.deepEqual(aggregation.categories[0], { value: 769, category: 'USA', agg: false }); + assert.strictEqual(aggregation.categories.length, 6); + assert.deepStrictEqual(aggregation.categories[0], { value: 769, category: 'USA', agg: false }); testClient.drain(done); }); }); - describe('filters', function() { - + describe('filters', function () { describe('category', function () { - - it("should expose a filtered aggregation", function (done) { + it('should expose a filtered aggregation', function (done) { var params = { filters: { layers: [ - {country_places_count: {accept: ['CAN']}} + { country_places_count: { accept: ['CAN'] } } ] } }; @@ -64,13 +61,12 @@ describe('aggregation widgets', function() { } var aggregation = JSON.parse(res.body); - assert.equal(aggregation.categories.length, 1); - assert.deepEqual(aggregation.categories[0], { value: 256, category: 'CAN', agg: false }); + assert.strictEqual(aggregation.categories.length, 1); + assert.deepStrictEqual(aggregation.categories[0], { value: 256, category: 'CAN', agg: false }); testClient.drain(done); }); }); }); - }); }); diff --git a/test/acceptance/widgets/histogram-test.js b/test/acceptance/widgets/histogram-test.js index dafed514..fc624cda 100644 --- a/test/acceptance/widgets/histogram-test.js +++ b/test/acceptance/widgets/histogram-test.js @@ -5,10 +5,9 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('histogram widgets', function() { - - it("should expose layer histogram", function(done) { - var histogramMapConfig = { +describe('histogram widgets', function () { + it('should expose layer histogram', function (done) { + var histogramMapConfig = { version: '1.5.0', layers: [ { @@ -32,7 +31,7 @@ describe('histogram widgets', function() { var testClient = new TestClient(histogramMapConfig); - testClient.getWidget('pop_max', function(err, res) { + testClient.getWidget('pop_max', function (err, res) { if (err) { return done(err); } @@ -44,10 +43,9 @@ describe('histogram widgets', function() { }); }); - describe('filters', function() { - - describe('range', function() { - var histogramMapConfig = { + describe('filters', function () { + describe('range', function () { + var histogramMapConfig = { version: '1.5.0', layers: [ { @@ -69,16 +67,16 @@ describe('histogram widgets', function() { ] }; - it("should expose an histogram", function(done) { + it('should expose an histogram', function (done) { var testClient = new TestClient(histogramMapConfig); - testClient.getWidget('country_places_histogram', { own_filter: 0 }, function(err, res) { + testClient.getWidget('country_places_histogram', { own_filter: 0 }, function (err, res) { if (err) { return done(err); } var histogram = JSON.parse(res.body); // notice min value - assert.deepEqual( + assert.deepStrictEqual( histogram.bins[0], { bin: 0, freq: 6497, min: 0, max: 742572, avg: 113511.16823149147 } ); @@ -87,7 +85,7 @@ describe('histogram widgets', function() { }); }); - it("should expose a filtered histogram", function(done) { + it('should expose a filtered histogram', function (done) { var params = { filters: { layers: [ @@ -98,14 +96,14 @@ describe('histogram widgets', function() { } }; var testClient = new TestClient(histogramMapConfig); - testClient.getWidget('country_places_histogram', params, function(err, res) { + testClient.getWidget('country_places_histogram', params, function (err, res) { if (err) { return done(err); } var histogram = JSON.parse(res.body); // notice min value - assert.deepEqual(histogram.bins[0], { + assert.deepStrictEqual(histogram.bins[0], { bin: 0, freq: 62, min: 4000000, @@ -117,7 +115,7 @@ describe('histogram widgets', function() { }); }); - it("should expose a filtered histogram using dataviews for filtering", function(done) { + it('should expose a filtered histogram using dataviews for filtering', function (done) { var params = { filters: { dataviews: { @@ -126,14 +124,14 @@ describe('histogram widgets', function() { } }; var testClient = new TestClient(histogramMapConfig); - testClient.getWidget('country_places_histogram', params, function(err, res) { + testClient.getWidget('country_places_histogram', params, function (err, res) { if (err) { return done(err); } var histogram = JSON.parse(res.body); // notice min value - assert.deepEqual(histogram.bins[0], { + assert.deepStrictEqual(histogram.bins[0], { bin: 0, freq: 62, min: 4000000, @@ -146,5 +144,4 @@ describe('histogram widgets', function() { }); }); }); - }); diff --git a/test/acceptance/widgets/named-maps-test.js b/test/acceptance/widgets/named-maps-test.js index 622b7bc0..b93f26eb 100644 --- a/test/acceptance/widgets/named-maps-test.js +++ b/test/acceptance/widgets/named-maps-test.js @@ -3,7 +3,7 @@ var assert = require('../../support/assert'); var step = require('step'); -var url = require('url'); +const { URL } = require('url'); var queue = require('queue-async'); var helper = require('../../support/test-helper'); @@ -13,7 +13,7 @@ var serverOptions = require('../../../lib/server-options'); var LayergroupToken = require('../../../lib/models/layergroup-token'); -describe('named-maps widgets', function() { +describe('named-maps widgets', function () { var server; before(function () { @@ -27,19 +27,19 @@ describe('named-maps widgets', function() { var layergroup; var keysToDelete; - beforeEach(function(done) { + beforeEach(function (done) { keysToDelete = {}; - var widgetsTemplate = { + var widgetsTemplate = { version: '0.0.1', name: widgetsTemplateName, - layergroup: { + layergroup: { version: '1.5.0', layers: [ { type: 'cartodb', options: { - sql: "select * from populated_places_simple_reduced_private", + sql: 'select * from populated_places_simple_reduced_private', cartocss: '#layer { marker-fill: blue; }', cartocss_version: '2.3.0', widgets: { @@ -70,11 +70,10 @@ describe('named-maps widgets', function() { } }; - var template_params = {}; + var templateParams = {}; step( - function createTemplate() - { + function createTemplate () { var next = this; assert.response( server, @@ -90,15 +89,15 @@ describe('named-maps widgets', function() { { status: 200 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function instantiateTemplate(err, res) { + function instantiateTemplate (err, res) { assert.ifError(err); - assert.deepEqual(JSON.parse(res.body), { template_id: widgetsTemplateName }); + assert.deepStrictEqual(JSON.parse(res.body), { template_id: widgetsTemplateName }); var next = this; assert.response( server, @@ -109,21 +108,21 @@ describe('named-maps widgets', function() { host: username, 'Content-Type': 'application/json' }, - data: JSON.stringify(template_params) + data: JSON.stringify(templateParams) }, { status: 200 }, - function(res) { + function (res) { next(null, res); } ); }, - function finish(err, res) { + function finish (err, res) { assert.ifError(err); layergroup = JSON.parse(res.body); - assert.ok(layergroup.hasOwnProperty('layergroupid'), "Missing 'layergroupid' from: " + res.body); + assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'), "Missing 'layergroupid' from: " + res.body); layergroupid = layergroup.layergroupid; keysToDelete['map_cfg|' + LayergroupToken.parse(layergroup.layergroupid).token] = 0; @@ -132,12 +131,11 @@ describe('named-maps widgets', function() { return done(); } ); - }); - afterEach(function(done) { + afterEach(function (done) { step( - function deleteTemplate(err) { + function deleteTemplate (err) { assert.ifError(err); var next = this; assert.response( @@ -152,19 +150,19 @@ describe('named-maps widgets', function() { { status: 204 }, - function(res, err) { + function (res, err) { next(err, res); } ); }, - function deleteRedisKeys(err) { + function deleteRedisKeys (err) { assert.ifError(err); helper.deleteRedisKeys(keysToDelete, done); } ); }); - function getWidget(widgetName, callback) { + function getWidget (widgetName, callback) { assert.response( server, { @@ -177,7 +175,7 @@ describe('named-maps widgets', function() { { status: 200 }, - function(res, err) { + function (res, err) { if (err) { return callback(err); } @@ -187,11 +185,11 @@ describe('named-maps widgets', function() { ); } - it('should be able to retrieve widgets from all URLs', function(done) { - var widgetsPaths = layergroup.metadata.layers.reduce(function(paths, layer) { + it('should be able to retrieve widgets from all URLs', function (done) { + var widgetsPaths = layergroup.metadata.layers.reduce(function (paths, layer) { var widgets = layer.widgets || {}; - Object.keys(widgets).forEach(function(widget) { - paths.push(url.parse(widgets[widget].url.http).path); + Object.keys(widgets).forEach(function (widget) { + paths.push(new URL(widgets[widget].url.http).pathname); }); return paths; @@ -199,8 +197,8 @@ describe('named-maps widgets', function() { var widgetsQueue = queue(widgetsPaths.length); - widgetsPaths.forEach(function(path) { - widgetsQueue.defer(function(path, done) { + widgetsPaths.forEach(function (path) { + widgetsQueue.defer(function (path, done) { assert.response( server, { @@ -213,7 +211,7 @@ describe('named-maps widgets', function() { { status: 200 }, - function(res, err) { + function (res, err) { if (err) { return done(err); } @@ -224,33 +222,31 @@ describe('named-maps widgets', function() { }, path); }); - widgetsQueue.awaitAll(function(err, results) { - assert.equal(results.length, 3); + widgetsQueue.awaitAll(function (err, results) { + assert.strictEqual(results.length, 3); done(err); }); }); - - it("should retrieve aggregation", function(done) { - getWidget('country_places_count', function(err, response, aggregation) { + it('should retrieve aggregation', function (done) { + getWidget('country_places_count', function (err, response, aggregation) { assert.ok(!err, err); - assert.equal(aggregation.type, 'aggregation'); - assert.equal(aggregation.max, 769); + assert.strictEqual(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.max, 769); return done(); }); }); - it("should retrieve histogram", function(done) { - getWidget('pop_max', function(err, response, histogram) { + it('should retrieve histogram', function (done) { + getWidget('pop_max', function (err, response, histogram) { assert.ok(!err, err); - assert.equal(histogram.type, 'histogram'); - assert.equal(histogram.bin_width, 743250); + assert.strictEqual(histogram.type, 'histogram'); + assert.strictEqual(histogram.bin_width, 743250); return done(); }); }); - }); diff --git a/test/acceptance/widgets/ported/aggregation-test.js b/test/acceptance/widgets/ported/aggregation-test.js index d16faad2..dfc4c502 100644 --- a/test/acceptance/widgets/ported/aggregation-test.js +++ b/test/acceptance/widgets/ported/aggregation-test.js @@ -5,11 +5,9 @@ require('../../../support/test-helper'); var assert = require('../../../support/assert'); var TestClient = require('../../../support/test-client'); -describe('widgets', function() { - - describe('aggregations', function() { - - afterEach(function(done) { +describe('widgets', function () { + describe('aggregations', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -40,21 +38,21 @@ describe('widgets', function() { ] }; - it('can be fetched from a valid aggregation', function(done) { + it('can be fetched from a valid aggregation', function (done) { this.testClient = new TestClient(aggregationMapConfig); this.testClient.getWidget('adm0name', { own_filter: 0 }, function (err, res, aggregation) { assert.ok(!err, err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.type, 'aggregation'); - assert.equal(aggregation.categories.length, 6); + assert.strictEqual(aggregation.categories.length, 6); - assert.deepEqual( + assert.deepStrictEqual( aggregation.categories[0], { category: 'United States of America', value: 769, agg: false } ); - assert.deepEqual( + assert.deepStrictEqual( aggregation.categories[aggregation.categories.length - 1], { category: 'Other', value: 4914, agg: true } ); @@ -74,8 +72,8 @@ describe('widgets', function() { } ]; - filteredCategoriesScenarios.forEach(function(scenario) { - it('can filter some categories: ' + scenario.accept.join(', '), function(done) { + filteredCategoriesScenarios.forEach(function (scenario) { + it('can filter some categories: ' + scenario.accept.join(', '), function (done) { this.testClient = new TestClient(aggregationMapConfig); var adm0nameFilter = { adm0name: { @@ -93,22 +91,22 @@ describe('widgets', function() { this.testClient.getWidget('adm0name', params, function (err, res, aggregation) { assert.ok(!err, err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.type, 'aggregation'); - assert.equal(aggregation.categories.length, scenario.accept.length); + assert.strictEqual(aggregation.categories.length, scenario.accept.length); - var categoriesByCategory = aggregation.categories.reduce(function(byCategory, row) { + var categoriesByCategory = aggregation.categories.reduce(function (byCategory, row) { byCategory[row.category] = row; return byCategory; }, {}); - var scenarioByCategory = scenario.accept.reduce(function(byCategory, category, index) { + var scenarioByCategory = scenario.accept.reduce(function (byCategory, category, index) { byCategory[category] = { category: category, value: scenario.values[index], agg: false }; return byCategory; }, {}); - Object.keys(categoriesByCategory).forEach(function(category) { - assert.deepEqual(categoriesByCategory[category], scenarioByCategory[category]); + Object.keys(categoriesByCategory).forEach(function (category) { + assert.deepStrictEqual(categoriesByCategory[category], scenarioByCategory[category]); }); done(); @@ -140,22 +138,21 @@ describe('widgets', function() { ] }; - it('can sum other column for aggregation value', function(done) { - + it('can sum other column for aggregation value', function (done) { this.testClient = new TestClient(aggregationSumMapConfig); this.testClient.getWidget('adm0name', { own_filter: 0 }, function (err, res, aggregation) { assert.ok(!err, err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.type, 'aggregation'); - assert.equal(aggregation.categories.length, 6); + assert.strictEqual(aggregation.categories.length, 6); - assert.deepEqual( + assert.deepStrictEqual( aggregation.categories[0], { category: 'China', value: 374537585, agg: false } ); - assert.deepEqual( + assert.deepStrictEqual( aggregation.categories[aggregation.categories.length - 1], { category: 'Other', value: 1412626289, agg: true } ); @@ -174,8 +171,8 @@ describe('widgets', function() { } ]; - filteredCategoriesSumScenarios.forEach(function(scenario) { - it('can filter some categories with sum aggregation: ' + scenario.accept.join(', '), function(done) { + filteredCategoriesSumScenarios.forEach(function (scenario) { + it('can filter some categories with sum aggregation: ' + scenario.accept.join(', '), function (done) { this.testClient = new TestClient(aggregationSumMapConfig); var adm0nameFilter = { adm0name: { @@ -193,22 +190,22 @@ describe('widgets', function() { this.testClient.getWidget('adm0name', params, function (err, res, aggregation) { assert.ok(!err, err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.type, 'aggregation'); - assert.equal(aggregation.categories.length, scenario.accept.length); + assert.strictEqual(aggregation.categories.length, scenario.accept.length); - var categoriesByCategory = aggregation.categories.reduce(function(byCategory, row) { + var categoriesByCategory = aggregation.categories.reduce(function (byCategory, row) { byCategory[row.category] = row; return byCategory; }, {}); - var scenarioByCategory = scenario.accept.reduce(function(byCategory, category, index) { + var scenarioByCategory = scenario.accept.reduce(function (byCategory, category, index) { byCategory[category] = { category: category, value: scenario.values[index], agg: false }; return byCategory; }, {}); - Object.keys(categoriesByCategory).forEach(function(category) { - assert.deepEqual(categoriesByCategory[category], scenarioByCategory[category]); + Object.keys(categoriesByCategory).forEach(function (category) { + assert.deepStrictEqual(categoriesByCategory[category], scenarioByCategory[category]); }); done(); @@ -239,8 +236,8 @@ describe('widgets', function() { ] }; - ['1', 1].forEach(function(filterValue) { - it('can filter numeric categories: ' + (typeof filterValue), function(done) { + ['1', 1].forEach(function (filterValue) { + it('can filter numeric categories: ' + (typeof filterValue), function (done) { this.testClient = new TestClient(numericAggregationMapConfig); var scalerankFilter = { scalerank: { @@ -256,18 +253,18 @@ describe('widgets', function() { this.testClient.getWidget('scalerank', params, function (err, res, aggregation) { assert.ok(!err, err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.type, 'aggregation'); - assert.equal(aggregation.categories.length, 1); - assert.deepEqual(aggregation.categories[0], { category: '1', value: 179, agg: false }); + assert.strictEqual(aggregation.categories.length, 1); + assert.deepStrictEqual(aggregation.categories[0], { category: 1, value: 179, agg: false }); done(); }); }); }); - describe('search', function() { - afterEach(function(done) { + describe('search', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -275,8 +272,8 @@ describe('widgets', function() { } }); - ['1', 1].forEach(function(userQuery) { - it('can search numeric categories: ' + (typeof userQuery), function(done) { + ['1', 1].forEach(function (userQuery) { + it('can search numeric categories: ' + (typeof userQuery), function (done) { this.testClient = new TestClient(numericAggregationMapConfig); var scalerankFilter = { scalerank: { @@ -292,10 +289,10 @@ describe('widgets', function() { this.testClient.widgetSearch('scalerank', userQuery, params, function (err, res, searchResult) { assert.ok(!err, err); assert.ok(searchResult); - assert.equal(searchResult.type, 'aggregation'); + assert.strictEqual(searchResult.type, 'aggregation'); - assert.equal(searchResult.categories.length, 2); - assert.deepEqual( + assert.strictEqual(searchResult.categories.length, 2); + assert.deepStrictEqual( searchResult.categories, [{ category: 10, value: 515 }, { category: 1, value: 179 }] ); @@ -306,18 +303,18 @@ describe('widgets', function() { }); var adm0name = 'Argentina'; - [adm0name, adm0name.toLowerCase(), adm0name.toUpperCase()].forEach(function(userQuery) { - it('should search with case insensitive: ' + userQuery, function(done) { + [adm0name, adm0name.toLowerCase(), adm0name.toUpperCase()].forEach(function (userQuery) { + it('should search with case insensitive: ' + userQuery, function (done) { this.testClient = new TestClient(aggregationMapConfig); this.testClient.widgetSearch('adm0name', userQuery, function (err, res, searchResult) { assert.ok(!err, err); assert.ok(searchResult); - assert.equal(searchResult.type, 'aggregation'); + assert.strictEqual(searchResult.type, 'aggregation'); - assert.equal(searchResult.categories.length, 1); - assert.deepEqual( + assert.strictEqual(searchResult.categories.length, 1); + assert.deepStrictEqual( searchResult.categories, - [{ category:"Argentina", value:159 }] + [{ category: 'Argentina', value: 159 }] ); done(); @@ -325,18 +322,18 @@ describe('widgets', function() { }); }); - [adm0name].forEach(function(userQuery) { - it('should search with sum aggregation: ' + userQuery, function(done) { + [adm0name].forEach(function (userQuery) { + it('should search with sum aggregation: ' + userQuery, function (done) { this.testClient = new TestClient(aggregationSumMapConfig); this.testClient.widgetSearch('adm0name', userQuery, function (err, res, searchResult) { assert.ok(!err, err); assert.ok(searchResult); - assert.equal(searchResult.type, 'aggregation'); + assert.strictEqual(searchResult.type, 'aggregation'); - assert.equal(searchResult.categories.length, 1); - assert.deepEqual( + assert.strictEqual(searchResult.categories.length, 1); + assert.deepStrictEqual( searchResult.categories, - [{ category:"Argentina", value:28015640 }] + [{ category: 'Argentina', value: 28015640 }] ); done(); @@ -344,7 +341,5 @@ describe('widgets', function() { }); }); }); - }); - }); diff --git a/test/acceptance/widgets/ported/formula-test.js b/test/acceptance/widgets/ported/formula-test.js index 546c86d3..6499314f 100644 --- a/test/acceptance/widgets/ported/formula-test.js +++ b/test/acceptance/widgets/ported/formula-test.js @@ -2,14 +2,12 @@ require('../../../support/test-helper'); -var assert = require('../../../support/assert'); +var assert = require('../../../support/assert'); var TestClient = require('../../../support/test-client'); -describe('widgets', function() { - - describe('formula', function() { - - afterEach(function(done) { +describe('widgets', function () { + describe('formula', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -17,7 +15,7 @@ describe('widgets', function() { } }); - function widgetsMapConfig(widgets) { + function widgetsMapConfig (widgets) { return { version: '1.5.0', layers: [ @@ -42,8 +40,8 @@ describe('widgets', function() { sum: [653496264, 0] }; - Object.keys(operations).forEach(function(operation) { - it('should do ' + operation + ' over column', function(done) { + Object.keys(operations).forEach(function (operation) { + it('should do ' + operation + ' over column', function (done) { var widgets = { pop_max_f: { type: 'formula', @@ -56,17 +54,17 @@ describe('widgets', function() { this.testClient = new TestClient(widgetsMapConfig(widgets)); this.testClient.getWidget('pop_max_f', function (err, res, result) { assert.ok(!err, err); - assert.equal(result.operation, operation); - assert.equal(result.result, operations[operation][0]); - assert.equal(result.nulls, operations[operation][1]); + assert.strictEqual(result.operation, operation); + assert.strictEqual(result.result, operations[operation][0]); + assert.strictEqual(result.nulls, operations[operation][1]); done(); }); }); }); - it('does not require column for count formula', function(done) { - var operation = 'count'; + it('does not require column for count formula', function (done) { + var operation = 'count'; var widgets = { pop_max_count_f: { type: 'formula', @@ -78,14 +76,12 @@ describe('widgets', function() { this.testClient = new TestClient(widgetsMapConfig(widgets)); this.testClient.getWidget('pop_max_count_f', function (err, res, result) { assert.ok(!err, err); - assert.equal(result.operation, operation); - assert.equal(result.result, operations[operation][0]); - assert.equal(result.nulls, operations[operation][1]); + assert.strictEqual(result.operation, operation); + assert.strictEqual(result.result, operations[operation][0]); + assert.strictEqual(result.nulls, operations[operation][1]); done(); }); }); - }); - }); diff --git a/test/acceptance/widgets/ported/histogram-test.js b/test/acceptance/widgets/ported/histogram-test.js index 587a7fef..bcfa30f2 100644 --- a/test/acceptance/widgets/ported/histogram-test.js +++ b/test/acceptance/widgets/ported/histogram-test.js @@ -2,14 +2,12 @@ require('../../../support/test-helper'); -var assert = require('../../../support/assert'); +var assert = require('../../../support/assert'); var TestClient = require('../../../support/test-client'); -describe('widgets', function() { - - describe('histograms', function() { - - afterEach(function(done) { +describe('widgets', function () { + describe('histograms', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -17,7 +15,7 @@ describe('widgets', function() { } }); - function histogramsMapConfig(widgets) { + function histogramsMapConfig (widgets) { return { version: '1.5.0', layers: [ @@ -47,33 +45,33 @@ describe('widgets', function() { }; } - it('can be fetched from a valid histogram', function(done) { + it('can be fetched from a valid histogram', function (done) { this.testClient = new TestClient(histogramsMapConfig()); this.testClient.getWidget('scalerank', function (err, res, histogram) { assert.ok(!err, err); assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); validateHistogramBins(histogram); assert.ok(histogram.bins.length); - assert.deepEqual(histogram.bins[0], { bin: 0, freq: 179, min: 1, max: 1, avg: 1 }); + assert.deepStrictEqual(histogram.bins[0], { bin: 0, freq: 179, min: 1, max: 1, avg: 1 }); done(); }); }); - it('can be fetched from a valid histogram', function(done) { + it('can be fetched from a valid histogram', function (done) { this.testClient = new TestClient(histogramsMapConfig()); this.testClient.getWidget('pop_max', function (err, res, histogram) { assert.ok(!err, err); assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); validateHistogramBins(histogram); assert.ok(histogram.bins.length); - assert.deepEqual( + assert.deepStrictEqual( histogram.bins[histogram.bins.length - 1], { bin: 47, freq: 1, min: 35676000, max: 35676000, avg: 35676000 } ); @@ -82,7 +80,7 @@ describe('widgets', function() { }); }); - it('can be fetched from a valid filtered histogram', function(done) { + it('can be fetched from a valid filtered histogram', function (done) { this.testClient = new TestClient(histogramsMapConfig()); var popMaxFilter = { pop_max: { @@ -99,12 +97,12 @@ describe('widgets', function() { this.testClient.getWidget('pop_max', params, function (err, res, histogram) { assert.ok(!err, err); assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); validateHistogramBins(histogram); assert.ok(histogram.bins.length); - assert.deepEqual( + assert.deepStrictEqual( histogram.bins[histogram.bins.length - 1], { bin: 7, min: 8829000, max: 9904000, avg: 9340914.714285715, freq: 7 } ); @@ -113,7 +111,7 @@ describe('widgets', function() { }); }); - it('returns array with freq=0 entries for empty bins', function(done) { + it('returns array with freq=0 entries for empty bins', function (done) { var histogram20binsMapConfig = { version: '1.5.0', layers: [ @@ -139,10 +137,10 @@ describe('widgets', function() { this.testClient = new TestClient(histogram20binsMapConfig); this.testClient.getWidget('pop_max', { start: 0, end: 35676000, bins: 20 }, function (err, res, histogram) { assert.ok(!err, err); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); validateHistogramBins(histogram); assert.ok(histogram.bins.length); - assert.deepEqual( + assert.deepStrictEqual( histogram.bins[histogram.bins.length - 1], { bin: 19, freq: 1, min: 35676000, max: 35676000, avg: 35676000 } ); @@ -154,7 +152,7 @@ describe('widgets', function() { }); }); - it('can use a fixed number of bins', function(done) { + it('can use a fixed number of bins', function (done) { var fixedBinsHistogramMapConfig = histogramsMapConfig({ pop_max: { type: 'histogram', @@ -167,18 +165,18 @@ describe('widgets', function() { this.testClient = new TestClient(fixedBinsHistogramMapConfig); this.testClient.getWidget('pop_max', { bins: 5 }, function (err, res, histogram) { assert.ok(!err, err); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); - assert.equal(histogram.bins_count, 5); + assert.strictEqual(histogram.bins_count, 5); validateHistogramBins(histogram); assert.ok(histogram.bins.length); - assert.deepEqual( + assert.deepStrictEqual( histogram.bins[0], { bin: 0, min: 0, max: 7067423, avg: 280820.0057731959, freq: 7275 } ); - assert.deepEqual( + assert.deepStrictEqual( histogram.bins[histogram.bins.length - 1], { bin: 4, freq: 1, min: 35676000, max: 35676000, avg: 35676000 } ); @@ -187,13 +185,13 @@ describe('widgets', function() { }); }); - function validateHistogramBins(histogram) { + function validateHistogramBins (histogram) { var binWidth = histogram.bin_width; var start = histogram.bins_start; var end = start + (histogram.bins_count * binWidth); var firstBin = histogram.bins[0]; - assert.equal(firstBin.min, start, + assert.strictEqual(firstBin.min, start, 'First bin does not match min and start ' + JSON.stringify({ min: firstBin.min, start: start @@ -201,21 +199,21 @@ describe('widgets', function() { ); var lastBin = histogram.bins[histogram.bins.length - 1]; - assert.equal(lastBin.max, end, + assert.strictEqual(lastBin.max, end, 'Last bin does not match max and end ' + JSON.stringify({ max: lastBin.max, end: end }) ); - function getBinStartEnd(binIndex) { + function getBinStartEnd (binIndex) { return { start: start + (binIndex * binWidth), end: start + ((binIndex + 1) * binWidth) }; } - histogram.bins.forEach(function(bin) { + histogram.bins.forEach(function (bin) { var binStartEnd = getBinStartEnd(bin.bin); assert.ok(binStartEnd.start <= bin.min, @@ -235,7 +233,7 @@ describe('widgets', function() { ); assert.ok(bin.avg >= bin.min && bin.avg <= bin.max, - 'Bin avg not between min and max values' + JSON.stringify({ + 'Bin avg not between min and max values' + JSON.stringify({ bin: bin.bin, avg: bin.avg, min: bin.min, @@ -245,8 +243,8 @@ describe('widgets', function() { }); } - describe('datetime column', function() { - afterEach(function(done) { + describe('datetime column', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -260,7 +258,7 @@ describe('widgets', function() { } }; - it('can use a datetime column', function(done) { + it('can use a datetime column', function (done) { this.testClient = new TestClient(histogramsMapConfig({ updated_at: { type: 'histogram', @@ -272,7 +270,7 @@ describe('widgets', function() { this.testClient.getWidget('updated_at', function (err, res, histogram) { assert.ok(!err, err); assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); assert.ok(histogram.bins.length); @@ -280,7 +278,7 @@ describe('widgets', function() { }); }); - it('can use a datetime filtered column', function(done) { + it('can use a datetime filtered column', function (done) { this.testClient = new TestClient(histogramsMapConfig({ updated_at: { type: 'histogram', @@ -298,7 +296,7 @@ describe('widgets', function() { this.testClient.getWidget('updated_at', params, function (err, res, histogram) { assert.ok(!err, err); assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); assert.ok(histogram.bins.length); @@ -306,7 +304,7 @@ describe('widgets', function() { }); }); - it('can use a datetime filtered column with no results', function(done) { + it('can use a datetime filtered column with no results', function (done) { this.testClient = new TestClient(histogramsMapConfig({ updated_at: { type: 'histogram', @@ -329,15 +327,15 @@ describe('widgets', function() { this.testClient.getWidget('updated_at', params, function (err, res, histogram) { assert.ok(!err, err); assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); - assert.equal(histogram.bins.length, 0); + assert.strictEqual(histogram.bins.length, 0); done(); }); }); - it('can getTile with datetime filtered column', function(done) { + it('can getTile with datetime filtered column', function (done) { this.testClient = new TestClient(histogramsMapConfig({ updated_at: { type: 'histogram', @@ -360,7 +358,7 @@ describe('widgets', function() { }); }); - it('can use two columns with different types', function(done) { + it('can use two columns with different types', function (done) { this.testClient = new TestClient(histogramsMapConfig({ updated_at: { type: 'histogram', @@ -392,7 +390,7 @@ describe('widgets', function() { this.testClient.getWidget('updated_at', params, function (err, res, histogram) { assert.ok(!err, err); assert.ok(histogram); - assert.equal(histogram.type, 'histogram'); + assert.strictEqual(histogram.type, 'histogram'); assert.ok(histogram.bins.length); @@ -400,7 +398,5 @@ describe('widgets', function() { }); }); }); - }); - }); diff --git a/test/acceptance/widgets/regressions-test.js b/test/acceptance/widgets/regressions-test.js index 6b67a138..b568eef1 100644 --- a/test/acceptance/widgets/regressions-test.js +++ b/test/acceptance/widgets/regressions-test.js @@ -5,11 +5,9 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('widgets-regressions', function() { - - describe('aggregations', function() { - - afterEach(function(done) { +describe('widgets-regressions', function () { + describe('aggregations', function () { + afterEach(function (done) { if (this.testClient) { this.testClient.drain(done); } else { @@ -17,7 +15,7 @@ describe('widgets-regressions', function() { } }); - it('should work when there is a mix of layers with and without widgets', function(done) { + it('should work when there is a mix of layers with and without widgets', function (done) { var layersWithNoWidgetsMapConfig = { version: '1.5.0', layers: [ @@ -54,16 +52,16 @@ describe('widgets-regressions', function() { this.testClient.getWidget('adm0name', { own_filter: 0 }, function (err, res, aggregation) { assert.ok(!err, err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.type, 'aggregation'); - assert.equal(aggregation.categories.length, 6); + assert.strictEqual(aggregation.categories.length, 6); - assert.deepEqual( + assert.deepStrictEqual( aggregation.categories[0], { category: 'China', value: 374537585, agg: false } ); - assert.deepEqual( + assert.deepStrictEqual( aggregation.categories[aggregation.categories.length - 1], { category: 'Other', value: 1412626289, agg: true } ); @@ -72,7 +70,7 @@ describe('widgets-regressions', function() { }); }); - it('should work when there is a mix of layers with and without widgets, source and sql', function(done) { + it('should work when there is a mix of layers with and without widgets, source and sql', function (done) { var mixOfLayersMapConfig = { version: '1.5.0', layers: [ @@ -105,7 +103,7 @@ describe('widgets-regressions', function() { { type: 'mapnik', options: { - source: {id: 'head-limited'}, + source: { id: 'head-limited' }, cartocss: '#layer0 { marker-fill: red; marker-width: 10; }', cartocss_version: '2.0.1', widgets: { @@ -119,10 +117,10 @@ describe('widgets-regressions', function() { } }, { - "type": "http", - "options": { - "urlTemplate": "http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png", - "subdomains": "abcd" + type: 'http', + options: { + urlTemplate: 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', + subdomains: 'abcd' } } ], @@ -149,24 +147,23 @@ describe('widgets-regressions', function() { }; this.testClient = new TestClient(mixOfLayersMapConfig); - this.testClient.getLayergroup(function(err, layergroup) { + this.testClient.getLayergroup(function (err, layergroup) { assert.ok(!err, err); assert.ok(layergroup.metadata); var metadata = layergroup.metadata; - assert.equal(metadata.layers.length, 3); - assert.equal(metadata.analyses.length, 2); - assert.equal(Object.keys(metadata.dataviews).length, 4); - assert.deepEqual( + assert.strictEqual(metadata.layers.length, 3); + assert.strictEqual(metadata.analyses.length, 2); + assert.strictEqual(Object.keys(metadata.dataviews).length, 4); + assert.deepStrictEqual( Object.keys(metadata.dataviews), ['wadus', 'adm0name_categories', 'adm1name_categories', 'pop_max_histogram'] ); - done(); }); }); - it('should work with layers not containing sql', function(done) { + it('should work with layers not containing sql', function (done) { var nonSqlLayersMapConfig = { version: '1.5.0', layers: [ @@ -189,10 +186,10 @@ describe('widgets-regressions', function() { } }, { - "type": "http", - "options": { - "urlTemplate": "http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png", - "subdomains": "abcd" + type: 'http', + options: { + urlTemplate: 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', + subdomains: 'abcd' } } ] @@ -202,16 +199,16 @@ describe('widgets-regressions', function() { this.testClient.getWidget('adm0name', { own_filter: 0 }, function (err, res, aggregation) { assert.ok(!err, err); assert.ok(aggregation); - assert.equal(aggregation.type, 'aggregation'); + assert.strictEqual(aggregation.type, 'aggregation'); - assert.equal(aggregation.categories.length, 6); + assert.strictEqual(aggregation.categories.length, 6); - assert.deepEqual( + assert.deepStrictEqual( aggregation.categories[0], { category: 'China', value: 374537585, agg: false } ); - assert.deepEqual( + assert.deepStrictEqual( aggregation.categories[aggregation.categories.length - 1], { category: 'Other', value: 1412626289, agg: true } ); @@ -220,9 +217,7 @@ describe('widgets-regressions', function() { }); }); - - it('should not count the polygons outside the bounding box', function(done) { - + it('should not count the polygons outside the bounding box', function (done) { // $ % $ = not intersecting left triangle // $$ **VVVVV** %% % = not intersecting right triangle // $$$ *VVVVV* %%% * = intersecting triangle @@ -233,32 +228,32 @@ describe('widgets-regressions', function() { // $$$$$$$$ %%%%%%%% const notIntersectingLeftTriangle = { - type: "Polygon", - coordinates:[[ - [-161.015625,69.28725695167886], - [-162.7734375,-7.710991655433217], - [-40.78125,-8.059229627200192], - [-161.015625,69.28725695167886] + type: 'Polygon', + coordinates: [[ + [-161.015625, 69.28725695167886], + [-162.7734375, -7.710991655433217], + [-40.78125, -8.059229627200192], + [-161.015625, 69.28725695167886] ]] }; const notIntersectingRightTriangle = { - type: "Polygon", + type: 'Polygon', coordinates: [[ - [-29.179687499999996,-7.01366792756663], - [103.71093749999999,-6.664607562172573], - [105.46875,69.16255790810501], - [-29.179687499999996,-7.01366792756663] + [-29.179687499999996, -7.01366792756663], + [103.71093749999999, -6.664607562172573], + [105.46875, 69.16255790810501], + [-29.179687499999996, -7.01366792756663] ]] }; const intersectingTriangle = { - type: "Polygon", - coordinates:[[ - [-117.42187500000001,68.13885164925573], - [-35.859375,20.96143961409684], - [59.4140625,68.52823492039876], - [-117.42187500000001,68.13885164925573] + type: 'Polygon', + coordinates: [[ + [-117.42187500000001, 68.13885164925573], + [-35.859375, 20.96143961409684], + [59.4140625, 68.52823492039876], + [-117.42187500000001, 68.13885164925573] ]] }; @@ -283,13 +278,13 @@ describe('widgets-regressions', function() { version: '1.5.0', layers: [ { - "type": "cartodb", - "options": { - "source": { - "id": "a0" + type: 'cartodb', + options: { + source: { + id: 'a0' }, - "cartocss": "#points { marker-width: 10; marker-fill: red; }", - "cartocss_version": "2.3.0" + cartocss: '#points { marker-width: 10; marker-fill: red; }', + cartocss_version: '2.3.0' } } ], @@ -300,17 +295,17 @@ describe('widgets-regressions', function() { }, type: 'aggregation', options: { - column: "name", - aggregation: "count", + column: 'name', + aggregation: 'count' } } }, analyses: [ { - "id": "a0", - "type": "source", - "params": { - "query": query + id: 'a0', + type: 'source', + params: { + query: query } } ] @@ -320,14 +315,12 @@ describe('widgets-regressions', function() { const params = { bbox: '-77.34374999999999,45.82879925192134,17.578125,55.97379820507658' }; - this.testClient.getDataview('val_formula', params, function(err, dataview) { + this.testClient.getDataview('val_formula', params, function (err, dataview) { assert.ifError(err); - assert.equal(dataview.categories.length, 1); - assert.equal(dataview.categories[0].category, 'intersectingTriangle'); + assert.strictEqual(dataview.categories.length, 1); + assert.strictEqual(dataview.categories[0].category, 'intersectingTriangle'); done(); }); }); - }); - }); diff --git a/test/acceptance/widgets/widgets-test.js b/test/acceptance/widgets/widgets-test.js index a760a5c4..35af676a 100644 --- a/test/acceptance/widgets/widgets-test.js +++ b/test/acceptance/widgets/widgets-test.js @@ -5,10 +5,9 @@ require('../../support/test-helper'); var assert = require('../../support/assert'); var TestClient = require('../../support/test-client'); -describe('widget filters', function() { - - describe('combine widget filters', function() { - var combinedWidgetsMapConfig = { +describe('widget filters', function () { + describe('combine widget filters', function () { + var combinedWidgetsMapConfig = { version: '1.5.0', layers: [ { @@ -37,7 +36,7 @@ describe('widget filters', function() { ] }; - it("should expose a filtered aggregation", function(done) { + it('should expose a filtered aggregation', function (done) { var params = { filters: { layers: [ @@ -48,7 +47,7 @@ describe('widget filters', function() { } }; var testClient = new TestClient(combinedWidgetsMapConfig); - testClient.getWidget('country_places_count', params, function(err, res) { + testClient.getWidget('country_places_count', params, function (err, res) { if (err) { return done(err); } @@ -56,10 +55,10 @@ describe('widget filters', function() { var aggregation = JSON.parse(res.body); // first one would be CHN if reject filter wasn't applied - assert.deepEqual(aggregation.categories[0], { value: 769, category: "USA", agg: false }); + assert.deepStrictEqual(aggregation.categories[0], { value: 769, category: 'USA', agg: false }); // confirm 'CHN' was filtered out (reject) - assert.equal(aggregation.categories.reduce(function(sum, row) { + assert.strictEqual(aggregation.categories.reduce(function (sum, row) { return sum + (row.category === 'CHN' ? 1 : 0); }, 0), 0); @@ -67,7 +66,7 @@ describe('widget filters', function() { }); }); - it("should expose a filtered aggregation", function(done) { + it('should expose a filtered aggregation', function (done) { var params = { filters: { layers: [ @@ -79,7 +78,7 @@ describe('widget filters', function() { } }; var testClient = new TestClient(combinedWidgetsMapConfig); - testClient.getWidget('country_places_count', params, function(err, res) { + testClient.getWidget('country_places_count', params, function (err, res) { if (err) { return done(err); } @@ -87,10 +86,10 @@ describe('widget filters', function() { var aggregation = JSON.parse(res.body); // first one would be CHN if reject filter wasn't applied - assert.deepEqual(aggregation.categories[0], { value: 4, category: 'IND', agg: false }); + assert.deepStrictEqual(aggregation.categories[0], { value: 4, category: 'IND', agg: false }); // confirm 'CHN' was filtered out (reject) - assert.equal(aggregation.categories.reduce(function(sum, row) { + assert.strictEqual(aggregation.categories.reduce(function (sum, row) { return sum + (row.category === 'CHN' ? 1 : 0); }, 0), 0); @@ -98,7 +97,7 @@ describe('widget filters', function() { }); }); - it("should allow to filter by bounding box a filtered aggregation", function(done) { + it('should allow to filter by bounding box a filtered aggregation', function (done) { var params = { filters: { layers: [ @@ -110,7 +109,7 @@ describe('widget filters', function() { bbox: '-20,0,45,60' }; var testClient = new TestClient(combinedWidgetsMapConfig); - testClient.getWidget('country_places_count', params, function(err, res) { + testClient.getWidget('country_places_count', params, function (err, res) { if (err) { return done(err); } @@ -118,10 +117,10 @@ describe('widget filters', function() { var aggregation = JSON.parse(res.body); // first one would be CHN if reject filter wasn't applied - assert.deepEqual(aggregation.categories[0], { value: 96, category: "RUS", agg: false }); + assert.deepStrictEqual(aggregation.categories[0], { value: 96, category: 'RUS', agg: false }); // confirm 'CHN' was filtered out (reject) - assert.equal(aggregation.categories.reduce(function(sum, row) { + assert.strictEqual(aggregation.categories.reduce(function (sum, row) { return sum + (row.category === 'CHN' ? 1 : 0); }, 0), 0); @@ -129,7 +128,7 @@ describe('widget filters', function() { }); }); - it("should allow to filter by bounding box a filtered aggregation, with reject", function(done) { + it('should allow to filter by bounding box a filtered aggregation, with reject', function (done) { var params = { filters: { layers: [ @@ -142,7 +141,7 @@ describe('widget filters', function() { bbox: '-20,0,45,60' }; var testClient = new TestClient(combinedWidgetsMapConfig); - testClient.getWidget('country_places_count', params, function(err, res) { + testClient.getWidget('country_places_count', params, function (err, res) { if (err) { return done(err); } @@ -150,10 +149,10 @@ describe('widget filters', function() { var aggregation = JSON.parse(res.body); // first one would be CHN if reject filter wasn't applied - assert.deepEqual(aggregation.categories[0], { value: 77, category: "TUR", agg: false }); + assert.deepStrictEqual(aggregation.categories[0], { value: 77, category: 'TUR', agg: false }); // confirm 'CHN' was filtered out (reject) - assert.equal(aggregation.categories.reduce(function(sum, row) { + assert.strictEqual(aggregation.categories.reduce(function (sum, row) { return sum + (row.category === 'CHN' ? 1 : 0); }, 0), 0); diff --git a/test/fixtures/test_mapconfigFactory.js b/test/fixtures/test_mapconfigFactory.js index f1af550c..6b6ee1a0 100644 --- a/test/fixtures/test_mapconfigFactory.js +++ b/test/fixtures/test_mapconfigFactory.js @@ -1,13 +1,13 @@ -function getVectorMapConfig(opts) { +function getVectorMapConfig (opts) { return { buffersize: { mvt: 1 }, - layers: _generateLayers(opts), + layers: _generateLayers(opts) }; } -function _generateLayers(opts) { +function _generateLayers (opts) { const numberOfLayers = opts.numberOfLayers || 1; const layers = []; for (let index = 0; index < numberOfLayers; index++) { @@ -17,8 +17,8 @@ function _generateLayers(opts) { return layers; } -function _generateLayerConfig(opts) { - const additionalColumns = opts.additionalColumns ? opts.additionalColumns.join(',')+',' : ''; +function _generateLayerConfig (opts) { + const additionalColumns = opts.additionalColumns ? opts.additionalColumns.join(',') + ',' : ''; return { type: 'mapnik', options: { @@ -58,7 +58,4 @@ function _generateLayerConfig(opts) { }; } - - - -module.exports = { getVectorMapConfig }; \ No newline at end of file +module.exports = { getVectorMapConfig }; diff --git a/test/integration/analysis-backend-limits-test.js b/test/integration/analysis-backend-limits-test.js index be16ef90..233507fe 100644 --- a/test/integration/analysis-backend-limits-test.js +++ b/test/integration/analysis-backend-limits-test.js @@ -10,32 +10,31 @@ var cartodbRedis = require('cartodb-redis'); var AnalysisBackend = require('../../lib/backends/analysis'); -describe('analysis-backend limits', function() { - +describe('analysis-backend limits', function () { var redisClient; var keysToDelete; var user = 'localhost'; - beforeEach(function() { + beforeEach(function () { redisClient = redis.createClient(global.environment.redis.port); keysToDelete = {}; var redisPool = new RedisPool(global.environment.redis); - this.metadataBackend = cartodbRedis({pool: redisPool}); + this.metadataBackend = cartodbRedis({ pool: redisPool }); }); - afterEach(function(done) { - redisClient.quit(function() { + afterEach(function (done) { + redisClient.quit(function () { testHelper.deleteRedisKeys(keysToDelete, done); }); }); - function withAnalysesLimits(limits, callback) { - redisClient.SELECT(5, function(err) { + function withAnalysesLimits (limits, callback) { + redisClient.SELECT(5, function (err) { if (err) { return callback(err); } var analysesLimitsKey = 'limits:analyses:' + user; - redisClient.HMSET([analysesLimitsKey].concat(limits), function(err) { + redisClient.HMSET([analysesLimitsKey].concat(limits), function (err) { if (err) { return callback(err); } @@ -45,52 +44,52 @@ describe('analysis-backend limits', function() { }); } - it("should use limits from configuration", function(done) { + it('should use limits from configuration', function (done) { var analysisBackend = new AnalysisBackend(this.metadataBackend, { limits: { moran: { timeout: 5000 }, kmeans: { timeout: 5000 } } }); - analysisBackend.getAnalysesLimits(user, function(err, result) { + analysisBackend.getAnalysesLimits(user, function (err, result) { assert.ok(!err, err); assert.ok(result.analyses.moran); - assert.equal(result.analyses.moran.timeout, 5000); + assert.strictEqual(result.analyses.moran.timeout, 5000); assert.ok(result.analyses.kmeans); - assert.equal(result.analyses.kmeans.timeout, 5000); + assert.strictEqual(result.analyses.kmeans.timeout, 5000); done(); }); }); - it("should use limits from redis", function(done) { + it('should use limits from redis', function (done) { var self = this; var limits = ['moran', 5000]; - withAnalysesLimits(limits, function(err) { + withAnalysesLimits(limits, function (err) { if (err) { return done(err); } var analysisBackend = new AnalysisBackend(self.metadataBackend); - analysisBackend.getAnalysesLimits(user, function(err, result) { + analysisBackend.getAnalysesLimits(user, function (err, result) { assert.ok(!err, err); assert.ok(result.analyses.moran); - assert.equal(result.analyses.moran.timeout, 5000); + assert.strictEqual(result.analyses.moran.timeout, 5000); done(); }); }); }); - it("should use limits from redis and configuration, redis takes priority", function(done) { + it('should use limits from redis and configuration, redis takes priority', function (done) { var self = this; var limits = ['moran', 5000]; - withAnalysesLimits(limits, function(err) { + withAnalysesLimits(limits, function (err) { if (err) { return done(err); } @@ -100,22 +99,22 @@ describe('analysis-backend limits', function() { moran: { timeout: 1000 } } }); - analysisBackend.getAnalysesLimits(user, function(err, result) { + analysisBackend.getAnalysesLimits(user, function (err, result) { assert.ok(!err, err); assert.ok(result.analyses.moran); - assert.equal(result.analyses.moran.timeout, 5000); + assert.strictEqual(result.analyses.moran.timeout, 5000); done(); }); }); }); - it("should use limits from redis and configuration, defaulting for values not present in redis", function(done) { + it('should use limits from redis and configuration, defaulting for values not present in redis', function (done) { var self = this; var limits = ['moran', 5000]; - withAnalysesLimits(limits, function(err) { + withAnalysesLimits(limits, function (err) { if (err) { return done(err); } @@ -126,25 +125,25 @@ describe('analysis-backend limits', function() { kmeans: { timeout: 1000 } } }); - analysisBackend.getAnalysesLimits(user, function(err, result) { + analysisBackend.getAnalysesLimits(user, function (err, result) { assert.ok(!err, err); assert.ok(result.analyses.moran); - assert.equal(result.analyses.moran.timeout, 5000); + assert.strictEqual(result.analyses.moran.timeout, 5000); assert.ok(result.analyses.kmeans); - assert.equal(result.analyses.kmeans.timeout, 1000); + assert.strictEqual(result.analyses.kmeans.timeout, 1000); done(); }); }); }); - it("should allow to set other limits per analysis via configuration, and keep timeout from redis", function(done) { + it('should allow to set other limits per analysis via configuration, and keep timeout from redis', function (done) { var self = this; var limits = ['aggregate-intersection', 5000]; - withAnalysesLimits(limits, function(err) { + withAnalysesLimits(limits, function (err) { if (err) { return done(err); } @@ -154,16 +153,15 @@ describe('analysis-backend limits', function() { 'aggregate-intersection': { timeout: 10000, maxNumberOfRows: 1e5 } } }); - analysisBackend.getAnalysesLimits(user, function(err, result) { + analysisBackend.getAnalysesLimits(user, function (err, result) { assert.ok(!err, err); assert.ok(result.analyses['aggregate-intersection']); - assert.equal(result.analyses['aggregate-intersection'].timeout, 5000); - assert.equal(result.analyses['aggregate-intersection'].maxNumberOfRows, 1e5); + assert.strictEqual(result.analyses['aggregate-intersection'].timeout, 5000); + assert.strictEqual(result.analyses['aggregate-intersection'].maxNumberOfRows, 1e5); done(); }); }); }); - }); diff --git a/test/integration/mapconfig-named-layers-datasource-test.js b/test/integration/mapconfig-named-layers-datasource-test.js index 261069cb..8ff3f9ed 100644 --- a/test/integration/mapconfig-named-layers-datasource-test.js +++ b/test/integration/mapconfig-named-layers-datasource-test.js @@ -57,10 +57,10 @@ var template = { auth: { method: 'open' }, - "placeholders": { - "color": { - "type": "css_color", - "default": "#cc3300" + placeholders: { + color: { + type: 'css_color', + default: '#cc3300' } }, layergroup: { @@ -78,14 +78,14 @@ var multipleLayersTemplate = { method: 'token', valid_tokens: ['valid1', 'valid2'] }, - "placeholders": { - "polygon_color": { - "type": "css_color", - "default": "green" + placeholders: { + polygon_color: { + type: 'css_color', + default: 'green' }, - "color": { - "type": "css_color", - "default": "red" + color: { + type: 'css_color', + default: 'red' } }, layergroup: { @@ -96,9 +96,9 @@ var multipleLayersTemplate = { } }; -describe('named_layers datasources', function() { - beforeEach(function(done) { - templateMaps.addTemplate(username, template, function(err) { +describe('named_layers datasources', function () { + beforeEach(function (done) { + templateMaps.addTemplate(username, template, function (err) { if (err) { return done(err); } @@ -106,8 +106,8 @@ describe('named_layers datasources', function() { }); }); - afterEach(function(done) { - templateMaps.delTemplate(username, templateName, function(err) { + afterEach(function (done) { + templateMaps.delTemplate(username, templateName, function (err) { if (err) { return done(err); } @@ -115,7 +115,7 @@ describe('named_layers datasources', function() { }); }); - function makeNamedMapLayerConfig(layers) { + function makeNamedMapLayerConfig (layers) { return { version: '1.3.0', layers: layers @@ -141,13 +141,13 @@ describe('named_layers datasources', function() { { desc: 'without datasource for non-named layers', config: makeNamedMapLayerConfig([wadusLayer]), - test: function(err, layers, datasource, done) { + test: function (err, layers, datasource, done) { assert.ok(!err); - assert.equal(layers.length, 1); + assert.strictEqual(layers.length, 1); - assert.equal(layers[0].type, 'cartodb'); - assert.equal(layers[0].options.sql, wadusSql); - assert.deepEqual(datasource.getLayerDatasource(0), {}); + assert.strictEqual(layers[0].type, 'cartodb'); + assert.strictEqual(layers[0].options.sql, wadusSql); + assert.deepStrictEqual(datasource.getLayerDatasource(0), {}); done(); } @@ -156,18 +156,18 @@ describe('named_layers datasources', function() { { desc: 'with datasource for the named layer but not for the normal', config: makeNamedMapLayerConfig([wadusLayer, simpleNamedLayer]), - test: function(err, layers, datasource, done) { + test: function (err, layers, datasource, done) { assert.ok(!err); - assert.equal(layers.length, 2); + assert.strictEqual(layers.length, 2); - assert.equal(layers[0].type, 'cartodb'); - assert.equal(layers[0].options.sql, wadusSql); - assert.deepEqual(datasource.getLayerDatasource(0), {}); + assert.strictEqual(layers[0].type, 'cartodb'); + assert.strictEqual(layers[0].options.sql, wadusSql); + assert.deepStrictEqual(datasource.getLayerDatasource(0), {}); - assert.equal(layers[1].type, 'cartodb'); - assert.equal(layers[1].options.sql, wadusTemplateSql); + assert.strictEqual(layers[1].type, 'cartodb'); + assert.strictEqual(layers[1].options.sql, wadusTemplateSql); var layerDatasource = datasource.getLayerDatasource(1); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); done(); @@ -177,24 +177,24 @@ describe('named_layers datasources', function() { { desc: 'with datasource for the multiple layers in the named but not for the normal', config: makeNamedMapLayerConfig([wadusLayer, multipleLayersNamedLayer]), - test: function(err, layers, datasource, done) { + test: function (err, layers, datasource, done) { assert.ok(!err); - assert.equal(layers.length, 3); + assert.strictEqual(layers.length, 3); - assert.equal(layers[0].type, 'cartodb'); - assert.equal(layers[0].options.sql, wadusSql); - assert.deepEqual(datasource.getLayerDatasource(0), {}); + assert.strictEqual(layers[0].type, 'cartodb'); + assert.strictEqual(layers[0].options.sql, wadusSql); + assert.deepStrictEqual(datasource.getLayerDatasource(0), {}); - assert.equal(layers[1].type, 'mapnik'); - assert.equal(layers[1].options.sql, wadusMapnikSql); + assert.strictEqual(layers[1].type, 'mapnik'); + assert.strictEqual(layers[1].options.sql, wadusMapnikSql); var layerDatasource = datasource.getLayerDatasource(1); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); - assert.equal(layers[2].type, 'cartodb'); - assert.equal(layers[2].options.sql, wadusTemplateSql); + assert.strictEqual(layers[2].type, 'cartodb'); + assert.strictEqual(layers[2].options.sql, wadusTemplateSql); layerDatasource = datasource.getLayerDatasource(2); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); done(); @@ -204,26 +204,26 @@ describe('named_layers datasources', function() { { desc: 'all with datasource because all are named', config: makeNamedMapLayerConfig([multipleLayersNamedLayer, simpleNamedLayer]), - test: function(err, layers, datasource, done) { + test: function (err, layers, datasource, done) { assert.ok(!err); - assert.equal(layers.length, 3); + assert.strictEqual(layers.length, 3); - assert.equal(layers[0].type, 'mapnik'); - assert.equal(layers[0].options.sql, wadusMapnikSql); + assert.strictEqual(layers[0].type, 'mapnik'); + assert.strictEqual(layers[0].options.sql, wadusMapnikSql); var layerDatasource = datasource.getLayerDatasource(0); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); - assert.equal(layers[1].type, 'cartodb'); - assert.equal(layers[1].options.sql, wadusTemplateSql); + assert.strictEqual(layers[1].type, 'cartodb'); + assert.strictEqual(layers[1].options.sql, wadusTemplateSql); layerDatasource = datasource.getLayerDatasource(1); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); - assert.equal(layers[2].type, 'cartodb'); - assert.equal(layers[2].options.sql, wadusTemplateSql); + assert.strictEqual(layers[2].type, 'cartodb'); + assert.strictEqual(layers[2].options.sql, wadusTemplateSql); layerDatasource = datasource.getLayerDatasource(2); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); done(); @@ -240,53 +240,52 @@ describe('named_layers datasources', function() { wadusLayer, multipleLayersNamedLayer ]), - test: function(err, layers, datasource, done) { - + test: function (err, layers, datasource, done) { assert.ok(!err); - assert.equal(layers.length, 8); + assert.strictEqual(layers.length, 8); - assert.equal(layers[0].type, 'cartodb'); - assert.equal(layers[0].options.sql, wadusTemplateSql); + assert.strictEqual(layers[0].type, 'cartodb'); + assert.strictEqual(layers[0].options.sql, wadusTemplateSql); var layerDatasource = datasource.getLayerDatasource(0); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); - assert.equal(layers[1].type, 'mapnik'); - assert.equal(layers[1].options.sql, wadusMapnikSql); + assert.strictEqual(layers[1].type, 'mapnik'); + assert.strictEqual(layers[1].options.sql, wadusMapnikSql); layerDatasource = datasource.getLayerDatasource(1); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); - assert.equal(layers[2].type, 'cartodb'); - assert.equal(layers[2].options.sql, wadusTemplateSql); + assert.strictEqual(layers[2].type, 'cartodb'); + assert.strictEqual(layers[2].options.sql, wadusTemplateSql); layerDatasource = datasource.getLayerDatasource(2); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); - assert.equal(layers[3].type, 'cartodb'); - assert.equal(layers[3].options.sql, wadusSql); - assert.deepEqual(datasource.getLayerDatasource(3), {}); + assert.strictEqual(layers[3].type, 'cartodb'); + assert.strictEqual(layers[3].options.sql, wadusSql); + assert.deepStrictEqual(datasource.getLayerDatasource(3), {}); - assert.equal(layers[4].type, 'cartodb'); - assert.equal(layers[4].options.sql, wadusTemplateSql); + assert.strictEqual(layers[4].type, 'cartodb'); + assert.strictEqual(layers[4].options.sql, wadusTemplateSql); layerDatasource = datasource.getLayerDatasource(4); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); - assert.equal(layers[5].type, 'cartodb'); - assert.equal(layers[5].options.sql, wadusSql); - assert.deepEqual(datasource.getLayerDatasource(5), {}); + assert.strictEqual(layers[5].type, 'cartodb'); + assert.strictEqual(layers[5].options.sql, wadusSql); + assert.deepStrictEqual(datasource.getLayerDatasource(5), {}); - assert.equal(layers[6].type, 'mapnik'); - assert.equal(layers[6].options.sql, wadusMapnikSql); + assert.strictEqual(layers[6].type, 'mapnik'); + assert.strictEqual(layers[6].options.sql, wadusMapnikSql); layerDatasource = datasource.getLayerDatasource(6); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); - assert.equal(layers[7].type, 'cartodb'); - assert.equal(layers[7].options.sql, wadusTemplateSql); + assert.strictEqual(layers[7].type, 'cartodb'); + assert.strictEqual(layers[7].options.sql, wadusTemplateSql); layerDatasource = datasource.getLayerDatasource(7); - assert.notEqual(layerDatasource, undefined); + assert.notStrictEqual(layerDatasource, undefined); assert.ok(layerDatasource.user); done(); @@ -294,12 +293,12 @@ describe('named_layers datasources', function() { } ]; - testScenarios.forEach(function(testScenario) { - it('should return a list of layers ' + testScenario.desc, function(done) { + testScenarios.forEach(function (testScenario) { + it('should return a list of layers ' + testScenario.desc, function (done) { var params = {}; var context = {}; mapConfigNamedLayersAdapter.getMapConfig(username, testScenario.config, params, context, - function(err, mapConfig) { + function (err, mapConfig) { assert.ifError(err); testScenario.test(err, mapConfig.layers, context.datasource, done); } diff --git a/test/integration/mapconfig-named-layers-expanded-test.js b/test/integration/mapconfig-named-layers-expanded-test.js index b0d2ea22..6785198e 100644 --- a/test/integration/mapconfig-named-layers-expanded-test.js +++ b/test/integration/mapconfig-named-layers-expanded-test.js @@ -8,8 +8,7 @@ var TemplateMaps = require('../../lib/backends/template-maps'); var PgConnection = require('../../lib/backends/pg-connection'); var MapConfigNamedLayersAdapter = require('../../lib/models/mapconfig/adapter/mapconfig-named-layers-adapter'); -describe('mapconfig-named-layers-adapter', function() { - +describe('mapconfig-named-layers-adapter', function () { // configure redis pool instance to use in tests var redisPool = new RedisPool(global.environment.redis); var pgConnection = new PgConnection(require('cartodb-redis')({ pool: redisPool })); @@ -47,10 +46,10 @@ describe('mapconfig-named-layers-adapter', function() { auth: { method: 'open' }, - "placeholders": { - "color": { - "type": "css_color", - "default": "#cc3300" + placeholders: { + color: { + type: 'css_color', + default: '#cc3300' } }, layergroup: { @@ -83,14 +82,14 @@ describe('mapconfig-named-layers-adapter', function() { method: 'token', valid_tokens: ['valid1', 'valid2'] }, - "placeholders": { - "polygon_color": { - "type": "css_color", - "default": "green" + placeholders: { + polygon_color: { + type: 'css_color', + default: 'green' }, - "color": { - "type": "css_color", - "default": "red" + color: { + type: 'css_color', + default: 'red' } }, layergroup: { @@ -124,7 +123,7 @@ describe('mapconfig-named-layers-adapter', function() { } }; - function makeNamedMapLayerConfig(options) { + function makeNamedMapLayerConfig (options) { return { version: '1.3.0', layers: [ @@ -139,41 +138,41 @@ describe('mapconfig-named-layers-adapter', function() { var params = {}; var context = {}; - beforeEach(function(done) { + beforeEach(function (done) { templateMaps.addTemplate(username, template, done); }); - afterEach(function(done) { + afterEach(function (done) { templateMaps.delTemplate(username, templateName, done); }); - it('should fail for named map layer with missing name', function(done) { + it('should fail for named map layer with missing name', function (done) { var missingNamedMapLayerConfig = makeNamedMapLayerConfig({ config: {} }); mapConfigNamedLayersAdapter.getMapConfig(username, missingNamedMapLayerConfig, params, context, - function(err, mapConfig) { + function (err, mapConfig) { assert.ok(err); assert.ok(!mapConfig); assert.ok(!context.datasource); - assert.equal(err.message, 'Missing Named Map `name` in layer options'); + assert.strictEqual(err.message, 'Missing Named Map `name` in layer options'); done(); } ); }); - it('should fail for non-existing template name', function(done) { + it('should fail for non-existing template name', function (done) { var missingTemplateName = 'wadus'; var nonExistentNamedMapLayerConfig = makeNamedMapLayerConfig({ name: missingTemplateName }); mapConfigNamedLayersAdapter.getMapConfig(username, nonExistentNamedMapLayerConfig, params, context, - function(err, mapConfig) { + function (err, mapConfig) { assert.ok(err); assert.ok(!mapConfig); assert.ok(!context.datasource); - assert.equal( + assert.strictEqual( err.message, "Template '" + missingTemplateName + "' of user '" + username + "' not found" ); @@ -182,8 +181,8 @@ describe('mapconfig-named-layers-adapter', function() { ); }); - it('should fail if not properly authorized', function(done) { - templateMaps.addTemplate(username, tokenAuthTemplate, function(err) { + it('should fail if not properly authorized', function (done) { + templateMaps.addTemplate(username, tokenAuthTemplate, function (err) { if (err) { return done(err); } @@ -192,11 +191,11 @@ describe('mapconfig-named-layers-adapter', function() { name: tokenAuthTemplateName }); mapConfigNamedLayersAdapter.getMapConfig(username, nonAuthTokensNamedMapLayerConfig, params, context, - function(err, mapConfig) { + function (err, mapConfig) { assert.ok(err); assert.ok(!mapConfig); assert.ok(!context.datasource); - assert.equal(err.message, "Unauthorized '" + tokenAuthTemplateName + "' template instantiation"); + assert.strictEqual(err.message, "Unauthorized '" + tokenAuthTemplateName + "' template instantiation"); templateMaps.delTemplate(username, tokenAuthTemplateName, done); } @@ -204,8 +203,8 @@ describe('mapconfig-named-layers-adapter', function() { }); }); - it('should fail for nested named map layers', function(done) { - templateMaps.addTemplate(username, nestedNamedMapTemplate, function(err) { + it('should fail for nested named map layers', function (done) { + templateMaps.addTemplate(username, nestedNamedMapTemplate, function (err) { if (err) { return done(err); } @@ -214,11 +213,11 @@ describe('mapconfig-named-layers-adapter', function() { name: nestedNamedMapTemplateName }); mapConfigNamedLayersAdapter.getMapConfig(username, nestedNamedMapLayerConfig, params, context, - function(err, mapConfig) { + function (err, mapConfig) { assert.ok(err); assert.ok(!mapConfig); assert.ok(!context.datasource); - assert.equal(err.message, 'Nested named layers are not allowed'); + assert.strictEqual(err.message, 'Nested named layers are not allowed'); templateMaps.delTemplate(username, nestedNamedMapTemplateName, done); } @@ -226,25 +225,25 @@ describe('mapconfig-named-layers-adapter', function() { }); }); - it('should return an expanded list of layers for a named map layer', function(done) { + it('should return an expanded list of layers for a named map layer', function (done) { var validNamedMapMapLayerConfig = makeNamedMapLayerConfig({ name: templateName }); mapConfigNamedLayersAdapter.getMapConfig(username, validNamedMapMapLayerConfig, params, context, - function(err, mapConfig) { + function (err, mapConfig) { assert.ok(!err); var layers = mapConfig.layers; assert.ok(layers.length, 1); assert.ok(layers[0].type, 'cartodb'); - assert.notEqual(context.datasource.getLayerDatasource(0), undefined); + assert.notStrictEqual(context.datasource.getLayerDatasource(0), undefined); done(); } ); }); - it('should return on auth=token with valid tokens provided', function(done) { - templateMaps.addTemplate(username, tokenAuthTemplate, function(err) { + it('should return on auth=token with valid tokens provided', function (done) { + templateMaps.addTemplate(username, tokenAuthTemplate, function (err) { if (err) { return done(err); } @@ -254,11 +253,11 @@ describe('mapconfig-named-layers-adapter', function() { auth_tokens: ['valid1'] }); mapConfigNamedLayersAdapter.getMapConfig(username, validAuthTokensNamedMapLayerConfig, params, context, - function(err, mapConfig) { + function (err, mapConfig) { assert.ok(!err); var layers = mapConfig.layers; - assert.equal(layers.length, 1); - assert.notEqual(context.datasource.getLayerDatasource(0), undefined); + assert.strictEqual(layers.length, 1); + assert.notStrictEqual(context.datasource.getLayerDatasource(0), undefined); templateMaps.delTemplate(username, tokenAuthTemplateName, done); } @@ -266,8 +265,8 @@ describe('mapconfig-named-layers-adapter', function() { }); }); - it('should return an expanded list of layers for a named map layer, multiple layers version', function(done) { - templateMaps.addTemplate(username, multipleLayersTemplate, function(err) { + it('should return an expanded list of layers for a named map layer, multiple layers version', function (done) { + templateMaps.addTemplate(username, multipleLayersTemplate, function (err) { if (err) { return done(err); } @@ -277,18 +276,18 @@ describe('mapconfig-named-layers-adapter', function() { auth_tokens: ['valid2'] }); mapConfigNamedLayersAdapter.getMapConfig(username, multipleLayersNamedMapLayerConfig, params, context, - function(err, mapConfig) { + function (err, mapConfig) { assert.ok(!err); var layers = mapConfig.layers; - assert.equal(layers.length, 2); + assert.strictEqual(layers.length, 2); - assert.equal(layers[0].type, 'mapnik'); - assert.equal(layers[0].options.cartocss, '#layer { polygon-fill: green; }'); - assert.notEqual(context.datasource.getLayerDatasource(0), undefined); + assert.strictEqual(layers[0].type, 'mapnik'); + assert.strictEqual(layers[0].options.cartocss, '#layer { polygon-fill: green; }'); + assert.notStrictEqual(context.datasource.getLayerDatasource(0), undefined); - assert.equal(layers[1].type, 'cartodb'); - assert.equal(layers[1].options.cartocss, '#layer { marker-fill: red; }'); - assert.notEqual(context.datasource.getLayerDatasource(1), undefined); + assert.strictEqual(layers[1].type, 'cartodb'); + assert.strictEqual(layers[1].options.cartocss, '#layer { marker-fill: red; }'); + assert.notStrictEqual(context.datasource.getLayerDatasource(1), undefined); templateMaps.delTemplate(username, multipleLayersTemplateName, done); } @@ -296,14 +295,14 @@ describe('mapconfig-named-layers-adapter', function() { }); }); - it('should replace template params with the given config', function(done) { - templateMaps.addTemplate(username, multipleLayersTemplate, function(err) { + it('should replace template params with the given config', function (done) { + templateMaps.addTemplate(username, multipleLayersTemplate, function (err) { if (err) { return done(err); } - var color = '#cc3300', - polygonColor = '#ff9900'; + var color = '#cc3300'; + var polygonColor = '#ff9900'; var multipleLayersNamedMapLayerConfig = makeNamedMapLayerConfig({ name: multipleLayersTemplateName, @@ -314,18 +313,18 @@ describe('mapconfig-named-layers-adapter', function() { auth_tokens: ['valid2'] }); mapConfigNamedLayersAdapter.getMapConfig(username, multipleLayersNamedMapLayerConfig, params, context, - function(err, mapConfig) { + function (err, mapConfig) { assert.ok(!err); var layers = mapConfig.layers; - assert.equal(layers.length, 2); + assert.strictEqual(layers.length, 2); - assert.equal(layers[0].type, 'mapnik'); - assert.equal(layers[0].options.cartocss, '#layer { polygon-fill: ' + polygonColor + '; }'); - assert.notEqual(context.datasource.getLayerDatasource(0), undefined); + assert.strictEqual(layers[0].type, 'mapnik'); + assert.strictEqual(layers[0].options.cartocss, '#layer { polygon-fill: ' + polygonColor + '; }'); + assert.notStrictEqual(context.datasource.getLayerDatasource(0), undefined); - assert.equal(layers[1].type, 'cartodb'); - assert.equal(layers[1].options.cartocss, '#layer { marker-fill: ' + color + '; }'); - assert.notEqual(context.datasource.getLayerDatasource(1), undefined); + assert.strictEqual(layers[1].type, 'cartodb'); + assert.strictEqual(layers[1].options.cartocss, '#layer { marker-fill: ' + color + '; }'); + assert.notStrictEqual(context.datasource.getLayerDatasource(1), undefined); templateMaps.delTemplate(username, multipleLayersTemplateName, done); } diff --git a/test/integration/mapconfig-overviews-adapter-test.js b/test/integration/mapconfig-overviews-adapter-test.js index e1bb932a..60bb793c 100644 --- a/test/integration/mapconfig-overviews-adapter-test.js +++ b/test/integration/mapconfig-overviews-adapter-test.js @@ -12,7 +12,7 @@ var FilterStatsBackend = require('../../lib/backends/filter-stats'); var MapConfigOverviewsAdapter = require('../../lib/models/mapconfig/adapter/mapconfig-overviews-adapter'); var redisPool = new RedisPool(global.environment.redis); -var metadataBackend = cartodbRedis({pool: redisPool}); +var metadataBackend = cartodbRedis({ pool: redisPool }); var pgConnection = new PgConnection(metadataBackend); var pgQueryRunner = new PgQueryRunner(pgConnection); var overviewsMetadataBackend = new OverviewsMetadataBackend(pgQueryRunner); @@ -20,74 +20,72 @@ var filterStatsBackend = new FilterStatsBackend(pgQueryRunner); var mapConfigOverviewsAdapter = new MapConfigOverviewsAdapter(overviewsMetadataBackend, filterStatsBackend); -describe('MapConfigOverviewsAdapter', function() { - - it('should not modify layers for which no overviews are available', function(done) { +describe('MapConfigOverviewsAdapter', function () { + it('should not modify layers for which no overviews are available', function (done) { var sql = 'SELECT * FROM test_table'; var cartocss = '#layer { marker-fill: black; }'; - var cartocss_version = '2.3.0'; - var layer_without_overviews = { + var cartocssVersion = '2.3.0'; + var layerWithoutOverviews = { type: 'cartodb', options: { sql: sql, cartocss: cartocss, - cartocss_version: cartocss_version + cartocss_version: cartocssVersion } }; var _mapConfig = { - layers: [layer_without_overviews] + layers: [layerWithoutOverviews] }; var params = {}; var context = {}; - mapConfigOverviewsAdapter.getMapConfig('localhost', _mapConfig, params, context, function(err, mapConfig) { + mapConfigOverviewsAdapter.getMapConfig('localhost', _mapConfig, params, context, function (err, mapConfig) { assert.ok(!err); var layers = mapConfig.layers; - assert.equal(layers.length, 1); - assert.equal(layers[0].type, 'cartodb'); - assert.equal(layers[0].options.sql, sql); - assert.equal(layers[0].options.cartocss, cartocss); - assert.equal(layers[0].options.cartocss_version, cartocss_version); - assert.equal(layers[0].options.overviews, undefined); + assert.strictEqual(layers.length, 1); + assert.strictEqual(layers[0].type, 'cartodb'); + assert.strictEqual(layers[0].options.sql, sql); + assert.strictEqual(layers[0].options.cartocss, cartocss); + assert.strictEqual(layers[0].options.cartocss_version, cartocssVersion); + assert.strictEqual(layers[0].options.overviews, undefined); done(); }); }); }); -describe('MapConfigOverviewsAdapter', function() { - - it('should add overviews metadata for layers using tables with overviews', function(done) { +describe('MapConfigOverviewsAdapter', function () { + it('should add overviews metadata for layers using tables with overviews', function (done) { var sql = 'SELECT * FROM test_table_overviews'; var cartocss = '#layer { marker-fill: black; }'; - var cartocss_version = '2.3.0'; - var layer_with_overviews = { + var cartocssVersion = '2.3.0'; + var layerWithOverviews = { type: 'cartodb', options: { sql: sql, cartocss: cartocss, - cartocss_version: cartocss_version + cartocss_version: cartocssVersion } }; var _mapConfig = { - layers: [layer_with_overviews] + layers: [layerWithOverviews] }; var params = {}; var context = {}; - mapConfigOverviewsAdapter.getMapConfig('localhost', _mapConfig, params, context, function(err, mapConfig) { + mapConfigOverviewsAdapter.getMapConfig('localhost', _mapConfig, params, context, function (err, mapConfig) { assert.ok(!err); var layers = mapConfig.layers; - assert.equal(layers.length, 1); - assert.equal(layers[0].type, 'cartodb'); - assert.equal(layers[0].options.sql, sql); - assert.equal(layers[0].options.cartocss, cartocss); - assert.equal(layers[0].options.cartocss_version, cartocss_version); + assert.strictEqual(layers.length, 1); + assert.strictEqual(layers[0].type, 'cartodb'); + assert.strictEqual(layers[0].options.sql, sql); + assert.strictEqual(layers[0].options.cartocss, cartocss); + assert.strictEqual(layers[0].options.cartocss_version, cartocssVersion); assert.ok(layers[0].options.query_rewrite_data); - var expected_data = { + var expectedData = { overviews: { test_table_overviews: { schema: 'public', @@ -96,7 +94,7 @@ describe('MapConfigOverviewsAdapter', function() { } } }; - assert.deepEqual(layers[0].options.query_rewrite_data, expected_data); + assert.deepStrictEqual(layers[0].options.query_rewrite_data, expectedData); done(); }); }); diff --git a/test/integration/overviews-metadata-api-test.js b/test/integration/overviews-metadata-api-test.js index 237fb2f9..951fa94c 100644 --- a/test/integration/overviews-metadata-api-test.js +++ b/test/integration/overviews-metadata-api-test.js @@ -11,37 +11,35 @@ var PgConnection = require('../../lib/backends/pg-connection'); var PgQueryRunner = require('../../lib/backends/pg-query-runner'); var OverviewsMetadataBackend = require('../../lib/backends/overviews-metadata'); - -describe('OverviewsMetadataBackend', function() { - +describe('OverviewsMetadataBackend', function () { var overviewsMetadataBackend; - before(function() { + before(function () { var redisPool = new RedisPool(global.environment.redis); - var metadataBackend = cartodbRedis({pool: redisPool}); + var metadataBackend = cartodbRedis({ pool: redisPool }); var pgConnection = new PgConnection(metadataBackend); var pgQueryRunner = new PgQueryRunner(pgConnection); overviewsMetadataBackend = new OverviewsMetadataBackend(pgQueryRunner); }); - it('should return an empty relation for tables that have no overviews', function(done) { + it('should return an empty relation for tables that have no overviews', function (done) { var query = 'select * from test_table'; - overviewsMetadataBackend.getOverviewsMetadata('localhost', query, function(err, result) { + overviewsMetadataBackend.getOverviewsMetadata('localhost', query, function (err, result) { assert.ok(!err, err); - assert.deepEqual(result, {}); + assert.deepStrictEqual(result, {}); done(); }); }); - it('should return overviews metadata', function(done) { + it('should return overviews metadata', function (done) { var query = 'select * from test_table_overviews'; - overviewsMetadataBackend.getOverviewsMetadata('localhost', query, function(err, result) { + overviewsMetadataBackend.getOverviewsMetadata('localhost', query, function (err, result) { assert.ok(!err, err); - assert.deepEqual(result, { - 'test_table_overviews': { + assert.deepStrictEqual(result, { + test_table_overviews: { schema: 'public', 1: { table: '_vovw_1_test_table_overviews' }, 2: { table: '_vovw_2_test_table_overviews' } @@ -51,5 +49,4 @@ describe('OverviewsMetadataBackend', function() { done(); }); }); - }); diff --git a/test/integration/pg-query-runner-test.js b/test/integration/pg-query-runner-test.js index e7f403f4..182da582 100644 --- a/test/integration/pg-query-runner-test.js +++ b/test/integration/pg-query-runner-test.js @@ -10,37 +10,35 @@ var cartodbRedis = require('cartodb-redis'); var PgConnection = require('../../lib/backends/pg-connection'); var PgQueryRunner = require('../../lib/backends/pg-query-runner'); - -describe('PgQueryRunner', function() { - +describe('PgQueryRunner', function () { var queryRunner; - before(function() { + before(function () { var redisPool = new RedisPool(global.environment.redis); - var metadataBackend = cartodbRedis({pool: redisPool}); + var metadataBackend = cartodbRedis({ pool: redisPool }); var pgConnection = new PgConnection(metadataBackend); queryRunner = new PgQueryRunner(pgConnection); }); - it('should work for happy case', function(done) { + it('should work for happy case', function (done) { var query = 'select cartodb_id from test_table limit 3'; - queryRunner.run('localhost', query, function(err, result) { + queryRunner.run('localhost', query, function (err, result) { assert.ok(!err, err); assert.ok(Array.isArray(result)); - assert.equal(result.length, 3); + assert.strictEqual(result.length, 3); done(); }); }); - it('should receive rows array even on error', function(done) { + it('should receive rows array even on error', function (done) { var query = 'select __error___ from test_table'; - queryRunner.run('localhost', query, function(err, result) { + queryRunner.run('localhost', query, function (err, result) { assert.ok(err); assert.ok(Array.isArray(result)); - assert.equal(result.length, 0); + assert.strictEqual(result.length, 0); done(); }); diff --git a/test/integration/profiler-test.js b/test/integration/profiler-test.js index 2db98261..291b29f1 100644 --- a/test/integration/profiler-test.js +++ b/test/integration/profiler-test.js @@ -6,15 +6,15 @@ var assert = require('assert'); var StatsClient = require('../../lib/stats/client'); var ProfilerProxy = require('../../lib/stats/profiler-proxy'); -describe('profiler + statsd', function() { +describe('profiler + statsd', function () { var statsInstance; - before(function() { + before(function () { statsInstance = StatsClient.instance; StatsClient.instance = null; }); - after(function() { + after(function () { StatsClient.instance = statsInstance; }); @@ -27,10 +27,9 @@ describe('profiler + statsd', function() { }; // See https://github.com/CartoDB/Windshaft/issues/167 - it('profiler does not throw uncaught exception on invalid host/port', function(done) { - + it('profiler does not throw uncaught exception on invalid host/port', function (done) { var statsClient = StatsClient.getInstance(statsdConfig); - var profiler = new ProfilerProxy({profile: true, statsd_client: statsClient}); + var profiler = new ProfilerProxy({ profile: true, statsd_client: statsClient }); profiler.start('test'); profiler.done('wadus'); @@ -39,9 +38,9 @@ describe('profiler + statsd', function() { profiler.sendStats(); // force a call to validate sendStats does not throw and uncaught exception - statsClient.timing('forced', 50, 1, function(err) { + statsClient.timing('forced', 50, 1, function (err) { assert.ok(err); - assert.equal(err.code, 'ENOTFOUND'); + assert.strictEqual(err.code, 'ENOTFOUND'); done(); }); }); diff --git a/test/integration/query-tables-test.js b/test/integration/query-tables-test.js index dcc3aad8..f93472aa 100644 --- a/test/integration/query-tables-test.js +++ b/test/integration/query-tables-test.js @@ -11,16 +11,14 @@ var PgConnection = require('../../lib/backends/pg-connection'); var QueryTables = require('cartodb-query-tables').queryTables; - -describe('QueryTables', function() { - +describe('QueryTables', function () { var connection; - before(function(done) { + before(function (done) { var redisPool = new RedisPool(global.environment.redis); - var metadataBackend = cartodbRedis({pool: redisPool}); + var metadataBackend = cartodbRedis({ pool: redisPool }); var pgConnection = new PgConnection(metadataBackend); - pgConnection.getConnection('localhost', function(err, pgConnection) { + pgConnection.getConnection('localhost', function (err, pgConnection) { if (err) { return done(err); } @@ -36,26 +34,25 @@ describe('QueryTables', function() { var query = 'select * from test_table'; return QueryTables.getQueryMetadataModel(connection, query) .then(result => { - assert.equal(result.getLastUpdatedAt(), 1234567890123); + assert.strictEqual(result.getLastUpdatedAt(), 1234567890123); - assert.equal(result.tables.length, 1); - assert.equal(result.tables[0].dbname, 'test_windshaft_cartodb_user_1_db'); - assert.equal(result.tables[0].schema_name, 'public'); - assert.equal(result.tables[0].table_name, 'test_table'); + assert.strictEqual(result.tables.length, 1); + assert.strictEqual(result.tables[0].dbname, 'test_windshaft_cartodb_user_1_db'); + assert.strictEqual(result.tables[0].schema_name, 'public'); + assert.strictEqual(result.tables[0].table_name, 'test_table'); }); - }); it('should work with private tables', function () { var query = 'select * from test_table_private_1'; return QueryTables.getQueryMetadataModel(connection, query) .then(result => { - assert.equal(result.getLastUpdatedAt(), 1234567890123); + assert.strictEqual(result.getLastUpdatedAt(), 1234567890123); - assert.equal(result.tables.length, 1); - assert.equal(result.tables[0].dbname, 'test_windshaft_cartodb_user_1_db'); - assert.equal(result.tables[0].schema_name, 'public'); - assert.equal(result.tables[0].table_name, 'test_table_private_1'); + assert.strictEqual(result.tables.length, 1); + assert.strictEqual(result.tables[0].dbname, 'test_windshaft_cartodb_user_1_db'); + assert.strictEqual(result.tables[0].schema_name, 'public'); + assert.strictEqual(result.tables[0].table_name, 'test_table_private_1'); }); }); }); diff --git a/test/integration/template-maps-limits-test.js b/test/integration/template-maps-limits-test.js index 95bcc410..2619a57a 100644 --- a/test/integration/template-maps-limits-test.js +++ b/test/integration/template-maps-limits-test.js @@ -7,15 +7,13 @@ var redis = require('redis'); var RedisPool = require('redis-mpool'); var TemplateMaps = require('../../lib/backends/template-maps'); - -describe('TemplateMaps limits', function() { - +describe('TemplateMaps limits', function () { var OWNER = 'username'; var templateCounter = 0; - function templateUniqueName() { + function templateUniqueName () { return 'tpl_' + templateCounter++; } - function createTemplate() { + function createTemplate () { return { version: '0.0.1', name: templateUniqueName(), @@ -35,18 +33,18 @@ describe('TemplateMaps limits', function() { var redisClient = redis.createClient(global.environment.redis.port); var redisPool = new RedisPool(global.environment.redis); - afterEach(function(done) { + afterEach(function (done) { redisClient.del('map_tpl|' + OWNER, done); }); - it('should allow to create templates when there is no limit in options', function(done) { + it('should allow to create templates when there is no limit in options', function (done) { var templateMaps = new TemplateMaps(redisPool); - templateMaps.addTemplate(OWNER, createTemplate(), function(err, templateName, template) { + templateMaps.addTemplate(OWNER, createTemplate(), function (err, templateName, template) { assert.ok(!err, err); assert.ok(template); - templateMaps.addTemplate(OWNER, createTemplate(), function(err, templateName, template) { + templateMaps.addTemplate(OWNER, createTemplate(), function (err, templateName, template) { assert.ok(!err, err); assert.ok(template); done(); @@ -54,25 +52,25 @@ describe('TemplateMaps limits', function() { }); }); - it('should allow to create templates with limit in options', function(done) { - var templateMaps = new TemplateMaps(redisPool, {max_user_templates: 1}); + it('should allow to create templates with limit in options', function (done) { + var templateMaps = new TemplateMaps(redisPool, { max_user_templates: 1 }); - templateMaps.addTemplate(OWNER, createTemplate(), function(err, templateName, template) { + templateMaps.addTemplate(OWNER, createTemplate(), function (err, templateName, template) { assert.ok(!err, err); assert.ok(template); done(); }); }); - it('should fail to create more templates than allowed by options', function(done) { - var templateMaps = new TemplateMaps(redisPool, {max_user_templates: 1}); + it('should fail to create more templates than allowed by options', function (done) { + var templateMaps = new TemplateMaps(redisPool, { max_user_templates: 1 }); - templateMaps.addTemplate(OWNER, createTemplate(), function(err, templateName, template) { + templateMaps.addTemplate(OWNER, createTemplate(), function (err, templateName, template) { assert.ok(!err, err); assert.ok(template); - templateMaps.addTemplate(OWNER, createTemplate(), function(err) { + templateMaps.addTemplate(OWNER, createTemplate(), function (err) { assert.ok(err); - assert.equal(err.http_status, 409); + assert.strictEqual(err.http_status, 409); done(); }); }); diff --git a/test/monkey/leaflet.js b/test/monkey/leaflet.js index 9dc79889..845d9a6a 100755 --- a/test/monkey/leaflet.js +++ b/test/monkey/leaflet.js @@ -3,125 +3,817 @@ Leaflet is a BSD-licensed JavaScript library for map display and interaction. See http://leaflet.cloudmade.com for more information. */ -(function(a){var b={VERSION:"0.3",ROOT_URL:function(){for(var a=document.getElementsByTagName("script"),b=/^(.*\/)leaflet-?([\w-]*)\.js.*$/,e=0,f=a.length;e0},removeEventListener:function(a,b,c){if(!this.hasEventListeners(a))return this;for(var d=0,e=this._leaflet_events,f=e[a].length;d=this.min.x&&a.x<=this.max.x&&b.y>=this.min.y&&a.y<=this.max.y}});L.Transformation=L.Class.extend({initialize:function(a,b,c,d){this._a=a;this._b=b;this._c=c;this._d=d},transform:function(a,b){return this._transform(a.clone(),b)},_transform:function(a,b){b=b||1;a.x=b*(this._a*a.x+this._b);a.y=b*(this._c*a.y+this._d);return a},untransform:function(a,b){b=b||1;return new L.Point((a.x/b-this._b)/this._a,(a.y/b-this._d)/this._c)}});L.LineUtil={simplify:function(a,b){if(!b||!a.length)return a.slice();a=this.reducePoints(a,b);return a=this.simplifyDP(a,b)},pointToSegmentDistance:function(a,b,c){return Math.sqrt(this._sqPointToSegmentDist(a,b,c))},closestPointOnSegment:function(a,b,c){a=this._sqClosestPointOnSegment(a,b,c);a.distance=Math.sqrt(a._sqDist);return a},simplifyDP:function(a,b){for(var c=0,d=0,e=b*b,f=1,g=a.length,h;fc&&(d=f,c=h);return c>=e?(c=a.slice(0,d),d= -a.slice(d),g=this.simplifyDP(c,b).slice(0,g-2),d=this.simplifyDP(d,b),g.concat(d)):[a[0],a[g-1]]},reducePoints:function(a,b){for(var c=[a[0]],d=b*b,e=1,f=0,g=a.length;eb.max.x&&(c|=2);a.yb.max.y&&(c|=8);return c},_sqDist:function(a,b){var c=b.x-a.x,d=b.y-a.y;return c*c+d*d},_sqClosestPointOnSegment:function(a, -b,c){var d=c.x-b.x,e=c.y-b.y,f=b;if(d||e){var g=((a.x-b.x)*d+(a.y-b.y)*e)/this._sqDist(b,c);g>1?f=c:g>0&&(f=new L.Point(b.x+d*g,b.y+e*g))}f._sqDist=this._sqDist(a,f);return f},_sqPointToSegmentDist:function(a,b,c){return this._sqClosestPointOnSegment(a,b,c)._sqDist}};L.PolyUtil={};L.PolyUtil.clipPolygon=function(a,b){var c,d=[1,4,2,8],e,f,g,h,j,k,l=L.LineUtil;e=0;for(j=a.length;e0&&c<=h;f=b}}function e(){if(g)j.type="dblclick",b(j),f=null}var f,g=!1,h=250,j;a["_leaflet_touchstart"+c]=d;a["_leaflet_touchend"+c]=e;a.addEventListener("touchstart",d,!1);a.addEventListener("touchend",e,!1)},removeDoubleTapListener:function(a,b){a.removeEventListener(a,a["_leaflet_touchstart"+b],!1);a.removeEventListener(a,a["_leaflet_touchend"+b], -!1)}});L.DomUtil={get:function(a){return typeof a=="string"?document.getElementById(a):a},getStyle:function(a,b){var c=a.style[b];!c&&a.currentStyle&&(c=a.currentStyle[b]);if(!c||c=="auto")c=(c=document.defaultView.getComputedStyle(a,null))?c[b]:null;return c=="auto"?null:c},getViewportOffset:function(a){var b=0,c=0,d=a,e=document.body;do if(b+=d.offsetTop||0,c+=d.offsetLeft||0,d.offsetParent==e&&L.DomUtil.getStyle(d,"position")=="absolute")break;while(d=d.offsetParent);d=a;do{if(d===e)break;b-=d.scrollTop|| -0;c-=d.scrollLeft||0}while(d=d.parentNode);return new L.Point(c,b)},create:function(a,b,c){a=document.createElement(a);a.className=b;c&&c.appendChild(a);return a},disableTextSelection:function(){document.selection&&document.selection.empty&&document.selection.empty();if(!this._onselectstart)this._onselectstart=document.onselectstart,document.onselectstart=L.Util.falseFn},enableTextSelection:function(){document.onselectstart=this._onselectstart;this._onselectstart=null},hasClass:function(a,b){return a.className.length> -0&&RegExp("(^|\\s)"+b+"(\\s|$)").test(a.className)},addClass:function(a,b){L.DomUtil.hasClass(a,b)||(a.className+=(a.className?" ":"")+b)},removeClass:function(a,b){a.className=a.className.replace(/(\S+)\s*/g,function(a,d){if(d==b)return"";return a}).replace(/^\s+/,"")},setOpacity:function(a,b){L.Browser.ie?a.style.filter="alpha(opacity="+Math.round(b*100)+")":a.style.opacity=b},testProp:function(a){for(var b=document.documentElement.style,c=0;c1)){var b=a.touches&&a.touches.length==1?a.touches[0]:a;L.DomEvent.preventDefault(a);L.Browser.touch&&(b.target.className+=" leaflet-active");this._moved=!1;L.DomUtil.disableTextSelection();this._setMovingCursor();this._startPos=this._newPos=L.DomUtil.getPosition(this._element);this._startPoint=new L.Point(b.clientX,b.clientY);L.DomEvent.addListener(document, -L.Draggable.MOVE,this._onMove,this);L.DomEvent.addListener(document,L.Draggable.END,this._onUp,this)}},_onMove:function(a){if(!(a.touches&&a.touches.length>1)){L.DomEvent.preventDefault(a);a=a.touches&&a.touches.length==1?a.touches[0]:a;if(!this._moved)this.fire("dragstart"),this._moved=!0;this._newPos=this._startPos.add(new L.Point(a.clientX,a.clientY)).subtract(this._startPoint);L.Util.requestAnimFrame(this._updatePosition,this,!0)}},_updatePosition:function(){L.DomUtil.setPosition(this._element, -this._newPos);this.fire("drag")},_onUp:function(a){if(a.changedTouches){var a=a.changedTouches[0],b=a.target,c=this._newPos&&this._newPos.distanceTo(this._startPos)||0;b.className=b.className.replace(" leaflet-active","");c=b.lat&&a.lat<=c.lat&&d.lng>=b.lng&&a.lng<=c.lng}});L.Projection={};L.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=a.lng*b,a=Math.max(Math.min(c,a.lat),-c)*b,a=Math.log(Math.tan(Math.PI/4+a/2));return new L.Point(d,a)},unproject:function(a,b){var c=L.LatLng.RAD_TO_DEG;return new L.LatLng((2*Math.atan(Math.exp(a.y))-Math.PI/2)*c,a.x*c,b)}};L.Projection.LonLat={project:function(a){return new L.Point(a.lng,a.lat)},unproject:function(a,b){return new L.LatLng(a.y,a.x,b)}};L.Projection.Mercator={MAX_LATITUDE:85.0840591556,R_MINOR:6356752.3142,R_MAJOR:6378137,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=this.R_MAJOR,e=a.lng*b*d,a=Math.max(Math.min(c,a.lat),-c)*b,b=this.R_MINOR/d,b=Math.sqrt(1-b*b),c=b*Math.sin(a),c=Math.pow((1-c)/(1+c),b*0.5),a=-d*Math.log(Math.tan(0.5*(Math.PI*0.5-a))/c);return new L.Point(e,a)},unproject:function(a,b){for(var c=L.LatLng.RAD_TO_DEG,d=this.R_MAJOR,e=a.x*c/d,f=this.R_MINOR/d,f=Math.sqrt(1-f*f),d=Math.exp(-a.y/d), -g=Math.PI/2-2*Math.atan(d),h=15,j=0.1;Math.abs(j)>1.0E-7&&--h>0;)j=f*Math.sin(g),j=Math.PI/2-2*Math.atan(d*Math.pow((1-j)/(1+j),0.5*f))-g,g+=j;return new L.LatLng(g*c,e,b)}};L.CRS={latLngToPoint:function(a,b){return this.transformation._transform(this.projection.project(a),b)},pointToLatLng:function(a,b,c){return this.projection.unproject(this.transformation.untransform(a,b),c)},project:function(a){return this.projection.project(a)}};L.CRS.EPSG3857=L.Util.extend({},L.CRS,{code:"EPSG:3857",projection:L.Projection.SphericalMercator,transformation:new L.Transformation(0.5/Math.PI,0.5,-0.5/Math.PI,0.5),project:function(a){return this.projection.project(a).multiplyBy(6378137)}});L.CRS.EPSG900913=L.Util.extend({},L.CRS.EPSG3857,{code:"EPSG:900913"});L.CRS.EPSG4326=L.Util.extend({},L.CRS,{code:"EPSG:4326",projection:L.Projection.LonLat,transformation:new L.Transformation(1/360,0.5,-1/360,0.5)});L.CRS.EPSG3395=L.Util.extend({},L.CRS,{code:"EPSG:3395",projection:L.Projection.Mercator,transformation:function(){var a=L.Projection.Mercator;return new L.Transformation(0.5/(Math.PI*a.R_MAJOR),0.5,-0.5/(Math.PI*a.R_MINOR),0.5)}()});L.LayerGroup=L.Class.extend({initialize:function(a){this._layers={};if(a)for(var b=0,c=a.length;ba.max.x||ba.max.y))this._tiles[d].parentNode==this._container&&this._container.removeChild(this._tiles[d]),delete this._tiles[d]},_addTile:function(a,b){var c=this._getTilePos(a),d=this._map.getZoom(),e=a.x+":"+a.y,f=1<=f){this._tilesToLoad--;return}}else a.x=(a.x%f+f)%f;if(a.y<0||a.y>=f){this._tilesToLoad--;return}}var g=this._createTile();L.DomUtil.setPosition(g, -c);this._tiles[e]=g;if(this.options.scheme=="tms")a.y=f-a.y-1;this._loadTile(g,a,d);b.appendChild(g)},_getTilePos:function(a){var b=this._map.getPixelOrigin();return a.multiplyBy(this.options.tileSize).subtract(b)},getTileUrl:function(a,b){return this._url.replace("{s}",this.options.subdomains[(a.x+a.y)%this.options.subdomains.length]).replace("{z}",b).replace("{x}",a.x).replace("{y}",a.y)},_createTileProto:function(){this._tileImg=L.DomUtil.create("img","leaflet-tile");this._tileImg.galleryimg="no"; -var a=this.options.tileSize;this._tileImg.style.width=a+"px";this._tileImg.style.height=a+"px"},_createTile:function(){var a=this._tileImg.cloneNode(!1);a.onselectstart=a.onmousemove=L.Util.falseFn;return a},_loadTile:function(a,b,c){a._layer=this;a.onload=this._tileOnLoad;a.onerror=this._tileOnError;a.src=this.getTileUrl(b,c)},_tileOnLoad:function(){var a=this._layer;this.className+=" leaflet-tile-loaded";a.fire("tileload",{tile:this,url:this.src});a._tilesToLoad--;a._tilesToLoad||a.fire("load")}, -_tileOnError:function(){var a=this._layer;a.fire("tileerror",{tile:this,url:this.src});if(a=a.options.errorTileUrl)this.src=a}});L.TileLayer.WMS=L.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(a,b){this._url=a;this.wmsParams=L.Util.extend({},this.defaultWmsParams);this.wmsParams.width=this.wmsParams.height=this.options.tileSize;for(var c in b)this.options.hasOwnProperty(c)||(this.wmsParams[c]=b[c]);L.Util.setOptions(this,b)},onAdd:function(a){this.wmsParams[parseFloat(this.wmsParams.version)>=1.3?"crs":"srs"]=a.options.crs.code; -L.TileLayer.prototype.onAdd.call(this,a)},getTileUrl:function(a){var b=this.options.tileSize,a=a.multiplyBy(b),b=a.add(new L.Point(b,b)),a=this._map.unproject(a,this._zoom,!0),b=this._map.unproject(b,this._zoom,!0),a=this._map.options.crs.project(a),b=this._map.options.crs.project(b),b=[a.x,b.y,b.x,a.y].join(",");return this._url+L.Util.getParamString(this.wmsParams)+"&bbox="+b}});L.TileLayer.Canvas=L.TileLayer.extend({options:{async:!1},initialize:function(a){L.Util.setOptions(this,a)},_createTileProto:function(){this._canvasProto=L.DomUtil.create("canvas","leaflet-tile");var a=this.options.tileSize;this._canvasProto.width=a;this._canvasProto.height=a},_createTile:function(){var a=this._canvasProto.cloneNode(!1);a.onselectstart=a.onmousemove=L.Util.falseFn;return a},_loadTile:function(a,b,c){a._layer=this;this.drawTile(a,b,c);this.options.async||this.tileDrawn(a)},drawTile:function(){}, -tileDrawn:function(a){this._tileOnLoad.call(a)}});L.ImageOverlay=L.Class.extend({includes:L.Mixin.Events,initialize:function(a,b){this._url=a;this._bounds=b},onAdd:function(a){this._map=a;this._image||this._initImage();a.getPanes().overlayPane.appendChild(this._image);a.on("viewreset",this._reset,this);this._reset()},onRemove:function(a){a.getPanes().overlayPane.removeChild(this._image);a.off("viewreset",this._reset,this)},_initImage:function(){this._image=L.DomUtil.create("img","leaflet-image-layer");this._image.style.visibility="hidden";L.Util.extend(this._image, -{galleryimg:"no",onselectstart:L.Util.falseFn,onmousemove:L.Util.falseFn,onload:this._onImageLoad,src:this._url})},_reset:function(){var a=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),b=this._map.latLngToLayerPoint(this._bounds.getSouthEast()).subtract(a);L.DomUtil.setPosition(this._image,a);this._image.style.width=b.x+"px";this._image.style.height=b.y+"px"},_onImageLoad:function(){this.style.visibility=""}});L.Popup=L.Class.extend({includes:L.Mixin.Events,options:{minWidth:50,maxWidth:300,autoPan:!0,closeButton:!0,offset:new L.Point(0,2),autoPanPadding:new L.Point(5,5)},initialize:function(a){L.Util.setOptions(this,a)},onAdd:function(a){this._map=a;this._container||this._initLayout();this._updateContent();this._container.style.opacity="0";this._map._panes.popupPane.appendChild(this._container);this._map.on("viewreset",this._updatePosition,this);if(this._map.options.closePopupOnClick)this._map.on("preclick", -this._close,this);this._update();this._container.style.opacity="1";this._opened=!0},onRemove:function(a){a._panes.popupPane.removeChild(this._container);a.off("viewreset",this._updatePosition,this);a.off("click",this._close,this);this._container.style.opacity="0";this._opened=!1},setLatLng:function(a){this._latlng=a;this._opened&&this._update();return this},setContent:function(a){this._content=a;this._opened&&this._update();return this},_close:function(){this._opened&&this._map.removeLayer(this)}, -_initLayout:function(){this._container=L.DomUtil.create("div","leaflet-popup");if(this.options.closeButton)this._closeButton=L.DomUtil.create("a","leaflet-popup-close-button",this._container),this._closeButton.href="#close",L.DomEvent.addListener(this._closeButton,"click",this._onCloseButtonClick,this);this._wrapper=L.DomUtil.create("div","leaflet-popup-content-wrapper",this._container);L.DomEvent.disableClickPropagation(this._wrapper);this._contentNode=L.DomUtil.create("div","leaflet-popup-content", -this._wrapper);this._tipContainer=L.DomUtil.create("div","leaflet-popup-tip-container",this._container);this._tip=L.DomUtil.create("div","leaflet-popup-tip",this._tipContainer)},_update:function(){this._container.style.visibility="hidden";this._updateContent();this._updateLayout();this._updatePosition();this._container.style.visibility="";this._adjustPan()},_updateContent:function(){if(this._content)typeof this._content=="string"?this._contentNode.innerHTML=this._content:(this._contentNode.innerHTML= -"",this._contentNode.appendChild(this._content))},_updateLayout:function(){this._container.style.width="";this._container.style.whiteSpace="nowrap";var a=this._container.offsetWidth;this._container.style.width=(a>this.options.maxWidth?this.options.maxWidth:ae.x)c.x=b.x+ -this._containerWidth-e.x+d.x;if(b.y<0)c.y=b.y-d.y;if(b.y+a>e.y)c.y=b.y+a-e.y+d.y;(c.x||c.y)&&this._map.panBy(c)}},_onCloseButtonClick:function(a){this._close();L.DomEvent.stop(a)}});L.Icon=L.Class.extend({iconUrl:L.ROOT_URL+"images/marker.png",shadowUrl:L.ROOT_URL+"images/marker-shadow.png",iconSize:new L.Point(25,41),shadowSize:new L.Point(41,41),iconAnchor:new L.Point(13,41),popupAnchor:new L.Point(0,-33),initialize:function(a){if(a)this.iconUrl=a},createIcon:function(){return this._createIcon("icon")},createShadow:function(){return this._createIcon("shadow")},_createIcon:function(a){var b=this[a+"Size"],c=this[a+"Url"],d=this._createImg(c);if(!c)return null;d.className="leaflet-marker-"+ -a;d.style.marginLeft=-this.iconAnchor.x+"px";d.style.marginTop=-this.iconAnchor.y+"px";if(b)d.style.width=b.x+"px",d.style.height=b.y+"px";return d},_createImg:function(a){var b;L.Browser.ie6?(b=document.createElement("div"),b.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+a+'")'):(b=document.createElement("img"),b.src=a);return b}});L.Marker=L.Class.extend({includes:L.Mixin.Events,options:{icon:new L.Icon,title:"",clickable:!0,draggable:!1},initialize:function(a,b){L.Util.setOptions(this,b);this._latlng=a},onAdd:function(a){this._map=a;this._initIcon();a.on("viewreset",this._reset,this);this._reset()},onRemove:function(a){this._removeIcon();this.closePopup&&this.closePopup();a.off("viewreset",this._reset,this)},getLatLng:function(){return this._latlng},setLatLng:function(a){this._latlng=a;this._icon&&this._reset()},setIcon:function(a){this._removeIcon(); -this._icon=this._shadow=null;this.options.icon=a;this._initIcon();this._reset()},_initIcon:function(){if(!this._icon){this._icon=this.options.icon.createIcon();if(this.options.title)this._icon.title=this.options.title;this._initInteraction()}if(!this._shadow)this._shadow=this.options.icon.createShadow();this._map._panes.markerPane.appendChild(this._icon);this._shadow&&this._map._panes.shadowPane.appendChild(this._shadow)},_removeIcon:function(){this._map._panes.markerPane.removeChild(this._icon); -this._shadow&&this._map._panes.shadowPane.removeChild(this._shadow)},_reset:function(){var a=this._map.latLngToLayerPoint(this._latlng).round();L.DomUtil.setPosition(this._icon,a);this._shadow&&L.DomUtil.setPosition(this._shadow,a);this._icon.style.zIndex=a.y},_initInteraction:function(){if(this.options.clickable){this._icon.className+=" leaflet-clickable";L.DomEvent.addListener(this._icon,"click",this._onMouseClick,this);for(var a=["dblclick","mousedown","mouseover","mouseout"],b=0;b';a=a.firstChild;a.style.behavior="url(#default#VML)";return a&&typeof a.adj=="object"}(); -L.Path=L.Browser.svg||!L.Browser.vml?L.Path:L.Path.extend({statics:{VML:!0,CLIP_PADDING:0.02},_createElement:function(){try{return document.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(a){return document.createElement("')}}catch(a){return function(a){return document.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_initRoot:function(){if(!this._map._pathRoot)this._map._pathRoot=document.createElement("div"),this._map._pathRoot.className= -"leaflet-vml-container",this._map._panes.overlayPane.appendChild(this._map._pathRoot),this._map.on("moveend",this._updateViewport,this),this._updateViewport()},_initPath:function(){this._container=this._createElement("shape");this._container.className+=" leaflet-vml-shape"+(this.options.clickable?" leaflet-clickable":"");this._container.coordsize="1 1";this._path=this._createElement("path");this._container.appendChild(this._path);this._map._pathRoot.appendChild(this._container)},_initStyle:function(){this.options.stroke? -(this._stroke=this._createElement("stroke"),this._stroke.endcap="round",this._container.appendChild(this._stroke)):this._container.stroked=!1;this.options.fill?(this._container.filled=!0,this._fill=this._createElement("fill"),this._container.appendChild(this._fill)):this._container.filled=!1;this._updateStyle()},_updateStyle:function(){if(this.options.stroke)this._stroke.weight=this.options.weight+"px",this._stroke.color=this.options.color,this._stroke.opacity=this.options.opacity;if(this.options.fill)this._fill.color= -this.options.fillColor||this.options.color,this._fill.opacity=this.options.fillOpacity},_updatePath:function(){this._container.style.display="none";this._path.v=this.getPathString()+" ";this._container.style.display=""}});L.Browser.canvas=function(){return!!document.createElement("canvas").getContext}(); -L.Path=L.Path.SVG&&!window.L_PREFER_CANVAS||!L.Browser.canvas?L.Path:L.Path.extend({statics:{CANVAS:!0,SVG:!1},options:{updateOnMoveEnd:!0},_initElements:function(){this._initRoot()},_initRoot:function(){var a=this._map._pathRoot,b=this._map._canvasCtx;if(!a)a=this._map._pathRoot=document.createElement("canvas"),a.style.position="absolute",b=this._map._canvasCtx=a.getContext("2d"),b.lineCap="round",b.lineJoin="round",this._map._panes.overlayPane.appendChild(a),this._map.on("moveend",this._updateCanvasViewport, -this),this._updateCanvasViewport();this._ctx=b},_updateStyle:function(){if(this.options.stroke)this._ctx.lineWidth=this.options.weight,this._ctx.strokeStyle=this.options.color;if(this.options.fill)this._ctx.fillStyle=this.options.fillColor||this.options.color},_drawPath:function(){var a,b,c,d,e,f;this._ctx.beginPath();a=0;for(c=this._parts.length;aa.y!=e.y>a.y&&a.x<(e.x-d.x)*(a.y-d.y)/(e.y-d.y)+d.x&&(b=!b)}return b}});(function(){function a(a){return L.FeatureGroup.extend({initialize:function(a,b){this._layers={};this._options=b;this.setLatLngs(a)},setStyle:function(a){for(var b in this._layers)this._layers.hasOwnProperty(b)&&this._layers[b].setStyle&&this._layers[b].setStyle(a)},setLatLngs:function(c){var d=0,e=c.length;for(this._iterateLayers(function(a){da.max.x||c.y-b>a.max.y||c.x+b0?Math.ceil(b):Math.floor(b))),a=b-a,c=this._centerOffset.subtract(this._delta).divideBy(this._scale),d=this._map.unproject(this._map.getPixelOrigin().add(this._startCenter).add(c));L.DomEvent.removeListener(document,"touchmove",this._onTouchMove);L.DomEvent.removeListener(document,"touchend",this._onTouchEnd);this._map._runAnimation(d,b,Math.pow(2,a)/this._scale,this._startCenter.add(c))}}});L.Handler.ScrollWheelZoom=L.Handler.extend({enable:function(){if(!this._enabled)L.DomEvent.addListener(this._map._container,"mousewheel",this._onWheelScroll,this),this._delta=0,this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._map._container,"mousewheel",this._onWheelScroll),this._enabled=!1},_onWheelScroll:function(a){this._delta+=L.DomEvent.getWheelDelta(a);this._lastMousePos=this._map.mouseEventToContainerPoint(a);clearTimeout(this._timer);this._timer=setTimeout(L.Util.bind(this._performZoom, -this),50);L.DomEvent.preventDefault(a)},_performZoom:function(){var a=Math.round(this._delta),a=Math.max(Math.min(a,4),-4);this._delta=0;if(a){var b=this._getCenterForScrollWheelZoom(this._lastMousePos,a),a=this._map.getZoom()+a;this._map._limitZoom(a)!=this._map._zoom&&this._map.setView(b,a)}},_getCenterForScrollWheelZoom:function(a,b){var c=this._map.getPixelBounds().getCenter(),d=this._map.getSize().divideBy(2),d=a.subtract(d).multiplyBy(1-Math.pow(2,-b));return this._map.unproject(c.add(d),this._map._zoom, -!0)}});L.Handler.DoubleClickZoom=L.Handler.extend({enable:function(){if(!this._enabled)this._map.on("dblclick",this._onDoubleClick,this._map),this._enabled=!0},disable:function(){if(this._enabled)this._map.off("dblclick",this._onDoubleClick,this._map),this._enabled=!1},_onDoubleClick:function(a){this.setView(a.latlng,this._zoom+1)}});L.Handler.ShiftDragZoom=L.Handler.extend({initialize:function(a){this._map=a;this._container=a._container;this._pane=a._panes.overlayPane},enable:function(){if(!this._enabled)L.DomEvent.addListener(this._container,"mousedown",this._onMouseDown,this),this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._container,"mousedown",this._onMouseDown),this._enabled=!1},_onMouseDown:function(a){if(!a.shiftKey||a.which!=1&&a.button!=1)return!1;L.DomUtil.disableTextSelection(); -this._startLayerPoint=this._map.mouseEventToLayerPoint(a);this._box=L.DomUtil.create("div","leaflet-zoom-box",this._pane);L.DomUtil.setPosition(this._box,this._startLayerPoint);this._container.style.cursor="crosshair";L.DomEvent.addListener(document,"mousemove",this._onMouseMove,this);L.DomEvent.addListener(document,"mouseup",this._onMouseUp,this);L.DomEvent.preventDefault(a)},_onMouseMove:function(a){var b=this._map.mouseEventToLayerPoint(a),a=b.x-this._startLayerPoint.x,c=b.y-this._startLayerPoint.y, -b=new L.Point(Math.min(b.x,this._startLayerPoint.x),Math.min(b.y,this._startLayerPoint.y));L.DomUtil.setPosition(this._box,b);this._box.style.width=Math.abs(a)-4+"px";this._box.style.height=Math.abs(c)-4+"px"},_onMouseUp:function(a){this._pane.removeChild(this._box);this._container.style.cursor="";L.DomUtil.enableTextSelection();L.DomEvent.removeListener(document,"mousemove",this._onMouseMove);L.DomEvent.removeListener(document,"mouseup",this._onMouseUp);a=this._map.mouseEventToLayerPoint(a);this._map.fitBounds(new L.LatLngBounds(this._map.layerPointToLatLng(this._startLayerPoint), -this._map.layerPointToLatLng(a)))}});L.Handler.MarkerDrag=L.Handler.extend({initialize:function(a){this._marker=a},enable:function(){if(!this._enabled){if(!this._draggable)this._draggable=new L.Draggable(this._marker._icon,this._marker._icon),this._draggable.on("dragstart",this._onDragStart,this),this._draggable.on("drag",this._onDrag,this),this._draggable.on("dragend",this._onDragEnd,this);this._draggable.enable();this._enabled=!0}},disable:function(){if(this._enabled)this._draggable.disable(),this._enabled=!1},moved:function(){return this._draggable&& -this._draggable._moved},_onDragStart:function(){this._marker.closePopup();this._marker.fire("movestart");this._marker.fire("dragstart")},_onDrag:function(){var a=L.DomUtil.getPosition(this._marker._icon);this._marker._shadow&&L.DomUtil.setPosition(this._marker._shadow,a);this._marker._latlng=this._marker._map.layerPointToLatLng(a);this._marker.fire("move");this._marker.fire("drag")},_onDragEnd:function(){this._marker.fire("moveend");this._marker.fire("dragend")}});L.Control={};L.Control.Position={TOP_LEFT:"topLeft",TOP_RIGHT:"topRight",BOTTOM_LEFT:"bottomLeft",BOTTOM_RIGHT:"bottomRight"};L.Control.Zoom=L.Class.extend({onAdd:function(a){this._map=a;this._container=L.DomUtil.create("div","leaflet-control-zoom");this._zoomInButton=this._createButton("Zoom in","leaflet-control-zoom-in",this._map.zoomIn,this._map);this._zoomOutButton=this._createButton("Zoom out","leaflet-control-zoom-out",this._map.zoomOut,this._map);this._container.appendChild(this._zoomInButton);this._container.appendChild(this._zoomOutButton)},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_LEFT}, -_createButton:function(a,b,c,d){var e=document.createElement("a");e.href="#";e.title=a;e.className=b;L.DomEvent.disableClickPropagation(e);L.DomEvent.addListener(e,"click",L.DomEvent.preventDefault);L.DomEvent.addListener(e,"click",c,d);return e}});L.Control.Attribution=L.Class.extend({onAdd:function(a){this._container=L.DomUtil.create("div","leaflet-control-attribution");this._map=a;this._prefix='Powered by Leaflet';this._attributions={};this._update()},getPosition:function(){return L.Control.Position.BOTTOM_RIGHT},getContainer:function(){return this._container},setPrefix:function(a){this._prefix=a;this._update()},addAttribution:function(a){a&&(this._attributions[a]=!0,this._update())},removeAttribution:function(a){a&& -(delete this._attributions[a],this._update())},_update:function(){if(this._map){var a=[],b;for(b in this._attributions)this._attributions.hasOwnProperty(b)&&a.push(b);b=[];this._prefix&&b.push(this._prefix);a.length&&b.push(a.join(", "));this._container.innerHTML=b.join(" — ")}}});L.Control.Layers=L.Class.extend({options:{collapsed:!0},initialize:function(a,b,c){L.Util.setOptions(this,c);this._layers={};for(var d in a)a.hasOwnProperty(d)&&this._addLayer(a[d],d);for(d in b)b.hasOwnProperty(d)&&this._addLayer(b[d],d,!0)},onAdd:function(a){this._map=a;this._initLayout();this._update()},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_RIGHT},addBaseLayer:function(a,b){this._addLayer(a,b);this._update();return this},addOverlay:function(a, -b){this._addLayer(a,b,!0);this._update();return this},removeLayer:function(a){delete this._layers[L.Util.stamp(a)];this._update();return this},_initLayout:function(){this._container=L.DomUtil.create("div","leaflet-control-layers");L.DomEvent.disableClickPropagation(this._container);this._form=L.DomUtil.create("form","leaflet-control-layers-list");if(this.options.collapsed){L.DomEvent.addListener(this._container,"mouseover",this._expand,this);L.DomEvent.addListener(this._container,"mouseout",this._collapse, -this);var a=this._layersLink=L.DomUtil.create("a","leaflet-control-layers-toggle");a.href="#";a.title="Layers";L.DomEvent.addListener(a,"focus",this._expand,this);L.DomEvent.addListener(this._map,L.Draggable.START,this._collapse,this);this._container.appendChild(a)}else this._expand();this._baseLayersList=L.DomUtil.create("div","leaflet-control-layers-base",this._form);this._separator=L.DomUtil.create("div","leaflet-control-layers-separator",this._form);this._overlaysList=L.DomUtil.create("div","leaflet-control-layers-overlays", -this._form);this._container.appendChild(this._form)},_addLayer:function(a,b,c){this._layers[L.Util.stamp(a)]={layer:a,name:b,overlay:c}},_update:function(){if(this._container){this._baseLayersList.innerHTML="";this._overlaysList.innerHTML="";var a=!1,b=!1,c;for(c in this._layers)if(this._layers.hasOwnProperty(c)){var d=this._layers[c];this._addItem(d);b=b||d.overlay;a=a||!d.overlay}this._separator.style.display=b&&a?"":"none"}},_addItem:function(a){var b=document.createElement("label"),c=document.createElement("input"); -if(!a.overlay)c.name="leaflet-base-layers";c.type=a.overlay?"checkbox":"radio";c.checked=this._map.hasLayer(a.layer);c.layerId=L.Util.stamp(a.layer);L.DomEvent.addListener(c,"click",this._onInputClick,this);var d=document.createTextNode(" "+a.name);b.appendChild(c);b.appendChild(d);(a.overlay?this._overlaysList:this._baseLayersList).appendChild(b)},_onInputClick:function(){var a,b,c,d=this._form.getElementsByTagName("input"),e=d.length;for(a=0;a 0; }, + removeEventListener: function (a, b, c) { if (!this.hasEventListeners(a)) return this; for (var d = 0, e = this._leaflet_events, f = e[a].length; d < f; d++) if (e[a][d].action === b && (!c || e[a][d].context === c)) { e[a].splice(d, 1); break; } return this; }, + fireEvent: function (a, + b) { if (this.hasEventListeners(a)) { for (var c = L.Util.extend({ type: a, target: this }, b), d = this._leaflet_events[a].slice(), e = 0, f = d.length; e < f; e++)d[e].action.call(d[e].context || this, c); return this; } } +}; L.Mixin.Events.on = L.Mixin.Events.addEventListener; L.Mixin.Events.off = L.Mixin.Events.removeEventListener; L.Mixin.Events.fire = L.Mixin.Events.fireEvent; (function () { var a = navigator.userAgent.toLowerCase(); var b = !!window.ActiveXObject; var c = a.indexOf('webkit') != -1; var d = typeof orientation !== 'undefined' ? !0 : !1; var e = a.indexOf('android') != -1; var f = window.opera; L.Browser = { ie: b, ie6: b && !window.XMLHttpRequest, webkit: c, webkit3d: c && 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix(), gecko: a.indexOf('gecko') != -1, opera: f, android: e, mobileWebkit: d && c, mobileOpera: d && f, mobile: d, touch: 'ontouchstart' in document.documentElement }; })(); L.Point = function (a, b, c) { this.x = c ? Math.round(a) : a; this.y = c ? Math.round(b) : b; }; +L.Point.prototype = { + add: function (a) { return this.clone()._add(a); }, + _add: function (a) { this.x += a.x; this.y += a.y; return this; }, + subtract: function (a) { return this.clone()._subtract(a); }, + _subtract: function (a) { this.x -= a.x; this.y -= a.y; return this; }, + divideBy: function (a, b) { return new L.Point(this.x / a, this.y / a, b); }, + multiplyBy: function (a) { return new L.Point(this.x * a, this.y * a); }, + distanceTo: function (a) { var b = a.x - this.x; var a = a.y - this.y; return Math.sqrt(b * b + a * a); }, + round: function () { return this.clone()._round(); }, + _round: function () { + this.x = +Math.round(this.x); this.y = Math.round(this.y); return this; + }, + clone: function () { return new L.Point(this.x, this.y); }, + toString: function () { return 'Point(' + L.Util.formatNum(this.x) + ', ' + L.Util.formatNum(this.y) + ')'; } +}; L.Bounds = L.Class.extend({ + initialize: function (a, b) { if (a) for (var c = a instanceof Array ? a : [a, b], d = 0, e = c.length; d < e; d++) this.extend(c[d]); }, + extend: function (a) { !this.min && !this.max ? (this.min = new L.Point(a.x, a.y), this.max = new L.Point(a.x, a.y)) : (this.min.x = Math.min(a.x, this.min.x), this.max.x = Math.max(a.x, this.max.x), this.min.y = Math.min(a.y, this.min.y), this.max.y = Math.max(a.y, this.max.y)); }, + getCenter: function (a) { return new L.Point((this.min.x + this.max.x) / 2, (this.min.y + this.max.y) / 2, a); }, + contains: function (a) { + var b; + a instanceof L.Bounds ? (b = a.min, a = a.max) : b = a; return b.x >= this.min.x && a.x <= this.max.x && b.y >= this.min.y && a.y <= this.max.y; + } +}); L.Transformation = L.Class.extend({ initialize: function (a, b, c, d) { this._a = a; this._b = b; this._c = c; this._d = d; }, transform: function (a, b) { return this._transform(a.clone(), b); }, _transform: function (a, b) { b = b || 1; a.x = b * (this._a * a.x + this._b); a.y = b * (this._c * a.y + this._d); return a; }, untransform: function (a, b) { b = b || 1; return new L.Point((a.x / b - this._b) / this._a, (a.y / b - this._d) / this._c); } }); L.LineUtil = { + simplify: function (a, b) { if (!b || !a.length) return a.slice(); a = this.reducePoints(a, b); return a = this.simplifyDP(a, b); }, + pointToSegmentDistance: function (a, b, c) { return Math.sqrt(this._sqPointToSegmentDist(a, b, c)); }, + closestPointOnSegment: function (a, b, c) { a = this._sqClosestPointOnSegment(a, b, c); a.distance = Math.sqrt(a._sqDist); return a; }, + simplifyDP: function (a, b) { + for (var c = 0, d = 0, e = b * b, f = 1, g = a.length, h; f < g - 1; f++)h = this._sqPointToSegmentDist(a[f], a[0], a[g - 1]), h > c && (d = f, c = h); return c >= e ? (c = a.slice(0, d), d = +a.slice(d), g = this.simplifyDP(c, b).slice(0, g - 2), d = this.simplifyDP(d, b), g.concat(d)) : [a[0], a[g - 1]]; + }, + reducePoints: function (a, b) { for (var c = [a[0]], d = b * b, e = 1, f = 0, g = a.length; e < g; e++) this._sqDist(a[e], a[f]) < d || (c.push(a[e]), f = e); f < g - 1 && c.push(a[g - 1]); return c; }, + clipSegment: function (a, b, c, d) { + var d = d ? this._lastCode : this._getBitCode(a, c); var e = this._getBitCode(b, c); for (this._lastCode = e; ;) { + if (d | e) if (d & e) return !1; else { var f = d || e; var g = this._getEdgeIntersection(a, b, f, c); var h = this._getBitCode(g, c); f == d ? (a = g, d = h) : (b = g, e = h); } else { + return [a, + b]; + } + } + }, + _getEdgeIntersection: function (a, b, c, d) { var e = b.x - a.x; var b = b.y - a.y; var f = d.min; var d = d.max; if (c & 8) return new L.Point(a.x + e * (d.y - a.y) / b, d.y); else if (c & 4) return new L.Point(a.x + e * (f.y - a.y) / b, f.y); else if (c & 2) return new L.Point(d.x, a.y + b * (d.x - a.x) / e); else if (c & 1) return new L.Point(f.x, a.y + b * (f.x - a.x) / e); }, + _getBitCode: function (a, b) { var c = 0; a.x < b.min.x ? c |= 1 : a.x > b.max.x && (c |= 2); a.y < b.min.y ? c |= 4 : a.y > b.max.y && (c |= 8); return c; }, + _sqDist: function (a, b) { var c = b.x - a.x; var d = b.y - a.y; return c * c + d * d; }, + _sqClosestPointOnSegment: function (a, + b, c) { var d = c.x - b.x; var e = c.y - b.y; var f = b; if (d || e) { var g = ((a.x - b.x) * d + (a.y - b.y) * e) / this._sqDist(b, c); g > 1 ? f = c : g > 0 && (f = new L.Point(b.x + d * g, b.y + e * g)); }f._sqDist = this._sqDist(a, f); return f; }, + _sqPointToSegmentDist: function (a, b, c) { return this._sqClosestPointOnSegment(a, b, c)._sqDist; } +}; L.PolyUtil = {}; L.PolyUtil.clipPolygon = function (a, b) { var c; var d = [1, 4, 2, 8]; var e; var f; var g; var h; var j; var k; var l = L.LineUtil; e = 0; for (j = a.length; e < j; e++)a[e]._code = l._getBitCode(a[e], b); for (g = 0; g < 4; g++) { k = d[g]; c = []; e = 0; j = a.length; for (f = j - 1; e < j; f = e++) if (h = a[e], f = a[f], h._code & k) { if (!(f._code & k))f = l._getEdgeIntersection(f, h, k, b), f._code = l._getBitCode(f, b), c.push(f); } else { if (f._code & k)f = l._getEdgeIntersection(f, h, k, b), f._code = l._getBitCode(f, b), c.push(f); c.push(h); }a = c; } return a; }; L.DomEvent = { + addListener: function (a, b, c, d) { + function e (b) { return c.call(d || a, b || L.DomEvent._getEvent()); } var f = L.Util.stamp(c); if (L.Browser.touch && b == 'dblclick' && this.addDoubleTapListener) this.addDoubleTapListener(a, e, f); else if ('addEventListener' in a) { + if (b == 'mousewheel')a.addEventListener('DOMMouseScroll', e, !1), a.addEventListener(b, e, !1); else if (b == 'mouseenter' || b == 'mouseleave') { + var g = e; var e = function (b) { if (L.DomEvent._checkMouse(a, b)) return g(b); }; a.addEventListener(b == 'mouseenter' ? 'mouseover' : 'mouseout', + e, !1); + } else a.addEventListener(b, e, !1); + } else 'attachEvent' in a && a.attachEvent('on' + b, e); a['_leaflet_' + b + f] = e; + }, + removeListener: function (a, b, c) { + var c = L.Util.stamp(c); var d = '_leaflet_' + b + c; handler = a[d]; L.Browser.touch && b == 'dblclick' && this.removeDoubleTapListener ? this.removeDoubleTapListener(a, c) : 'removeEventListener' in a ? b == 'mousewheel' ? (a.removeEventListener('DOMMouseScroll', handler, !1), a.removeEventListener(b, handler, !1)) : b == 'mouseenter' || b == 'mouseleave' ? a.removeEventListener(b == 'mouseenter' ? 'mouseover' : 'mouseout', + handler, !1) : a.removeEventListener(b, handler, !1) : 'detachEvent' in a && a.detachEvent('on' + b, handler); a[d] = null; + }, + _checkMouse: function (a, b) { var c = b.relatedTarget; if (!c) return !0; try { for (;c && c != a;)c = c.parentNode; } catch (d) { return !1; } return c != a; }, + _getEvent: function () { var a = window.event; if (!a) for (var b = arguments.callee.caller; b;) { if ((a = b.arguments[0]) && Event == a.constructor) break; b = b.caller; } return a; }, + stopPropagation: function (a) { a.stopPropagation ? a.stopPropagation() : a.cancelBubble = !0; }, + disableClickPropagation: function (a) { + L.DomEvent.addListener(a, + 'mousedown', L.DomEvent.stopPropagation); L.DomEvent.addListener(a, 'click', L.DomEvent.stopPropagation); L.DomEvent.addListener(a, 'dblclick', L.DomEvent.stopPropagation); + }, + preventDefault: function (a) { a.preventDefault ? a.preventDefault() : a.returnValue = !1; }, + stop: function (a) { L.DomEvent.preventDefault(a); L.DomEvent.stopPropagation(a); }, + getMousePosition: function (a, b) { + var c = new L.Point(a.pageX ? a.pageX : a.clientX + document.body.scrollLeft + document.documentElement.scrollLeft, a.pageY ? a.pageY : a.clientY + document.body.scrollTop + +document.documentElement.scrollTop); return b ? c.subtract(L.DomUtil.getViewportOffset(b)) : c; + }, + getWheelDelta: function (a) { var b = 0; a.wheelDelta && (b = a.wheelDelta / 120); a.detail && (b = -a.detail / 3); return b; } +}; L.Util.extend(L.DomEvent, { + addDoubleTapListener: function (a, b, c) { function d (a) { if (a.touches.length == 1) { var b = Date.now(); var c = b - (f || b); j = a.touches[0]; g = c > 0 && c <= h; f = b; } } function e () { if (g)j.type = 'dblclick', b(j), f = null; } var f; var g = !1; var h = 250; var j; a['_leaflet_touchstart' + c] = d; a['_leaflet_touchend' + c] = e; a.addEventListener('touchstart', d, !1); a.addEventListener('touchend', e, !1); }, + removeDoubleTapListener: function (a, b) { + a.removeEventListener(a, a['_leaflet_touchstart' + b], !1); a.removeEventListener(a, a['_leaflet_touchend' + b], + !1); + } +}); L.DomUtil = { + get: function (a) { return typeof a === 'string' ? document.getElementById(a) : a; }, + getStyle: function (a, b) { var c = a.style[b]; !c && a.currentStyle && (c = a.currentStyle[b]); if (!c || c == 'auto')c = (c = document.defaultView.getComputedStyle(a, null)) ? c[b] : null; return c == 'auto' ? null : c; }, + getViewportOffset: function (a) { + var b = 0; var c = 0; var d = a; var e = document.body; do if (b += d.offsetTop || 0, c += d.offsetLeft || 0, d.offsetParent == e && L.DomUtil.getStyle(d, 'position') == 'absolute') break; while (d = d.offsetParent);d = a; do { + if (d === e) break; b -= d.scrollTop || +0; c -= d.scrollLeft || 0; + } while (d = d.parentNode);return new L.Point(c, b); + }, + create: function (a, b, c) { a = document.createElement(a); a.className = b; c && c.appendChild(a); return a; }, + disableTextSelection: function () { document.selection && document.selection.empty && document.selection.empty(); if (!this._onselectstart) this._onselectstart = document.onselectstart, document.onselectstart = L.Util.falseFn; }, + enableTextSelection: function () { document.onselectstart = this._onselectstart; this._onselectstart = null; }, + hasClass: function (a, b) { + return a.className.length > +0 && RegExp('(^|\\s)' + b + '(\\s|$)').test(a.className); + }, + addClass: function (a, b) { L.DomUtil.hasClass(a, b) || (a.className += (a.className ? ' ' : '') + b); }, + removeClass: function (a, b) { a.className = a.className.replace(/(\S+)\s*/g, function (a, d) { if (d == b) return ''; return a; }).replace(/^\s+/, ''); }, + setOpacity: function (a, b) { L.Browser.ie ? a.style.filter = 'alpha(opacity=' + Math.round(b * 100) + ')' : a.style.opacity = b; }, + testProp: function (a) { for (var b = document.documentElement.style, c = 0; c < a.length; c++) if (a[c] in b) return a[c]; return !1; }, + getTranslateString: function (a) { + return L.DomUtil.TRANSLATE_OPEN + +a.x + 'px,' + a.y + 'px' + L.DomUtil.TRANSLATE_CLOSE; + }, + getScaleString: function (a, b) { return L.DomUtil.getTranslateString(b) + ' scale(' + a + ') ' + L.DomUtil.getTranslateString(b.multiplyBy(-1)); }, + setPosition: function (a, b) { a._leaflet_pos = b; L.Browser.webkit ? a.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(b) : (a.style.left = b.x + 'px', a.style.top = b.y + 'px'); }, + getPosition: function (a) { return a._leaflet_pos; } +}; +L.Util.extend(L.DomUtil, { TRANSITION: L.DomUtil.testProp(['transition', 'webkitTransition', 'OTransition', 'MozTransition', 'msTransition']), TRANSFORM: L.DomUtil.testProp(['transformProperty', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']), TRANSLATE_OPEN: 'translate' + (L.Browser.webkit3d ? '3d(' : '('), TRANSLATE_CLOSE: L.Browser.webkit3d ? ',0)' : ')' }); L.Draggable = L.Class.extend({ + includes: L.Mixin.Events, + statics: { START: L.Browser.touch ? 'touchstart' : 'mousedown', END: L.Browser.touch ? 'touchend' : 'mouseup', MOVE: L.Browser.touch ? 'touchmove' : 'mousemove', TAP_TOLERANCE: 15 }, + initialize: function (a, b) { this._element = a; this._dragStartTarget = b || a; }, + enable: function () { if (!this._enabled)L.DomEvent.addListener(this._dragStartTarget, L.Draggable.START, this._onDown, this), this._enabled = !0; }, + disable: function () { + if (this._enabled) { + L.DomEvent.removeListener(this._dragStartTarget, + L.Draggable.START, this._onDown), this._enabled = !1; + } + }, + _onDown: function (a) { + if (!(a.shiftKey || a.which != 1 && a.button != 1 && !a.touches) && !(a.touches && a.touches.length > 1)) { + var b = a.touches && a.touches.length == 1 ? a.touches[0] : a; L.DomEvent.preventDefault(a); L.Browser.touch && (b.target.className += ' leaflet-active'); this._moved = !1; L.DomUtil.disableTextSelection(); this._setMovingCursor(); this._startPos = this._newPos = L.DomUtil.getPosition(this._element); this._startPoint = new L.Point(b.clientX, b.clientY); L.DomEvent.addListener(document, + L.Draggable.MOVE, this._onMove, this); L.DomEvent.addListener(document, L.Draggable.END, this._onUp, this); + } + }, + _onMove: function (a) { if (!(a.touches && a.touches.length > 1)) { L.DomEvent.preventDefault(a); a = a.touches && a.touches.length == 1 ? a.touches[0] : a; if (!this._moved) this.fire('dragstart'), this._moved = !0; this._newPos = this._startPos.add(new L.Point(a.clientX, a.clientY)).subtract(this._startPoint); L.Util.requestAnimFrame(this._updatePosition, this, !0); } }, + _updatePosition: function () { + L.DomUtil.setPosition(this._element, + this._newPos); this.fire('drag'); + }, + _onUp: function (a) { if (a.changedTouches) { var a = a.changedTouches[0]; var b = a.target; var c = this._newPos && this._newPos.distanceTo(this._startPos) || 0; b.className = b.className.replace(' leaflet-active', ''); c < L.Draggable.TAP_TOLERANCE && this._simulateEvent('click', a); }L.DomUtil.enableTextSelection(); this._restoreCursor(); L.DomEvent.removeListener(document, L.Draggable.MOVE, this._onMove); L.DomEvent.removeListener(document, L.Draggable.END, this._onUp); this._moved && this.fire('dragend'); }, + _removeActiveClass: function () {}, + _setMovingCursor: function () { this._bodyCursor = document.body.style.cursor; document.body.style.cursor = 'move'; }, + _restoreCursor: function () { document.body.style.cursor = this._bodyCursor; }, + _simulateEvent: function (a, b) { var c = document.createEvent('MouseEvent'); c.initMouseEvent(a, !0, !0, window, 1, b.screenX, b.screenY, b.clientX, b.clientY, !1, !1, !1, !1, 0, null); b.target.dispatchEvent(c); } +}); L.Transition = L.Class.extend({ includes: L.Mixin.Events, statics: { CUSTOM_PROPS_SETTERS: { position: L.DomUtil.setPosition }, implemented: function () { return L.Transition.NATIVE || L.Transition.TIMER; } }, options: { easing: 'ease', duration: 0.5 }, _setProperty: function (a, b) { var c = L.Transition.CUSTOM_PROPS_SETTERS; if (a in c)c[a](this._el, b); else this._el.style[a] = b; } }); L.Transition = L.Transition.extend({ + statics: (function () { var a = L.DomUtil.TRANSITION; return { NATIVE: !!a, TRANSITION: a, PROPERTY: a + 'Property', DURATION: a + 'Duration', EASING: a + 'TimingFunction', END: a == 'webkitTransition' || a == 'OTransition' ? a + 'End' : 'transitionend', CUSTOM_PROPS_PROPERTIES: { position: L.Browser.webkit ? L.DomUtil.TRANSFORM : 'top, left' } }; }()), + options: { fakeStepInterval: 100 }, + initialize: function (a, b) { + this._el = a; L.Util.setOptions(this, b); L.DomEvent.addListener(a, L.Transition.END, this._onTransitionEnd, this); this._onFakeStep = +L.Util.bind(this._onFakeStep, this); + }, + run: function (a) { + var b; var c = []; var d = L.Transition.CUSTOM_PROPS_PROPERTIES; for (b in a)a.hasOwnProperty(b) && (b = d[b] ? d[b] : b, b = b.replace(/([A-Z])/g, function (a) { return '-' + a.toLowerCase(); }), c.push(b)); this._onTransitionEnd(); this._el.style[L.Transition.DURATION] = this.options.duration + 's'; this._el.style[L.Transition.EASING] = this.options.easing; this._el.style[L.Transition.PROPERTY] = c.join(', '); for (b in a)a.hasOwnProperty(b) && this._setProperty(b, a[b]); this._inProgress = !0; this.fire('start'); + L.Transition.NATIVE ? this._timer = setInterval(this._onFakeStep, this.options.fakeStepInterval) : this._onTransitionEnd(); + }, + _onFakeStep: function () { this.fire('step'); }, + _onTransitionEnd: function () { if (this._inProgress) this._inProgress = !1, clearInterval(this._timer), this._el.style[L.Transition.PROPERTY] = 'none', this.fire('step'), this.fire('end'); } +}); L.Transition = L.Transition.NATIVE ? L.Transition : L.Transition.extend({ + statics: { getTime: Date.now || function () { return +new Date(); }, TIMER: !0, EASINGS: { ease: [0.25, 0.1, 0.25, 1], linear: [0, 0, 1, 1], 'ease-in': [0.42, 0, 1, 1], 'ease-out': [0, 0, 0.58, 1], 'ease-in-out': [0.42, 0, 0.58, 1] }, CUSTOM_PROPS_GETTERS: { position: L.DomUtil.getPosition }, UNIT_RE: /^[\d\.]+(\D*)$/ }, + options: { fps: 50 }, + initialize: function (a, b) { + this._el = a; L.Util.extend(this.options, b); var c = L.Transition.EASINGS[this.options.easing] || L.Transition.EASINGS.ease; this._p1 = +new L.Point(0, 0); this._p2 = new L.Point(c[0], c[1]); this._p3 = new L.Point(c[2], c[3]); this._p4 = new L.Point(1, 1); this._step = L.Util.bind(this._step, this); this._interval = Math.round(1E3 / this.options.fps); + }, + run: function (a) { + this._props = {}; var b = L.Transition.CUSTOM_PROPS_GETTERS; var c = L.Transition.UNIT_RE; this.fire('start'); for (var d in a) if (a.hasOwnProperty(d)) { var e = {}; if (d in b)e.from = b[d](this._el); else { var f = this._el.style[d].match(c); e.from = parseFloat(f[0]); e.unit = f[1]; }e.to = a[d]; this._props[d] = e; }clearInterval(this._timer); + this._timer = setInterval(this._step, this._interval); this._startTime = L.Transition.getTime(); + }, + _step: function () { var a = L.Transition.getTime() - this._startTime; var b = this.options.duration * 1E3; a < b ? this._runFrame(this._cubicBezier(a / b)) : (this._runFrame(1), this._complete()); }, + _runFrame: function (a) { + var b = L.Transition.CUSTOM_PROPS_SETTERS; var c; var d; for (c in this._props) { + this._props.hasOwnProperty(c) && (d = this._props[c], c in b ? (d = d.to.subtract(d.from).multiplyBy(a).add(d.from), b[c](this._el, d)) : this._el.style[c] = (d.to - d.from) * +a + d.from + d.unit); + } this.fire('step'); + }, + _complete: function () { clearInterval(this._timer); this.fire('end'); }, + _cubicBezier: function (a) { var b = 3 * Math.pow(1 - a, 2) * a; var c = 3 * (1 - a) * Math.pow(a, 2); var d = Math.pow(a, 3); var a = this._p1.multiplyBy(Math.pow(1 - a, 3)); var b = this._p2.multiplyBy(b); var c = this._p3.multiplyBy(c); var d = this._p4.multiplyBy(d); return a.add(b).add(c).add(d).y; } +}); L.LatLng = function (a, b, c) { var d = parseFloat(a); var e = parseFloat(b); if (isNaN(d) || isNaN(e)) throw Error('Invalid LatLng object: (' + a + ', ' + b + ')'); c !== !0 && (d = Math.max(Math.min(d, 90), -90), e = (e + 180) % 360 + (e < -180 ? 180 : -180)); this.lat = d; this.lng = e; }; L.Util.extend(L.LatLng, { DEG_TO_RAD: Math.PI / 180, RAD_TO_DEG: 180 / Math.PI, MAX_MARGIN: 1.0E-9 }); +L.LatLng.prototype = { equals: function (a) { if (!(a instanceof L.LatLng)) return !1; return Math.max(Math.abs(this.lat - a.lat), Math.abs(this.lng - a.lng)) <= L.LatLng.MAX_MARGIN; }, toString: function () { return 'LatLng(' + L.Util.formatNum(this.lat) + ', ' + L.Util.formatNum(this.lng) + ')'; } }; L.LatLngBounds = L.Class.extend({ + initialize: function (a, b) { if (a) for (var c = a instanceof Array ? a : [a, b], d = 0, e = c.length; d < e; d++) this.extend(c[d]); }, + extend: function (a) { !this._southWest && !this._northEast ? (this._southWest = new L.LatLng(a.lat, a.lng), this._northEast = new L.LatLng(a.lat, a.lng)) : (this._southWest.lat = Math.min(a.lat, this._southWest.lat), this._southWest.lng = Math.min(a.lng, this._southWest.lng), this._northEast.lat = Math.max(a.lat, this._northEast.lat), this._northEast.lng = Math.max(a.lng, this._northEast.lng)); }, + getCenter: function () { return new L.LatLng((this._southWest.lat + this._northEast.lat) / 2, (this._southWest.lng + this._northEast.lng) / 2); }, + getSouthWest: function () { return this._southWest; }, + getNorthEast: function () { return this._northEast; }, + getNorthWest: function () { return new L.LatLng(this._northEast.lat, this._southWest.lng); }, + getSouthEast: function () { return new L.LatLng(this._southWest.lat, this._northEast.lng); }, + contains: function (a) { + var b = this._southWest; var c = this._northEast; var d; a instanceof L.LatLngBounds ? (d = a.getSouthWest(), + a = a.getNorthEast()) : d = a; return d.lat >= b.lat && a.lat <= c.lat && d.lng >= b.lng && a.lng <= c.lng; + } +}); L.Projection = {}; L.Projection.SphericalMercator = { MAX_LATITUDE: 85.0511287798, project: function (a) { var b = L.LatLng.DEG_TO_RAD; var c = this.MAX_LATITUDE; var d = a.lng * b; var a = Math.max(Math.min(c, a.lat), -c) * b; var a = Math.log(Math.tan(Math.PI / 4 + a / 2)); return new L.Point(d, a); }, unproject: function (a, b) { var c = L.LatLng.RAD_TO_DEG; return new L.LatLng((2 * Math.atan(Math.exp(a.y)) - Math.PI / 2) * c, a.x * c, b); } }; L.Projection.LonLat = { project: function (a) { return new L.Point(a.lng, a.lat); }, unproject: function (a, b) { return new L.LatLng(a.y, a.x, b); } }; L.Projection.Mercator = { + MAX_LATITUDE: 85.0840591556, + R_MINOR: 6356752.3142, + R_MAJOR: 6378137, + project: function (a) { var b = L.LatLng.DEG_TO_RAD; var c = this.MAX_LATITUDE; var d = this.R_MAJOR; var e = a.lng * b * d; var a = Math.max(Math.min(c, a.lat), -c) * b; var b = this.R_MINOR / d; var b = Math.sqrt(1 - b * b); var c = b * Math.sin(a); var c = Math.pow((1 - c) / (1 + c), b * 0.5); var a = -d * Math.log(Math.tan(0.5 * (Math.PI * 0.5 - a)) / c); return new L.Point(e, a); }, + unproject: function (a, b) { + for (var c = L.LatLng.RAD_TO_DEG, d = this.R_MAJOR, e = a.x * c / d, f = this.R_MINOR / d, f = Math.sqrt(1 - f * f), d = Math.exp(-a.y / d), + g = Math.PI / 2 - 2 * Math.atan(d), h = 15, j = 0.1; Math.abs(j) > 1.0E-7 && --h > 0;)j = f * Math.sin(g), j = Math.PI / 2 - 2 * Math.atan(d * Math.pow((1 - j) / (1 + j), 0.5 * f)) - g, g += j; return new L.LatLng(g * c, e, b); + } +}; L.CRS = { latLngToPoint: function (a, b) { return this.transformation._transform(this.projection.project(a), b); }, pointToLatLng: function (a, b, c) { return this.projection.unproject(this.transformation.untransform(a, b), c); }, project: function (a) { return this.projection.project(a); } }; L.CRS.EPSG3857 = L.Util.extend({}, L.CRS, { code: 'EPSG:3857', projection: L.Projection.SphericalMercator, transformation: new L.Transformation(0.5 / Math.PI, 0.5, -0.5 / Math.PI, 0.5), project: function (a) { return this.projection.project(a).multiplyBy(6378137); } }); L.CRS.EPSG900913 = L.Util.extend({}, L.CRS.EPSG3857, { code: 'EPSG:900913' }); L.CRS.EPSG4326 = L.Util.extend({}, L.CRS, { code: 'EPSG:4326', projection: L.Projection.LonLat, transformation: new L.Transformation(1 / 360, 0.5, -1 / 360, 0.5) }); L.CRS.EPSG3395 = L.Util.extend({}, L.CRS, { code: 'EPSG:3395', projection: L.Projection.Mercator, transformation: (function () { var a = L.Projection.Mercator; return new L.Transformation(0.5 / (Math.PI * a.R_MAJOR), 0.5, -0.5 / (Math.PI * a.R_MINOR), 0.5); }()) }); L.LayerGroup = L.Class.extend({ + initialize: function (a) { this._layers = {}; if (a) for (var b = 0, c = a.length; b < c; b++) this.addLayer(a[b]); }, + addLayer: function (a) { this._layers[L.Util.stamp(a)] = a; this._map && this._map.addLayer(a); return this; }, + removeLayer: function (a) { delete this._layers[L.Util.stamp(a)]; this._map && this._map.removeLayer(a); return this; }, + clearLayers: function () { this._iterateLayers(this.removeLayer, this); return this; }, + onAdd: function (a) { this._map = a; this._iterateLayers(a.addLayer, a); }, + onRemove: function (a) { + this._iterateLayers(a.removeLayer, + a); delete this._map; + }, + _iterateLayers: function (a, b) { for (var c in this._layers) this._layers.hasOwnProperty(c) && a.call(b, this._layers[c]); } +}); L.FeatureGroup = L.LayerGroup.extend({ + includes: L.Mixin.Events, + addLayer: function (a) { this._initEvents(a); L.LayerGroup.prototype.addLayer.call(this, a); this._popupContent && a.bindPopup && a.bindPopup(this._popupContent); }, + bindPopup: function (a) { this._popupContent = a; for (var b in this._layers) this._layers.hasOwnProperty(b) && this._layers[b].bindPopup && this._layers[b].bindPopup(a); }, + _events: ['click', 'dblclick', 'mouseover', 'mouseout'], + _initEvents: function (a) { + for (var b = 0, c = this._events.length; b < c; b++) { + a.on(this._events[b], + this._propagateEvent, this); + } + }, + _propagateEvent: function (a) { a.layer = a.target; a.target = this; this.fire(a.type, a); } +}); L.TileLayer = L.Class.extend({ + includes: L.Mixin.Events, + options: { minZoom: 0, maxZoom: 18, tileSize: 256, subdomains: 'abc', errorTileUrl: '', attribution: '', opacity: 1, scheme: 'xyz', continuousWorld: !1, noWrap: !1, unloadInvisibleTiles: L.Browser.mobile, updateWhenIdle: L.Browser.mobile }, + initialize: function (a, b) { L.Util.setOptions(this, b); this._url = a; if (typeof this.options.subdomains === 'string') this.options.subdomains = this.options.subdomains.split(''); }, + onAdd: function (a, b) { + this._map = a; this._insertAtTheBottom = b; this._initContainer(); + this._createTileProto(); a.on('viewreset', function (a) { this._reset(a.hard); }, this); if (this.options.updateWhenIdle)a.on('moveend', this._update, this); else this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this), a.on('move', this._limitedUpdate, this); this._reset(); this._update(); + }, + onRemove: function () { + this._map.getPanes().tilePane.removeChild(this._container); this._container = null; this._map.off('viewreset', this._reset, this); this.options.updateWhenIdle ? this._map.off('moveend', this._update, this) + : this._map.off('move', this._limitedUpdate, this); + }, + getAttribution: function () { return this.options.attribution; }, + setOpacity: function (a) { this.options.opacity = a; this._setOpacity(a); if (L.Browser.webkit) for (i in this._tiles) this._tiles[i].style.webkitTransform += ' translate(0,0)'; }, + _setOpacity: function (a) { a < 1 && L.DomUtil.setOpacity(this._container, a); }, + _initContainer: function () { + var a = this._map.getPanes().tilePane; var b = a.firstChild; if (!this._container || a.empty) { + this._container = L.DomUtil.create('div', 'leaflet-layer'), + this._insertAtTheBottom && b ? a.insertBefore(this._container, b) : a.appendChild(this._container), this._setOpacity(this.options.opacity); + } + }, + _reset: function (a) { this._tiles = {}; if (a && this._container) this._container.innerHTML = ''; this._initContainer(); this._container.innerHTML = ''; }, + _update: function () { + var a = this._map.getPixelBounds(); var b = this.options.tileSize; var c = new L.Point(Math.floor(a.min.x / b), Math.floor(a.min.y / b)); var a = new L.Point(Math.floor(a.max.x / b), Math.floor(a.max.y / b)); var c = new L.Bounds(c, a); this._addTilesFromCenterOut(c); + this.options.unloadInvisibleTiles && this._removeOtherTiles(c); + }, + _addTilesFromCenterOut: function (a) { for (var b = [], c = a.getCenter(), d = a.min.y; d <= a.max.y; d++) for (var e = a.min.x; e <= a.max.x; e++)e + ':' + d in this._tiles || b.push(new L.Point(e, d)); b.sort(function (a, b) { return a.distanceTo(c) - b.distanceTo(c); }); a = document.createDocumentFragment(); this._tilesToLoad = b.length; d = 0; for (e = this._tilesToLoad; d < e; d++) this._addTile(b[d], a); this._container.appendChild(a); }, + _removeOtherTiles: function (a) { + var b, c, d; for (d in this._tiles) { + if (this._tiles.hasOwnProperty(d) && +(b = d.split(':'), c = parseInt(b[0], 10), b = parseInt(b[1], 10), c < a.min.x || c > a.max.x || b < a.min.y || b > a.max.y)) this._tiles[d].parentNode == this._container && this._container.removeChild(this._tiles[d]), delete this._tiles[d]; + } + }, + _addTile: function (a, b) { + var c = this._getTilePos(a); var d = this._map.getZoom(); var e = a.x + ':' + a.y; var f = 1 << d; if (!this.options.continuousWorld) { if (this.options.noWrap) { if (a.x < 0 || a.x >= f) { this._tilesToLoad--; return; } } else a.x = (a.x % f + f) % f; if (a.y < 0 || a.y >= f) { this._tilesToLoad--; return; } } var g = this._createTile(); L.DomUtil.setPosition(g, + c); this._tiles[e] = g; if (this.options.scheme == 'tms')a.y = f - a.y - 1; this._loadTile(g, a, d); b.appendChild(g); + }, + _getTilePos: function (a) { var b = this._map.getPixelOrigin(); return a.multiplyBy(this.options.tileSize).subtract(b); }, + getTileUrl: function (a, b) { return this._url.replace('{s}', this.options.subdomains[(a.x + a.y) % this.options.subdomains.length]).replace('{z}', b).replace('{x}', a.x).replace('{y}', a.y); }, + _createTileProto: function () { + this._tileImg = L.DomUtil.create('img', 'leaflet-tile'); this._tileImg.galleryimg = 'no'; + var a = this.options.tileSize; this._tileImg.style.width = a + 'px'; this._tileImg.style.height = a + 'px'; + }, + _createTile: function () { var a = this._tileImg.cloneNode(!1); a.onselectstart = a.onmousemove = L.Util.falseFn; return a; }, + _loadTile: function (a, b, c) { a._layer = this; a.onload = this._tileOnLoad; a.onerror = this._tileOnError; a.src = this.getTileUrl(b, c); }, + _tileOnLoad: function () { var a = this._layer; this.className += ' leaflet-tile-loaded'; a.fire('tileload', { tile: this, url: this.src }); a._tilesToLoad--; a._tilesToLoad || a.fire('load'); }, + _tileOnError: function () { var a = this._layer; a.fire('tileerror', { tile: this, url: this.src }); if (a = a.options.errorTileUrl) this.src = a; } +}); L.TileLayer.WMS = L.TileLayer.extend({ + defaultWmsParams: { service: 'WMS', request: 'GetMap', version: '1.1.1', layers: '', styles: '', format: 'image/jpeg', transparent: !1 }, + initialize: function (a, b) { this._url = a; this.wmsParams = L.Util.extend({}, this.defaultWmsParams); this.wmsParams.width = this.wmsParams.height = this.options.tileSize; for (var c in b) this.options.hasOwnProperty(c) || (this.wmsParams[c] = b[c]); L.Util.setOptions(this, b); }, + onAdd: function (a) { + this.wmsParams[parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs'] = a.options.crs.code; + L.TileLayer.prototype.onAdd.call(this, a); + }, + getTileUrl: function (a) { var b = this.options.tileSize; var a = a.multiplyBy(b); var b = a.add(new L.Point(b, b)); var a = this._map.unproject(a, this._zoom, !0); var b = this._map.unproject(b, this._zoom, !0); var a = this._map.options.crs.project(a); var b = this._map.options.crs.project(b); var b = [a.x, b.y, b.x, a.y].join(','); return this._url + L.Util.getParamString(this.wmsParams) + '&bbox=' + b; } +}); L.TileLayer.Canvas = L.TileLayer.extend({ + options: { async: !1 }, + initialize: function (a) { L.Util.setOptions(this, a); }, + _createTileProto: function () { this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile'); var a = this.options.tileSize; this._canvasProto.width = a; this._canvasProto.height = a; }, + _createTile: function () { var a = this._canvasProto.cloneNode(!1); a.onselectstart = a.onmousemove = L.Util.falseFn; return a; }, + _loadTile: function (a, b, c) { a._layer = this; this.drawTile(a, b, c); this.options.async || this.tileDrawn(a); }, + drawTile: function () {}, + tileDrawn: function (a) { this._tileOnLoad.call(a); } +}); L.ImageOverlay = L.Class.extend({ + includes: L.Mixin.Events, + initialize: function (a, b) { this._url = a; this._bounds = b; }, + onAdd: function (a) { this._map = a; this._image || this._initImage(); a.getPanes().overlayPane.appendChild(this._image); a.on('viewreset', this._reset, this); this._reset(); }, + onRemove: function (a) { a.getPanes().overlayPane.removeChild(this._image); a.off('viewreset', this._reset, this); }, + _initImage: function () { + this._image = L.DomUtil.create('img', 'leaflet-image-layer'); this._image.style.visibility = 'hidden'; L.Util.extend(this._image, + { galleryimg: 'no', onselectstart: L.Util.falseFn, onmousemove: L.Util.falseFn, onload: this._onImageLoad, src: this._url }); + }, + _reset: function () { var a = this._map.latLngToLayerPoint(this._bounds.getNorthWest()); var b = this._map.latLngToLayerPoint(this._bounds.getSouthEast()).subtract(a); L.DomUtil.setPosition(this._image, a); this._image.style.width = b.x + 'px'; this._image.style.height = b.y + 'px'; }, + _onImageLoad: function () { this.style.visibility = ''; } +}); L.Popup = L.Class.extend({ + includes: L.Mixin.Events, + options: { minWidth: 50, maxWidth: 300, autoPan: !0, closeButton: !0, offset: new L.Point(0, 2), autoPanPadding: new L.Point(5, 5) }, + initialize: function (a) { L.Util.setOptions(this, a); }, + onAdd: function (a) { + this._map = a; this._container || this._initLayout(); this._updateContent(); this._container.style.opacity = '0'; this._map._panes.popupPane.appendChild(this._container); this._map.on('viewreset', this._updatePosition, this); if (this._map.options.closePopupOnClick) { + this._map.on('preclick', + this._close, this); + } this._update(); this._container.style.opacity = '1'; this._opened = !0; + }, + onRemove: function (a) { a._panes.popupPane.removeChild(this._container); a.off('viewreset', this._updatePosition, this); a.off('click', this._close, this); this._container.style.opacity = '0'; this._opened = !1; }, + setLatLng: function (a) { this._latlng = a; this._opened && this._update(); return this; }, + setContent: function (a) { this._content = a; this._opened && this._update(); return this; }, + _close: function () { this._opened && this._map.removeLayer(this); }, + _initLayout: function () { + this._container = L.DomUtil.create('div', 'leaflet-popup'); if (this.options.closeButton) this._closeButton = L.DomUtil.create('a', 'leaflet-popup-close-button', this._container), this._closeButton.href = '#close', L.DomEvent.addListener(this._closeButton, 'click', this._onCloseButtonClick, this); this._wrapper = L.DomUtil.create('div', 'leaflet-popup-content-wrapper', this._container); L.DomEvent.disableClickPropagation(this._wrapper); this._contentNode = L.DomUtil.create('div', 'leaflet-popup-content', + this._wrapper); this._tipContainer = L.DomUtil.create('div', 'leaflet-popup-tip-container', this._container); this._tip = L.DomUtil.create('div', 'leaflet-popup-tip', this._tipContainer); + }, + _update: function () { this._container.style.visibility = 'hidden'; this._updateContent(); this._updateLayout(); this._updatePosition(); this._container.style.visibility = ''; this._adjustPan(); }, + _updateContent: function () { + if (this._content) { + typeof this._content === 'string' ? this._contentNode.innerHTML = this._content : (this._contentNode.innerHTML = +'', this._contentNode.appendChild(this._content)); + } + }, + _updateLayout: function () { this._container.style.width = ''; this._container.style.whiteSpace = 'nowrap'; var a = this._container.offsetWidth; this._container.style.width = (a > this.options.maxWidth ? this.options.maxWidth : a < this.options.minWidth ? this.options.minWidth : a) + 'px'; this._container.style.whiteSpace = ''; this._containerWidth = this._container.offsetWidth; }, + _updatePosition: function () { + var a = this._map.latLngToLayerPoint(this._latlng); this._containerBottom = -a.y - this.options.offset.y; + this._containerLeft = a.x - Math.round(this._containerWidth / 2) + this.options.offset.x; this._container.style.bottom = this._containerBottom + 'px'; this._container.style.left = this._containerLeft + 'px'; + }, + _adjustPan: function () { + if (this.options.autoPan) { + var a = this._container.offsetHeight; var b = this._map.layerPointToContainerPoint(new L.Point(this._containerLeft, -a - this._containerBottom)); var c = new L.Point(0, 0); var d = this.options.autoPanPadding; var e = this._map.getSize(); if (b.x < 0)c.x = b.x - d.x; if (b.x + this._containerWidth > e.x) { + c.x = b.x + +this._containerWidth - e.x + d.x; + } if (b.y < 0)c.y = b.y - d.y; if (b.y + a > e.y)c.y = b.y + a - e.y + d.y; (c.x || c.y) && this._map.panBy(c); + } + }, + _onCloseButtonClick: function (a) { this._close(); L.DomEvent.stop(a); } +}); L.Icon = L.Class.extend({ + iconUrl: L.ROOT_URL + 'images/marker.png', + shadowUrl: L.ROOT_URL + 'images/marker-shadow.png', + iconSize: new L.Point(25, 41), + shadowSize: new L.Point(41, 41), + iconAnchor: new L.Point(13, 41), + popupAnchor: new L.Point(0, -33), + initialize: function (a) { if (a) this.iconUrl = a; }, + createIcon: function () { return this._createIcon('icon'); }, + createShadow: function () { return this._createIcon('shadow'); }, + _createIcon: function (a) { + var b = this[a + 'Size']; var c = this[a + 'Url']; var d = this._createImg(c); if (!c) return null; d.className = 'leaflet-marker-' + +a; d.style.marginLeft = -this.iconAnchor.x + 'px'; d.style.marginTop = -this.iconAnchor.y + 'px'; if (b)d.style.width = b.x + 'px', d.style.height = b.y + 'px'; return d; + }, + _createImg: function (a) { var b; L.Browser.ie6 ? (b = document.createElement('div'), b.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + a + '")') : (b = document.createElement('img'), b.src = a); return b; } +}); L.Marker = L.Class.extend({ + includes: L.Mixin.Events, + options: { icon: new L.Icon(), title: '', clickable: !0, draggable: !1 }, + initialize: function (a, b) { L.Util.setOptions(this, b); this._latlng = a; }, + onAdd: function (a) { this._map = a; this._initIcon(); a.on('viewreset', this._reset, this); this._reset(); }, + onRemove: function (a) { this._removeIcon(); this.closePopup && this.closePopup(); a.off('viewreset', this._reset, this); }, + getLatLng: function () { return this._latlng; }, + setLatLng: function (a) { this._latlng = a; this._icon && this._reset(); }, + setIcon: function (a) { + this._removeIcon(); + this._icon = this._shadow = null; this.options.icon = a; this._initIcon(); this._reset(); + }, + _initIcon: function () { if (!this._icon) { this._icon = this.options.icon.createIcon(); if (this.options.title) this._icon.title = this.options.title; this._initInteraction(); } if (!this._shadow) this._shadow = this.options.icon.createShadow(); this._map._panes.markerPane.appendChild(this._icon); this._shadow && this._map._panes.shadowPane.appendChild(this._shadow); }, + _removeIcon: function () { + this._map._panes.markerPane.removeChild(this._icon); + this._shadow && this._map._panes.shadowPane.removeChild(this._shadow); + }, + _reset: function () { var a = this._map.latLngToLayerPoint(this._latlng).round(); L.DomUtil.setPosition(this._icon, a); this._shadow && L.DomUtil.setPosition(this._shadow, a); this._icon.style.zIndex = a.y; }, + _initInteraction: function () { + if (this.options.clickable) { + this._icon.className += ' leaflet-clickable'; L.DomEvent.addListener(this._icon, 'click', this._onMouseClick, this); for (var a = ['dblclick', 'mousedown', 'mouseover', 'mouseout'], b = 0; b < a.length; b++) { + L.DomEvent.addListener(this._icon, + a[b], this._fireMouseEvent, this); + } + } if (L.Handler.MarkerDrag) this.dragging = new L.Handler.MarkerDrag(this), this.options.draggable && this.dragging.enable(); + }, + _onMouseClick: function (a) { L.DomEvent.stopPropagation(a); (!this.dragging || !this.dragging.moved()) && this.fire(a.type); }, + _fireMouseEvent: function (a) { this.fire(a.type); L.DomEvent.stopPropagation(a); } +}); L.Marker.include({ openPopup: function () { this._popup.setLatLng(this._latlng); this._map.openPopup(this._popup); return this; }, closePopup: function () { this._popup && this._popup._close(); }, bindPopup: function (a, b) { b = L.Util.extend({ offset: this.options.icon.popupAnchor }, b); this._popup = new L.Popup(b); this._popup.setContent(a); this.on('click', this.openPopup, this); return this; } }); L.Path = L.Class.extend({ + includes: [L.Mixin.Events], + statics: { CLIP_PADDING: 0.5 }, + options: { stroke: !0, color: '#0033ff', weight: 5, opacity: 0.5, fill: !1, fillColor: null, fillOpacity: 0.2, clickable: !0, updateOnMoveEnd: !0 }, + initialize: function (a) { L.Util.setOptions(this, a); }, + onAdd: function (a) { + this._map = a; this._initElements(); this._initEvents(); this.projectLatlngs(); this._updatePath(); a.on('viewreset', this.projectLatlngs, this); this._updateTrigger = this.options.updateOnMoveEnd ? 'moveend' : 'viewreset'; a.on(this._updateTrigger, + this._updatePath, this); + }, + onRemove: function (a) { a._pathRoot.removeChild(this._container); a.off('viewreset', this._projectLatlngs, this); a.off(this._updateTrigger, this._updatePath, this); }, + projectLatlngs: function () {}, + setStyle: function (a) { L.Util.setOptions(this, a); this._container && this._updateStyle(); return this; }, + _initElements: function () { this._initRoot(); this._initPath(); this._initStyle(); }, + _updateViewport: function () { + var a = L.Path.CLIP_PADDING; var b = this._map.getSize(); var c = L.DomUtil.getPosition(this._map._mapPane).multiplyBy(-1).subtract(b.multiplyBy(a)); + var a = c.add(b.multiplyBy(1 + a * 2)); this._map._pathViewport = new L.Bounds(c, a); + }, + _redraw: function () { this.projectLatlngs(); this._updatePath(); } +}); L.Path.include({ bindPopup: function (a, b) { if (!this._popup || this._popup.options !== b) this._popup = new L.Popup(b); this._popup.setContent(a); if (!this._openPopupAdded) this.on('click', this._openPopup, this), this._openPopupAdded = !0; return this; }, _openPopup: function (a) { this._popup.setLatLng(a.latlng); this._map.openPopup(this._popup); } }); L.Path.SVG_NS = 'http://www.w3.org/2000/svg'; L.Browser.svg = !(!document.createElementNS || !document.createElementNS(L.Path.SVG_NS, 'svg').createSVGRect); +L.Path = L.Path.extend({ + statics: { SVG: L.Browser.svg }, + getPathString: function () {}, + _initElements: function () { this._initRoot(); this._initPath(); this._initStyle(); }, + _initRoot: function () { if (!this._map._pathRoot) this._map._pathRoot = this._createElement('svg'), this._map._panes.overlayPane.appendChild(this._map._pathRoot), this._map.on('moveend', this._updateSvgViewport, this), this._updateSvgViewport(); }, + _updateSvgViewport: function () { + this._updateViewport(); var a = this._map._pathViewport; var b = a.min; var c = a.max; var a = c.x - b.x; var c = c.y - +b.y; var d = this._map._pathRoot; var e = this._map._panes.overlayPane; L.Browser.mobileWebkit && e.removeChild(d); L.DomUtil.setPosition(d, b); d.setAttribute('width', a); d.setAttribute('height', c); d.setAttribute('viewBox', [b.x, b.y, a, c].join(' ')); L.Browser.mobileWebkit && e.appendChild(d); + }, + _initPath: function () { this._container = this._createElement('g'); this._path = this._createElement('path'); this._container.appendChild(this._path); this._map._pathRoot.appendChild(this._container); }, + _initStyle: function () { + this.options.stroke && +(this._path.setAttribute('stroke-linejoin', 'round'), this._path.setAttribute('stroke-linecap', 'round')); this.options.fill ? this._path.setAttribute('fill-rule', 'evenodd') : this._path.setAttribute('fill', 'none'); this._updateStyle(); + }, + _updateStyle: function () { + this.options.stroke && (this._path.setAttribute('stroke', this.options.color), this._path.setAttribute('stroke-opacity', this.options.opacity), this._path.setAttribute('stroke-width', this.options.weight)); this.options.fill && (this._path.setAttribute('fill', + this.options.fillColor || this.options.color), this._path.setAttribute('fill-opacity', this.options.fillOpacity)); + }, + _updatePath: function () { var a = this.getPathString(); a || (a = 'M0 0'); this._path.setAttribute('d', a); }, + _createElement: function (a) { return document.createElementNS(L.Path.SVG_NS, a); }, + _initEvents: function () { + if (this.options.clickable) { + L.Browser.vml || this._path.setAttribute('class', 'leaflet-clickable'); L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this); for (var a = ['dblclick', 'mousedown', + 'mouseover', 'mouseout'], b = 0; b < a.length; b++)L.DomEvent.addListener(this._container, a[b], this._fireMouseEvent, this); + } + }, + _onMouseClick: function (a) { (!this._map.dragging || !this._map.dragging.moved()) && this._fireMouseEvent(a); }, + _fireMouseEvent: function (a) { this.hasEventListeners(a.type) && (this.fire(a.type, { latlng: this._map.mouseEventToLatLng(a), layerPoint: this._map.mouseEventToLayerPoint(a) }), L.DomEvent.stopPropagation(a)); } +}); L.Browser.vml = (function () { var a = document.createElement('div'); a.innerHTML = ''; a = a.firstChild; a.style.behavior = 'url(#default#VML)'; return a && typeof a.adj === 'object'; }()); +L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({ + statics: { VML: !0, CLIP_PADDING: 0.02 }, + _createElement: (function () { try { return document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml'), function (a) { return document.createElement(''); }; } catch (a) { return function (a) { return document.createElement('<' + a + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">'); }; } }()), + _initRoot: function () { + if (!this._map._pathRoot) { + this._map._pathRoot = document.createElement('div'), this._map._pathRoot.className = +'leaflet-vml-container', this._map._panes.overlayPane.appendChild(this._map._pathRoot), this._map.on('moveend', this._updateViewport, this), this._updateViewport(); + } + }, + _initPath: function () { this._container = this._createElement('shape'); this._container.className += ' leaflet-vml-shape' + (this.options.clickable ? ' leaflet-clickable' : ''); this._container.coordsize = '1 1'; this._path = this._createElement('path'); this._container.appendChild(this._path); this._map._pathRoot.appendChild(this._container); }, + _initStyle: function () { + this.options.stroke + ? (this._stroke = this._createElement('stroke'), this._stroke.endcap = 'round', this._container.appendChild(this._stroke)) : this._container.stroked = !1; this.options.fill ? (this._container.filled = !0, this._fill = this._createElement('fill'), this._container.appendChild(this._fill)) : this._container.filled = !1; this._updateStyle(); + }, + _updateStyle: function () { + if (this.options.stroke) this._stroke.weight = this.options.weight + 'px', this._stroke.color = this.options.color, this._stroke.opacity = this.options.opacity; if (this.options.fill) { + this._fill.color = +this.options.fillColor || this.options.color, this._fill.opacity = this.options.fillOpacity; + } + }, + _updatePath: function () { this._container.style.display = 'none'; this._path.v = this.getPathString() + ' '; this._container.style.display = ''; } +}); L.Browser.canvas = (function () { return !!document.createElement('canvas').getContext; }()); +L.Path = L.Path.SVG && !window.L_PREFER_CANVAS || !L.Browser.canvas ? L.Path : L.Path.extend({ + statics: { CANVAS: !0, SVG: !1 }, + options: { updateOnMoveEnd: !0 }, + _initElements: function () { this._initRoot(); }, + _initRoot: function () { + var a = this._map._pathRoot; var b = this._map._canvasCtx; if (!a) { + a = this._map._pathRoot = document.createElement('canvas'), a.style.position = 'absolute', b = this._map._canvasCtx = a.getContext('2d'), b.lineCap = 'round', b.lineJoin = 'round', this._map._panes.overlayPane.appendChild(a), this._map.on('moveend', this._updateCanvasViewport, + this), this._updateCanvasViewport(); + } this._ctx = b; + }, + _updateStyle: function () { if (this.options.stroke) this._ctx.lineWidth = this.options.weight, this._ctx.strokeStyle = this.options.color; if (this.options.fill) this._ctx.fillStyle = this.options.fillColor || this.options.color; }, + _drawPath: function () { var a, b, c, d, e, f; this._ctx.beginPath(); a = 0; for (c = this._parts.length; a < c; a++) { b = 0; for (d = this._parts[a].length; b < d; b++)e = this._parts[a][b], f = (b === 0 ? 'move' : 'line') + 'To', this._ctx[f](e.x, e.y); this instanceof L.Polygon && this._ctx.closePath(); } }, + _checkIfEmpty: function () { return !this._parts.length; }, + _updatePath: function () { if (!this._checkIfEmpty()) { this._drawPath(); this._ctx.save(); this._updateStyle(); var a = this.options.opacity; var b = this.options.fillOpacity; if (this.options.fill) { if (b < 1) this._ctx.globalAlpha = b; this._ctx.fill(); } if (this.options.stroke) { if (a < 1) this._ctx.globalAlpha = a; this._ctx.stroke(); } this._ctx.restore(); } }, + _updateCanvasViewport: function () { + this._updateViewport(); var a = this._map._pathViewport; var b = a.min; var a = a.max.subtract(b); var c = this._map._pathRoot; + L.DomUtil.setPosition(c, b); c.width = a.x; c.height = a.y; c.getContext('2d').translate(-b.x, -b.y); + }, + _initEvents: function () { if (this.options.clickable) this._map.on('click', this._onClick, this); }, + _onClick: function (a) { this._containsPoint(a.layerPoint) && this.fire('click', a); }, + onRemove: function (a) { a.off('viewreset', this._projectLatlngs, this); a.off(this._updateTrigger, this._updatePath, this); a.fire(this._updateTrigger); } +}); L.Polyline = L.Path.extend({ + initialize: function (a, b) { L.Path.prototype.initialize.call(this, b); this._latlngs = a; }, + options: { smoothFactor: 1, noClip: !1, updateOnMoveEnd: !0 }, + projectLatlngs: function () { this._originalPoints = []; for (var a = 0, b = this._latlngs.length; a < b; a++) this._originalPoints[a] = this._map.latLngToLayerPoint(this._latlngs[a]); }, + getPathString: function () { for (var a = 0, b = this._parts.length, c = ''; a < b; a++)c += this._getPathPartStr(this._parts[a]); return c; }, + getLatLngs: function () { return this._latlngs; }, + setLatLngs: function (a) { + this._latlngs = +a; this._redraw(); return this; + }, + addLatLng: function (a) { this._latlngs.push(a); this._redraw(); return this; }, + spliceLatLngs: function () { var a = [].splice.apply(this._latlngs, arguments); this._redraw(); return a; }, + closestLayerPoint: function (a) { for (var b = Infinity, c = this._parts, d, e, f = null, g = 0, h = c.length; g < h; g++) for (var j = c[g], k = 1, l = j.length; k < l; k++) if (d = j[k - 1], e = j[k], d = L.LineUtil._sqClosestPointOnSegment(a, d, e), d._sqDist < b)b = d._sqDist, f = d; if (f)f.distance = Math.sqrt(b); return f; }, + _getPathPartStr: function (a) { + for (var b = +L.Path.VML, c = 0, d = a.length, e = '', f; c < d; c++)f = a[c], b && f._round(), e += (c ? 'L' : 'M') + f.x + ' ' + f.y; return e; + }, + _clipPoints: function () { var a = this._originalPoints; var b = a.length; var c; var d; var e; if (this.options.noClip) this._parts = [a]; else { var f = this._parts = []; var g = this._map._pathViewport; var h = L.LineUtil; for (d = c = 0; c < b - 1; c++) if (e = h.clipSegment(a[c], a[c + 1], g, c)) if (f[d] = f[d] || [], f[d].push(e[0]), e[1] != a[c + 1] || c == b - 2)f[d].push(e[1]), d++; } }, + _simplifyPoints: function () { + for (var a = this._parts, b = L.LineUtil, c = 0, d = a.length; c < d; c++) { + a[c] = b.simplify(a[c], + this.options.smoothFactor); + } + }, + _updatePath: function () { this._clipPoints(); this._simplifyPoints(); L.Path.prototype._updatePath.call(this); } +}); L.Polyline.include(!L.Path.CANVAS ? {} : { _containsPoint: function (a, b) { var c; var d; var e; var f; var g; var h; var j = this.options.weight / 2; L.Browser.touch && (j += 10); c = 0; for (f = this._parts.length; c < f; c++) { h = this._parts[c]; d = 0; g = h.length; for (e = g - 1; d < g; e = d++) if (b || d !== 0) if (e = L.LineUtil.pointToSegmentDistance(a, h[e], h[d]), e <= j) return !0; } return !1; } }); L.Polygon = L.Polyline.extend({ + options: { fill: !0 }, + initialize: function (a, b) { L.Polyline.prototype.initialize.call(this, a, b); if (a[0] instanceof Array) this._latlngs = a[0], this._holes = a.slice(1); }, + projectLatlngs: function () { L.Polyline.prototype.projectLatlngs.call(this); this._holePoints = []; if (this._holes) for (var a = 0, b = this._holes.length; a < b; a++) { this._holePoints[a] = []; for (var c = 0, d = this._holes[a].length; c < d; c++) this._holePoints[a][c] = this._map.latLngToLayerPoint(this._holes[a][c]); } }, + _clipPoints: function () { + var a = +[]; this._parts = [this._originalPoints].concat(this._holePoints); if (!this.options.noClip) { for (var b = 0, c = this._parts.length; b < c; b++) { var d = L.PolyUtil.clipPolygon(this._parts[b], this._map._pathViewport); d.length && a.push(d); } this._parts = a; } + }, + _getPathPartStr: function (a) { return L.Polyline.prototype._getPathPartStr.call(this, a) + (L.Browser.svg ? 'z' : 'x'); } +}); L.Polygon.include(!L.Path.CANVAS ? {} : { _containsPoint: function (a) { var b = !1; var c; var d; var e; var f; var g; var h; var j; if (L.Polyline.prototype._containsPoint.call(this, a, !0)) return !0; f = 0; for (h = this._parts.length; f < h; f++) { c = this._parts[f]; g = 0; j = c.length; for (e = j - 1; g < j; e = g++)d = c[g], e = c[e], d.y > a.y != e.y > a.y && a.x < (e.x - d.x) * (a.y - d.y) / (e.y - d.y) + d.x && (b = !b); } return b; } }); (function () { function a (a) { return L.FeatureGroup.extend({ initialize: function (a, b) { this._layers = {}; this._options = b; this.setLatLngs(a); }, setStyle: function (a) { for (var b in this._layers) this._layers.hasOwnProperty(b) && this._layers[b].setStyle && this._layers[b].setStyle(a); }, setLatLngs: function (c) { var d = 0; var e = c.length; for (this._iterateLayers(function (a) { d < e ? a.setLatLngs(c[d++]) : this.removeLayer(a); }, this); d < e;) this.addLayer(new a(c[d++], this._options)); } }); }L.MultiPolyline = a(L.Polyline); L.MultiPolygon = a(L.Polygon); })(); L.Circle = L.Path.extend({ + initialize: function (a, b, c) { L.Path.prototype.initialize.call(this, c); this._latlng = a; this._mRadius = b; }, + options: { fill: !0 }, + setLatLng: function (a) { this._latlng = a; this._redraw(); return this; }, + setRadius: function (a) { this._mRadius = a; this._redraw(); return this; }, + projectLatlngs: function () { var a = this._map.options.scale(this._map._zoom); this._point = this._map.latLngToLayerPoint(this._latlng); this._radius = this._mRadius / 40075017 * a; }, + getPathString: function () { + var a = this._point; var b = this._radius; if (this._checkIfEmpty()) return ''; + return L.Browser.svg ? 'M' + a.x + ',' + (a.y - b) + 'A' + b + ',' + b + ',0,1,1,' + (a.x - 0.1) + ',' + (a.y - b) + ' z' : (a._round(), b = Math.round(b), 'AL ' + a.x + ',' + a.y + ' ' + b + ',' + b + ' 0,23592600'); + }, + _checkIfEmpty: function () { var a = this._map._pathViewport; var b = this._radius; var c = this._point; return c.x - b > a.max.x || c.y - b > a.max.y || c.x + b < a.min.x || c.y + b < a.min.y; } +}); L.Circle.include(!L.Path.CANVAS ? {} : { _drawPath: function () { var a = this._point; this._ctx.beginPath(); this._ctx.arc(a.x, a.y, this._radius, 0, Math.PI * 2); }, _containsPoint: function (a) { var b = this.options.stroke ? this.options.weight / 2 : 0; return a.distanceTo(this._point) <= this._radius + b; } }); L.CircleMarker = L.Circle.extend({ options: { radius: 10, weight: 2 }, initialize: function (a, b) { L.Circle.prototype.initialize.call(this, a, null, b); this._radius = this.options.radius; }, projectLatlngs: function () { this._point = this._map.latLngToLayerPoint(this._latlng); }, setRadius: function (a) { this._radius = a; this._redraw(); return this; } }); L.GeoJSON = L.LayerGroup.extend({ includes: L.Mixin.Events, initialize: function (a, b) { L.Util.setOptions(this, b); this._geojson = a; this._layers = {}; a && this.addGeoJSON(a); }, addGeoJSON: function (a) { if (a.features) for (var b = 0, c = a.features.length; b < c; b++) this.addGeoJSON(a.features[b]); else b = a.type == 'Feature' ? a.geometry : a, c = L.GeoJSON.geometryToLayer(b, this.options.pointToLayer), this.fire('featureparse', { layer: c, properties: a.properties, geometryType: b.type, bbox: a.bbox, id: a.id }), this.addLayer(c); } }); +L.Util.extend(L.GeoJSON, { + geometryToLayer: function (a, b) { + var c = a.coordinates; var d; var e; var f; var g = []; switch (a.type) { + case 'Point':return d = this.coordsToLatLng(c), b ? b(d) : new L.Marker(d); case 'MultiPoint':e = 0; for (f = c.length; e < f; e++)d = this.coordsToLatLng(c[e]), d = b ? b(d) : new L.Marker(d), g.push(d); return new L.FeatureGroup(g); case 'LineString':return c = this.coordsToLatLngs(c), new L.Polyline(c); case 'Polygon':return c = this.coordsToLatLngs(c, 1), new L.Polygon(c); case 'MultiLineString':return c = this.coordsToLatLngs(c, 1), new L.MultiPolyline(c); + case 'MultiPolygon':return c = this.coordsToLatLngs(c, 2), new L.MultiPolygon(c); case 'GeometryCollection':e = 0; for (f = a.geometries.length; e < f; e++)d = this.geometryToLayer(a.geometries[e]), g.push(d); return new L.FeatureGroup(g); default:throw Error('Invalid GeoJSON object.'); + } + }, + coordsToLatLng: function (a, b) { var c = parseFloat(a[b ? 0 : 1]); var d = parseFloat(a[b ? 1 : 0]); return new L.LatLng(c, d); }, + coordsToLatLngs: function (a, b, c) { + var d; var e = []; var f; var g = a.length; for (f = 0; f < g; f++) { + d = b ? this.coordsToLatLngs(a[f], b - 1, c) : this.coordsToLatLng(a[f], + c), e.push(d); + } return e; + } +}); L.Handler = L.Class.extend({ initialize: function (a) { this._map = a; }, enabled: function () { return !!this._enabled; } }); L.Handler.MapDrag = L.Handler.extend({ + enable: function () { if (!this._enabled) { if (!this._draggable) this._draggable = new L.Draggable(this._map._mapPane, this._map._container), this._draggable.on('dragstart', this._onDragStart, this), this._draggable.on('drag', this._onDrag, this), this._draggable.on('dragend', this._onDragEnd, this); this._draggable.enable(); this._enabled = !0; } }, + disable: function () { if (this._enabled) this._draggable.disable(), this._enabled = !1; }, + moved: function () { return this._draggable && this._draggable._moved; }, + _onDragStart: function () { this._map.fire('movestart'); this._map.fire('dragstart'); }, + _onDrag: function () { this._map.fire('move'); this._map.fire('drag'); }, + _onDragEnd: function () { this._map.fire('moveend'); this._map.fire('dragend'); } +}); L.Handler.TouchZoom = L.Handler.extend({ + enable: function () { if (L.Browser.touch && !this._enabled)L.DomEvent.addListener(this._map._container, 'touchstart', this._onTouchStart, this), this._enabled = !0; }, + disable: function () { if (this._enabled)L.DomEvent.removeListener(this._map._container, 'touchstart', this._onTouchStart, this), this._enabled = !1; }, + _onTouchStart: function (a) { + if (a.touches && !(a.touches.length != 2 || this._map._animatingZoom)) { + var b = this._map.mouseEventToLayerPoint(a.touches[0]); var c = this._map.mouseEventToLayerPoint(a.touches[1]); + var d = this._map.containerPointToLayerPoint(this._map.getSize().divideBy(2)); this._startCenter = b.add(c).divideBy(2, !0); this._startDist = b.distanceTo(c); this._moved = !1; this._zooming = !0; this._centerOffset = d.subtract(this._startCenter); L.DomEvent.addListener(document, 'touchmove', this._onTouchMove, this); L.DomEvent.addListener(document, 'touchend', this._onTouchEnd, this); L.DomEvent.preventDefault(a); + } + }, + _onTouchMove: function (a) { + if (a.touches && a.touches.length == 2) { + if (!this._moved) { + this._map._mapPane.className += ' leaflet-zoom-anim', + this._map._prepareTileBg(), this._moved = !0; + } var b = this._map.mouseEventToLayerPoint(a.touches[0]); var c = this._map.mouseEventToLayerPoint(a.touches[1]); this._scale = b.distanceTo(c) / this._startDist; this._delta = b.add(c).divideBy(2, !0).subtract(this._startCenter); this._map._tileBg.style.webkitTransform = [L.DomUtil.getTranslateString(this._delta), L.DomUtil.getScaleString(this._scale, this._startCenter)].join(' '); L.DomEvent.preventDefault(a); + } + }, + _onTouchEnd: function () { + if (this._moved && this._zooming) { + this._zooming = +!1; var a = this._map.getZoom(); var b = Math.log(this._scale) / Math.LN2; var b = this._map._limitZoom(a + (b > 0 ? Math.ceil(b) : Math.floor(b))); var a = b - a; var c = this._centerOffset.subtract(this._delta).divideBy(this._scale); var d = this._map.unproject(this._map.getPixelOrigin().add(this._startCenter).add(c)); L.DomEvent.removeListener(document, 'touchmove', this._onTouchMove); L.DomEvent.removeListener(document, 'touchend', this._onTouchEnd); this._map._runAnimation(d, b, Math.pow(2, a) / this._scale, this._startCenter.add(c)); + } + } +}); L.Handler.ScrollWheelZoom = L.Handler.extend({ + enable: function () { if (!this._enabled)L.DomEvent.addListener(this._map._container, 'mousewheel', this._onWheelScroll, this), this._delta = 0, this._enabled = !0; }, + disable: function () { if (this._enabled)L.DomEvent.removeListener(this._map._container, 'mousewheel', this._onWheelScroll), this._enabled = !1; }, + _onWheelScroll: function (a) { + this._delta += L.DomEvent.getWheelDelta(a); this._lastMousePos = this._map.mouseEventToContainerPoint(a); clearTimeout(this._timer); this._timer = setTimeout(L.Util.bind(this._performZoom, + this), 50); L.DomEvent.preventDefault(a); + }, + _performZoom: function () { var a = Math.round(this._delta); var a = Math.max(Math.min(a, 4), -4); this._delta = 0; if (a) { var b = this._getCenterForScrollWheelZoom(this._lastMousePos, a); var a = this._map.getZoom() + a; this._map._limitZoom(a) != this._map._zoom && this._map.setView(b, a); } }, + _getCenterForScrollWheelZoom: function (a, b) { + var c = this._map.getPixelBounds().getCenter(); var d = this._map.getSize().divideBy(2); var d = a.subtract(d).multiplyBy(1 - Math.pow(2, -b)); return this._map.unproject(c.add(d), this._map._zoom, + !0); + } +}); L.Handler.DoubleClickZoom = L.Handler.extend({ enable: function () { if (!this._enabled) this._map.on('dblclick', this._onDoubleClick, this._map), this._enabled = !0; }, disable: function () { if (this._enabled) this._map.off('dblclick', this._onDoubleClick, this._map), this._enabled = !1; }, _onDoubleClick: function (a) { this.setView(a.latlng, this._zoom + 1); } }); L.Handler.ShiftDragZoom = L.Handler.extend({ + initialize: function (a) { this._map = a; this._container = a._container; this._pane = a._panes.overlayPane; }, + enable: function () { if (!this._enabled)L.DomEvent.addListener(this._container, 'mousedown', this._onMouseDown, this), this._enabled = !0; }, + disable: function () { if (this._enabled)L.DomEvent.removeListener(this._container, 'mousedown', this._onMouseDown), this._enabled = !1; }, + _onMouseDown: function (a) { + if (!a.shiftKey || a.which != 1 && a.button != 1) return !1; L.DomUtil.disableTextSelection(); + this._startLayerPoint = this._map.mouseEventToLayerPoint(a); this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._pane); L.DomUtil.setPosition(this._box, this._startLayerPoint); this._container.style.cursor = 'crosshair'; L.DomEvent.addListener(document, 'mousemove', this._onMouseMove, this); L.DomEvent.addListener(document, 'mouseup', this._onMouseUp, this); L.DomEvent.preventDefault(a); + }, + _onMouseMove: function (a) { + var b = this._map.mouseEventToLayerPoint(a); var a = b.x - this._startLayerPoint.x; var c = b.y - this._startLayerPoint.y; + var b = new L.Point(Math.min(b.x, this._startLayerPoint.x), Math.min(b.y, this._startLayerPoint.y)); L.DomUtil.setPosition(this._box, b); this._box.style.width = Math.abs(a) - 4 + 'px'; this._box.style.height = Math.abs(c) - 4 + 'px'; + }, + _onMouseUp: function (a) { + this._pane.removeChild(this._box); this._container.style.cursor = ''; L.DomUtil.enableTextSelection(); L.DomEvent.removeListener(document, 'mousemove', this._onMouseMove); L.DomEvent.removeListener(document, 'mouseup', this._onMouseUp); a = this._map.mouseEventToLayerPoint(a); this._map.fitBounds(new L.LatLngBounds(this._map.layerPointToLatLng(this._startLayerPoint), + this._map.layerPointToLatLng(a))); + } +}); L.Handler.MarkerDrag = L.Handler.extend({ + initialize: function (a) { this._marker = a; }, + enable: function () { if (!this._enabled) { if (!this._draggable) this._draggable = new L.Draggable(this._marker._icon, this._marker._icon), this._draggable.on('dragstart', this._onDragStart, this), this._draggable.on('drag', this._onDrag, this), this._draggable.on('dragend', this._onDragEnd, this); this._draggable.enable(); this._enabled = !0; } }, + disable: function () { if (this._enabled) this._draggable.disable(), this._enabled = !1; }, + moved: function () { + return this._draggable && +this._draggable._moved; + }, + _onDragStart: function () { this._marker.closePopup(); this._marker.fire('movestart'); this._marker.fire('dragstart'); }, + _onDrag: function () { var a = L.DomUtil.getPosition(this._marker._icon); this._marker._shadow && L.DomUtil.setPosition(this._marker._shadow, a); this._marker._latlng = this._marker._map.layerPointToLatLng(a); this._marker.fire('move'); this._marker.fire('drag'); }, + _onDragEnd: function () { this._marker.fire('moveend'); this._marker.fire('dragend'); } +}); L.Control = {}; L.Control.Position = { TOP_LEFT: 'topLeft', TOP_RIGHT: 'topRight', BOTTOM_LEFT: 'bottomLeft', BOTTOM_RIGHT: 'bottomRight' }; L.Control.Zoom = L.Class.extend({ + onAdd: function (a) { this._map = a; this._container = L.DomUtil.create('div', 'leaflet-control-zoom'); this._zoomInButton = this._createButton('Zoom in', 'leaflet-control-zoom-in', this._map.zoomIn, this._map); this._zoomOutButton = this._createButton('Zoom out', 'leaflet-control-zoom-out', this._map.zoomOut, this._map); this._container.appendChild(this._zoomInButton); this._container.appendChild(this._zoomOutButton); }, + getContainer: function () { return this._container; }, + getPosition: function () { return L.Control.Position.TOP_LEFT; }, + _createButton: function (a, b, c, d) { var e = document.createElement('a'); e.href = '#'; e.title = a; e.className = b; L.DomEvent.disableClickPropagation(e); L.DomEvent.addListener(e, 'click', L.DomEvent.preventDefault); L.DomEvent.addListener(e, 'click', c, d); return e; } +}); L.Control.Attribution = L.Class.extend({ + onAdd: function (a) { this._container = L.DomUtil.create('div', 'leaflet-control-attribution'); this._map = a; this._prefix = 'Powered by Leaflet'; this._attributions = {}; this._update(); }, + getPosition: function () { return L.Control.Position.BOTTOM_RIGHT; }, + getContainer: function () { return this._container; }, + setPrefix: function (a) { this._prefix = a; this._update(); }, + addAttribution: function (a) { a && (this._attributions[a] = !0, this._update()); }, + removeAttribution: function (a) { + a && +(delete this._attributions[a], this._update()); + }, + _update: function () { if (this._map) { var a = []; var b; for (b in this._attributions) this._attributions.hasOwnProperty(b) && a.push(b); b = []; this._prefix && b.push(this._prefix); a.length && b.push(a.join(', ')); this._container.innerHTML = b.join(' — '); } } +}); L.Control.Layers = L.Class.extend({ + options: { collapsed: !0 }, + initialize: function (a, b, c) { L.Util.setOptions(this, c); this._layers = {}; for (var d in a)a.hasOwnProperty(d) && this._addLayer(a[d], d); for (d in b)b.hasOwnProperty(d) && this._addLayer(b[d], d, !0); }, + onAdd: function (a) { this._map = a; this._initLayout(); this._update(); }, + getContainer: function () { return this._container; }, + getPosition: function () { return L.Control.Position.TOP_RIGHT; }, + addBaseLayer: function (a, b) { this._addLayer(a, b); this._update(); return this; }, + addOverlay: function (a, + b) { this._addLayer(a, b, !0); this._update(); return this; }, + removeLayer: function (a) { delete this._layers[L.Util.stamp(a)]; this._update(); return this; }, + _initLayout: function () { + this._container = L.DomUtil.create('div', 'leaflet-control-layers'); L.DomEvent.disableClickPropagation(this._container); this._form = L.DomUtil.create('form', 'leaflet-control-layers-list'); if (this.options.collapsed) { + L.DomEvent.addListener(this._container, 'mouseover', this._expand, this); L.DomEvent.addListener(this._container, 'mouseout', this._collapse, + this); var a = this._layersLink = L.DomUtil.create('a', 'leaflet-control-layers-toggle'); a.href = '#'; a.title = 'Layers'; L.DomEvent.addListener(a, 'focus', this._expand, this); L.DomEvent.addListener(this._map, L.Draggable.START, this._collapse, this); this._container.appendChild(a); + } else this._expand(); this._baseLayersList = L.DomUtil.create('div', 'leaflet-control-layers-base', this._form); this._separator = L.DomUtil.create('div', 'leaflet-control-layers-separator', this._form); this._overlaysList = L.DomUtil.create('div', 'leaflet-control-layers-overlays', + this._form); this._container.appendChild(this._form); + }, + _addLayer: function (a, b, c) { this._layers[L.Util.stamp(a)] = { layer: a, name: b, overlay: c }; }, + _update: function () { if (this._container) { this._baseLayersList.innerHTML = ''; this._overlaysList.innerHTML = ''; var a = !1; var b = !1; var c; for (c in this._layers) if (this._layers.hasOwnProperty(c)) { var d = this._layers[c]; this._addItem(d); b = b || d.overlay; a = a || !d.overlay; } this._separator.style.display = b && a ? '' : 'none'; } }, + _addItem: function (a) { + var b = document.createElement('label'); var c = document.createElement('input'); + if (!a.overlay)c.name = 'leaflet-base-layers'; c.type = a.overlay ? 'checkbox' : 'radio'; c.checked = this._map.hasLayer(a.layer); c.layerId = L.Util.stamp(a.layer); L.DomEvent.addListener(c, 'click', this._onInputClick, this); var d = document.createTextNode(' ' + a.name); b.appendChild(c); b.appendChild(d); (a.overlay ? this._overlaysList : this._baseLayersList).appendChild(b); + }, + _onInputClick: function () { + var a; var b; var c; var d = this._form.getElementsByTagName('input'); var e = d.length; for (a = 0; a < e; a++) { + b = d[a], c = this._layers[b.layerId], b.checked ? this._map.addLayer(c.layer, + !c.overlay) : this._map.removeLayer(c.layer); + } + }, + _expand: function () { L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded'); }, + _collapse: function () { this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', ''); } +}); L.Map = L.Class.extend({ + includes: L.Mixin.Events, + options: { crs: L.CRS.EPSG3857 || L.CRS.EPSG4326, scale: function (a) { return 256 * (1 << a); }, center: null, zoom: null, layers: [], dragging: !0, touchZoom: L.Browser.touch && !L.Browser.android, scrollWheelZoom: !L.Browser.touch, doubleClickZoom: !0, shiftDragZoom: !0, zoomControl: !0, attributionControl: !0, fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android, zoomAnimation: L.DomUtil.TRANSITION && !L.Browser.android && !L.Browser.mobileOpera, trackResize: !0, closePopupOnClick: !0 }, + initialize: function (a, + b) { L.Util.setOptions(this, b); this._container = L.DomUtil.get(a); this._initLayout(); L.DomEvent && (this._initEvents(), L.Handler && this._initInteraction(), L.Control && this._initControls()); var c = this.options.center; var d = this.options.zoom; c !== null && d !== null && this.setView(c, d, !0); c = this.options.layers; c = c instanceof Array ? c : [c]; this._tileLayersNum = 0; this._initLayers(c); }, + setView: function (a, b) { this._resetView(a, this._limitZoom(b)); return this; }, + setZoom: function (a) { return this.setView(this.getCenter(), a); }, + zoomIn: function () { + return this.setZoom(this._zoom + +1); + }, + zoomOut: function () { return this.setZoom(this._zoom - 1); }, + fitBounds: function (a) { var b = this.getBoundsZoom(a); return this.setView(a.getCenter(), b); }, + fitWorld: function () { var a = new L.LatLng(-60, -170); var b = new L.LatLng(85, 179); return this.fitBounds(new L.LatLngBounds(a, b)); }, + panTo: function (a) { return this.setView(a, this._zoom); }, + panBy: function (a) { this.fire('movestart'); this._rawPanBy(a); this.fire('move'); this.fire('moveend'); return this; }, + addLayer: function (a, b) { + var c = L.Util.stamp(a); if (this._layers[c]) return this; + this._layers[c] = a; if (a.options && !isNaN(a.options.maxZoom)) this._layersMaxZoom = Math.max(this._layersMaxZoom || 0, a.options.maxZoom); if (a.options && !isNaN(a.options.minZoom)) this._layersMinZoom = Math.min(this._layersMinZoom || Infinity, a.options.minZoom); this.options.zoomAnimation && L.TileLayer && a instanceof L.TileLayer && (this._tileLayersNum++, a.on('load', this._onTileLayerLoad, this)); this.attributionControl && a.getAttribution && this.attributionControl.addAttribution(a.getAttribution()); c = function () { + a.onAdd(this, + b); this.fire('layeradd', { layer: a }); + }; if (this._loaded)c.call(this); else this.on('load', c, this); return this; + }, + removeLayer: function (a) { var b = L.Util.stamp(a); this._layers[b] && (a.onRemove(this), delete this._layers[b], this.options.zoomAnimation && L.TileLayer && a instanceof L.TileLayer && (this._tileLayersNum--, a.off('load', this._onTileLayerLoad, this)), this.attributionControl && a.getAttribution && this.attributionControl.removeAttribution(a.getAttribution()), this.fire('layerremove', { layer: a })); return this; }, + hasLayer: function (a) { + return L.Util.stamp(a) in +this._layers; + }, + invalidateSize: function () { var a = map.getSize(); this._sizeChanged = !0; this._rawPanBy(a.subtract(map.getSize()).divideBy(2)); this.fire('move'); clearTimeout(this._sizeTimer); this._sizeTimer = setTimeout(L.Util.bind(function () { this.fire('moveend'); }, this), 200); return this; }, + getCenter: function (a) { var b = this.getSize().divideBy(2); return this.unproject(this._getTopLeftPoint().add(b), this._zoom, a); }, + getZoom: function () { return this._zoom; }, + getBounds: function () { + var a = this.getPixelBounds(); var b = this.unproject(new L.Point(a.min.x, + a.max.y)); var a = this.unproject(new L.Point(a.max.x, a.min.y)); return new L.LatLngBounds(b, a); + }, + getMinZoom: function () { return isNaN(this.options.minZoom) ? this._layersMinZoom || 0 : this.options.minZoom; }, + getMaxZoom: function () { return isNaN(this.options.maxZoom) ? this._layersMaxZoom || Infinity : this.options.maxZoom; }, + getBoundsZoom: function (a) { + var b = this.getSize(); var c = this.getMinZoom(); var d = this.getMaxZoom(); var e = a.getNorthEast(); var a = a.getSouthWest(); var f; var g; do { + c++, f = this.project(e, c), g = this.project(a, c), f = new L.Point(f.x - g.x, g.y - +f.y); + } while (f.x <= b.x && f.y <= b.y && c <= d);return c - 1; + }, + getSize: function () { if (!this._size || this._sizeChanged) this._size = new L.Point(this._container.clientWidth, this._container.clientHeight), this._sizeChanged = !1; return this._size; }, + getPixelBounds: function () { var a = this._getTopLeftPoint(); var b = this.getSize(); return new L.Bounds(a, a.add(b)); }, + getPixelOrigin: function () { return this._initialTopLeftPoint; }, + getPanes: function () { return this._panes; }, + mouseEventToContainerPoint: function (a) { + return L.DomEvent.getMousePosition(a, + this._container); + }, + mouseEventToLayerPoint: function (a) { return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(a)); }, + mouseEventToLatLng: function (a) { return this.layerPointToLatLng(this.mouseEventToLayerPoint(a)); }, + containerPointToLayerPoint: function (a) { return a.subtract(L.DomUtil.getPosition(this._mapPane)); }, + layerPointToContainerPoint: function (a) { return a.add(L.DomUtil.getPosition(this._mapPane)); }, + layerPointToLatLng: function (a) { return this.unproject(a.add(this._initialTopLeftPoint)); }, + latLngToLayerPoint: function (a) { return this.project(a)._round()._subtract(this._initialTopLeftPoint); }, + project: function (a, b) { b = typeof b === 'undefined' ? this._zoom : b; return this.options.crs.latLngToPoint(a, this.options.scale(b)); }, + unproject: function (a, b, c) { b = typeof b === 'undefined' ? this._zoom : b; return this.options.crs.pointToLatLng(a, this.options.scale(b), c); }, + _initLayout: function () { + var a = this._container; a.className += ' leaflet-container'; this.options.fadeAnimation && (a.className += ' leaflet-fade-anim'); var b = L.DomUtil.getStyle(a, 'position'); if (b != 'absolute' && b != 'relative')a.style.position = 'relative'; this._initPanes(); + this._initControlPos && this._initControlPos(); + }, + _initPanes: function () { + var a = this._panes = {}; this._mapPane = a.mapPane = this._createPane('leaflet-map-pane', this._container); this._tilePane = a.tilePane = this._createPane('leaflet-tile-pane', this._mapPane); this._objectsPane = a.objectsPane = this._createPane('leaflet-objects-pane', this._mapPane); a.shadowPane = this._createPane('leaflet-shadow-pane'); a.overlayPane = this._createPane('leaflet-overlay-pane'); a.markerPane = this._createPane('leaflet-marker-pane'); a.popupPane = +this._createPane('leaflet-popup-pane'); + }, + _createPane: function (a, b) { return L.DomUtil.create('div', a, b || this._objectsPane); }, + _resetView: function (a, b, c) { + var d = this._zoom != b; this.fire('movestart'); this._zoom = b; this._initialTopLeftPoint = this._getNewTopLeftPoint(a); c ? this._initialTopLeftPoint._add(L.DomUtil.getPosition(this._mapPane)) : L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0)); this._tileLayersToLoad = this._tileLayersNum; this.fire('viewreset', { hard: !c }); this.fire('move'); d && this.fire('zoomend'); + this.fire('moveend'); if (!this._loaded) this._loaded = !0, this.fire('load'); + }, + _initLayers: function (a) { this._layers = {}; for (var b = 0, c = a.length; b < c; b++) this.addLayer(a[b]); }, + _initControls: function () { this.options.zoomControl && this.addControl(new L.Control.Zoom()); if (this.options.attributionControl) this.attributionControl = new L.Control.Attribution(), this.addControl(this.attributionControl); }, + _rawPanBy: function (a) { var b = L.DomUtil.getPosition(this._mapPane); L.DomUtil.setPosition(this._mapPane, b.subtract(a)); }, + _initEvents: function () { + L.DomEvent.addListener(this._container, + 'click', this._onMouseClick, this); for (var a = ['dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove'], b = 0; b < a.length; b++)L.DomEvent.addListener(this._container, a[b], this._fireMouseEvent, this); this.options.trackResize && L.DomEvent.addListener(window, 'resize', this._onResize, this); + }, + _onResize: function () { L.Util.requestAnimFrame(this.invalidateSize, this); }, + _onMouseClick: function (a) { if (!this.dragging || !this.dragging.moved()) this.fire('pre' + a.type), this._fireMouseEvent(a); }, + _fireMouseEvent: function (a) { + var b = +a.type; var b = b == 'mouseenter' ? 'mouseover' : b == 'mouseleave' ? 'mouseout' : b; this.hasEventListeners(b) && this.fire(b, { latlng: this.mouseEventToLatLng(a), layerPoint: this.mouseEventToLayerPoint(a) }); + }, + _initInteraction: function () { var a = { dragging: L.Handler.MapDrag, touchZoom: L.Handler.TouchZoom, doubleClickZoom: L.Handler.DoubleClickZoom, scrollWheelZoom: L.Handler.ScrollWheelZoom, shiftDragZoom: L.Handler.ShiftDragZoom }; var b; for (b in a)a.hasOwnProperty(b) && a[b] && (this[b] = new a[b](this), this.options[b] && this[b].enable()); }, + _onTileLayerLoad: function () { + this._tileLayersToLoad--; + if (this._tileLayersNum && !this._tileLayersToLoad && this._tileBg)clearTimeout(this._clearTileBgTimer), this._clearTileBgTimer = setTimeout(L.Util.bind(this._clearTileBg, this), 500); + }, + _getTopLeftPoint: function () { if (!this._loaded) throw Error('Set map center and zoom first.'); return this._initialTopLeftPoint.subtract(L.DomUtil.getPosition(this._mapPane)); }, + _getNewTopLeftPoint: function (a) { var b = this.getSize().divideBy(2); return this.project(a).subtract(b).round(); }, + _limitZoom: function (a) { + var b = this.getMinZoom(); + var c = this.getMaxZoom(); return Math.max(b, Math.min(c, a)); + } +}); L.Map.include({ + locate: function (a) { var b = { timeout: 1E4 }; L.Util.extend(b, a); navigator.geolocation ? navigator.geolocation.getCurrentPosition(L.Util.bind(this._handleGeolocationResponse, this), L.Util.bind(this._handleGeolocationError, this), b) : this.fire('locationerror', { code: 0, message: 'Geolocation not supported.' }); return this; }, + locateAndSetView: function (a, b) { this._setViewOnLocate = !0; this._maxLocateZoom = a || Infinity; return this.locate(b); }, + _handleGeolocationError: function (a) { + var a = a.code; var b = a == 1 ? 'permission denied' + : a == 2 ? 'position unavailable' : 'timeout'; if (this._setViewOnLocate) this.fitWorld(), this._setViewOnLocate = !1; this.fire('locationerror', { code: a, message: 'Geolocation error: ' + b + '.' }); + }, + _handleGeolocationResponse: function (a) { + var b = 180 * a.coords.accuracy / 4E7; var c = b * 2; var d = a.coords.latitude; var e = a.coords.longitude; var f = new L.LatLng(d - b, e - c); var b = new L.LatLng(d + b, e + c); var f = new L.LatLngBounds(f, b); if (this._setViewOnLocate)b = Math.min(this.getBoundsZoom(f), this._maxLocateZoom), this.setView(f.getCenter(), b), this._setViewOnLocate = !1; + this.fire('locationfound', { latlng: new L.LatLng(d, e), bounds: f, accuracy: a.coords.accuracy }); + } +}); L.Map.include({ openPopup: function (a) { this.closePopup(); this._popup = a; return this.addLayer(a); }, closePopup: function () { this._popup && this.removeLayer(this._popup); return this; } }); L.Map.include(!L.Transition || !L.Transition.implemented() ? {} : { + setView: function (a, b, c) { var b = this._limitZoom(b); var d = this._zoom != b; if (this._loaded && !c && this._layers && (c = this._getNewTopLeftPoint(a).subtract(this._getTopLeftPoint()), d ? this._zoomToIfCenterInView && this._zoomToIfCenterInView(a, b, c) : this._panByIfClose(c))) return this; this._resetView(a, b); return this; }, + panBy: function (a) { + if (!this._panTransition) { + this._panTransition = new L.Transition(this._mapPane, { duration: 0.3 }), this._panTransition.on('step', this._onPanTransitionStep, + this), this._panTransition.on('end', this._onPanTransitionEnd, this); + } this.fire(this, 'movestart'); this._panTransition.run({ position: L.DomUtil.getPosition(this._mapPane).subtract(a) }); return this; + }, + _onPanTransitionStep: function () { this.fire('move'); }, + _onPanTransitionEnd: function () { this.fire('moveend'); }, + _panByIfClose: function (a) { if (this._offsetIsWithinView(a)) return this.panBy(a), !0; return !1; }, + _offsetIsWithinView: function (a, b) { var c = b || 1; var d = this.getSize(); return Math.abs(a.x) <= d.x * c && Math.abs(a.y) <= d.y * c; } +}); L.Map.include(!L.DomUtil.TRANSITION ? {} : { + _zoomToIfCenterInView: function (a, b, c) { if (this._animatingZoom) return !0; if (!this.options.zoomAnimation) return !1; var d = Math.pow(2, b - this._zoom); var c = c.divideBy(1 - 1 / d); if (!this._offsetIsWithinView(c, 1)) return !1; this._mapPane.className += ' leaflet-zoom-anim'; c = this.containerPointToLayerPoint(this.getSize().divideBy(2)).add(c); this._prepareTileBg(); this._runAnimation(a, b, d, c); return !0; }, + _runAnimation: function (a, b, c, d) { + this._animatingZoom = !0; this._animateToCenter = a; this._animateToZoom = +b; a = L.DomUtil.TRANSFORM; if (L.Browser.gecko || window.opera) this._tileBg.style[a] += ' translate(0,0)'; L.Browser.android ? (this._tileBg.style[a + 'Origin'] = d.x + 'px ' + d.y + 'px', c = 'scale(' + c + ')') : c = L.DomUtil.getScaleString(c, d); L.Util.falseFn(this._tileBg.offsetWidth); d = {}; d[a] = this._tileBg.style[a] + ' ' + c; this._tileBg.transition.run(d); + }, + _prepareTileBg: function () { + if (!this._tileBg) this._tileBg = this._createPane('leaflet-tile-pane', this._mapPane), this._tileBg.style.zIndex = 1; var a = this._tilePane; var b = this._tileBg; b.style[L.DomUtil.TRANSFORM] = +''; b.style.visibility = 'hidden'; b.empty = !0; a.empty = !1; this._tilePane = this._panes.tilePane = b; this._tileBg = a; if (!this._tileBg.transition) this._tileBg.transition = new L.Transition(this._tileBg, { duration: 0.3, easing: 'cubic-bezier(0.25,0.1,0.25,0.75)' }), this._tileBg.transition.on('end', this._onZoomTransitionEnd, this); this._stopLoadingBgTiles(); + }, + _stopLoadingBgTiles: function () { + for (var a = [].slice.call(this._tileBg.getElementsByTagName('img')), b = 0, c = a.length; b < c; b++) { + a[b].complete || (a[b].parentNode.removeChild(a[b]), + a[b] = null); + } + }, + _onZoomTransitionEnd: function () { this._restoreTileFront(); L.Util.falseFn(this._tileBg.offsetWidth); this._resetView(this._animateToCenter, this._animateToZoom, !0); this._mapPane.className = this._mapPane.className.replace(' leaflet-zoom-anim', ''); this._animatingZoom = !1; }, + _restoreTileFront: function () { this._tilePane.innerHTML = ''; this._tilePane.style.visibility = ''; this._tilePane.style.zIndex = 2; this._tileBg.style.zIndex = 1; }, + _clearTileBg: function () { + if (!this._animatingZoom && !this.touchZoom._zooming) { + this._tileBg.innerHTML = +''; + } + } +}); L.Map.include({ + addControl: function (a) { a.onAdd(this); var b = a.getPosition(); var c = this._controlCorners[b]; var a = a.getContainer(); L.DomUtil.addClass(a, 'leaflet-control'); b.indexOf('bottom') != -1 ? c.insertBefore(a, c.firstChild) : c.appendChild(a); return this; }, + removeControl: function (a) { var b = this._controlCorners[a.getPosition()]; var c = a.getContainer(); b.removeChild(c); if (a.onRemove)a.onRemove(this); return this; }, + _initControlPos: function () { + var a = this._controlCorners = {}; var b = L.DomUtil.create('div', 'leaflet-control-container', + this._container); L.Browser.touch && (b.className += ' leaflet-big-buttons'); a.topLeft = L.DomUtil.create('div', 'leaflet-top leaflet-left', b); a.topRight = L.DomUtil.create('div', 'leaflet-top leaflet-right', b); a.bottomLeft = L.DomUtil.create('div', 'leaflet-bottom leaflet-left', b); a.bottomRight = L.DomUtil.create('div', 'leaflet-bottom leaflet-right', b); + } +}); diff --git a/test/support/assert.js b/test/support/assert.js index 1d449ea2..a088a967 100644 --- a/test/support/assert.js +++ b/test/support/assert.js @@ -23,8 +23,8 @@ var assert = module.exports = exports = require('assert'); * @param {function} callback Will call to home with null in case there is no error, otherwise with the error itself * @see FUZZY in http://www.imagemagick.org/script/command-line-options.php#metric */ -assert.imageBufferIsSimilarToFile = function(buffer, referenceImageRelativeFilePath, tolerance, callback) { - callback = callback || function(err) { assert.ifError(err); }; +assert.imageBufferIsSimilarToFile = function (buffer, referenceImageRelativeFilePath, tolerance, callback) { + callback = callback || function (err) { assert.ifError(err); }; var referenceImageFilePath = path.resolve(referenceImageRelativeFilePath); var referenceImageBuffer = fs.readFileSync(referenceImageFilePath, { encoding: null }); @@ -32,21 +32,21 @@ assert.imageBufferIsSimilarToFile = function(buffer, referenceImageRelativeFileP assert.imageBuffersAreSimilar(buffer, referenceImageBuffer, tolerance, callback); }; -assert.imageBuffersAreSimilar = function(bufferA, bufferB, tolerance, callback) { - var testImage = mapnik.Image.fromBytes(Buffer.isBuffer(bufferA) ? bufferA : new Buffer(bufferA, 'binary')); - var referenceImage = mapnik.Image.fromBytes(Buffer.isBuffer(bufferB) ? bufferB : new Buffer(bufferB, 'binary')); +assert.imageBuffersAreSimilar = function (bufferA, bufferB, tolerance, callback) { + var testImage = mapnik.Image.fromBytes(Buffer.isBuffer(bufferA) ? bufferA : Buffer.from(bufferA, 'binary')); + var referenceImage = mapnik.Image.fromBytes(Buffer.isBuffer(bufferB) ? bufferB : Buffer.from(bufferB, 'binary')); imagesAreSimilar(testImage, referenceImage, tolerance, callback); }; -assert.imageIsSimilarToFile = function(testImage, referenceImageRelativeFilePath, tolerance, callback, format='png') { - callback = callback || function(err) { assert.ifError(err); }; +assert.imageIsSimilarToFile = function (testImage, referenceImageRelativeFilePath, tolerance, callback, format = 'png') { + callback = callback || function (err) { assert.ifError(err); }; var referenceImageFilePath = path.resolve(referenceImageRelativeFilePath); - var referenceImage = mapnik.Image.fromBytes(fs.readFileSync(referenceImageFilePath, { encoding: null })); + var referenceImage = mapnik.Image.fromBytes(fs.readFileSync(referenceImageFilePath, { encoding: null })); - imagesAreSimilar(testImage, referenceImage, tolerance, function(err) { + imagesAreSimilar(testImage, referenceImage, tolerance, function (err) { if (err) { var testImageFilePath = randomImagePath(format); testImage.save(testImageFilePath, format); @@ -55,7 +55,7 @@ assert.imageIsSimilarToFile = function(testImage, referenceImageRelativeFilePath }, format); }; -function imagesAreSimilar(testImage, referenceImage, tolerance, callback, format='png') { +function imagesAreSimilar (testImage, referenceImage, tolerance, callback, format = 'png') { if (testImage.width() !== referenceImage.width() || testImage.height() !== referenceImage.height()) { return callback(new Error('Images are not the same size')); } @@ -79,18 +79,18 @@ function imagesAreSimilar(testImage, referenceImage, tolerance, callback, format } } -function randomImagePath(format='png') { +function randomImagePath (format = 'png') { return path.resolve('test/results/' + format + '/image-test-' + Date.now() + '.' + format); } -assert.response = function(server, req, res, callback) { +assert.response = function (server, req, res, callback) { if (!callback) { callback = res; res = {}; } - var port = 0, // let the OS to choose a free port - host = '127.0.0.1'; + var port = 0; // let the OS to choose a free port + var host = '127.0.0.1'; var listener = server.listen(port, host); listener.on('error', callback); @@ -111,7 +111,7 @@ assert.response = function(server, req, res, callback) { requestParams.body = req.body || req.data; } - request(requestParams, function assert$response$requestHandler(error, response, body) { + request(requestParams, function assert$response$requestHandler (error, response, body) { listener.close(function () { if (error) { return callback(null, error); @@ -125,11 +125,11 @@ assert.response = function(server, req, res, callback) { }); }; -function validateResponseBody(response, expected) { +function validateResponseBody (response, expected) { if (expected.body) { - var eql = expected.body instanceof RegExp ? - expected.body.test(response.body) : - expected.body === response.body; + var eql = expected.body instanceof RegExp + ? expected.body.test(response.body) + : expected.body === response.body; if (!eql) { return new Error(colorize( '[red]{Invalid response body.}\n' + @@ -140,7 +140,7 @@ function validateResponseBody(response, expected) { } } -function validateResponseStatus(response, expected) { +function validateResponseStatus (response, expected) { var status = expected.status || expected.statusCode; const message = colorize('[red]{Invalid response status code.}\n' + ' Expected: [green]{' + status + '}\n' + @@ -157,15 +157,15 @@ function validateResponseStatus(response, expected) { } } -function validateResponseHeaders(response, expected) { +function validateResponseHeaders (response, expected) { // Assert response headers if (expected.headers) { var keys = Object.keys(expected.headers); for (var i = 0, len = keys.length; i < len; ++i) { - var name = keys[i], - actual = response.headers[name.toLowerCase()], - expectedHeader = expected.headers[name], - headerEql = expectedHeader instanceof RegExp ? expectedHeader.test(actual) : expectedHeader === actual; + var name = keys[i]; + var actual = response.headers[name.toLowerCase()]; + var expectedHeader = expected.headers[name]; + var headerEql = expectedHeader instanceof RegExp ? expectedHeader.test(actual) : expectedHeader === actual; if (!headerEql) { return new Error(colorize( 'Invalid response header [bold]{' + name + '}.\n' + @@ -177,7 +177,7 @@ function validateResponseHeaders(response, expected) { } } -function validateResponse(response, expected) { +function validateResponse (response, expected) { // Assert response body return validateResponseBody(response, expected) || validateResponseStatus(response, expected) || @@ -185,65 +185,64 @@ function validateResponse(response, expected) { } // @param tolerance number of tolerated grid cell differences -assert.utfgridEqualsFile = function(buffer, file_b, tolerance, callback) { +assert.utfgridEqualsFile = function (buffer, fileB, tolerance, callback) { // jshint maxcomplexity:9 fs.writeFileSync('/tmp/grid.json', buffer, 'binary'); // <-- to debug/update - var expected_json = JSON.parse(fs.readFileSync(file_b, 'utf8')); + var expectedJson = JSON.parse(fs.readFileSync(fileB, 'utf8')); var err = null; - var Celldiff = function(x, y, ev, ov) { + var Celldiff = function (x, y, ev, ov) { this.x = x; this.y = y; this.ev = ev; this.ov = ov; }; - Celldiff.prototype.toString = function() { + Celldiff.prototype.toString = function () { return '(' + this.x + ',' + this.y + ')["' + this.ev + '" != "' + this.ov + '"]'; }; try { - var obtained_json = Object.prototype.toString() === buffer.toString() ? buffer : JSON.parse(buffer); + var obtainedJson = Object.prototype.toString() === buffer.toString() ? buffer : JSON.parse(buffer); // compare grid - var obtained_grid = obtained_json.grid; - var expected_grid = expected_json.grid; - var nrows = obtained_grid.length; - if (nrows !== expected_grid.length) { - throw new Error( "Obtained grid rows (" + nrows + - ") != expected grid rows (" + expected_grid.length + ")" ); + var obtainedGrid = obtainedJson.grid; + var expectedGrid = expectedJson.grid; + var nrows = obtainedGrid.length; + if (nrows !== expectedGrid.length) { + throw new Error('Obtained grid rows (' + nrows + + ') != expected grid rows (' + expectedGrid.length + ')'); } var celldiff = []; - for (var i=0; i tolerance ) { - throw new Error( celldiff.length + " cell differences: " + celldiff ); + if (celldiff.length > tolerance) { + throw new Error(celldiff.length + ' cell differences: ' + celldiff); } - assert.deepEqual(obtained_json.keys, expected_json.keys); + assert.deepStrictEqual(obtainedJson.keys, expectedJson.keys); } catch (e) { err = e; } callback(err); }; - /** * Colorize the given string using ansi-escape sequences. * Disabled when --boring is set. @@ -251,9 +250,9 @@ assert.utfgridEqualsFile = function(buffer, file_b, tolerance, callback) { * @param {String} str * @return {String} */ -function colorize(str) { +function colorize (str) { var colors = { bold: 1, red: 31, green: 32, yellow: 33 }; - return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function(_, color, str) { + return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function (_, color, str) { return '\x1B[' + colors[color] + 'm' + str + '\x1B[0m'; }); } diff --git a/test/support/test-client.js b/test/support/test-client.js index 0483f0ce..634509c0 100644 --- a/test/support/test-client.js +++ b/test/support/test-client.js @@ -2,7 +2,7 @@ var qs = require('querystring'); var step = require('step'); -var urlParser = require('url'); +const { URL } = require('url'); var PSQL = require('cartodb-psql'); var _ = require('underscore'); var mapnik = require('windshaft').mapnik; @@ -17,13 +17,13 @@ var serverOptions = require('../../lib/server-options'); serverOptions.analysis.batch.inlineExecution = true; const MAPNIK_SUPPORTED_FORMATS = { - 'png': true, - 'png32': true, + png: true, + png32: true, 'grid.json': true, - 'mvt': true + mvt: true }; -function TestClient(config, apiKey) { +function TestClient (config, apiKey) { this.mapConfig = isMapConfig(config) ? config : null; this.template = isTemplate(config) ? config : null; this.apiKey = apiKey; @@ -33,11 +33,11 @@ function TestClient(config, apiKey) { module.exports = TestClient; -function isMapConfig(config) { +function isMapConfig (config) { return config && config.layers; } -function isTemplate(config) { +function isTemplate (config) { return config && config.layergroup; } @@ -116,7 +116,7 @@ module.exports.SQL = { ONE_POINT: 'select 1 as cartodb_id, \'SRID=3857;POINT(0 0)\'::geometry the_geom_webmercator' }; -function resErr2errRes(callback) { +function resErr2errRes (callback) { return (res, err) => { if (err) { return callback(err); @@ -130,10 +130,10 @@ function layergroupidTemplate (layergroupId, params) { // {user}@{token}:{cache_buster} // {token}:{cache_buster} - return `${signer ? signer + '@' : ''}${token}:${params.cacheBuster ? Date.now() : cacheBuster }`; + return `${signer ? signer + '@' : ''}${token}:${params.cacheBuster ? Date.now() : cacheBuster}`; } -TestClient.prototype.getWidget = function(widgetName, params, callback) { +TestClient.prototype.getWidget = function (widgetName, params, callback) { var self = this; if (!callback) { @@ -147,7 +147,7 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) { } step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(self.server, { @@ -165,14 +165,14 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } var parsedBody = JSON.parse(res.body); var expectedWidgetURLS = { - http: "/api/v1/map/" + parsedBody.layergroupid + "/0/widget/" + widgetName + http: '/api/v1/map/' + parsedBody.layergroupid + '/0/widget/' + widgetName }; assert.ok(parsedBody.metadata.layers[0].widgets[widgetName]); assert.ok( @@ -180,7 +180,7 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) { ); var expectedDataviewsURLS = { - http: "/api/v1/map/" + parsedBody.layergroupid + "/dataview/" + widgetName + http: '/api/v1/map/' + parsedBody.layergroupid + '/dataview/' + widgetName }; assert.ok(parsedBody.metadata.dataviews[widgetName]); assert.ok( @@ -191,7 +191,7 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) { } ); }, - function getWidgetResult(err, layergroupId) { + function getWidgetResult (err, layergroupId) { assert.ifError(err); var next = this; @@ -199,10 +199,10 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) { self.keysToDelete['user:localhost:mapviews:global'] = 5; var urlParams = { - own_filter: params.hasOwnProperty('own_filter') ? params.own_filter : 1 + own_filter: Object.prototype.hasOwnProperty.call(params, 'own_filter') ? params.own_filter : 1 }; - ['bbox', 'bins', 'start', 'end'].forEach(function(extraParam) { - if (params.hasOwnProperty(extraParam)) { + ['bbox', 'bins', 'start', 'end'].forEach(function (extraParam) { + if (Object.prototype.hasOwnProperty.call(params, extraParam)) { urlParams[extraParam] = params[extraParam]; } }); @@ -223,7 +223,7 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -232,7 +232,7 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) { } ); }, - function finish(err, res) { + function finish (err, res) { var widget; if (!err && res.body) { widget = JSON.parse(res.body); @@ -242,7 +242,7 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) { ); }; -TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, callback) { +TestClient.prototype.widgetSearch = function (widgetName, userQuery, params, callback) { var self = this; if (!callback) { @@ -256,7 +256,7 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call } step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(self.server, { @@ -274,14 +274,14 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } var parsedBody = JSON.parse(res.body); var expectedWidgetURLS = { - http: "/api/v1/map/" + parsedBody.layergroupid + "/0/widget/" + widgetName + http: '/api/v1/map/' + parsedBody.layergroupid + '/0/widget/' + widgetName }; assert.ok(parsedBody.metadata.layers[0].widgets[widgetName]); assert.ok( @@ -289,7 +289,7 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call ); var expectedDataviewsURLS = { - http: "/api/v1/map/" + parsedBody.layergroupid + "/dataview/" + widgetName + http: '/api/v1/map/' + parsedBody.layergroupid + '/dataview/' + widgetName }; assert.ok(parsedBody.metadata.dataviews[widgetName]); assert.ok( @@ -300,7 +300,7 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call } ); }, - function getWidgetSearchResult(err, layergroupId) { + function getWidgetSearchResult (err, layergroupId) { assert.ifError(err); var next = this; @@ -309,7 +309,7 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call var urlParams = { q: userQuery, - own_filter: params.hasOwnProperty('own_filter') ? params.own_filter : 1 + own_filter: Object.prototype.hasOwnProperty.call(params, 'own_filter') ? params.own_filter : 1 }; if (params && params.bbox) { urlParams.bbox = params.bbox; @@ -330,7 +330,7 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -339,7 +339,7 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call } ); }, - function finish(err, res) { + function finish (err, res) { var searchResult; if (!err && res.body) { searchResult = JSON.parse(res.body); @@ -349,7 +349,7 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call ); }; -TestClient.prototype.getDataview = function(dataviewName, params, callback) { +TestClient.prototype.getDataview = function (dataviewName, params, callback) { var self = this; if (!callback) { @@ -417,7 +417,7 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) { } ); }, - function createLayergroup(err, templateId) { + function createLayergroup (err, templateId) { assert.ifError(err); var next = this; @@ -434,9 +434,9 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) { queryParams.filters = JSON.stringify(params.filters); } - var path = templateId ? - urlNamed + '/' + templateId + '?' + qs.stringify(queryParams) : - url; + var path = templateId + ? urlNamed + '/' + templateId + '?' + qs.stringify(queryParams) + : url; assert.response(self.server, { @@ -454,13 +454,13 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } var parsedBody = JSON.parse(res.body); var expectedDataviewsURLS = { - http: "/api/v1/map/" + parsedBody.layergroupid + "/dataview/" + dataviewName + http: '/api/v1/map/' + parsedBody.layergroupid + '/dataview/' + dataviewName }; assert.ok(parsedBody.metadata.dataviews[dataviewName]); assert.ok( @@ -470,7 +470,7 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) { } ); }, - function getDataviewResult(err, layergroupId) { + function getDataviewResult (err, layergroupId) { assert.ifError(err); var next = this; @@ -478,15 +478,15 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) { self.keysToDelete['user:localhost:mapviews:global'] = 5; var urlParams = {}; - if (params.hasOwnProperty('no_filters')) { + if (Object.prototype.hasOwnProperty.call(params, 'no_filters')) { urlParams.no_filters = params.no_filters; } - if (params.hasOwnProperty('own_filter')) { + if (Object.prototype.hasOwnProperty.call(params, 'own_filter')) { urlParams.own_filter = params.own_filter; } - ['bbox', 'bins', 'start', 'end', 'aggregation', 'offset', 'categories'].forEach(function(extraParam) { - if (params.hasOwnProperty(extraParam)) { + ['bbox', 'bins', 'start', 'end', 'aggregation', 'offset', 'categories'].forEach(function (extraParam) { + if (Object.prototype.hasOwnProperty.call(params, extraParam)) { urlParams[extraParam] = params[extraParam]; } }); @@ -505,7 +505,7 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) { } }, expectedResponse, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -513,7 +513,7 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) { } ); }, - function finish(err, dataview, headers = null) { + function finish (err, dataview, headers = null) { if (err) { return callback(err); } @@ -522,7 +522,7 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) { ); }; -TestClient.prototype.getFeatureAttributes = function(featureId, layerId, params, callback) { +TestClient.prototype.getFeatureAttributes = function (featureId, layerId, params, callback) { var self = this; if (!callback) { @@ -551,7 +551,7 @@ TestClient.prototype.getFeatureAttributes = function(featureId, layerId, params, }; step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(self.server, { @@ -569,7 +569,7 @@ TestClient.prototype.getFeatureAttributes = function(featureId, layerId, params, 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -585,7 +585,7 @@ TestClient.prototype.getFeatureAttributes = function(featureId, layerId, params, } ); }, - function getFeatureAttributes(err, layergroupId) { + function getFeatureAttributes (err, layergroupId) { assert.ifError(err); var next = this; @@ -601,7 +601,7 @@ TestClient.prototype.getFeatureAttributes = function(featureId, layerId, params, } }, expectedResponse, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -610,7 +610,7 @@ TestClient.prototype.getFeatureAttributes = function(featureId, layerId, params, } ); }, - function finish(err, attributes) { + function finish (err, attributes) { if (err) { return callback(err); } @@ -651,7 +651,7 @@ TestClient.prototype.getClusterFeatures = function (zoom, clusterId, layerId, pa }; step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(self.server, { @@ -669,7 +669,7 @@ TestClient.prototype.getClusterFeatures = function (zoom, clusterId, layerId, pa 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -706,7 +706,7 @@ TestClient.prototype.getClusterFeatures = function (zoom, clusterId, layerId, pa } }, expectedResponse, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -715,7 +715,7 @@ TestClient.prototype.getClusterFeatures = function (zoom, clusterId, layerId, pa } ); }, - function finish(err, attributes) { + function finish (err, attributes) { if (err) { return callback(err); } @@ -725,7 +725,7 @@ TestClient.prototype.getClusterFeatures = function (zoom, clusterId, layerId, pa ); }; -TestClient.prototype.getTile = function(z, x, y, params, callback) { +TestClient.prototype.getTile = function (z, x, y, params, callback) { var self = this; if (!callback) { @@ -737,7 +737,7 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { var urlNamed = url + '/named'; if (this.apiKey) { - url += '?' + qs.stringify({api_key: this.apiKey}); + url += '?' + qs.stringify({ api_key: this.apiKey }); } var layergroupId; @@ -784,9 +784,13 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { } ); }, - function createLayergroup(err, templateId) { + function createLayergroup (err, templateId) { var next = this; + if (err) { + return next(err); + } + if (layergroupId) { return next(null, layergroupId); } @@ -803,9 +807,9 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { queryParams.aggregation = params.aggregation; } - var path = templateId ? - urlNamed + '/' + templateId + '?' + qs.stringify(queryParams) : - url; + var path = templateId + ? urlNamed + '/' + templateId + '?' + qs.stringify(queryParams) + : url; assert.response(self.server, { @@ -823,7 +827,7 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -831,7 +835,7 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { } ); }, - function getTileResult(err, layergroupId) { + function getTileResult (err, layergroupId) { // jshint maxcomplexity:13 assert.ifError(err); @@ -853,7 +857,7 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { throw new Error(`Missing layer filter while fetching ${format} tile, review params argument`); } - url += [z,x,y].join('/'); + url += [z, x, y].join('/'); url += '.' + format; const queryParams = {}; @@ -896,7 +900,6 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { } } - var isGeojson = format.match(/geojson$/); if (isGeojson) { @@ -917,26 +920,26 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { assert.response(self.server, request, expectedResponse, resErr2errRes(this)); }, - function finish(err, res) { + function finish (err, res) { if (err) { return callback(err); } var body; switch (res.headers['content-type']) { - case 'image/png': - body = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); - break; - case 'application/x-protobuf': - body = new mapnik.VectorTile(z, x, y); - body.setDataSync(new Buffer(res.body, 'binary')); - break; - case 'application/json; charset=utf-8': - body = JSON.parse(res.body); - break; - default: - body = res.body; - break; + case 'image/png': + body = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); + break; + case 'application/x-protobuf': + body = new mapnik.VectorTile(z, x, y); + body.setDataSync(Buffer.from(res.body, 'binary')); + break; + case 'application/json; charset=utf-8': + body = JSON.parse(res.body); + break; + default: + body = res.body; + break; } return callback(err, res, body); @@ -993,7 +996,7 @@ TestClient.prototype.getLayergroup = function (params, callback) { data: JSON.stringify(self.mapConfig) }, params.response, - function(res, err) { + function (res, err) { var parsedBody; // If there is a response, we are still interested in catching the created keys // to be able to delete them on the .drain() method. @@ -1016,16 +1019,16 @@ TestClient.prototype.getLayergroup = function (params, callback) { TestClient.prototype.getStaticCenter = function (params, callback) { var self = this; - let { layergroupid, zoom, lat, lng, width, height, format } = params; + const { layergroupid, zoom, lat, lng, width, height, format } = params; - var url = `/api/v1/map/`; + var url = '/api/v1/map/'; if (this.apiKey) { - url += '?' + qs.stringify({api_key: this.apiKey}); + url += '?' + qs.stringify({ api_key: this.apiKey }); } step( - function createLayergroup() { + function createLayergroup () { var next = this; if (layergroupid) { @@ -1033,7 +1036,7 @@ TestClient.prototype.getStaticCenter = function (params, callback) { } var data = self.mapConfig; - var path = url; + var path = url; assert.response(self.server, { @@ -1051,7 +1054,7 @@ TestClient.prototype.getStaticCenter = function (params, callback) { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -1059,7 +1062,7 @@ TestClient.prototype.getStaticCenter = function (params, callback) { } ); }, - function getStaticResult(err, layergroupId) { + function getStaticResult (err, layergroupId) { assert.ifError(err); self.keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0; @@ -1070,7 +1073,7 @@ TestClient.prototype.getStaticCenter = function (params, callback) { url = `/api/v1/map/static/center/${layergroupid}/${zoom}/${lat}/${lng}/${width}/${height}.${format}`; if (self.apiKey) { - url += '?' + qs.stringify({api_key: self.apiKey}); + url += '?' + qs.stringify({ api_key: self.apiKey }); } var request = { @@ -1091,22 +1094,22 @@ TestClient.prototype.getStaticCenter = function (params, callback) { assert.response(self.server, request, expectedResponse, resErr2errRes(this)); }, - function(err, res) { + function (err, res) { if (err) { return callback(err); } var body; switch (res.headers['content-type']) { - case 'image/png': - body = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); - break; - case 'application/json; charset=utf-8': - body = JSON.parse(res.body); - break; - default: - body = res.body; - break; + case 'image/png': + body = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); + break; + case 'application/json; charset=utf-8': + body = JSON.parse(res.body); + break; + default: + body = res.body; + break; } return callback(err, res, body); @@ -1114,18 +1117,18 @@ TestClient.prototype.getStaticCenter = function (params, callback) { ); }; -TestClient.prototype.getNodeStatus = function(nodeName, callback) { +TestClient.prototype.getNodeStatus = function (nodeName, callback) { var self = this; var url = '/api/v1/map'; if (this.apiKey) { - url += '?' + qs.stringify({api_key: this.apiKey}); + url += '?' + qs.stringify({ api_key: this.apiKey }); } var nodes = {}; step( - function createLayergroup() { + function createLayergroup () { var next = this; assert.response(self.server, { @@ -1143,14 +1146,14 @@ TestClient.prototype.getNodeStatus = function(nodeName, callback) { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } var parsedBody = JSON.parse(res.body); - nodes = parsedBody.metadata.analyses.reduce(function(nodes, analysis) { - return Object.keys(analysis.nodes).reduce(function(nodes, nodeName) { + nodes = parsedBody.metadata.analyses.reduce(function (nodes, analysis) { + return Object.keys(analysis.nodes).reduce(function (nodes, nodeName) { var node = analysis.nodes[nodeName]; nodes[nodeName] = node.url.http; return nodes; @@ -1161,16 +1164,16 @@ TestClient.prototype.getNodeStatus = function(nodeName, callback) { } ); }, - function getNodeStatusResult(err, layergroupId) { + function getNodeStatusResult (err, layergroupId) { assert.ifError(err); self.keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0; self.keysToDelete['user:localhost:mapviews:global'] = 5; - url = urlParser.parse(nodes[nodeName]).path; + url = new URL(nodes[nodeName]).pathname; if (self.apiKey) { - url += '?' + qs.stringify({api_key: self.apiKey}); + url += '?' + qs.stringify({ api_key: self.apiKey }); } var request = { @@ -1190,7 +1193,7 @@ TestClient.prototype.getNodeStatus = function(nodeName, callback) { assert.response(self.server, request, expectedResponse, resErr2errRes(this)); }, - function finish(err, res) { + function finish (err, res) { if (err) { return callback(err); } @@ -1199,7 +1202,7 @@ TestClient.prototype.getNodeStatus = function(nodeName, callback) { ); }; -TestClient.prototype.getAttributes = function(params, callback) { +TestClient.prototype.getAttributes = function (params, callback) { var self = this; if (!Number.isFinite(params.featureId)) { @@ -1223,7 +1226,7 @@ TestClient.prototype.getAttributes = function(params, callback) { } step( - function createLayergroup() { + function createLayergroup () { var next = this; if (layergroupid) { @@ -1246,7 +1249,7 @@ TestClient.prototype.getAttributes = function(params, callback) { 'Content-Type': 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return next(err); } @@ -1256,7 +1259,7 @@ TestClient.prototype.getAttributes = function(params, callback) { } ); }, - function getAttributes(err, layergroupId) { + function getAttributes (err, layergroupId) { assert.ifError(err); self.keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0; @@ -1265,7 +1268,7 @@ TestClient.prototype.getAttributes = function(params, callback) { url = `/api/v1/map/${layergroupId}/${params.layer}/attributes/${params.featureId}`; if (self.apiKey) { - url += '?' + qs.stringify({api_key: self.apiKey}); + url += '?' + qs.stringify({ api_key: self.apiKey }); } var request = { @@ -1285,7 +1288,7 @@ TestClient.prototype.getAttributes = function(params, callback) { assert.response(self.server, request, expectedResponse, resErr2errRes(this)); }, - function finish(err, res) { + function finish (err, res) { if (err) { return callback(err); } @@ -1295,11 +1298,11 @@ TestClient.prototype.getAttributes = function(params, callback) { ); }; -TestClient.prototype.drain = function(callback) { +TestClient.prototype.drain = function (callback) { helper.deleteRedisKeys(this.keysToDelete, callback); }; -module.exports.getStaticMap = function getStaticMap(templateName, params, callback) { +module.exports.getStaticMap = function getStaticMap (templateName, params, callback) { var self = this; self.server = new CartodbWindshaft(serverOptions); @@ -1335,8 +1338,8 @@ module.exports.getStaticMap = function getStaticMap(templateName, params, callba var server = new CartodbWindshaft(serverOptions); assert.response(server, requestOptions, expectedResponse, function (res, err) { - helper.deleteRedisKeys({'user:localhost:mapviews:global': 5}, function() { - return callback(err, mapnik.Image.fromBytes(new Buffer(res.body, 'binary'))); + helper.deleteRedisKeys({ 'user:localhost:mapviews:global': 5 }, function () { + return callback(err, mapnik.Image.fromBytes(Buffer.from(res.body, 'binary'))); }); }); }; @@ -1407,11 +1410,11 @@ TestClient.prototype.getAnalysesCatalog = function (params, callback) { var url = '/api/v1/map/analyses/catalog'; if (this.apiKey) { - url += '?' + qs.stringify({api_key: this.apiKey}); + url += '?' + qs.stringify({ api_key: this.apiKey }); } if (params.jsonp) { - url += '&' + qs.stringify({callback: params.jsonp}); + url += '&' + qs.stringify({ callback: params.jsonp }); } assert.response(this.server, @@ -1426,12 +1429,12 @@ TestClient.prototype.getAnalysesCatalog = function (params, callback) { { status: params.status || 200, headers: { - 'Content-Type': params.jsonp ? - 'text/javascript; charset=utf-8' : - 'application/json; charset=utf-8' + 'Content-Type': params.jsonp + ? 'text/javascript; charset=utf-8' + : 'application/json; charset=utf-8' } }, - function(res, err) { + function (res, err) { if (err) { return callback(err); } @@ -1443,7 +1446,7 @@ TestClient.prototype.getAnalysesCatalog = function (params, callback) { ); }; -TestClient.prototype.getNamedMapList = function(params, callback) { +TestClient.prototype.getNamedMapList = function (params, callback) { const request = { url: `/api/v1/map/named?${qs.stringify({ api_key: this.apiKey })}`, method: 'GET', @@ -1473,8 +1476,8 @@ TestClient.prototype.getNamedMapList = function(params, callback) { }); }; -TestClient.prototype.getNamedTile = function (name, z, x, y, format, options, callback) { - const { params } = options; +TestClient.prototype.getNamedTile = function (name, z, x, y, format, options, callback) { + const { params } = options; if (!this.apiKey) { return callback(new Error('apiKey param is mandatory to create a new template')); @@ -1504,7 +1507,7 @@ TestClient.prototype.getNamedTile = function (name, z, x, y, format, options, c const templateId = JSON.parse(res.body).template_id; const queryParams = params ? `?${qs.stringify(params)}` : ''; - const url = `/api/v1/map/named/${templateId}/all/${[z,x,y].join('/')}.${format}${queryParams}`; + const url = `/api/v1/map/named/${templateId}/all/${[z, x, y].join('/')}.${format}${queryParams}`; const namedTileRequest = { url, method: 'GET', @@ -1516,15 +1519,15 @@ TestClient.prototype.getNamedTile = function (name, z, x, y, format, options, c let contentType; switch (format) { - case 'png': - contentType = 'image/png'; - break; - case 'mvt': - contentType = 'application/x-protobuf'; - break; - default: - contentType = 'application/json'; - break; + case 'png': + contentType = 'image/png'; + break; + case 'mvt': + contentType = 'application/x-protobuf'; + break; + default: + contentType = 'application/json'; + break; } const namedTileResponse = Object.assign({ @@ -1537,19 +1540,19 @@ TestClient.prototype.getNamedTile = function (name, z, x, y, format, options, c assert.response(this.server, namedTileRequest, namedTileResponse, (res, err) => { let body; switch (res.headers['content-type']) { - case 'image/png': - body = mapnik.Image.fromBytes(new Buffer(res.body, 'binary')); - break; - case 'application/x-protobuf': - body = new mapnik.VectorTile(z, x, y); - body.setDataSync(new Buffer(res.body, 'binary')); - break; - case 'application/json; charset=utf-8': - body = JSON.parse(res.body); - break; - default: - body = res.body; - break; + case 'image/png': + body = mapnik.Image.fromBytes(Buffer.from(res.body, 'binary')); + break; + case 'application/x-protobuf': + body = new mapnik.VectorTile(z, x, y); + body.setDataSync(Buffer.from(res.body, 'binary')); + break; + case 'application/json; charset=utf-8': + body = JSON.parse(res.body); + break; + default: + body = res.body; + break; } return callback(err, res, body); @@ -1586,12 +1589,12 @@ TestClient.prototype.createTemplate = function (params, callback) { assert.response(this.server, createTemplateRequest, createTemplateResponse, (res, err) => { let body; switch (res.headers['content-type']) { - case 'application/json; charset=utf-8': - body = JSON.parse(res.body); - break; - default: - body = res.body; - break; + case 'application/json; charset=utf-8': + body = JSON.parse(res.body); + break; + default: + body = res.body; + break; } return callback(err, res, body); @@ -1607,7 +1610,7 @@ TestClient.prototype.deleteTemplate = function (params, callback) { url: `/api/v1/map/named/${params.templateId}?${qs.stringify({ api_key: this.apiKey })}`, method: 'DELETE', headers: { - host: 'localhost', + host: 'localhost' } }; @@ -1623,12 +1626,12 @@ TestClient.prototype.deleteTemplate = function (params, callback) { assert.response(this.server, deleteTemplateRequest, deleteTemplateResponse, (res, err) => { let body; switch (res.headers['content-type']) { - case 'application/json; charset=utf-8': - body = JSON.parse(res.body); - break; - default: - body = res.body; - break; + case 'application/json; charset=utf-8': + body = JSON.parse(res.body); + break; + default: + body = res.body; + break; } return callback(err, res, body); @@ -1664,19 +1667,18 @@ TestClient.prototype.updateTemplate = function (params, callback) { assert.response(this.server, updateTemplateRequest, updateTemplateResponse, (res, err) => { let body; switch (res.headers['content-type']) { - case 'application/json; charset=utf-8': - body = JSON.parse(res.body); - break; - default: - body = res.body; - break; + case 'application/json; charset=utf-8': + body = JSON.parse(res.body); + break; + default: + body = res.body; + break; } return callback(err, res, body); }); }; - TestClient.prototype.getTemplate = function (params, callback) { if (!this.apiKey) { return callback(new Error('apiKey param is mandatory to create a new template')); @@ -1704,12 +1706,12 @@ TestClient.prototype.getTemplate = function (params, callback) { assert.response(this.server, getTemplateRequest, getTemplateResponse, (res, err) => { let body; switch (res.headers['content-type']) { - case 'application/json; charset=utf-8': - body = JSON.parse(res.body); - break; - default: - body = res.body; - break; + case 'application/json; charset=utf-8': + body = JSON.parse(res.body); + break; + default: + body = res.body; + break; } return callback(err, res, body); diff --git a/test/support/test-helper.js b/test/support/test-helper.js index 1ae8d77d..9ec178f7 100644 --- a/test/support/test-helper.js +++ b/test/support/test-helper.js @@ -9,7 +9,7 @@ var assert = require('assert'); var fs = require('fs'); -var LZMA = require('lzma').LZMA; +var LZMA = require('lzma').LZMA; var lzmaWorker = new LZMA(); @@ -18,7 +18,7 @@ var log4js = require('log4js'); const setICUEnvVariable = require('../../lib/utils/icu-data-env-setter'); // set environment specific variables -global.environment = require('../../config/environments/test'); +global.environment = require('../../config/environments/test'); global.environment.name = 'test'; process.env.NODE_ENV = 'test'; @@ -28,82 +28,78 @@ setICUEnvVariable(); log4js.configure({ appenders: [] }); global.logger = log4js.getLogger(); - // Utility function to compress & encode LZMA -function lzma_compress_to_base64(payload, mode, callback) { - lzmaWorker.compress(payload, mode, - function(ints) { - ints = ints.map(function(c) { return String.fromCharCode(c + 128); }).join(''); - var base64 = new Buffer(ints, 'binary').toString('base64'); - callback(null, base64); - }, - function(/*percent*/) { - //console.log("Compressing: " + percent + "%"); - } - ); +function lzmaCompressToBase64 (payload, mode, callback) { + lzmaWorker.compress(payload, mode, + function (ints) { + ints = ints.map(function (c) { return String.fromCharCode(c + 128); }).join(''); + var base64 = Buffer.from(ints, 'binary').toString('base64'); + callback(null, base64); + }, + function (/* percent */) { + // console.log("Compressing: " + percent + "%"); + } + ); } // Check that the response headers do not request caching // Throws on failure -function checkNoCache(res) { - assert.ok(!res.headers.hasOwnProperty('x-cache-channel')); - assert.ok(!res.headers.hasOwnProperty('surrogate-key')); - assert.ok(!res.headers.hasOwnProperty('cache-control')); // is this correct ? - assert.ok(!res.headers.hasOwnProperty('last-modified')); // is this correct ? +function checkNoCache (res) { + assert.ok(!Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel')); + assert.ok(!Object.prototype.hasOwnProperty.call(res.headers, 'surrogate-key')); + assert.ok(!Object.prototype.hasOwnProperty.call(res.headers, 'cache-control')); // is this correct ? + assert.ok(!Object.prototype.hasOwnProperty.call(res.headers, 'last-modified')); // is this correct ? } - /** * Check that the response headers do not request caching * @see checkNoCache * @param res */ -function checkCache(res) { - assert.ok(res.headers.hasOwnProperty('x-cache-channel')); - assert.ok(res.headers.hasOwnProperty('cache-control')); - assert.ok(res.headers.hasOwnProperty('last-modified')); +function checkCache (res) { + assert.ok(Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel')); + assert.ok(Object.prototype.hasOwnProperty.call(res.headers, 'cache-control')); + assert.ok(Object.prototype.hasOwnProperty.call(res.headers, 'last-modified')); } -function checkSurrogateKey(res, expectedKey) { - assert.ok(res.headers.hasOwnProperty('surrogate-key')); +function checkSurrogateKey (res, expectedKey) { + assert.ok(Object.prototype.hasOwnProperty.call(res.headers, 'surrogate-key')); - function createSet(keys, key) { + function createSet (keys, key) { keys[key] = true; return keys; } var keys = res.headers['surrogate-key'].split(' ').reduce(createSet, {}); var expectedKeys = expectedKey.split(' ').reduce(createSet, {}); - assert.deepEqual(keys, expectedKeys); + assert.deepStrictEqual(keys, expectedKeys); } var uncaughtExceptions = []; -process.on('uncaughtException', function(err) { +process.on('uncaughtException', function (err) { uncaughtExceptions.push(err); }); -beforeEach(function() { +beforeEach(function () { uncaughtExceptions = []; }); -//global afterEach to capture uncaught exceptions -afterEach(function() { - assert.equal( +// global afterEach to capture uncaught exceptions +afterEach(function () { + assert.strictEqual( uncaughtExceptions.length, 0, 'uncaughtException:\n\n' + uncaughtExceptions.map(err => err.stack).join('\n\n')); }); - var redisClient; -beforeEach(function() { +beforeEach(function () { if (!redisClient) { redisClient = redis.createClient(global.environment.redis.port); } }); -//global afterEach to capture test suites that leave keys in redis -afterEach(function(done) { - +// global afterEach to capture test suites that leave keys in redis +afterEach(function (done) { var expectedKeys = { 'rails:test_windshaft_cartodb_user_1_db:test_table_private_1': true, 'rails:test_windshaft_cartodb_user_1_db:my_table': true, @@ -115,56 +111,56 @@ afterEach(function(done) { 'api_keys:cartodb250user:4321': true, 'api_keys:cartodb250user:default_public': true, 'api_keys:localhost:regular1': true, - 'api_keys:localhost:regular2': true, + 'api_keys:localhost:regular2': true }; - var databasesTasks = { 0: 'users', 5: 'meta'}; + var databasesTasks = { 0: 'users', 5: 'meta' }; var keysFound = []; - function taskDone(err, db, keys) { + function taskDone (err, db, keys) { if (err) { return done(err); } delete databasesTasks[db]; - keys.forEach(function(k) { + keys.forEach(function (k) { if (!expectedKeys[k]) { - keysFound.push('[db='+db+']'+k); + keysFound.push('[db=' + db + ']' + k); } }); if (Object.keys(databasesTasks).length === 0) { - assert.equal(keysFound.length, 0, 'Unexpected keys found in redis: ' + keysFound.join(', ')); + assert.strictEqual(keysFound.length, 0, 'Unexpected keys found in redis: ' + keysFound.join(', ')); done(); } } - Object.keys(databasesTasks).forEach(function(db) { - redisClient.select(db, function() { + Object.keys(databasesTasks).forEach(function (db) { + redisClient.select(db, function () { // Check that we start with an empty redis db - redisClient.keys("*", function(err, keys) { + redisClient.keys('*', function (err, keys) { return taskDone(err, db, keys); }); }); }); }); -function deleteRedisKeys(keysToDelete, callback) { - +function deleteRedisKeys (keysToDelete, callback) { if (Object.keys(keysToDelete).length === 0) { return callback(); } - function taskDone(k) { + function taskDone (k) { delete keysToDelete[k]; if (Object.keys(keysToDelete).length === 0) { callback(); } } - Object.keys(keysToDelete).forEach(function(k) { + Object.keys(keysToDelete).forEach(function (k) { var redisClient = redis.createClient(global.environment.redis.port); - redisClient.select(keysToDelete[k], function() { - redisClient.del(k, function(err, deletedKeysCount) { + redisClient.select(keysToDelete[k], function () { + redisClient.del(k, function (err, deletedKeysCount) { + assert.ifError(err); redisClient.quit(); assert.notStrictEqual(deletedKeysCount, 0, 'No KEYS deleted for: [db=' + keysToDelete[k] + ']' + k); taskDone(k); @@ -173,21 +169,20 @@ function deleteRedisKeys(keysToDelete, callback) { }); } -function rmdirRecursiveSync(dirname) { +function rmdirRecursiveSync (dirname) { var files = fs.readdirSync(dirname); - for (var i=0; i `http://${s}.cdn.carto.com/${USERNAME}/api/v1/map/${TILE_RESOURCE}`) ); - assert.deepEqual( + assert.deepStrictEqual( urls.https, HTTPS_SUBDOMAINS .map(s => `https://cdn_${s}.ssl.cdn.carto.com/${USERNAME}/api/v1/map/${TILE_RESOURCE}`) @@ -204,27 +199,25 @@ describe('ResourceLocator', function() { }); }); - describe('getTemplateUrls', function() { - it('cdn_url templates should take precedence over http and https domains', function() { + describe('getTemplateUrls', function () { + it('cdn_url templates should take precedence over http and https domains', function () { var resourceLocator = new ResourceLocator(CDN_TEMPLATES_ENVIRONMENT); var urls = resourceLocator.getTemplateUrls(USERNAME, TILE_RESOURCE); assert.ok(urls); - assert.deepEqual(urls.http, { + assert.deepStrictEqual(urls.http, { urlTemplate: `http://{s}.cdn.carto.com/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, subdomains: HTTP_SUBDOMAINS }); - assert.deepEqual(urls.https, { + assert.deepStrictEqual(urls.https, { urlTemplate: `https://cdn_{s}.ssl.cdn.carto.com/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, subdomains: HTTPS_SUBDOMAINS }); }); }); - }); - describe('cdn and resource templates', function() { - + describe('cdn and resource templates', function () { var CDN_URL_AND_RESOURCE_TEMPLATES_ENVIRONMENT = { serverMetadata: { cdn_url: { @@ -232,11 +225,11 @@ describe('ResourceLocator', function() { https: 'cdn.ssl.carto.com', templates: { http: { - url: "http://{s}.cdn.carto.com", + url: 'http://{s}.cdn.carto.com', subdomains: HTTP_SUBDOMAINS }, https: { - url: "https://cdn_{s}.ssl.cdn.carto.com", + url: 'https://cdn_{s}.ssl.cdn.carto.com', subdomains: HTTPS_SUBDOMAINS } } @@ -248,8 +241,8 @@ describe('ResourceLocator', function() { } }; - describe('getUrls', function() { - it('should mix cdn_url templates and resources_url_templates', function() { + describe('getUrls', function () { + it('should mix cdn_url templates and resources_url_templates', function () { var resourceLocator = new ResourceLocator(CDN_URL_AND_RESOURCE_TEMPLATES_ENVIRONMENT); var urls = resourceLocator.getUrls(USERNAME, RESOURCE); assert.ok(urls); @@ -257,29 +250,29 @@ describe('ResourceLocator', function() { var httpSubdomain = ResourceLocator.subdomain(HTTP_SUBDOMAINS, RESOURCE); var httpsSubdomain = ResourceLocator.subdomain(HTTPS_SUBDOMAINS, RESOURCE); - assert.equal( + assert.strictEqual( urls.http, ['http://' + httpSubdomain + '.cdn.carto.com', 'u', USERNAME, 'api/v1/map', RESOURCE].join('/') ); - assert.equal( + assert.strictEqual( urls.https, `https://cdn_${httpsSubdomain}.ssl.cdn.carto.com/u/${USERNAME}/api/v1/map/${RESOURCE}` ); }); }); - describe('getTileUrls', function() { - it('should mix cdn_url templates and resources_url_templates', function() { + describe('getTileUrls', function () { + it('should mix cdn_url templates and resources_url_templates', function () { var resourceLocator = new ResourceLocator(CDN_URL_AND_RESOURCE_TEMPLATES_ENVIRONMENT); var urls = resourceLocator.getTileUrls(USERNAME, TILE_RESOURCE); assert.ok(urls); - assert.deepEqual( + assert.deepStrictEqual( urls.http, HTTP_SUBDOMAINS .map(s => `http://${s}.cdn.carto.com/u/${USERNAME}/api/v1/map/${TILE_RESOURCE}`) ); - assert.deepEqual( + assert.deepStrictEqual( urls.https, HTTPS_SUBDOMAINS .map(s => `https://cdn_${s}.ssl.cdn.carto.com/u/${USERNAME}/api/v1/map/${TILE_RESOURCE}`) @@ -287,23 +280,21 @@ describe('ResourceLocator', function() { }); }); - describe('getTemplateUrls', function() { - it('should mix cdn_url templates and resources_url_templates', function() { + describe('getTemplateUrls', function () { + it('should mix cdn_url templates and resources_url_templates', function () { var resourceLocator = new ResourceLocator(CDN_URL_AND_RESOURCE_TEMPLATES_ENVIRONMENT); var urls = resourceLocator.getTemplateUrls(USERNAME, TILE_RESOURCE); assert.ok(urls); - assert.deepEqual(urls.http, { + assert.deepStrictEqual(urls.http, { urlTemplate: `http://{s}.cdn.carto.com/u/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, subdomains: HTTP_SUBDOMAINS }); - assert.deepEqual(urls.https, { + assert.deepStrictEqual(urls.https, { urlTemplate: `https://cdn_{s}.ssl.cdn.carto.com/u/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, subdomains: HTTPS_SUBDOMAINS }); }); }); - }); - }); diff --git a/test/unit/overviews-query-rewriter-test.js b/test/unit/overviews-query-rewriter-test.js index 4b54d426..d510a12d 100644 --- a/test/unit/overviews-query-rewriter-test.js +++ b/test/unit/overviews-query-rewriter-test.js @@ -2,36 +2,34 @@ require('../support/test-helper'); -var assert = require('assert'); +var assert = require('assert'); var OverviewsQueryRewriter = require('../../lib/utils/overviews-query-rewriter'); var overviewsQueryRewriter = new OverviewsQueryRewriter({ zoom_level: 'ZoomLevel()' }); -function normalize_whitespace(txt) { - return txt.replace(/\s+/g, " ").trim(); +function normalizeWhitespace (txt) { + return txt.replace(/\s+/g, ' ').trim(); } // compare SQL statements ignoring whitespace -function assertSameSql(sql1, sql2) { - assert.equal(normalize_whitespace(sql1), normalize_whitespace(sql2)); +function assertSameSql (sql1, sql2) { + assert.strictEqual(normalizeWhitespace(sql1), normalizeWhitespace(sql2)); } -describe('Overviews query rewriter', function() { - - it('does not alter queries if no overviews data is present', function(){ - var sql = "SELECT * FROM table1"; - var overviews_sql = overviewsQueryRewriter.query(sql); - assert.equal(overviews_sql, sql); - overviews_sql = overviewsQueryRewriter.query(sql, {}); - assert.equal(overviews_sql, sql); - overviews_sql = overviewsQueryRewriter.query(sql, { overviews: {} }); - assert.equal(overviews_sql, sql); +describe('Overviews query rewriter', function () { + it('does not alter queries if no overviews data is present', function () { + var sql = 'SELECT * FROM table1'; + var overviewsSql = overviewsQueryRewriter.query(sql); + assert.strictEqual(overviewsSql, sql); + overviewsSql = overviewsQueryRewriter.query(sql, {}); + assert.strictEqual(overviewsSql, sql); + overviewsSql = overviewsQueryRewriter.query(sql, { overviews: {} }); + assert.strictEqual(overviewsSql, sql); }); - - it('does not alter queries which don\'t use overviews', function(){ - var sql = "SELECT * FROM table1"; + it('does not alter queries which don\'t use overviews', function () { + var sql = 'SELECT * FROM table1'; var data = { overviews: { table2: { @@ -41,14 +39,12 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); }); - // jshint multistr:true - - it('generates query with single overview layer for level 0', function(){ - var sql = "SELECT * FROM table1"; + it('generates query with single overview layer for level 0', function () { + var sql = 'SELECT * FROM table1'; var data = { overviews: { table1: { @@ -56,22 +52,22 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); + var overviewsSql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 0\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 0 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query with single overview layer for level >0', function(){ - var sql = "SELECT * FROM table1"; + it('generates query with single overview layer for level >0', function () { + var sql = 'SELECT * FROM table1'; var data = { overviews: { table1: { @@ -79,21 +75,21 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query with multiple overview layers for all levels up to N', function(){ - var sql = "SELECT * FROM table1"; + it('generates query with multiple overview layers for all levels up to N', function () { + var sql = 'SELECT * FROM table1'; var data = { overviews: { table1: { @@ -104,27 +100,27 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0\ - UNION ALL\ - SELECT * FROM table1_ov1, _vovw_scale WHERE _vovw_z = 1\ - UNION ALL\ - SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z = 2\ - UNION ALL\ - SELECT * FROM table1_ov3, _vovw_scale WHERE _vovw_z = 3\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 3\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0 + UNION ALL + SELECT * FROM table1_ov1, _vovw_scale WHERE _vovw_z = 1 + UNION ALL + SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z = 2 + UNION ALL + SELECT * FROM table1_ov3, _vovw_scale WHERE _vovw_z = 3 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 3 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query with multiple overview layers for random levels', function(){ - var sql = "SELECT * FROM table1"; + it('generates query with multiple overview layers for random levels', function () { + var sql = 'SELECT * FROM table1'; var data = { overviews: { table1: { @@ -134,25 +130,25 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0\ - UNION ALL\ - SELECT * FROM table1_ov1, _vovw_scale WHERE _vovw_z = 1\ - UNION ALL\ - SELECT * FROM table1_ov6, _vovw_scale WHERE _vovw_z > 1 AND _vovw_z <= 6\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 6\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0 + UNION ALL + SELECT * FROM table1_ov1, _vovw_scale WHERE _vovw_z = 1 + UNION ALL + SELECT * FROM table1_ov6, _vovw_scale WHERE _vovw_z > 1 AND _vovw_z <= 6 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 6 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query for a table with explicit schema', function(){ - var sql = "SELECT * FROM public.table1"; + it('generates query for a table with explicit schema', function () { + var sql = 'SELECT * FROM public.table1'; var data = { overviews: { 'public.table1': { @@ -160,21 +156,21 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM public.table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM public.table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM public.table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM public.table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query for a table with explicit schema in the overviews info', function(){ - var sql = "SELECT * FROM public.table1"; + it('generates query for a table with explicit schema in the overviews info', function () { + var sql = 'SELECT * FROM public.table1'; var data = { overviews: { 'public.table1': { @@ -182,68 +178,68 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM public.table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM public.table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1\ - "; + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM public.table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM public.table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1 + `; - assertSameSql(overviews_sql, expected_sql); + assertSameSql(overviewsSql, expectedSql); }); - it('uses schema name from overviews', function(){ - var sql = "SELECT * FROM public.table1"; + it('uses schema name from overviews', function () { + var sql = 'SELECT * FROM public.table1'; var data = { overviews: { - 'table1': { + table1: { schema: 'public', 2: { table: 'table1_ov2' } } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('ignores schema name from overviews if not necessary', function(){ - var sql = "SELECT * FROM table1"; + it('ignores schema name from overviews if not necessary', function () { + var sql = 'SELECT * FROM table1'; var data = { overviews: { - 'table1': { + table1: { schema: 'public', 2: { table: 'table1_ov2' } } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('uses redundant schema information', function(){ - var sql = "SELECT * FROM public.table1"; + it('uses redundant schema information', function () { + var sql = 'SELECT * FROM public.table1'; var data = { overviews: { 'public.table1': { @@ -252,21 +248,21 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM public.table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM public.table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM public.table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM public.table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query for a table that needs quoting with explicit schema', function(){ - var sql = "SELECT * FROM public.\"table 1\""; + it('generates query for a table that needs quoting with explicit schema', function () { + var sql = 'SELECT * FROM public."table 1"'; var data = { overviews: { 'public."table 1"': { @@ -274,21 +270,21 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM public.\"table 1_ov2\", _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM public.\"table 1\", _vovw_scale WHERE _vovw_z > 2\ - ) AS \"_vovw_table 1\"\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM public."table 1_ov2", _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM public."table 1", _vovw_scale WHERE _vovw_z > 2 + ) AS "_vovw_table 1" + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query for a table with explicit schema that needs quoting', function(){ - var sql = "SELECT * FROM \"user-1\".table1"; + it('generates query for a table with explicit schema that needs quoting', function () { + var sql = 'SELECT * FROM "user-1".table1'; var data = { overviews: { '"user-1".table1': { @@ -296,22 +292,21 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM \"user-1\".table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM \"user-1\".table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM "user-1".table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM "user-1".table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - - it('generates query for a table with explicit schema both needing quoting', function(){ - var sql = "SELECT * FROM \"user-1\".\"table 1\""; + it('generates query for a table with explicit schema both needing quoting', function () { + var sql = 'SELECT * FROM "user-1"."table 1"'; var data = { overviews: { '"user-1"."table 1"': { @@ -320,22 +315,21 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM \"user-1\".\"table 1_ov2\", _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM \"user-1\".\"table 1\", _vovw_scale WHERE _vovw_z > 2\ - ) AS \"_vovw_table 1\"\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM "user-1"."table 1_ov2", _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM "user-1"."table 1", _vovw_scale WHERE _vovw_z > 2 + ) AS "_vovw_table 1" + `; + assertSameSql(overviewsSql, expectedSql); }); - - it('generates query using overviews for queries with selected columns', function(){ - var sql = "SELECT column1, column2, column3 FROM table1"; + it('generates query using overviews for queries with selected columns', function () { + var sql = 'SELECT column1, column2, column3 FROM table1'; var data = { overviews: { table1: { @@ -343,21 +337,21 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT column1, column2, column3 FROM (\ - SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT column1, column2, column3 FROM ( + SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query using overviews for queries with a semicolon', function(){ - var sql = "SELECT column1, column2, column3 FROM table1;"; + it('generates query using overviews for queries with a semicolon', function () { + var sql = 'SELECT column1, column2, column3 FROM table1;'; var data = { overviews: { table1: { @@ -365,22 +359,22 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); + var overviewsSql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT column1, column2, column3 FROM (\ - SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1;\ - "; - assertSameSql(overviews_sql, expected_sql); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT column1, column2, column3 FROM ( + SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1; + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query using overviews for queries with extra whitespace', function(){ - var sql = " SELECT column1,column2, column3 FROM table1 "; + it('generates query using overviews for queries with extra whitespace', function () { + var sql = ' SELECT column1,column2, column3 FROM table1 '; var data = { overviews: { table1: { @@ -388,20 +382,20 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT column1,column2, column3 FROM (\ - SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT column1,column2, column3 FROM ( + SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z <= 2 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('does not alter queries which have not the simple supported form', function(){ + it('does not alter queries which have not the simple supported form', function () { var sql = "SELECT * FROM table1 WHERE column1='x'"; var data = { overviews: { @@ -410,48 +404,48 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); - sql = "SELECT * FROM table1 JOIN table2 ON (table1.col1=table2.col1)"; - overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + sql = 'SELECT * FROM table1 JOIN table2 ON (table1.col1=table2.col1)'; + overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); - sql = "SELECT a+b AS c FROM table1"; - overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + sql = 'SELECT a+b AS c FROM table1'; + overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); - sql = "SELECT f(a) AS b FROM table1"; - overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + sql = 'SELECT f(a) AS b FROM table1'; + overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); - sql = "SELECT * FROM table1 AS x"; - overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + sql = 'SELECT * FROM table1 AS x'; + overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); - sql = "WITH a AS (1) SELECT * FROM table1"; - overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + sql = 'WITH a AS (1) SELECT * FROM table1'; + overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); - sql = "SELECT * FROM table1 WHERE a=1"; - overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + sql = 'SELECT * FROM table1 WHERE a=1'; + overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); - sql = "\ - SELECT table1.* FROM table1 \ - JOIN areas ON ST_Intersects(table1.the_geom, areas.the_geom) \ - WHERE areas.name='A' \ - "; - overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + sql = ` + SELECT table1.* FROM table1 + JOIN areas ON ST_Intersects(table1.the_geom, areas.the_geom) + WHERE areas.name='A' + `; + overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); - sql = "SELECT table1.*, column1, column2, column3 FROM table1"; - overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + sql = 'SELECT table1.*, column1, column2, column3 FROM table1'; + overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); }); - it('generates overviews for wrapped query', function(){ - var sql = "SELECT * FROM (SELECT * FROM table1) AS wrapped_query WHERE 1=1"; + it('generates overviews for wrapped query', function () { + var sql = 'SELECT * FROM (SELECT * FROM table1) AS wrapped_query WHERE 1=1'; var data = { overviews: { table1: { @@ -461,25 +455,25 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (SELECT * FROM (\ - SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0\ - UNION ALL\ - SELECT * FROM table1_ov1, _vovw_scale WHERE _vovw_z = 1\ - UNION ALL\ - SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z = 2\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2\ - ) AS _vovw_table1) AS wrapped_query WHERE 1=1\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM (SELECT * FROM ( + SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0 + UNION ALL + SELECT * FROM table1_ov1, _vovw_scale WHERE _vovw_z = 1 + UNION ALL + SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z = 2 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 2 + ) AS _vovw_table1) AS wrapped_query WHERE 1=1 + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query for specific Z level', function(){ - var sql = "SELECT * FROM table1"; + it('generates query for specific Z level', function () { + var sql = 'SELECT * FROM table1'; var data = { overviews: { table1: { @@ -489,13 +483,13 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data, { zoom_level: 3 }); - var expected_sql = "SELECT * FROM table1_ov3"; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data, { zoom_level: 3 }); + var expectedSql = 'SELECT * FROM table1_ov3'; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query for specific nonpresent Z level', function(){ - var sql = "SELECT * FROM table1"; + it('generates query for specific nonpresent Z level', function () { + var sql = 'SELECT * FROM table1'; var data = { overviews: { table1: { @@ -505,13 +499,13 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data, { zoom_level: 1 }); - var expected_sql = "SELECT * FROM table1_ov2"; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data, { zoom_level: 1 }); + var expectedSql = 'SELECT * FROM table1_ov2'; + assertSameSql(overviewsSql, expectedSql); }); - it('does not use overviews for specific out-of-range Z level', function(){ - var sql = "SELECT * FROM table1"; + it('does not use overviews for specific out-of-range Z level', function () { + var sql = 'SELECT * FROM table1'; var data = { overviews: { table1: { @@ -521,16 +515,16 @@ describe('Overviews query rewriter', function() { } } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data, { zoom_level: 4 }); - var expected_sql = "SELECT * FROM table1"; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data, { zoom_level: 4 }); + var expectedSql = 'SELECT * FROM table1'; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query with filters', function(){ - var sql = "SELECT ST_Transform(the_geom, 3857) the_geom_webmercator, cartodb_id, name\ - FROM (SELECT *\ - FROM (select * from table1) _analysis_category_filter\ - WHERE name IN ($escape_0$X$escape_0$)) _cdb_analysis_query"; + it('generates query with filters', function () { + var sql = `SELECT ST_Transform(the_geom, 3857) the_geom_webmercator, cartodb_id, name + FROM (SELECT * + FROM (select * from table1) _analysis_category_filter + WHERE name IN ($escape_0$X$escape_0$)) _cdb_analysis_query`; var data = { overviews: { table1: { @@ -540,34 +534,34 @@ describe('Overviews query rewriter', function() { 3: { table: 'table1_ov3' } } }, - filters: { name_filter: { type: 'category', column: 'name', params: { accept: [ 'X' ] } } }, + filters: { name_filter: { type: 'category', column: 'name', params: { accept: ['X'] } } }, unfiltered_query: 'SELECT * FROM table1' }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - var expected_sql = "\ - SELECT * FROM (WITH\ - _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z )\ - SELECT * FROM (\ - SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0\ - UNION ALL\ - SELECT * FROM table1_ov1, _vovw_scale WHERE _vovw_z = 1\ - UNION ALL\ - SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z = 2\ - UNION ALL\ - SELECT * FROM table1_ov3, _vovw_scale WHERE _vovw_z = 3\ - UNION ALL\ - SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 3\ - ) AS _vovw_table1) _analysis_category_filter\ - WHERE name IN ($escape_0$X$escape_0$)\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + var expectedSql = ` + SELECT * FROM (WITH + _vovw_scale AS ( SELECT ZoomLevel() AS _vovw_z ) + SELECT * FROM ( + SELECT * FROM table1_ov0, _vovw_scale WHERE _vovw_z = 0 + UNION ALL + SELECT * FROM table1_ov1, _vovw_scale WHERE _vovw_z = 1 + UNION ALL + SELECT * FROM table1_ov2, _vovw_scale WHERE _vovw_z = 2 + UNION ALL + SELECT * FROM table1_ov3, _vovw_scale WHERE _vovw_z = 3 + UNION ALL + SELECT * FROM table1, _vovw_scale WHERE _vovw_z > 3 + ) AS _vovw_table1) _analysis_category_filter + WHERE name IN ($escape_0$X$escape_0$) + `; + assertSameSql(overviewsSql, expectedSql); }); - it('generates query with filters for specific zoom level', function(){ - var sql = "SELECT ST_Transform(the_geom, 3857) the_geom_webmercator, cartodb_id, name\ - FROM (SELECT *\ - FROM (select * from table1) _analysis_category_filter\ - WHERE name IN ($escape_0$X$escape_0$)) _cdb_analysis_query"; + it('generates query with filters for specific zoom level', function () { + var sql = `SELECT ST_Transform(the_geom, 3857) the_geom_webmercator, cartodb_id, name + FROM (SELECT * + FROM (select * from table1) _analysis_category_filter + WHERE name IN ($escape_0$X$escape_0$)) _cdb_analysis_query`; var data = { overviews: { table1: { @@ -577,23 +571,23 @@ describe('Overviews query rewriter', function() { 3: { table: 'table1_ov3' } } }, - filters: { name_filter: { type: 'category', column: 'name', params: { accept: [ 'X' ] } } }, + filters: { name_filter: { type: 'category', column: 'name', params: { accept: ['X'] } } }, unfiltered_query: 'SELECT * FROM table1', filter_stats: { unfiltered_rows: 1000, filtered_rows: 900 } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data, { zoom_level: 2 }); - var expected_sql = "\ - SELECT * FROM (SELECT * FROM table1_ov2) _analysis_category_filter\ - WHERE name IN ($escape_0$X$escape_0$)\ - "; - assertSameSql(overviews_sql, expected_sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data, { zoom_level: 2 }); + var expectedSql = ` + SELECT * FROM (SELECT * FROM table1_ov2) _analysis_category_filter + WHERE name IN ($escape_0$X$escape_0$) + `; + assertSameSql(overviewsSql, expectedSql); }); - it('does not generates query with aggressive filtering', function(){ - var sql = "SELECT ST_Transform(the_geom, 3857) the_geom_webmercator, cartodb_id, name\ - FROM (SELECT *\ - FROM (select * from table1) _analysis_category_filter\ - WHERE name IN ($escape_0$X$escape_0$)) _cdb_analysis_query"; + it('does not generates query with aggressive filtering', function () { + var sql = `SELECT ST_Transform(the_geom, 3857) the_geom_webmercator, cartodb_id, name + FROM (SELECT * + FROM (select * from table1) _analysis_category_filter + WHERE name IN ($escape_0$X$escape_0$)) _cdb_analysis_query`; var data = { overviews: { table1: { @@ -603,11 +597,11 @@ describe('Overviews query rewriter', function() { 3: { table: 'table1_ov3' } } }, - filters: { name_filter: { type: 'category', column: 'name', params: { accept: [ 'X' ] } } }, + filters: { name_filter: { type: 'category', column: 'name', params: { accept: ['X'] } } }, unfiltered_query: 'SELECT * FROM table1', filter_stats: { unfiltered_rows: 1000, filtered_rows: 10 } }; - var overviews_sql = overviewsQueryRewriter.query(sql, data); - assert.equal(overviews_sql, sql); + var overviewsSql = overviewsQueryRewriter.query(sql, data); + assert.strictEqual(overviewsSql, sql); }); }); diff --git a/test/unit/ported/profiler-test.js b/test/unit/ported/profiler-test.js index 5dcedf9a..f2a105c8 100644 --- a/test/unit/ported/profiler-test.js +++ b/test/unit/ported/profiler-test.js @@ -5,15 +5,14 @@ require('../../support/test-helper'); var assert = require('assert'); var ProfilerProxy = require('../../../lib/stats/profiler-proxy'); -describe('profiler', function() { - - it('Profiler is null in ProfilerProxy when profiling is not enabled', function() { - var profilerProxy = new ProfilerProxy({profile: false}); - assert.equal(profilerProxy.profiler, null); +describe('profiler', function () { + it('Profiler is null in ProfilerProxy when profiling is not enabled', function () { + var profilerProxy = new ProfilerProxy({ profile: false }); + assert.strictEqual(profilerProxy.profiler, null); }); - it('Profiler is NOT null in ProfilerProxy when profiling is enabled', function() { - var profilerProxy = new ProfilerProxy({profile: true}); - assert.notEqual(profilerProxy.profiler, null); + it('Profiler is NOT null in ProfilerProxy when profiling is enabled', function () { + var profilerProxy = new ProfilerProxy({ profile: true }); + assert.notStrictEqual(profilerProxy.profiler, null); }); }); diff --git a/test/unit/ported/stats-client-test.js b/test/unit/ported/stats-client-test.js index dba123b5..741d7ed6 100644 --- a/test/unit/ported/stats-client-test.js +++ b/test/unit/ported/stats-client-test.js @@ -6,35 +6,35 @@ var assert = require('assert'); var StatsClient = require('../../../lib/stats/client'); -describe('stats client', function() { +describe('stats client', function () { var statsInstance; - before(function() { + before(function () { statsInstance = StatsClient.instance; StatsClient.instance = null; }); - after(function() { + after(function () { StatsClient.instance = statsInstance; }); - it('reports errors when they repeat', function(done) { + it('reports errors when they repeat', function (done) { var WADUS_ERROR = 'wadus_error'; var statsClient = StatsClient.getInstance({ host: '127.0.0.1', port: 8033 }); statsClient.socket.emit('error', 'other_error'); assert.ok(statsClient.last_error); - assert.equal(statsClient.last_error.msg, 'other_error'); + assert.strictEqual(statsClient.last_error.msg, 'other_error'); assert.ok(!statsClient.last_error.interval); statsClient.socket.emit('error', WADUS_ERROR); assert.ok(statsClient.last_error); - assert.equal(statsClient.last_error.msg, WADUS_ERROR); + assert.strictEqual(statsClient.last_error.msg, WADUS_ERROR); assert.ok(!statsClient.last_error.interval); statsClient.socket.emit('error', WADUS_ERROR); assert.ok(statsClient.last_error); - assert.equal(statsClient.last_error.msg, WADUS_ERROR); + assert.strictEqual(statsClient.last_error.msg, WADUS_ERROR); assert.ok(statsClient.last_error.interval); done(); diff --git a/test/unit/ported/windshaft-server-test.js b/test/unit/ported/windshaft-server-test.js index 3085c266..14de3983 100644 --- a/test/unit/ported/windshaft-server-test.js +++ b/test/unit/ported/windshaft-server-test.js @@ -6,30 +6,28 @@ var assert = require('assert'); var cartodbServer = require('../../../lib/server'); var serverOptions = require('../../../lib/server-options'); - -describe('windshaft', function() { - - it('should have valid global environment', function() { - assert.equal(global.environment.name, 'test'); +describe('windshaft', function () { + it('should have valid global environment', function () { + assert.strictEqual(global.environment.name, 'test'); }); - it('can instantiate a Windshaft object (configured express instance)', function(){ + it('can instantiate a Windshaft object (configured express instance)', function () { var ws = cartodbServer(serverOptions); assert.ok(ws); }); - it('can spawn a new server on the global listen port', function(done){ + it('can spawn a new server on the global listen port', function (done) { var ws = cartodbServer(serverOptions); - var server = ws.listen(global.environment.port, function() { + var server = ws.listen(global.environment.port, function () { assert.ok(ws); server.close(done); /* allow proper tear down */ }); }); - it('throws exception if incorrect options passed in', function(){ + it('throws exception if incorrect options passed in', function () { assert.throws( - function(){ - var ws = cartodbServer({unbuffered_logging:true}); + function () { + var ws = cartodbServer({ unbuffered_logging: true }); ws.listen(); }, /Must initialise server with/ ); diff --git a/test/unit/prepare-context-test.js b/test/unit/prepare-context-test.js index b8675f99..928816d3 100644 --- a/test/unit/prepare-context-test.js +++ b/test/unit/prepare-context-test.js @@ -16,21 +16,20 @@ const credentialsMiddleware = require('../../lib/api/middlewares/credentials'); var windshaft = require('windshaft'); -describe('prepare-context', function() { - - var test_user = _.template(global.environment.postgres_auth_user, {user_id:1}); - var test_pubuser = global.environment.postgres.user; - var test_database = test_user + '_db'; +describe('prepare-context', function () { + var testUser = _.template(global.environment.postgres_auth_user, { user_id: 1 }); + var testPubuser = global.environment.postgres.user; + var testDatabase = testUser + '_db'; let cleanUpQueryParams; let dbConnSetup; let authorize; let setCredentials; - before(function() { + before(function () { var redisPool = new RedisPool(global.environment.redis); var mapStore = new windshaft.storage.MapStore(); - var metadataBackend = cartodbRedis({pool: redisPool}); + var metadataBackend = cartodbRedis({ pool: redisPool }); var pgConnection = new PgConnection(metadataBackend); var templateMaps = new TemplateMaps(redisPool); var authBackend = new AuthBackend(pgConnection, metadataBackend, mapStore, templateMaps); @@ -41,23 +40,22 @@ describe('prepare-context', function() { setCredentials = credentialsMiddleware(); }); - - it('can be found in server-options', function(){ + it('can be found in server-options', function () { assert.ok(_.isFunction(authorize)); assert.ok(_.isFunction(dbConnSetup)); assert.ok(_.isFunction(cleanUpQueryParams)); }); - function prepareRequest(req) { + function prepareRequest (req) { req.profiler = { - done: function() {} + done: function () {} }; return req; } - function prepareResponse(res) { - if(!res.locals) { + function prepareResponse (res) { + if (!res.locals) { res.locals = {}; } res.locals.user = 'localhost'; @@ -67,37 +65,37 @@ describe('prepare-context', function() { return res; } - it('cleans up request', function(done){ - var req = {headers: { host:'localhost' }, query: {dbuser:'hacker',dbname:'secret'}}; - var res = {}; + it('cleans up request', function (done) { + var req = { headers: { host: 'localhost' }, query: { dbuser: 'hacker', dbname: 'secret' } }; + var res = {}; - cleanUpQueryParams(prepareRequest(req), prepareResponse(res), function(err) { - if ( err ) { done(err); return; } - assert.ok(_.isObject(req.query), 'request has query'); - assert.ok(!req.query.hasOwnProperty('dbuser'), 'dbuser was removed from query'); - assert.ok(res.hasOwnProperty('locals'), 'response has locals'); - assert.ok(!res.locals.hasOwnProperty('interactivity'), 'response locals do not have interactivity'); - done(); - }); + cleanUpQueryParams(prepareRequest(req), prepareResponse(res), function (err) { + if (err) { done(err); return; } + assert.ok(_.isObject(req.query), 'request has query'); + assert.ok(!Object.prototype.hasOwnProperty.call(req.query, 'dbuser'), 'dbuser was removed from query'); + assert.ok(Object.prototype.hasOwnProperty.call(res, 'locals'), 'response has locals'); + assert.ok(!Object.prototype.hasOwnProperty.call(res.locals, 'interactivity'), 'response locals do not have interactivity'); + done(); + }); }); - it('sets dbname from redis metadata', function(done){ - var req = {headers: { host:'localhost' }, query: {} }; - var res = { set: function () {} }; + it('sets dbname from redis metadata', function (done) { + var req = { headers: { host: 'localhost' }, query: {} }; + var res = { set: function () {} }; - dbConnSetup(prepareRequest(req), prepareResponse(res), function(err) { - if ( err ) { done(err); return; } - assert.ok(_.isObject(req.query), 'request has query'); - assert.ok(!req.query.hasOwnProperty('dbuser'), 'dbuser was removed from query'); - assert.ok(res.hasOwnProperty('locals'), 'response has locals'); - assert.ok(!res.locals.hasOwnProperty('interactivity'), 'response locals do not have interactivity'); - assert.equal(res.locals.dbname, test_database); - assert.ok(res.locals.dbuser === test_pubuser, 'could inject dbuser ('+res.locals.dbuser+')'); - done(); - }); + dbConnSetup(prepareRequest(req), prepareResponse(res), function (err) { + if (err) { done(err); return; } + assert.ok(_.isObject(req.query), 'request has query'); + assert.ok(!Object.prototype.hasOwnProperty.call(req.query, 'dbuser'), 'dbuser was removed from query'); + assert.ok(Object.prototype.hasOwnProperty.call(res, 'locals'), 'response has locals'); + assert.ok(!Object.prototype.hasOwnProperty.call(res.locals, 'interactivity'), 'response locals do not have interactivity'); + assert.strictEqual(res.locals.dbname, testDatabase); + assert.ok(res.locals.dbuser === testPubuser, 'could inject dbuser (' + res.locals.dbuser + ')'); + done(); + }); }); - it('sets also dbuser for authenticated requests', function(done){ + it('sets also dbuser for authenticated requests', function (done) { var req = { headers: { host: 'localhost' @@ -116,18 +114,18 @@ describe('prepare-context', function() { // FIXME: review authorize-pgconnsetup workflow, It might we are doing authorization twice. authorize(prepareRequest(req), prepareResponse(res), function (err) { if (err) { done(err); return; } - dbConnSetup(req, res, function(err) { - if ( err ) { done(err); return; } + dbConnSetup(req, res, function (err) { + if (err) { done(err); return; } assert.ok(_.isObject(req.query), 'request has query'); - assert.ok(!req.query.hasOwnProperty('dbuser'), 'dbuser was removed from query'); - assert.ok(res.hasOwnProperty('locals'), 'response has locals'); - assert.ok(!res.locals.hasOwnProperty('interactivity'), 'request params do not have interactivity'); - assert.equal(res.locals.dbname, test_database); - assert.equal(res.locals.dbuser, test_user); + assert.ok(!Object.prototype.hasOwnProperty.call(req.query, 'dbuser'), 'dbuser was removed from query'); + assert.ok(Object.prototype.hasOwnProperty.call(res, 'locals'), 'response has locals'); + assert.ok(!Object.prototype.hasOwnProperty.call(res.locals, 'interactivity'), 'request params do not have interactivity'); + assert.strictEqual(res.locals.dbname, testDatabase); + assert.strictEqual(res.locals.dbuser, testUser); req = { headers: { - host:'localhost' + host: 'localhost' }, query: { map_key: '1235' @@ -136,22 +134,22 @@ describe('prepare-context', function() { res = { set: function () {} }; - dbConnSetup(prepareRequest(req), prepareResponse(res), function() { + dbConnSetup(prepareRequest(req), prepareResponse(res), function () { // wrong key resets params to no user - assert.ok(res.locals.dbuser === test_pubuser, 'could inject dbuser ('+res.locals.dbuser+')'); + assert.ok(res.locals.dbuser === testPubuser, 'could inject dbuser (' + res.locals.dbuser + ')'); done(); }); }); }); }); - it('it should remove invalid params', function(done) { + it('it should remove invalid params', function (done) { var config = { version: '1.3.0' }; var req = { headers: { - host:'localhost' + host: 'localhost' }, query: { non_included: 'toberemoved', @@ -163,25 +161,25 @@ describe('prepare-context', function() { var res = {}; cleanUpQueryParams(prepareRequest(req), prepareResponse(res), function (err) { - if ( err ) { + if (err) { return done(err); } - assert.deepEqual(config, req.query.config); - assert.equal('test', req.query.api_key); - assert.equal(undefined, req.query.non_included); + assert.deepStrictEqual(config, req.query.config); + assert.strictEqual('test', req.query.api_key); + assert.strictEqual(undefined, req.query.non_included); done(); }); }); - describe('Set apikey token', function(){ + describe('Set apikey token', function () { it('from query param', function (done) { var req = { headers: { host: 'localhost' }, query: { - api_key: '1234', + api_key: '1234' } }; var res = {}; @@ -191,7 +189,7 @@ describe('prepare-context', function() { } var query = res.locals; - assert.equal('1234', query.api_key); + assert.strictEqual('1234', query.api_key); done(); }); }); @@ -202,7 +200,7 @@ describe('prepare-context', function() { host: 'localhost' }, body: { - api_key: '1234', + api_key: '1234' } }; var res = {}; @@ -212,7 +210,7 @@ describe('prepare-context', function() { } var query = res.locals; - assert.equal('1234', query.api_key); + assert.strictEqual('1234', query.api_key); done(); }); }); @@ -221,7 +219,7 @@ describe('prepare-context', function() { var req = { headers: { host: 'localhost', - authorization: 'Basic bG9jYWxob3N0OjEyMzQ=', // user: localhost, password: 1234 + authorization: 'Basic bG9jYWxob3N0OjEyMzQ=' // user: localhost, password: 1234 } }; var res = {}; @@ -231,7 +229,7 @@ describe('prepare-context', function() { } var query = res.locals; - assert.equal('1234', query.api_key); + assert.strictEqual('1234', query.api_key); done(); }); }); diff --git a/test/unit/stats/reporter/named-map-provider-test.js b/test/unit/stats/reporter/named-map-provider-test.js index 48712be4..0183b69b 100644 --- a/test/unit/stats/reporter/named-map-provider-test.js +++ b/test/unit/stats/reporter/named-map-provider-test.js @@ -16,15 +16,15 @@ describe('named-map-provider-reporter', function () { const dummyCacheEntries = [ { k: 'foo:template_1', - v: { 'instantiation_1': 1 } + v: { instantiation_1: 1 } }, { k: 'bar:template_2', - v: { 'instantiation_1': 1, 'instantiation_2': 2 } + v: { instantiation_1: 1, instantiation_2: 2 } }, { k: 'buz:template_3', - v: { 'instantiation_1': 1, 'instantiation_2': 2, 'instantiation_3': 3 } + v: { instantiation_1: 1, instantiation_2: 2, instantiation_3: 3 } } ]; diff --git a/test/unit/substitution-tokens-test.js b/test/unit/substitution-tokens-test.js index 7a9e5cda..e850691d 100644 --- a/test/unit/substitution-tokens-test.js +++ b/test/unit/substitution-tokens-test.js @@ -3,8 +3,7 @@ var assert = require('assert'); var SubstitutionTokens = require('../../lib/utils/substitution-tokens'); -describe('SubstitutionTokens', function() { - +describe('SubstitutionTokens', function () { var sql = [ 'WITH hgrid AS (', ' SELECT CDB_HexagonGrid(', @@ -22,21 +21,21 @@ describe('SubstitutionTokens', function() { 'GROUP BY hgrid.cell' ].join('\n'); - it('should return tokens present in sql', function() { - assert.deepEqual(SubstitutionTokens.tokens(sql), ['bbox', 'scale_denominator', 'pixel_width', 'pixel_height']); + it('should return tokens present in sql', function () { + assert.deepStrictEqual(SubstitutionTokens.tokens(sql), ['bbox', 'scale_denominator', 'pixel_width', 'pixel_height']); }); - it('should return just one token', function() { - assert.deepEqual(SubstitutionTokens.tokens('select !bbox! from wadus'), ['bbox']); + it('should return just one token', function () { + assert.deepStrictEqual(SubstitutionTokens.tokens('select !bbox! from wadus'), ['bbox']); }); - it('should not return other tokens', function() { - assert.deepEqual(SubstitutionTokens.tokens('select !wadus! from wadus'), []); + it('should not return other tokens', function () { + assert.deepStrictEqual(SubstitutionTokens.tokens('select !wadus! from wadus'), []); }); - it('should report sql has tokens', function() { - assert.equal(SubstitutionTokens.hasTokens(sql), true); - assert.equal(SubstitutionTokens.hasTokens('select !bbox! from wadus'), true); - assert.equal(SubstitutionTokens.hasTokens('select !wadus! from wadus'), false); + it('should report sql has tokens', function () { + assert.strictEqual(SubstitutionTokens.hasTokens(sql), true); + assert.strictEqual(SubstitutionTokens.hasTokens('select !bbox! from wadus'), true); + assert.strictEqual(SubstitutionTokens.hasTokens('select !wadus! from wadus'), false); }); }); diff --git a/test/unit/table-name-parser-test.js b/test/unit/table-name-parser-test.js index e5cb73fa..1b97fea8 100644 --- a/test/unit/table-name-parser-test.js +++ b/test/unit/table-name-parser-test.js @@ -2,61 +2,58 @@ require('../support/test-helper'); -var assert = require('assert'); -var TableNameParser = require('../../lib/utils/table-name-parser'); +var assert = require('assert'); +var TableNameParser = require('../../lib/utils/table-name-parser'); -describe('TableNameParser', function() { +describe('TableNameParser', function () { + it('parses table names with scheme and quotes', function (done) { + var testCases = [ + ['xyz', { schema: null, table: 'xyz' }], + ['"xyz"', { schema: null, table: 'xyz' }], + ['"xy z"', { schema: null, table: 'xy z' }], + ['"xy.z"', { schema: null, table: 'xy.z' }], + ['"x.y.z"', { schema: null, table: 'x.y.z' }], + ['abc.xyz', { schema: 'abc', table: 'xyz' }], + ['"abc".xyz', { schema: 'abc', table: 'xyz' }], + ['abc."xyz"', { schema: 'abc', table: 'xyz' }], + ['"abc"."xyz"', { schema: 'abc', table: 'xyz' }], + ['"a bc"."x yz"', { schema: 'a bc', table: 'x yz' }], + ['"a bc".xyz', { schema: 'a bc', table: 'xyz' }], + ['"a.bc".xyz', { schema: 'a.bc', table: 'xyz' }], + ['"a.b.c".xyz', { schema: 'a.b.c', table: 'xyz' }], + ['"a.b.c.".xyz', { schema: 'a.b.c.', table: 'xyz' }], + ['"a""bc".xyz', { schema: 'a"bc', table: 'xyz' }], + ['"a""bc"."x""yz"', { schema: 'a"bc', table: 'x"yz' }] + ]; - it('parses table names with scheme and quotes', function(done){ + testCases.forEach(function (testCase) { + var tableName = testCase[0]; + var expectedResult = testCase[1]; + var result = TableNameParser.parse(tableName); + assert.deepStrictEqual(result, expectedResult); + }); + done(); + }); - var test_cases = [ - ['xyz', { schema: null, table: 'xyz' }], - ['"xyz"', { schema: null, table: 'xyz' }], - ['"xy z"', { schema: null, table: 'xy z' }], - ['"xy.z"', { schema: null, table: 'xy.z' }], - ['"x.y.z"', { schema: null, table: 'x.y.z' }], - ['abc.xyz', { schema: 'abc', table: 'xyz' }], - ['"abc".xyz', { schema: 'abc', table: 'xyz' }], - ['abc."xyz"', { schema: 'abc', table: 'xyz' }], - ['"abc"."xyz"', { schema: 'abc', table: 'xyz' }], - ['"a bc"."x yz"', { schema: 'a bc', table: 'x yz' }], - ['"a bc".xyz', { schema: 'a bc', table: 'xyz' }], - ['"a.bc".xyz', { schema: 'a.bc', table: 'xyz' }], - ['"a.b.c".xyz', { schema: 'a.b.c', table: 'xyz' }], - ['"a.b.c.".xyz', { schema: 'a.b.c.', table: 'xyz' }], - ['"a""bc".xyz', { schema: 'a"bc', table: 'xyz' }], - ['"a""bc"."x""yz"', { schema: 'a"bc', table: 'x"yz' }], - ]; + it('quotes identifiers that need quoting', function (done) { + assert.strictEqual(TableNameParser.quote('x yz'), '"x yz"'); + assert.strictEqual(TableNameParser.quote('x-yz'), '"x-yz"'); + assert.strictEqual(TableNameParser.quote('x.yz'), '"x.yz"'); + done(); + }); - test_cases.forEach(function(test_case) { - var table_name = test_case[0]; - var expected_result = test_case[1]; - var result = TableNameParser.parse(table_name); - assert.deepEqual(result, expected_result); - }); - done(); - }); - - it('quotes identifiers that need quoting', function(done){ - assert.equal(TableNameParser.quote('x yz'), '"x yz"'); - assert.equal(TableNameParser.quote('x-yz'), '"x-yz"'); - assert.equal(TableNameParser.quote('x.yz'), '"x.yz"'); - done(); - }); - - it('doubles quotes', function(done){ - assert.equal(TableNameParser.quote('x"yz'), '"x""yz"'); - assert.equal(TableNameParser.quote('x"y"z'), '"x""y""z"'); - assert.equal(TableNameParser.quote('x""y"z'), '"x""""y""z"'); - assert.equal(TableNameParser.quote('x "yz'), '"x ""yz"'); - assert.equal(TableNameParser.quote('x"y-y"z'), '"x""y-y""z"'); - done(); - }); - - it('does not quote identifiers that don\'t need to be quoted', function(done){ - assert.equal(TableNameParser.quote('xyz'), 'xyz'); - assert.equal(TableNameParser.quote('x_z123'), 'x_z123'); - done(); - }); + it('doubles quotes', function (done) { + assert.strictEqual(TableNameParser.quote('x"yz'), '"x""yz"'); + assert.strictEqual(TableNameParser.quote('x"y"z'), '"x""y""z"'); + assert.strictEqual(TableNameParser.quote('x""y"z'), '"x""""y""z"'); + assert.strictEqual(TableNameParser.quote('x "yz'), '"x ""yz"'); + assert.strictEqual(TableNameParser.quote('x"y-y"z'), '"x""y-y""z"'); + done(); + }); + it('does not quote identifiers that don\'t need to be quoted', function (done) { + assert.strictEqual(TableNameParser.quote('xyz'), 'xyz'); + assert.strictEqual(TableNameParser.quote('x_z123'), 'x_z123'); + done(); + }); }); diff --git a/test/unit/template-maps-auth-test.js b/test/unit/template-maps-auth-test.js index 4b7ff943..60ad8732 100644 --- a/test/unit/template-maps-auth-test.js +++ b/test/unit/template-maps-auth-test.js @@ -7,13 +7,12 @@ var RedisPool = require('redis-mpool'); var TemplateMaps = require('../../lib/backends/template-maps'); -describe('template_maps_auth', function() { - +describe('template_maps_auth', function () { // configure redis pool instance to use in tests - var redisPool = new RedisPool(global.environment.redis), - templateMaps = new TemplateMaps(redisPool, {max_user_templates: 1000}); + var redisPool = new RedisPool(global.environment.redis); + var templateMaps = new TemplateMaps(redisPool, { max_user_templates: 1000 }); - function makeTemplate(method, validTokens) { + function makeTemplate (method, validTokens) { var template = { name: 'wadus_template', auth: { @@ -28,11 +27,11 @@ describe('template_maps_auth', function() { return template; } - var methodToken = 'token', - methodOpen = 'open'; + var methodToken = 'token'; + var methodOpen = 'open'; - var tokenFoo = 'foo', - tokenBar = 'bar'; + var tokenFoo = 'foo'; + var tokenBar = 'bar'; var authorizationTestScenarios = [ { @@ -85,16 +84,16 @@ describe('template_maps_auth', function() { } ]; - authorizationTestScenarios.forEach(function(testScenario) { - it(testScenario.desc, function(done) { + authorizationTestScenarios.forEach(function (testScenario) { + it(testScenario.desc, function (done) { var debugMessage = testScenario.expected ? 'should be authorized' : 'unexpectedly authorized'; var result = templateMaps.isAuthorized(testScenario.template, testScenario.token); - assert.equal(result, testScenario.expected, debugMessage); + assert.strictEqual(result, testScenario.expected, debugMessage); done(); }); }); - it("auth as 'open' string is authorized", function(done) { + it("auth as 'open' string is authorized", function (done) { var template = { name: 'wadus_template', auth: 'open' @@ -103,5 +102,4 @@ describe('template_maps_auth', function() { assert.ok(templateMaps.isAuthorized(template)); done(); }); - }); diff --git a/test/unit/template-maps-defaults-test.js b/test/unit/template-maps-defaults-test.js index 3c98e77d..35f0eb53 100644 --- a/test/unit/template-maps-defaults-test.js +++ b/test/unit/template-maps-defaults-test.js @@ -7,17 +7,15 @@ var RedisPool = require('redis-mpool'); var TemplateMaps = require('../../lib/backends/template-maps'); var _ = require('underscore'); -describe('template_maps', function() { - - var redisPool = new RedisPool(global.environment.redis), - templateMaps = new TemplateMaps(redisPool); +describe('template_maps', function () { + var redisPool = new RedisPool(global.environment.redis); + var templateMaps = new TemplateMaps(redisPool); var owner = 'me'; var templateName = 'wadus'; - var defaultTemplate = { - version:'0.0.1', + version: '0.0.1', name: templateName, layergroup: { layers: [ @@ -32,7 +30,7 @@ describe('template_maps', function() { } }; - function makeTemplate(auth, placeholders) { + function makeTemplate (auth, placeholders) { return _.extend({}, defaultTemplate, { auth: auth, placeholders: placeholders @@ -90,20 +88,17 @@ describe('template_maps', function() { } ]; - testScenarios.forEach(function(testScenario) { - it('adding template returns a new instance with ' + testScenario.desc, function(done) { - - templateMaps.addTemplate(owner, testScenario.template, function(err, templateId, template) { + testScenarios.forEach(function (testScenario) { + it('adding template returns a new instance with ' + testScenario.desc, function (done) { + templateMaps.addTemplate(owner, testScenario.template, function (err, templateId, template) { assert.ok(!err, 'Unexpected error adding template: ' + (err && err.message)); assert.ok(testScenario.template !== template, 'template instances should be different'); - assert.equal(template.name, templateName); - assert.deepEqual(template.auth, testScenario.expected.auth); - assert.deepEqual(template.placeholders, testScenario.expected.placeholders); + assert.strictEqual(template.name, templateName); + assert.deepStrictEqual(template.auth, testScenario.expected.auth); + assert.deepStrictEqual(template.placeholders, testScenario.expected.placeholders); templateMaps.delTemplate(owner, templateName, done); }); - }); }); - }); diff --git a/test/unit/template-maps-test.js b/test/unit/template-maps-test.js index f4aa376b..57249be4 100644 --- a/test/unit/template-maps-test.js +++ b/test/unit/template-maps-test.js @@ -8,16 +8,15 @@ var TemplateMaps = require('../../lib/backends/template-maps'); var step = require('step'); var _ = require('underscore'); -describe('template_maps', function() { - - // configure redis pool instance to use in tests - var redis_pool = new RedisPool(global.environment.redis); +describe('template_maps', function () { + // configure redis pool instance to use in tests + var redisPool = new RedisPool(global.environment.redis); var keysToDelete; - beforeEach(function() { + beforeEach(function () { keysToDelete = {}; }); - afterEach(function(done) { + afterEach(function (done) { testHelper.deleteRedisKeys(keysToDelete, done); }); @@ -36,51 +35,57 @@ describe('template_maps', function() { } }; - it('does not accept template with unsupported version', function(done) { - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); - var tpl = { version:'6.6.6', - name:'k', auth: {}, layergroup: {layers:[wadusLayer]} }; - step( - function() { - tmap.addTemplate('me', tpl, this); - }, - function checkFailed(err) { - assert.ok(err); - assert.ok(err.message.match(/unsupported.*version/i), err); - return null; - }, - function finish(err) { - done(err); - } - ); - }); + it('does not accept template with unsupported version', function (done) { + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); + var tpl = { + version: '6.6.6', + name: 'k', + auth: {}, + layergroup: { layers: [wadusLayer] } + }; + step( + function () { + tmap.addTemplate('me', tpl, this); + }, + function checkFailed (err) { + assert.ok(err); + assert.ok(err.message.match(/unsupported.*version/i), err); + return null; + }, + function finish (err) { + done(err); + } + ); + }); - it('does not accept template with missing name', function(done) { - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); - var tpl = { version:'0.0.1', - auth: {}, layergroup: {layers:[wadusLayer]} }; - step( - function() { - tmap.addTemplate('me', tpl, this); - }, - function checkFailed(err) { - assert.ok(err); - assert.ok(err.message.match(/missing.*name/i), err); - return null; - }, - function finish(err) { - done(err); - } - ); - }); + it('does not accept template with missing name', function (done) { + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); + var tpl = { + version: '0.0.1', + auth: {}, + layergroup: { layers: [wadusLayer] } + }; + step( + function () { + tmap.addTemplate('me', tpl, this); + }, + function checkFailed (err) { + assert.ok(err); + assert.ok(err.message.match(/missing.*name/i), err); + return null; + }, + function finish (err) { + done(err); + } + ); + }); - describe('naming', function() { - - function createTemplate(name) { + describe('naming', function () { + function createTemplate (name) { return { - version:'0.0.1', + version: '0.0.1', name: name, auth: {}, layergroup: { @@ -90,12 +95,12 @@ describe('template_maps', function() { } }; } - var templateMaps = new TemplateMaps(redis_pool); + var templateMaps = new TemplateMaps(redisPool); - var invalidNames = [ "ab|", "a b", "a@b", "-1ab", "_x", "", " x", "x " ]; - invalidNames.forEach(function(invalidName) { - it('should NOT accept template with invalid name: ' + invalidName, function(done) { - templateMaps.addTemplate('me', createTemplate(invalidName), function(err) { + var invalidNames = ['ab|', 'a b', 'a@b', '-1ab', '_x', '', ' x', 'x ']; + invalidNames.forEach(function (invalidName) { + it('should NOT accept template with invalid name: ' + invalidName, function (done) { + templateMaps.addTemplate('me', createTemplate(invalidName), function (err) { assert.ok(err, "Unexpected success with invalid name '" + invalidName + "'"); assert.ok( err.message.match(/template.*name/i), @@ -107,467 +112,476 @@ describe('template_maps', function() { }); var validNames = [ - "AB", "1ab", "DFD19A1A-0AC6-11E5-B0CA-6476BA93D4F6", "25ad8300-0ac7-11e5-b93f-6476ba93d4f6" + 'AB', '1ab', 'DFD19A1A-0AC6-11E5-B0CA-6476BA93D4F6', '25ad8300-0ac7-11e5-b93f-6476ba93d4f6' ]; - validNames.forEach(function(validName) { - it('should accept template with valid name: ' + validName, function(done) { - templateMaps.addTemplate('me', createTemplate(validName), function(err) { + validNames.forEach(function (validName) { + it('should accept template with valid name: ' + validName, function (done) { + templateMaps.addTemplate('me', createTemplate(validName), function (err) { assert.ok(!err, "Unexpected error with valid name '" + validName + "': " + err); keysToDelete['map_tpl|me'] = 0; done(); }); }); }); - - }); - it('does not accept template with invalid placeholder name', function(done) { - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); - var tpl = { version:'0.0.1', - name: "valid", placeholders: {}, - auth: {}, layergroup: {layers:[wadusLayer]} }; - var invalidnames = [ "ab|", "a b", "a@b", "1ab", "_x", "", " x", "x " ]; - var testNext = function() { - if ( ! invalidnames.length ) { done(); return; } - var n = invalidnames.pop(); - tpl.placeholders = {}; - tpl.placeholders[n] = { type:'number', default:1 }; - tmap.addTemplate('me', tpl, function(err) { - if ( ! err ) { - done(new Error("Unexpected success with invalid name '" + n + "'")); - } - else if ( ! err.message.match(/invalid.*name/i) ) { - done(new Error("Unexpected error message with invalid name '" + n + "': " + err)); - } - else { - testNext(); - } - }); - }; - testNext(); - }); + it('does not accept template with invalid placeholder name', function (done) { + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); + var tpl = { + version: '0.0.1', + name: 'valid', + placeholders: {}, + auth: {}, + layergroup: { layers: [wadusLayer] } + }; + var invalidnames = ['ab|', 'a b', 'a@b', '1ab', '_x', '', ' x', 'x ']; + var testNext = function () { + if (!invalidnames.length) { done(); return; } + var n = invalidnames.pop(); + tpl.placeholders = {}; + tpl.placeholders[n] = { type: 'number', default: 1 }; + tmap.addTemplate('me', tpl, function (err) { + if (!err) { + done(new Error("Unexpected success with invalid name '" + n + "'")); + } else if (!err.message.match(/invalid.*name/i)) { + done(new Error("Unexpected error message with invalid name '" + n + "': " + err)); + } else { + testNext(); + } + }); + }; + testNext(); + }); - it('does not accept template with missing placeholder default', function(done) { - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); - var tpl = { version:'0.0.1', - name: "valid", placeholders: { v: {} }, - auth: {}, layergroup: {layers:[wadusLayer]} }; - tmap.addTemplate('me', tpl, function(err) { - if ( ! err ) { - done(new Error("Unexpected success with missing placeholder default")); - } - else if ( ! err.message.match(/missing default/i) ) { - done(new Error("Unexpected error message with missing placeholder default: " + err)); - } - else { - done(); - } - }); - }); - - it('does not accept template with missing placeholder type', function(done) { - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); - var tpl = { version:'0.0.1', - name: "valid", placeholders: { v: { default:1 } }, - auth: {}, layergroup: {layers:[wadusLayer]} }; - tmap.addTemplate('me', tpl, function(err) { - if ( ! err ) { - done(new Error("Unexpected success with missing placeholder type")); - } - else if ( ! err.message.match(/missing type/i) ) { - done(new Error("Unexpected error message with missing placeholder default: " + err)); - } - else { - done(); - } - }); - }); - - // See http://github.com/CartoDB/Windshaft-cartodb/issues/128 - it('does not accept template with invalid token auth (undefined tokens)', - function(done) { - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); - var tpl = { version:'0.0.1', - name: "invalid_auth1", placeholders: { }, - auth: { method: 'token' }, layergroup: {layers:[wadusLayer]} }; - tmap.addTemplate('me', tpl, function(err) { - if ( ! err ) { - done(new Error("Unexpected success with invalid token auth (undefined tokens)")); - } - else if ( ! err.message.match(/invalid 'token' authentication/i) ) { - done(new Error("Unexpected error message with invalid token auth (undefined tokens): " + err)); - } - else { - done(); - } - }); - }); - - it('add, get and delete a valid template', function(done) { - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); - var expected_failure = false; - var tpl_id; - var tpl = { version:'0.0.1', - name: 'first', auth: {}, layergroup: {layers:[wadusLayer]} }; - step( - function() { - tmap.addTemplate('me', tpl, this); - }, - function addOmonimousTemplate(err, id) { - assert.ifError(err); - tpl_id = id; - assert.equal(tpl_id, 'first'); - expected_failure = true; - // should fail, as it already exists - tmap.addTemplate('me', tpl, this); - }, - function getTemplate(err) { - if ( ! expected_failure && err ) { - throw err; - } - assert.ok(err); - assert.ok(err.message.match(/already exists/i), err); - tmap.getTemplate('me', tpl_id, this); - }, - function delTemplate(err, got_tpl) { - assert.ifError(err); - assert.deepEqual(got_tpl, _.extend({}, tpl, {auth: {method: 'open'}, placeholders: {}})); - tmap.delTemplate('me', tpl_id, this); - }, - function finish(err) { - done(err); - } - ); - }); - - it('add multiple templates, list them', function(done) { - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); - var tpl1 = { version:'0.0.1', name: 'first', auth: {}, layergroup: {layers:[wadusLayer]} }; - var tpl1_id; - var tpl2 = { version:'0.0.1', name: 'second', auth: {}, layergroup: {layers:[wadusLayer]} }; - var tpl2_id; - step( - function addTemplate1() { - tmap.addTemplate('me', tpl1, this); - }, - function addTemplate2(err, id) { - assert.ifError(err); - tpl1_id = id; - tmap.addTemplate('me', tpl2, this); - }, - function listTemplates(err, id) { - assert.ifError(err); - tpl2_id = id; - tmap.listTemplates('me', this); - }, - function checkTemplates(err, ids) { - assert.ifError(err); - assert.equal(ids.length, 2); - assert.ok(ids.indexOf(tpl1_id) !== -1, ids.join(',')); - assert.ok(ids.indexOf(tpl2_id) !== -1, ids.join(',')); - return null; - }, - function delTemplate1(err) { - if ( tpl1_id ) { - var next = this; - tmap.delTemplate('me', tpl1_id, function(e) { - if ( err || e ) { - next(new Error(err + '; ' + e)); + it('does not accept template with missing placeholder default', function (done) { + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); + var tpl = { + version: '0.0.1', + name: 'valid', + placeholders: { v: {} }, + auth: {}, + layergroup: { layers: [wadusLayer] } + }; + tmap.addTemplate('me', tpl, function (err) { + if (!err) { + done(new Error('Unexpected success with missing placeholder default')); + } else if (!err.message.match(/missing default/i)) { + done(new Error('Unexpected error message with missing placeholder default: ' + err)); + } else { + done(); } - else { - next(); - } - }); - } else { - assert.ifError(err); - return null; - } - }, - function delTemplate2(err) { - if ( tpl2_id ) { - var next = this; - tmap.delTemplate('me', tpl2_id, function(e) { - if ( err || e ) { - next(new Error(err + '; ' + e)); - } - else { - next(); - } - }); - } else { - assert.ifError(err); - return null; - } - }, - function finish(err) { - done(err); - } - ); - }); + }); + }); - it('update templates', function(done) { - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); - var expected_failure = false; - var owner = 'me'; - var tpl = { version:'0.0.1', - name: 'first', - auth: { method: 'open' }, - layergroup: {layers:[wadusLayer]} - }; - var tpl_id; - step( - function addTemplate() { - tmap.addTemplate(owner, tpl, this); - }, - // Updating template name should fail - function updateTemplateName(err, id) { - assert.ifError(err); - tpl_id = id; - expected_failure = true; - tpl.name = 'second'; - tmap.updTemplate(owner, tpl_id, tpl, this); - }, - function updateTemplateAuth(err) { - if ( err && ! expected_failure) { - throw err; - } - expected_failure = false; - assert.ok(err); - tpl.name = 'first'; - tpl.auth.method = 'token'; - tpl.auth.valid_tokens = [ 'tok1' ]; - tmap.updTemplate(owner, tpl_id, tpl, this); - }, - function updateTemplateWithInvalid(err) { - assert.ifError(err); - tpl.version = '999.999.999'; - expected_failure = true; - tmap.updTemplate(owner, tpl_id, tpl, this); - }, - function updateUnexistentTemplate(err) { - if ( err && ! expected_failure) { - throw err; - } - assert.ok(err); - assert.ok(err.message.match(/unsupported.*version/i), err); - tpl.version = '0.0.1'; - expected_failure = true; - tmap.updTemplate(owner, 'unexistent', tpl, this); - }, - function delTemplate(err) { - if ( err && ! expected_failure) { - throw err; - } - expected_failure = false; - assert.ok(err); - assert.ok(err.message.match(/cannot update name/i), err); - tmap.delTemplate(owner, tpl_id, this); - }, - function finish(err) { - done(err); - } - ); - }); + it('does not accept template with missing placeholder type', function (done) { + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); + var tpl = { + version: '0.0.1', + name: 'valid', + placeholders: { v: { default: 1 } }, + auth: {}, + layergroup: { layers: [wadusLayer] } + }; + tmap.addTemplate('me', tpl, function (err) { + if (!err) { + done(new Error('Unexpected success with missing placeholder type')); + } else if (!err.message.match(/missing type/i)) { + done(new Error('Unexpected error message with missing placeholder default: ' + err)); + } else { + done(); + } + }); + }); - it('instanciate templates', function() { + // See http://github.com/CartoDB/Windshaft-cartodb/issues/128 + it('does not accept template with invalid token auth (undefined tokens)', + function (done) { + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); + var tpl = { + version: '0.0.1', + name: 'invalid_auth1', + placeholders: { }, + auth: { method: 'token' }, + layergroup: { layers: [wadusLayer] } + }; + tmap.addTemplate('me', tpl, function (err) { + if (!err) { + done(new Error('Unexpected success with invalid token auth (undefined tokens)')); + } else if (!err.message.match(/invalid 'token' authentication/i)) { + done(new Error('Unexpected error message with invalid token auth (undefined tokens): ' + err)); + } else { + done(); + } + }); + }); + + it('add, get and delete a valid template', function (done) { + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); + var expectedFailure = false; + var tplId; + var tpl = { + version: '0.0.1', + name: 'first', + auth: {}, + layergroup: { layers: [wadusLayer] } + }; + step( + function () { + tmap.addTemplate('me', tpl, this); + }, + function addOmonimousTemplate (err, id) { + assert.ifError(err); + tplId = id; + assert.strictEqual(tplId, 'first'); + expectedFailure = true; + // should fail, as it already exists + tmap.addTemplate('me', tpl, this); + }, + function getTemplate (err) { + if (!expectedFailure && err) { + throw err; + } + assert.ok(err); + assert.ok(err.message.match(/already exists/i), err); + tmap.getTemplate('me', tplId, this); + }, + function delTemplate (err, gotTpl) { + assert.ifError(err); + assert.deepStrictEqual(gotTpl, _.extend({}, tpl, { auth: { method: 'open' }, placeholders: {} })); + tmap.delTemplate('me', tplId, this); + }, + function finish (err) { + done(err); + } + ); + }); + + it('add multiple templates, list them', function (done) { + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); + var tpl1 = { version: '0.0.1', name: 'first', auth: {}, layergroup: { layers: [wadusLayer] } }; + var tpl1Id; + var tpl2 = { version: '0.0.1', name: 'second', auth: {}, layergroup: { layers: [wadusLayer] } }; + var tpl2Id; + step( + function addTemplate1 () { + tmap.addTemplate('me', tpl1, this); + }, + function addTemplate2 (err, id) { + assert.ifError(err); + tpl1Id = id; + tmap.addTemplate('me', tpl2, this); + }, + function listTemplates (err, id) { + assert.ifError(err); + tpl2Id = id; + tmap.listTemplates('me', this); + }, + function checkTemplates (err, ids) { + assert.ifError(err); + assert.strictEqual(ids.length, 2); + assert.ok(ids.indexOf(tpl1Id) !== -1, ids.join(',')); + assert.ok(ids.indexOf(tpl2Id) !== -1, ids.join(',')); + return null; + }, + function delTemplate1 (err) { + if (tpl1Id) { + var next = this; + tmap.delTemplate('me', tpl1Id, function (e) { + if (err || e) { + next(new Error(err + '; ' + e)); + } else { + next(); + } + }); + } else { + assert.ifError(err); + return null; + } + }, + function delTemplate2 (err) { + if (tpl2Id) { + var next = this; + tmap.delTemplate('me', tpl2Id, function (e) { + if (err || e) { + next(new Error(err + '; ' + e)); + } else { + next(); + } + }); + } else { + assert.ifError(err); + return null; + } + }, + function finish (err) { + done(err); + } + ); + }); + + it('update templates', function (done) { + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); + var expectedFailure = false; + var owner = 'me'; + var tpl = { + version: '0.0.1', + name: 'first', + auth: { method: 'open' }, + layergroup: { layers: [wadusLayer] } + }; + var tplId; + step( + function addTemplate () { + tmap.addTemplate(owner, tpl, this); + }, + // Updating template name should fail + function updateTemplateName (err, id) { + assert.ifError(err); + tplId = id; + expectedFailure = true; + tpl.name = 'second'; + tmap.updTemplate(owner, tplId, tpl, this); + }, + function updateTemplateAuth (err) { + if (err && !expectedFailure) { + throw err; + } + expectedFailure = false; + assert.ok(err); + tpl.name = 'first'; + tpl.auth.method = 'token'; + tpl.auth.valid_tokens = ['tok1']; + tmap.updTemplate(owner, tplId, tpl, this); + }, + function updateTemplateWithInvalid (err) { + assert.ifError(err); + tpl.version = '999.999.999'; + expectedFailure = true; + tmap.updTemplate(owner, tplId, tpl, this); + }, + function updateUnexistentTemplate (err) { + if (err && !expectedFailure) { + throw err; + } + assert.ok(err); + assert.ok(err.message.match(/unsupported.*version/i), err); + tpl.version = '0.0.1'; + expectedFailure = true; + tmap.updTemplate(owner, 'unexistent', tpl, this); + }, + function delTemplate (err) { + if (err && !expectedFailure) { + throw err; + } + expectedFailure = false; + assert.ok(err); + assert.ok(err.message.match(/cannot update name/i), err); + tmap.delTemplate(owner, tplId, this); + }, + function finish (err) { + done(err); + } + ); + }); + + it('instanciate templates', function () { // jshint maxcomplexity:7 - var tmap = new TemplateMaps(redis_pool); - assert.ok(tmap); + var tmap = new TemplateMaps(redisPool); + assert.ok(tmap); - var tpl1 = { - version: '0.0.1', - name: 'acceptance1', - auth: { method: 'open' }, - placeholders: { - fill: { type: "css_color", default: "red" }, - color: { type: "css_color", default: "#a0fF9A" }, - name: { type: "sql_literal", default: "test" }, - zoom: { type: "number", default: "0" }, - test_number: { type: "number", default: 23 } - }, - layergroup: { - version: '1.0.0', - global_cartocss_version: '2.0.2', - layers: [ - { options: { - sql: "select '<%=name %>' || id, g from t", - cartocss: '#layer { marker-fill:<%= fill %>; marker-width: <%=test_number %>; }' - } }, - { options: { - sql: "select fun('<%= name%>') g from x", - cartocss: '#layer { line-color:<%= color %>; marker-fill:<%= color %>; }' - } }, - { options: { - sql: "select g from x", - cartocss: '#layer[zoom=<%=zoom%>] { }' - } } - ] - } - }; + var tpl1 = { + version: '0.0.1', + name: 'acceptance1', + auth: { method: 'open' }, + placeholders: { + fill: { type: 'css_color', default: 'red' }, + color: { type: 'css_color', default: '#a0fF9A' }, + name: { type: 'sql_literal', default: 'test' }, + zoom: { type: 'number', default: '0' }, + test_number: { type: 'number', default: 23 } + }, + layergroup: { + version: '1.0.0', + global_cartocss_version: '2.0.2', + layers: [ + { + options: { + sql: "select '<%=name %>' || id, g from t", + cartocss: '#layer { marker-fill:<%= fill %>; marker-width: <%=test_number %>; }' + } + }, + { + options: { + sql: "select fun('<%= name%>') g from x", + cartocss: '#layer { line-color:<%= color %>; marker-fill:<%= color %>; }' + } + }, + { + options: { + sql: 'select g from x', + cartocss: '#layer[zoom=<%=zoom%>] { }' + } + } + ] + } + }; - var inst = tmap.instance(tpl1, {}); + var inst = tmap.instance(tpl1, {}); - var lyr = inst.layers[0].options; - assert.equal(lyr.sql, "select 'test' || id, g from t"); - assert.equal(lyr.cartocss, '#layer { marker-fill:red; marker-width: 23; }'); + var lyr = inst.layers[0].options; + assert.strictEqual(lyr.sql, "select 'test' || id, g from t"); + assert.strictEqual(lyr.cartocss, '#layer { marker-fill:red; marker-width: 23; }'); - lyr = inst.layers[1].options; - assert.equal(lyr.sql, "select fun('test') g from x"); - assert.equal(lyr.cartocss, '#layer { line-color:#a0fF9A; marker-fill:#a0fF9A; }'); + lyr = inst.layers[1].options; + assert.strictEqual(lyr.sql, "select fun('test') g from x"); + assert.strictEqual(lyr.cartocss, '#layer { line-color:#a0fF9A; marker-fill:#a0fF9A; }'); - inst = tmap.instance(tpl1, {color:'yellow', name:"it's dangerous"}); + inst = tmap.instance(tpl1, { color: 'yellow', name: "it's dangerous" }); - lyr = inst.layers[0].options; - assert.equal(lyr.sql, "select 'it''s dangerous' || id, g from t"); - assert.equal(lyr.cartocss, '#layer { marker-fill:red; marker-width: 23; }'); + lyr = inst.layers[0].options; + assert.strictEqual(lyr.sql, "select 'it''s dangerous' || id, g from t"); + assert.strictEqual(lyr.cartocss, '#layer { marker-fill:red; marker-width: 23; }'); - lyr = inst.layers[1].options; - assert.equal(lyr.sql, "select fun('it''s dangerous') g from x"); - assert.equal(lyr.cartocss, '#layer { line-color:yellow; marker-fill:yellow; }'); + lyr = inst.layers[1].options; + assert.strictEqual(lyr.sql, "select fun('it''s dangerous') g from x"); + assert.strictEqual(lyr.cartocss, '#layer { line-color:yellow; marker-fill:yellow; }'); - // Invalid css_color - var err = null; - try { tmap.instance(tpl1, {color:'##ff00ff'}); } - catch (e) { err = e; } - assert.ok(err); - assert.ok(err.message.match(/invalid css_color/i), err); + // Invalid css_color + var err = null; + try { tmap.instance(tpl1, { color: '##ff00ff' }); } catch (e) { err = e; } + assert.ok(err); + assert.ok(err.message.match(/invalid css_color/i), err); - // Invalid css_color 2 (too few digits) - err = null; - try { tmap.instance(tpl1, {color:'#ff'}); } - catch (e) { err = e; } - assert.ok(err); - assert.ok(err.message.match(/invalid css_color/i), err); + // Invalid css_color 2 (too few digits) + err = null; + try { tmap.instance(tpl1, { color: '#ff' }); } catch (e) { err = e; } + assert.ok(err); + assert.ok(err.message.match(/invalid css_color/i), err); - // Invalid css_color 3 (too many digits) - err = null; - try { tmap.instance(tpl1, {color:'#1234567'}); } - catch (e) { err = e; } - assert.ok(err); - assert.ok(err.message.match(/invalid css_color/i), err); + // Invalid css_color 3 (too many digits) + err = null; + try { tmap.instance(tpl1, { color: '#1234567' }); } catch (e) { err = e; } + assert.ok(err); + assert.ok(err.message.match(/invalid css_color/i), err); - // Invalid number - err = null; - try { tmap.instance(tpl1, {zoom:'#'}); } - catch (e) { err = e; } - assert.ok(err); - assert.ok(err.message.match(/invalid number/i), err); + // Invalid number + err = null; + try { tmap.instance(tpl1, { zoom: '#' }); } catch (e) { err = e; } + assert.ok(err); + assert.ok(err.message.match(/invalid number/i), err); - // Invalid number 2 - err = null; - try { tmap.instance(tpl1, {zoom:'23e'}); } - catch (e) { err = e; } - assert.ok(err); - assert.ok(err.message.match(/invalid number/i), err); + // Invalid number 2 + err = null; + try { tmap.instance(tpl1, { zoom: '23e' }); } catch (e) { err = e; } + assert.ok(err); + assert.ok(err.message.match(/invalid number/i), err); - // Valid number - err = null; - try { tmap.instance(tpl1, {zoom:'-.23e10'}); } - catch (e) { err = e; } - assert.ok(!err); - }); - - // Can set a limit on the number of user templates - it('can limit number of user templates', function(done) { - var tmap = new TemplateMaps(redis_pool, { - max_user_templates: 2 + // Valid number + err = null; + try { tmap.instance(tpl1, { zoom: '-.23e10' }); } catch (e) { err = e; } + assert.ok(!err); }); - assert.ok(tmap); - var tpl = { version:'0.0.1', auth: {}, layergroup: {layers:[wadusLayer]} }; - var expectErr = false; - var idMe = []; - var idYou = []; - step( - function oneForMe() { - tpl.name = 'oneForMe'; - tmap.addTemplate('me', tpl, this); - }, - function twoForMe(err, id) { - assert.ifError(err); - assert.ok(id); - idMe.push(id); - tpl.name = 'twoForMe'; - tmap.addTemplate('me', tpl, this); - }, - function threeForMe(err, id) { - assert.ifError(err); - assert.ok(id); - idMe.push(id); - tpl.name = 'threeForMe'; - expectErr = true; - tmap.addTemplate('me', tpl, this); - }, - function errForMe(err/*, id*/) { - if ( err && ! expectErr ) { - throw err; - } - expectErr = false; - assert.ok(err); - assert.ok(err.message.match(/limit.*template/), err); - return null; - }, - function delOneMe(err) { - assert.ifError(err); - tmap.delTemplate('me', idMe.shift(), this); - }, - function threeForMeRetry(err) { - assert.ifError(err); - tpl.name = 'threeForMe'; - tmap.addTemplate('me', tpl, this); - }, - function oneForYou(err, id) { - assert.ifError(err); - assert.ok(id); - idMe.push(id); - tpl.name = 'oneForYou'; - tmap.addTemplate('you', tpl, this); - }, - function twoForYou(err, id) { - assert.ifError(err); - assert.ok(id); - idYou.push(id); - tpl.name = 'twoForYou'; - tmap.addTemplate('you', tpl, this); - }, - function threeForYou(err, id) { - assert.ifError(err); - assert.ok(id); - idYou.push(id); - tpl.name = 'threeForYou'; - expectErr = true; - tmap.addTemplate('you', tpl, this); - }, - function errForYou(err/*, id*/) { - if ( err && ! expectErr ) { - throw err; - } - expectErr = false; - assert.ok(err); - assert.ok(err.message.match(/limit.*template/), err); - return null; - }, - function finish(err) { - keysToDelete['map_tpl|you'] = 0; - keysToDelete['map_tpl|me'] = 0; - // TODO: delete all templates - done(err); - } - ); - }); - describe('emit', function() { + // Can set a limit on the number of user templates + it('can limit number of user templates', function (done) { + var tmap = new TemplateMaps(redisPool, { + max_user_templates: 2 + }); + assert.ok(tmap); + var tpl = { version: '0.0.1', auth: {}, layergroup: { layers: [wadusLayer] } }; + var expectErr = false; + var idMe = []; + var idYou = []; + step( + function oneForMe () { + tpl.name = 'oneForMe'; + tmap.addTemplate('me', tpl, this); + }, + function twoForMe (err, id) { + assert.ifError(err); + assert.ok(id); + idMe.push(id); + tpl.name = 'twoForMe'; + tmap.addTemplate('me', tpl, this); + }, + function threeForMe (err, id) { + assert.ifError(err); + assert.ok(id); + idMe.push(id); + tpl.name = 'threeForMe'; + expectErr = true; + tmap.addTemplate('me', tpl, this); + }, + function errForMe (err/*, id */) { + if (err && !expectErr) { + throw err; + } + expectErr = false; + assert.ok(err); + assert.ok(err.message.match(/limit.*template/), err); + return null; + }, + function delOneMe (err) { + assert.ifError(err); + tmap.delTemplate('me', idMe.shift(), this); + }, + function threeForMeRetry (err) { + assert.ifError(err); + tpl.name = 'threeForMe'; + tmap.addTemplate('me', tpl, this); + }, + function oneForYou (err, id) { + assert.ifError(err); + assert.ok(id); + idMe.push(id); + tpl.name = 'oneForYou'; + tmap.addTemplate('you', tpl, this); + }, + function twoForYou (err, id) { + assert.ifError(err); + assert.ok(id); + idYou.push(id); + tpl.name = 'twoForYou'; + tmap.addTemplate('you', tpl, this); + }, + function threeForYou (err, id) { + assert.ifError(err); + assert.ok(id); + idYou.push(id); + tpl.name = 'threeForYou'; + expectErr = true; + tmap.addTemplate('you', tpl, this); + }, + function errForYou (err/*, id */) { + if (err && !expectErr) { + throw err; + } + expectErr = false; + assert.ok(err); + assert.ok(err.message.match(/limit.*template/), err); + return null; + }, + function finish (err) { + keysToDelete['map_tpl|you'] = 0; + keysToDelete['map_tpl|me'] = 0; + // TODO: delete all templates + done(err); + } + ); + }); + + describe('emit', function () { var owner = 'me'; var templateName = 'emit'; var template = { - version:'0.0.1', + version: '0.0.1', name: templateName, auth: { method: 'open' @@ -581,61 +595,60 @@ describe('template_maps', function() { }; var templateUpdated = _.extend({}, template, { layergroup: { layers: [LAYER_PLAIN] } }); var templateMaps; - beforeEach(function() { - templateMaps = new TemplateMaps(redis_pool); + beforeEach(function () { + templateMaps = new TemplateMaps(redisPool); }); - it('should emit on template update', function(done) { - templateMaps.on('update', function(_owner, _templateName, _template) { - assert.equal(_owner, owner); - assert.equal(_templateName, templateName); - assert.deepEqual(_template, templateUpdated); + it('should emit on template update', function (done) { + templateMaps.on('update', function (_owner, _templateName, _template) { + assert.strictEqual(_owner, owner); + assert.strictEqual(_templateName, templateName); + assert.deepStrictEqual(_template, templateUpdated); templateMaps.delTemplate(owner, templateName, done); }); - templateMaps.addTemplate(owner, template, function(err, templateName, _template) { + templateMaps.addTemplate(owner, template, function (err, templateName, _template) { assert.ok(!err, err); - assert.deepEqual(_template, template); - templateMaps.updTemplate(owner, templateName, templateUpdated, function() {}); + assert.deepStrictEqual(_template, template); + templateMaps.updTemplate(owner, templateName, templateUpdated, function () {}); }); }); - it('should emit on template deletion', function(done) { - templateMaps.on('delete', function(_owner, _templateName) { - assert.equal(_owner, owner); - assert.equal(_templateName, templateName); + it('should emit on template deletion', function (done) { + templateMaps.on('delete', function (_owner, _templateName) { + assert.strictEqual(_owner, owner); + assert.strictEqual(_templateName, templateName); done(); }); - templateMaps.addTemplate(owner, template, function(err, templateName, _template) { + templateMaps.addTemplate(owner, template, function (err, templateName, _template) { assert.ok(!err, err); - assert.deepEqual(_template, template); - templateMaps.delTemplate(owner, templateName, function() {}); + assert.deepStrictEqual(_template, template); + templateMaps.delTemplate(owner, templateName, function () {}); }); }); - it('should NOT emit on template update when template is the same', function(done) { - templateMaps.on('update', function(_owner, _templateName, _template) { - assert.equal(_owner, owner); - assert.equal(_templateName, templateName); - assert.deepEqual(_template, templateUpdated); + it('should NOT emit on template update when template is the same', function (done) { + templateMaps.on('update', function (_owner, _templateName, _template) { + assert.strictEqual(_owner, owner); + assert.strictEqual(_templateName, templateName); + assert.deepStrictEqual(_template, templateUpdated); templateMaps.delTemplate(owner, templateName, done); }); - templateMaps.addTemplate(owner, template, function(err, templateName, _template) { + templateMaps.addTemplate(owner, template, function (err, templateName, _template) { assert.ok(!err, err); - assert.deepEqual(_template, template); + assert.deepStrictEqual(_template, template); - templateMaps.updTemplate(owner, templateName, template, function() { - templateMaps.updTemplate(owner, templateName, templateUpdated, function() {}); + templateMaps.updTemplate(owner, templateName, template, function () { + templateMaps.updTemplate(owner, templateName, templateUpdated, function () {}); }); }); }); }); - }); diff --git a/test/unit/utils/date-wrapper-test.js b/test/unit/utils/date-wrapper-test.js index a76d0792..b712fc6e 100644 --- a/test/unit/utils/date-wrapper-test.js +++ b/test/unit/utils/date-wrapper-test.js @@ -3,18 +3,17 @@ var assert = require('assert'); var dateWrapper = require('../../../lib/utils/date-wrapper'); -describe('date-wrapper', function() { - - it('should wrap property fields with spaces', function() { +describe('date-wrapper', function () { + it('should wrap property fields with spaces', function () { const actual = dateWrapper.wrapDates( - 'select * from table', - [{name: 'a'}, {name: 'b c'}] + 'select * from table', + [{ name: 'a' }, { name: 'b c' }] ); const expected = ` SELECT "a","b c" FROM (select * from table) _cdb_epoch_transformation `; - assert.equal(actual, expected); + assert.strictEqual(actual, expected); }); }); diff --git a/test/unit/valid-template-maps-test.js b/test/unit/valid-template-maps-test.js index e38d9488..94fa7706 100644 --- a/test/unit/valid-template-maps-test.js +++ b/test/unit/valid-template-maps-test.js @@ -7,21 +7,19 @@ var RedisPool = require('redis-mpool'); var TemplateMaps = require('../../lib/backends/template-maps'); var _ = require('underscore'); -describe('template_maps', function() { - - var redisPool = new RedisPool(global.environment.redis), - templateMaps = new TemplateMaps(redisPool); +describe('template_maps', function () { + var redisPool = new RedisPool(global.environment.redis); + var templateMaps = new TemplateMaps(redisPool); var owner = 'me'; var templateName = 'wadus'; - var defaultTemplate = { - version:'0.0.1', + version: '0.0.1', name: templateName }; - function makeTemplate(layers) { + function makeTemplate (layers) { var layergroup = { layers: layers }; @@ -30,14 +28,14 @@ describe('template_maps', function() { }); } - var layerWithMissingOptions = {}, - minimumValidLayer = { - options: { - sql: 'select 1 cartodb_id, null::geometry the_geom_webmercator', - cartocss: '#layer { marker-fill:blue; }', - cartocss_version: '2.3.0' - } - }; + var layerWithMissingOptions = {}; + var minimumValidLayer = { + options: { + sql: 'select 1 cartodb_id, null::geometry the_geom_webmercator', + cartocss: '#layer { marker-fill:blue; }', + cartocss_version: '2.3.0' + } + }; var testScenarios = [ { @@ -89,27 +87,18 @@ describe('template_maps', function() { } ]; - testScenarios.forEach(function(testScenario) { - it(testScenario.desc, function(done) { - - templateMaps.addTemplate(owner, testScenario.template, function(err) { - + testScenarios.forEach(function (testScenario) { + it(testScenario.desc, function (done) { + templateMaps.addTemplate(owner, testScenario.template, function (err) { if (testScenario.expected.isValid) { - assert.ok(!err); templateMaps.delTemplate(owner, templateName, done); - } else { - assert.ok(err); - assert.equal(err.message, testScenario.expected.message); + assert.strictEqual(err.message, testScenario.expected.message); done(); - } - }); - }); }); - });