Windshaft-cartodb/test/acceptance/ported/attributes-test.js

320 lines
12 KiB
JavaScript
Raw Normal View History

'use strict';
var testHelper = require('../../support/test-helper');
2015-07-08 05:46:58 +08:00
var assert = require('../../support/assert');
var step = require('step');
2019-10-07 15:40:50 +08:00
var cartodbServer = require('../../../lib/server');
var PortedServerOptions = require('./support/ported-server-options');
2019-10-07 15:40:50 +08:00
var LayergroupToken = require('../../../lib/models/layergroup-token');
2015-09-25 20:35:58 +08:00
2019-10-22 01:07:24 +08:00
describe('attributes', function () {
var server;
before(function () {
server = cartodbServer(PortedServerOptions);
server.setMaxListeners(0);
});
2015-07-08 05:46:58 +08:00
2019-11-14 02:36:30 +08:00
var testMapconfig1 = {
2015-07-08 05:46:58 +08:00
version: '1.1.0',
layers: [
2019-10-22 01:07:24 +08:00
{
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'
}
}
2015-07-08 05:46:58 +08:00
]
};
2019-10-22 01:07:24 +08:00
function checkCORSHeaders (res) {
assert.strictEqual(
2015-07-08 05:46:58 +08:00
res.headers['access-control-allow-headers'],
2020-02-13 19:52:20 +08:00
'X-Requested-With, X-Prototype-Version, X-CSRF-Token, Authorization, ' +
2020-02-18 00:07:26 +08:00
'Carto-Event, Carto-Event-Source, Carto-Event-Group-Id'
2015-07-08 05:46:58 +08:00
);
assert.strictEqual(res.headers['access-control-allow-origin'], '*');
2015-07-08 05:46:58 +08:00
}
2015-09-25 20:35:58 +08:00
var keysToDelete;
2019-10-22 01:07:24 +08:00
beforeEach(function () {
2015-09-26 00:41:44 +08:00
keysToDelete = {};
2015-09-25 20:35:58 +08:00
});
2019-10-22 01:07:24 +08:00
afterEach(function (done) {
2015-09-25 20:35:58 +08:00
testHelper.deleteRedisKeys(keysToDelete, done);
});
2019-10-22 01:07:24 +08:00
it('can only be fetched from layer having an attributes spec', function (done) {
2019-11-14 02:36:30 +08:00
var expectedToken;
step(
2019-11-14 02:36:30 +08:00
function doPost () {
var next = this;
assert.response(server, {
2019-10-02 01:34:03 +08:00
url: '/api/v1/map',
method: 'POST',
headers: {
host: 'localhost',
'Content-Type': 'application/json'
},
2019-11-14 02:36:30 +08:00
data: JSON.stringify(testMapconfig1)
2019-10-22 01:07:24 +08:00
}, {}, function (res, err) { next(err, res); });
},
2019-10-22 01:07:24 +08:00
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);
2019-11-14 02:36:30 +08:00
if (expectedToken) {
assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 2 });
} else {
2019-11-14 02:36:30 +08:00
expectedToken = parsedBody.layergroupid;
}
return null;
},
2019-11-14 02:36:30 +08:00
function doGetAttr0 (err) {
assert.ifError(err);
var next = this;
assert.response(server, {
2019-11-14 02:36:30 +08:00
url: '/api/v1/map/' + expectedToken + '/0/attributes/1',
method: 'GET',
headers: {
host: 'localhost'
2019-10-22 01:07:24 +08:00
}
}, {}, function (res, err) { next(err, res); });
},
2019-11-14 02:36:30 +08:00
function checkError0 (err, res) {
assert.ifError(err);
assert.strictEqual(
res.statusCode,
400,
2019-10-22 01:07:24 +08:00
res.statusCode + (res.statusCode !== 200 ? (': ' + res.body) : '')
);
var parsed = JSON.parse(res.body);
assert.strictEqual(parsed.errors[0], 'Layer 0 has no exposed attributes');
return null;
},
2019-11-14 02:36:30 +08:00
function doGetAttr1 (err) {
assert.ifError(err);
var next = this;
assert.response(server, {
2019-11-14 02:36:30 +08:00
url: '/api/v1/map/' + expectedToken + '/1/attributes/1',
method: 'GET',
headers: {
host: 'localhost'
}
2019-10-22 01:07:24 +08:00
}, {}, function (res, err) { next(err, res); });
},
2019-11-14 02:36:30 +08:00
function checkAttr1 (err, res) {
assert.ifError(err);
assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.deepStrictEqual(parsed, { n: 6 });
return null;
},
2019-11-14 02:36:30 +08:00
function doGetAttr1404 (err) {
assert.ifError(err);
var next = this;
assert.response(server, {
2019-11-14 02:36:30 +08:00
url: '/api/v1/map/' + expectedToken + '/1/attributes/-666',
method: 'GET',
headers: {
host: 'localhost'
2015-07-08 05:46:58 +08:00
}
2019-10-22 01:07:24 +08:00
}, {}, function (res, err) { next(err, res); });
},
2019-11-14 02:36:30 +08:00
function checkAttr1404 (err, res) {
assert.ifError(err);
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.strictEqual(msg, "Multiple features (0) identified by 'i' = -666 in layer 1");
return null;
},
2019-10-22 01:07:24 +08:00
function finish (err) {
2019-11-14 02:36:30 +08:00
keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
2015-09-25 20:35:58 +08:00
done(err);
}
);
});
2015-07-08 05:46:58 +08:00
// See https://github.com/CartoDB/Windshaft/issues/131
2019-10-22 01:07:24 +08:00
it('are checked at map creation time', function (done) {
// clone the mapconfig test
2019-11-14 02:36:30 +08:00
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'];
2015-07-08 05:46:58 +08:00
step(
2019-11-14 02:36:30 +08:00
function doPost () {
var next = this;
assert.response(server, {
2019-10-02 01:34:03 +08:00
url: '/api/v1/map',
method: 'POST',
headers: {
host: 'localhost',
'Content-Type': 'application/json'
},
data: JSON.stringify(mapconfig)
2019-10-22 01:07:24 +08:00
}, {}, function (res, err) { next(err, res); });
},
2019-10-22 01:07:24 +08:00
function checkPost (err, res) {
assert.ifError(err);
assert.strictEqual(res.statusCode, 404, 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, 'column "unexistant" does not exist');
return null;
},
2019-10-22 01:07:24 +08:00
function finish (err) {
done(err);
}
);
});
2015-07-08 05:46:58 +08:00
2019-10-22 01:07:24 +08:00
it('can be used with jsonp', function (done) {
2019-11-14 02:36:30 +08:00
var expectedToken;
2015-07-08 05:46:58 +08:00
step(
2019-11-14 02:36:30 +08:00
function doPost () {
2015-07-08 05:46:58 +08:00
var next = this;
assert.response(server, {
2019-10-02 01:34:03 +08:00
url: '/api/v1/map',
2015-07-08 05:46:58 +08:00
method: 'POST',
headers: {
host: 'localhost',
'Content-Type': 'application/json'
},
2019-11-14 02:36:30 +08:00
data: JSON.stringify(testMapconfig1)
2019-10-22 01:07:24 +08:00
}, {}, function (res, err) { next(err, res); });
2015-07-08 05:46:58 +08:00
},
2019-10-22 01:07:24 +08:00
function checkPost (err, res) {
2015-07-08 05:46:58 +08:00
assert.ifError(err);
assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body);
2015-07-08 05:46:58 +08:00
// CORS headers should be sent with response
// from layergroup creation via POST
checkCORSHeaders(res);
var parsedBody = JSON.parse(res.body);
2019-11-14 02:36:30 +08:00
if (expectedToken) {
assert.deepStrictEqual(parsedBody, { layergroupid: expectedToken, layercount: 2 });
2015-07-08 05:46:58 +08:00
} else {
2019-11-14 02:36:30 +08:00
expectedToken = parsedBody.layergroupid;
2015-07-08 05:46:58 +08:00
}
return null;
},
2019-11-14 02:36:30 +08:00
function doGetAttr0 (err) {
2015-07-08 05:46:58 +08:00
assert.ifError(err);
var next = this;
assert.response(server, {
2019-11-14 02:36:30 +08:00
url: '/api/v1/map/' + expectedToken +
2015-07-08 05:46:58 +08:00
'/0/attributes/1?callback=test',
method: 'GET',
headers: {
host: 'localhost'
}
2019-10-22 01:07:24 +08:00
}, {}, function (res, err) { next(err, res); });
2015-07-08 05:46:58 +08:00
},
2019-11-14 02:36:30 +08:00
function checkError0 (err, res) {
2015-07-08 05:46:58 +08:00
assert.ifError(err);
// jsonp errors should be returned with HTTP status 200
assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body);
assert.strictEqual(
2015-09-17 08:06:32 +08:00
res.body,
'/**/ typeof test === \'function\' && ' +
'test({"errors":["Layer 0 has no exposed attributes"],' +
'"errors_with_context":[{' +
'"type":"unknown","message":"Layer 0 has no exposed attributes"' +
'}]});'
2015-09-17 08:06:32 +08:00
);
2015-07-08 05:46:58 +08:00
return null;
},
2019-11-14 02:36:30 +08:00
function doGetAttr1 (err) {
2015-07-08 05:46:58 +08:00
assert.ifError(err);
var next = this;
assert.response(server, {
2019-11-14 02:36:30 +08:00
url: '/api/v1/map/' + expectedToken + '/1/attributes/1',
method: 'GET',
headers: {
host: 'localhost'
}
2019-10-22 01:07:24 +08:00
}, {}, function (res, err) { next(err, res); });
2015-07-08 05:46:58 +08:00
},
2019-11-14 02:36:30 +08:00
function checkAttr1 (err, res) {
2015-07-08 05:46:58 +08:00
assert.ifError(err);
assert.strictEqual(res.statusCode, 200, res.statusCode + ': ' + res.body);
2015-07-08 05:46:58 +08:00
var parsed = JSON.parse(res.body);
assert.deepStrictEqual(parsed, { n: 6 });
2015-07-08 05:46:58 +08:00
return null;
},
2019-10-22 01:07:24 +08:00
function finish (err) {
2019-11-14 02:36:30 +08:00
keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0;
2015-09-26 00:41:44 +08:00
keysToDelete['user:localhost:mapviews:global'] = 5;
2015-09-25 20:35:58 +08:00
done(err);
2015-07-08 05:46:58 +08:00
}
);
});
// Test that you cannot write to the database from an attributes tile request
//
// Test for http://github.com/CartoDB/Windshaft/issues/130
//
2019-10-22 01:07:24 +08:00
it('database access is read-only', function (done) {
2015-07-08 05:46:58 +08:00
// clone the mapconfig test
2019-11-14 02:36:30 +08:00
var mapconfig = JSON.parse(JSON.stringify(testMapconfig1));
2015-07-08 05:46:58 +08:00
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(
2019-11-14 02:36:30 +08:00
function doPost () {
2015-07-08 05:46:58 +08:00
var next = this;
assert.response(server, {
2019-10-02 01:34:03 +08:00
url: '/api/v1/map',
2015-07-08 05:46:58 +08:00
method: 'POST',
headers: {
host: 'localhost',
'Content-Type': 'application/json'
},
2015-07-08 05:46:58 +08:00
data: JSON.stringify(mapconfig)
2019-10-22 01:07:24 +08:00
}, {}, function (res, err) { next(err, res); });
2015-07-08 05:46:58 +08:00
},
2019-10-22 01:07:24 +08:00
function checkPost (err, res) {
2015-07-08 05:46:58 +08:00
assert.ifError(err);
// TODO: should be 403 Forbidden
assert.strictEqual(res.statusCode, 400, res.statusCode + ': ' + (res.statusCode === 200 ? '...' : res.body));
2015-07-08 05:46:58 +08:00
var parsed = JSON.parse(res.body);
assert.ok(parsed.errors);
assert.strictEqual(parsed.errors.length, 1);
2015-07-08 05:46:58 +08:00
var msg = parsed.errors[0];
assert.strictEqual(msg, 'cannot execute INSERT in a read-only transaction');
2015-07-08 05:46:58 +08:00
return null;
},
2019-10-22 01:07:24 +08:00
function finish (err) {
2015-07-08 05:46:58 +08:00
done(err);
}
);
});
});