diff --git a/lib/cartodb/template_maps.js b/lib/cartodb/template_maps.js index 233b1a49..14fae2e3 100644 --- a/lib/cartodb/template_maps.js +++ b/lib/cartodb/template_maps.js @@ -106,6 +106,11 @@ o._checkInvalidTemplate = function(template) { return new Error("Invalid characters in template name '" + tplname + "'"); } + var invalidError = isInvalidLayergroup(template.layergroup); + if (invalidError) { + return invalidError; + } + var placeholders = template.placeholders || {}; var placeholderKeys = Object.keys(placeholders); @@ -142,6 +147,32 @@ o._checkInvalidTemplate = function(template) { return false; }; +function isInvalidLayergroup(layergroup) { + if (!layergroup) { + return new Error('Missing layergroup'); + } + + var layers = layergroup.layers; + + if (!_.isArray(layers) || layers.length === 0) { + return new Error('Missing or empty layers array from layergroup config'); + } + + var invalidLayers = layers + .map(function(layer, layerIndex) { + return layer.options ? null : layerIndex; + }) + .filter(function(layerIndex) { + return layerIndex !== null; + }); + + if (invalidLayers.length) { + return new Error('Missing `options` in layergroup config for layers: ' + invalidLayers.join(', ')); + } + + return false; +} + function templateDefaults(template) { var templateAuth = _.defaults({}, template.auth || {}, { method: 'open' diff --git a/test/unit/cartodb/template_maps.test.js b/test/unit/cartodb/template_maps.test.js index 6abda6e3..f92999cc 100644 --- a/test/unit/cartodb/template_maps.test.js +++ b/test/unit/cartodb/template_maps.test.js @@ -12,11 +12,23 @@ suite('template_maps', function() { // configure redis pool instance to use in tests var redis_pool = RedisPool(global.environment.redis); + var wadusLayer = { + options: { + sql: 'select 1 cartodb_id, null::geometry the_geom_webmercator', + cartocss: '#layer { marker-fill:blue; }', + cartocss_version: '2.3.0' + } + }; + var validTemplate = { version:'0.0.1', name: 'first', auth: {}, - layergroup: {} + layergroup: { + layers: [ + wadusLayer + ] + } }; var owner = 'me'; @@ -24,7 +36,7 @@ suite('template_maps', function() { var tmap = new TemplateMaps(redis_pool); assert.ok(tmap); var tpl = { version:'6.6.6', - name:'k', auth: {}, layergroup: {} }; + name:'k', auth: {}, layergroup: {layers:[wadusLayer]} }; Step( function() { tmap.addTemplate('me', tpl, this); @@ -44,7 +56,7 @@ suite('template_maps', function() { var tmap = new TemplateMaps(redis_pool); assert.ok(tmap); var tpl = { version:'0.0.1', - auth: {}, layergroup: {} }; + auth: {}, layergroup: {layers:[wadusLayer]} }; Step( function() { tmap.addTemplate('me', tpl, this); @@ -64,7 +76,7 @@ suite('template_maps', function() { var tmap = new TemplateMaps(redis_pool); assert.ok(tmap); var tpl = { version:'0.0.1', - auth: {}, layergroup: {} }; + auth: {}, layergroup: {layers:[wadusLayer]} }; var invalidnames = [ "ab|", "a b", "a@b", "1ab", "_x", "", " x", "x " ]; var testNext = function() { if ( ! invalidnames.length ) { done(); return; } @@ -91,7 +103,7 @@ suite('template_maps', function() { assert.ok(tmap); var tpl = { version:'0.0.1', name: "valid", placeholders: {}, - auth: {}, layergroup: {} }; + auth: {}, layergroup: {layers:[wadusLayer]} }; var invalidnames = [ "ab|", "a b", "a@b", "1ab", "_x", "", " x", "x " ]; var testNext = function() { if ( ! invalidnames.length ) { done(); return; } @@ -119,7 +131,7 @@ suite('template_maps', function() { assert.ok(tmap); var tpl = { version:'0.0.1', name: "valid", placeholders: { v: {} }, - auth: {}, layergroup: {} }; + auth: {}, layergroup: {layers:[wadusLayer]} }; tmap.addTemplate('me', tpl, function(err) { if ( ! err ) { done(new Error("Unexpected success with missing placeholder default")); @@ -139,7 +151,7 @@ suite('template_maps', function() { assert.ok(tmap); var tpl = { version:'0.0.1', name: "valid", placeholders: { v: { default:1 } }, - auth: {}, layergroup: {} }; + auth: {}, layergroup: {layers:[wadusLayer]} }; tmap.addTemplate('me', tpl, function(err) { if ( ! err ) { done(new Error("Unexpected success with missing placeholder type")); @@ -161,7 +173,7 @@ suite('template_maps', function() { assert.ok(tmap); var tpl = { version:'0.0.1', name: "invalid_auth1", placeholders: { }, - auth: { method: 'token' }, layergroup: {} }; + 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)")); @@ -182,7 +194,7 @@ suite('template_maps', function() { var expected_failure = false; var tpl_id; var tpl = { version:'0.0.1', - name: 'first', auth: {}, layergroup: {} }; + name: 'first', auth: {}, layergroup: {layers:[wadusLayer]} }; Step( function() { tmap.addTemplate('me', tpl, this); @@ -216,9 +228,9 @@ suite('template_maps', function() { var tmap = new TemplateMaps(redis_pool); assert.ok(tmap); var expected_failure = false; - var tpl1 = { version:'0.0.1', name: 'first', auth: {}, layergroup: {} }; + 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: {} }; + var tpl2 = { version:'0.0.1', name: 'second', auth: {}, layergroup: {layers:[wadusLayer]} }; var tpl2_id; Step( function addTemplate1() { @@ -279,7 +291,7 @@ suite('template_maps', function() { var tpl = { version:'0.0.1', name: 'first', auth: { method: 'open' }, - layergroup: {} + layergroup: {layers:[wadusLayer]} }; var tpl_id; Step( @@ -434,7 +446,7 @@ suite('template_maps', function() { max_user_templates: 2 }); assert.ok(tmap); - var tpl = { version:'0.0.1', auth: {}, layergroup: {} }; + var tpl = { version:'0.0.1', auth: {}, layergroup: {layers:[wadusLayer]} }; var expectErr = false; var idMe = []; var idYou = []; diff --git a/test/unit/cartodb/template_maps_defaults.test.js b/test/unit/cartodb/template_maps_defaults.test.js index a8f8acfb..848c4aac 100644 --- a/test/unit/cartodb/template_maps_defaults.test.js +++ b/test/unit/cartodb/template_maps_defaults.test.js @@ -17,7 +17,15 @@ suite('template_maps', function() { version:'0.0.1', name: templateName, layergroup: { - layers: [] + layers: [ + { + options: { + sql: 'select 1 cartodb_id, null::geometry the_geom_webmercator', + cartocss: '#layer { marker-fill:blue; }', + cartocss_version: '2.3.0' + } + } + ] } }; diff --git a/test/unit/cartodb/valid_template_maps.test.js b/test/unit/cartodb/valid_template_maps.test.js new file mode 100644 index 00000000..09dab17c --- /dev/null +++ b/test/unit/cartodb/valid_template_maps.test.js @@ -0,0 +1,112 @@ +var assert = require('assert'); +var RedisPool = require('redis-mpool'); +var TemplateMaps = require('../../../lib/cartodb/template_maps.js'); +var test_helper = require('../../support/test_helper'); +var _ = require('underscore'); + +suite('template_maps', function() { + + var redisPool = new RedisPool(global.environment.redis), + templateMaps = new TemplateMaps(redisPool); + + var owner = 'me'; + var templateName = 'wadus'; + + + var defaultTemplate = { + version:'0.0.1', + name: templateName + }; + + function makeTemplate(layers) { + var layergroup = { + layers: layers + }; + return _.extend({}, defaultTemplate, { + layergroup: layergroup + }); + } + + 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 testScenarios = [ + { + desc: 'Missing layers array does not validate', + template: makeTemplate(), + expected: { + isValid: false, + message: 'Missing or empty layers array from layergroup config' + } + }, + { + desc: 'Empty layers array does not validate', + template: makeTemplate([]), + expected: { + isValid: false, + message: 'Missing or empty layers array from layergroup config' + } + }, + { + desc: 'Layer with missing options does not validate', + template: makeTemplate([ + layerWithMissingOptions + ]), + expected: { + isValid: false, + message: 'Missing `options` in layergroup config for layers: 0' + } + }, + { + desc: 'Multiple layers report invalid layer', + template: makeTemplate([ + minimumValidLayer, + layerWithMissingOptions + ]), + expected: { + isValid: false, + message: 'Missing `options` in layergroup config for layers: 1' + } + }, + { + desc: 'default auth but specified placeholders', + template: makeTemplate([ + minimumValidLayer + ]), + expected: { + isValid: true, + message: '' + } + } + ]; + + testScenarios.forEach(function(testScenario) { + test(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); + done(); + + } + + }); + + }); + }); + +});