Windshaft-cartodb/test/acceptance/multilayer-server-test.js

403 lines
14 KiB
JavaScript
Raw Normal View History

'use strict';
var testHelper = require('../support/test-helper');
2015-03-30 19:30:57 +08:00
var assert = require('../support/assert');
var _ = require('underscore');
2019-10-07 15:40:50 +08:00
var LayergroupToken = require('../../lib/models/layergroup-token');
var PgQueryRunner = require('../../lib/backends/pg-query-runner');
2019-09-13 22:32:37 +08:00
var QueryTables = require('cartodb-query-tables').queryTables;
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
2019-10-22 01:07:24 +08:00
describe('tests from old api translated to multilayer', function () {
var server;
before(function () {
server = createServer(serverOptions);
server.setMaxListeners(0);
});
var layergroupUrl = '/api/v1/map';
2015-09-25 20:06:53 +08:00
var keysToDelete;
2019-10-22 01:07:24 +08:00
beforeEach(function () {
2015-09-26 00:20:30 +08:00
keysToDelete = {};
2015-09-25 20:06:53 +08:00
});
2019-10-22 01:07:24 +08:00
afterEach(function (done) {
2015-09-25 20:06:53 +08:00
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";
2019-10-22 01:07:24 +08:00
function singleLayergroupConfig (sql, cartocss) {
return {
version: '1.0.0',
layers: [
{
type: 'mapnik',
options: {
sql: sql,
cartocss: cartocss,
cartocss_version: '2.0.1'
}
}
]
};
}
2019-10-22 01:07:24 +08:00
function createRequest (layergroup, userHost, apiKey) {
var url = layergroupUrl;
if (apiKey) {
url += '?api_key=' + apiKey;
}
2015-03-30 19:42:59 +08:00
return {
url: url,
2015-03-30 19:42:59 +08:00
method: 'POST',
headers: {
host: userHost || 'localhost',
'Content-Type': 'application/json'
},
data: JSON.stringify(layergroup)
};
}
2019-10-22 01:07:24 +08:00
it('layergroup creation fails if CartoCSS is bogus', function (done) {
var layergroup = singleLayergroupConfig(wadusSql, '#my_table3{');
2015-03-30 19:30:57 +08:00
assert.response(server,
2015-03-30 19:42:59 +08:00
createRequest(layergroup),
2015-03-30 19:30:57 +08:00
{
status: 400
},
2019-10-22 01:07:24 +08:00
function (res) {
2015-03-30 19:30:57 +08:00
var parsed = JSON.parse(res.body);
assert.ok(parsed.errors[0].match(/^style0/));
assert.ok(parsed.errors[0].match(/missing closing/));
2015-03-30 19:30:57 +08:00
done();
}
);
});
2019-10-22 01:07:24 +08:00
it('multiple bad styles returns 400 with all errors', function (done) {
var layergroup = singleLayergroupConfig(wadusSql, '#my_table4{backgxxxxxround-color:#fff;foo:bar}');
2015-03-30 19:30:57 +08:00
assert.response(server,
2015-03-30 19:42:59 +08:00
createRequest(layergroup),
2015-03-30 19:30:57 +08:00
{
status: 400
},
2019-10-22 01:07:24 +08:00
function (res) {
2015-03-30 19:30:57 +08:00
var parsed = JSON.parse(res.body);
assert.strictEqual(parsed.errors.length, 1);
2015-03-30 19:30:57 +08:00
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/));
done();
}
);
});
2015-03-30 19:38:34 +08:00
// Zoom is a special variable
2019-10-22 01:07:24 +08:00
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; }');
2015-03-30 19:38:34 +08:00
assert.response(server,
2015-03-30 19:42:59 +08:00
createRequest(layergroup),
2015-03-30 19:38:34 +08:00
{
status: 200
},
2019-10-22 01:07:24 +08:00
function (res) {
2015-03-30 19:38:34 +08:00
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid);
2015-09-25 20:06:53 +08:00
keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0;
2015-09-26 00:20:30 +08:00
keysToDelete['user:localhost:mapviews:global'] = 5;
2015-09-25 20:06:53 +08:00
2015-03-30 19:38:34 +08:00
done();
}
);
});
// See https://github.com/CartoDB/Windshaft-cartodb/issues/88
2019-10-22 01:07:24 +08:00
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;
global.environment.postgres.host = '6.6.6.6';
assert.response(server,
createRequest(layergroup, 'cartodb250user'),
{
status: 200
},
2019-10-22 01:07:24 +08:00
function (res) {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid);
2015-09-25 20:06:53 +08:00
keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0;
keysToDelete['user:cartodb250user:mapviews:global'] = 5;
global.environment.postgres.host = backupDBHost;
done();
}
);
});
// See https://github.com/CartoDB/Windshaft-cartodb/issues/89
2019-10-22 01:07:24 +08:00
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;
global.environment.postgres_auth_pass = '<%= user_password %>';
assert.response(server,
createRequest(layergroup, 'cartodb250user', '4321'),
{
status: 200
},
2019-10-22 01:07:24 +08:00
function (res) {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid);
2015-09-25 20:06:53 +08:00
keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0;
keysToDelete['user:cartodb250user:mapviews:global'] = 5;
global.environment.postgres_auth_pass = backupDBPass;
done();
}
);
});
2019-10-22 01:07:24 +08:00
it('creating a layergroup from lzma param', function (done) {
2015-03-30 21:01:17 +08:00
var params = {
config: JSON.stringify(singleLayergroupConfig(pointSql, '#layer { marker-fill:red; }'))
};
2019-10-22 01:07:24 +08:00
testHelper.lzma_compress_to_base64(JSON.stringify(params), 1, function (err, lzma) {
2015-03-30 21:01:17 +08:00
if (err) {
return done(err);
}
assert.response(server,
{
url: layergroupUrl + '?lzma=' + encodeURIComponent(lzma),
method: 'GET',
headers: {
host: 'localhost'
},
encoding: 'binary'
},
{
status: 200
},
2019-10-22 01:07:24 +08:00
function (res) {
2015-03-30 21:01:17 +08:00
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
2015-09-25 20:06:53 +08:00
keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0;
2015-09-26 00:20:30 +08:00
keysToDelete['user:localhost:mapviews:global'] = 5;
2015-09-25 20:06:53 +08:00
2015-03-30 21:01:17 +08:00
done();
}
);
});
});
2019-10-22 01:07:24 +08:00
it('creating a layergroup from lzma param, invalid json input', function (done) {
2015-03-30 21:06:00 +08:00
var params = {
config: 'WADUS'
};
2019-10-22 01:07:24 +08:00
testHelper.lzma_compress_to_base64(JSON.stringify(params), 1, function (err, lzma) {
2015-03-30 21:06:00 +08:00
if (err) {
return done(err);
}
assert.response(server,
{
url: layergroupUrl + '?lzma=' + encodeURIComponent(lzma),
method: 'GET',
headers: {
host: 'localhost'
},
encoding: 'binary'
},
{
status: 400
},
2019-10-22 01:07:24 +08:00
function (res) {
2015-03-30 21:06:00 +08:00
var parsed = JSON.parse(res.body);
2017-02-17 20:36:15 +08:00
assert.ok(parsed.errors);
assert.strictEqual(parsed.errors.length, 1);
assert.ok(parsed.errors[0].match(/Unexpected token W/));
2015-03-30 21:06:00 +08:00
done();
}
);
});
});
2019-10-22 01:07:24 +08:00
it('uses queries postgresql to figure affected tables in query', function (done) {
var tableName = 'gadm4';
var expectedCacheChannel = _.template('<%= databaseName %>:public.<%= tableName %>', {
2019-10-22 01:07:24 +08:00
databaseName: _.template(global.environment.postgres_auth_user, { user_id: 1 }) + '_db',
tableName: tableName
});
2019-10-22 01:07:24 +08:00
var layergroup = singleLayergroupConfig('select * from ' + tableName, '#gadm4 { marker-fill: red; }');
assert.response(server,
{
url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify(layergroup)),
method: 'GET',
headers: {
host: 'localhost'
}
},
{
status: 200
},
2019-10-22 01:07:24 +08:00
function (res) {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.ok(Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel'));
assert.strictEqual(res.headers['x-cache-channel'], expectedCacheChannel);
assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid);
2015-06-18 07:13:33 +08:00
2015-09-25 20:06:53 +08:00
keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0;
2015-09-26 00:20:30 +08:00
keysToDelete['user:localhost:mapviews:global'] = 5;
2015-09-25 20:06:53 +08:00
done();
}
);
});
// https://github.com/CartoDB/cartodb-postgresql/issues/86
2019-10-22 01:07:24 +08:00
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 %>', {
2019-10-22 01:07:24 +08:00
databaseName: _.template(global.environment.postgres_auth_user, { user_id: 1 }) + '_db',
tableName: tableName
});
2019-10-22 01:07:24 +08:00
var layergroup = singleLayergroupConfig('select * from ' + tableName, '#layer { marker-fill: red; }');
assert.response(server,
{
url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify(layergroup)),
method: 'GET',
headers: {
host: 'localhost'
}
},
{
status: 200
},
2019-10-22 01:07:24 +08:00
function (res) {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.ok(Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel'));
assert.strictEqual(res.headers['x-cache-channel'], expectedCacheChannel);
assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid);
done();
}
);
});
2019-10-22 01:07:24 +08:00
it('creates layergroup fails when postgresql queries fail to figure affected tables in query', function (done) {
var runQueryFn = PgQueryRunner.prototype.run;
2019-10-22 01:07:24 +08:00
PgQueryRunner.prototype.run = function (username, query, callback) {
return callback(new Error('fake error message'), []);
};
2019-10-22 01:07:24 +08:00
var layergroup = singleLayergroupConfig('select * from gadm4', '#gadm4 { marker-fill: red; }');
assert.response(server,
{
url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify(layergroup)),
method: 'GET',
headers: {
host: 'localhost'
}
},
{
status: 400
},
2019-10-22 01:07:24 +08:00
function (res) {
PgQueryRunner.prototype.run = runQueryFn;
assert.ok(!Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel'));
var parsed = JSON.parse(res.body);
assert.deepStrictEqual(parsed.errors, ['fake error message']);
done();
}
);
});
2019-10-22 01:07:24 +08:00
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)),
method: 'GET',
headers: {
host: 'localhost'
}
},
{
status: 200
},
2019-10-22 01:07:24 +08:00
function (res) {
2015-09-25 20:06:53 +08:00
keysToDelete['map_cfg|' + LayergroupToken.parse(JSON.parse(res.body).layergroupid).token] = 0;
2015-09-26 00:20:30 +08:00
keysToDelete['user:localhost:mapviews:global'] = 5;
2015-09-25 20:06:53 +08:00
2019-09-13 22:32:37 +08:00
var affectedFn = QueryTables.getQueryMetadataModel;
QueryTables.getQueryMetadataModel = function () {
return Promise.reject(new Error('fake error message'));
};
// reset internal cacheChannel cache
// FIXME: we need a better way to reset cache while running tests
server.layergroupAffectedTablesCache.cache.reset();
assert.response(server,
{
url: layergroupUrl + _.template('/<%= layergroupId %>/<%= z %>/<%= x %>/<%= y %>.png', {
layergroupId: JSON.parse(res.body).layergroupid,
z: 0,
x: 0,
y: 0
}),
method: 'GET',
headers: {
host: 'localhost'
},
encoding: 'binary'
},
{
status: 200
},
2019-10-22 01:07:24 +08:00
function (res) {
2019-09-13 22:32:37 +08:00
QueryTables.getQueryMetadataModel = affectedFn;
assert.ok(!Object.prototype.hasOwnProperty.call(res.headers, 'x-cache-channel'));
done();
}
);
}
);
});
});