WIP: implement timeout limit for raster
This commit is contained in:
parent
669707b26c
commit
87eb5407a8
@ -1,48 +1,25 @@
|
||||
require('../support/test_helper');
|
||||
|
||||
var assert = require('../support/assert');
|
||||
var TestClient = require('../support/test-client');
|
||||
var testHelper = require('../support/test_helper');
|
||||
const assert = require('../support/assert');
|
||||
const TestClient = require('../support/test-client');
|
||||
|
||||
var redis = require('redis');
|
||||
var keysToDelete;
|
||||
const timeoutErrorTilePath = `${process.cwd()}/assets/render-timeout-fallback.png`;
|
||||
|
||||
function withUserTimeoutRenderLimit(redisClient, user, userTimeoutLimit, callback) {
|
||||
redisClient.SELECT(5, function(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
var pointSleepSql = `
|
||||
SELECT
|
||||
pg_sleep(0.5),
|
||||
'SRID=3857;POINT(0 0)'::geometry the_geom_webmercator,
|
||||
1 cartodb_id
|
||||
`;
|
||||
|
||||
var userTimeoutLimitsKey = 'limits:timeout:' + user;
|
||||
var redisParams = [
|
||||
userTimeoutLimitsKey,
|
||||
'render', userTimeoutLimit,
|
||||
'render_public', userTimeoutLimit
|
||||
];
|
||||
|
||||
redisClient.hmset(redisParams, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
keysToDelete[userTimeoutLimitsKey] = 5;
|
||||
return callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createMapConfig (cartocss) {
|
||||
function createMapConfig (sql = pointSleepSql, cartocss = TestClient.CARTOCSS.POINTS) {
|
||||
return {
|
||||
version: '1.6.0',
|
||||
layers: [{
|
||||
type: "cartodb",
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: [
|
||||
'SELECT',
|
||||
' pg_sleep(1),',
|
||||
' 1 cartodb_id,',
|
||||
' \'SRID=3857;POINT(0 0)\'::geometry the_geom_webmercator'
|
||||
].join('\n'),
|
||||
cartocss: cartocss,
|
||||
sql,
|
||||
cartocss,
|
||||
cartocss_version: '2.3.0',
|
||||
interactivity: 'cartodb_id'
|
||||
}
|
||||
@ -51,29 +28,64 @@ function createMapConfig (cartocss) {
|
||||
}
|
||||
|
||||
describe('user timeout limits', function () {
|
||||
var redisClient = redis.createClient(global.environment.redis.port);
|
||||
describe('with onTileErrorStrategy ENABLED', function () {
|
||||
let onTileErrorStrategy;
|
||||
|
||||
beforeEach(function() {
|
||||
keysToDelete = {};
|
||||
before(function () {
|
||||
onTileErrorStrategy = global.environment.enabledFeatures.onTileErrorStrategy;
|
||||
global.environment.enabledFeatures.onTileErrorStrategy = true;
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
testHelper.deleteRedisKeys(keysToDelete, done);
|
||||
after(function () {
|
||||
global.environment.enabledFeatures.onTileErrorStrategy = onTileErrorStrategy;
|
||||
});
|
||||
|
||||
it('layergroup creation works even if test tile is slow', function (done) {
|
||||
withUserTimeoutRenderLimit(redisClient, 'localhost', 1, function (err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
it('layergroup creation works if test tile is fast but tile request fails if they are slow', function (done) {
|
||||
var testClient = new TestClient(createMapConfig(), 1234);
|
||||
|
||||
var mapConfig = createMapConfig(TestClient.CARTOCSS.POINTS);
|
||||
var testClient = new TestClient(mapConfig, 1234);
|
||||
testClient.getTile(4, 4, 4, {}, function (err /*, res, tile */) {
|
||||
assert.ok(err, err);
|
||||
// TODO: check timeout tile
|
||||
testClient.setUserRenderTimeoutLimit('localhost', 50, function (err) {
|
||||
assert.ifError(err);
|
||||
|
||||
testClient.getTile(0, 0, 0, {}, function (err, res, tile) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert.imageIsSimilarToFile(tile, timeoutErrorTilePath, 0.05, function (err) {
|
||||
assert.ifError(err);
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with onTileErrorStrategy DISABLED', function() {
|
||||
var onTileErrorStrategy;
|
||||
|
||||
beforeEach(function() {
|
||||
onTileErrorStrategy = global.environment.enabledFeatures.onTileErrorStrategy;
|
||||
global.environment.enabledFeatures.onTileErrorStrategy = false;
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
global.environment.enabledFeatures.onTileErrorStrategy = onTileErrorStrategy;
|
||||
});
|
||||
|
||||
it('layergroup creation works even if test tile is slow', function (done) {
|
||||
var testClient = new TestClient(createMapConfig(), 1234);
|
||||
testClient.setUserRenderTimeoutLimit('localhost', 50, function (err) {
|
||||
assert.ifError(err);
|
||||
var params = {
|
||||
status: 400,
|
||||
contentType: 'application/json; charset=utf-8'
|
||||
};
|
||||
|
||||
testClient.getTile(0, 0, 0, params, function (err, res, tile) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert.equal(tile.errors[0], 'Render timed out');
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -14,13 +14,13 @@ var helper = require('./test_helper');
|
||||
var CartodbWindshaft = require('../../lib/cartodb/server');
|
||||
var serverOptions = require('../../lib/cartodb/server_options');
|
||||
serverOptions.analysis.batch.inlineExecution = true;
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
|
||||
function TestClient(config, apiKey) {
|
||||
this.mapConfig = isMapConfig(config) ? config : null;
|
||||
this.template = isTemplate(config) ? config : null;
|
||||
this.apiKey = apiKey;
|
||||
this.keysToDelete = {};
|
||||
this.server = new CartodbWindshaft(serverOptions);
|
||||
}
|
||||
|
||||
module.exports = TestClient;
|
||||
@ -97,7 +97,7 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) {
|
||||
step(
|
||||
function createLayergroup() {
|
||||
var next = this;
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'POST',
|
||||
@ -156,7 +156,7 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) {
|
||||
|
||||
url = '/api/v1/map/' + layergroupId + '/0/widget/' + widgetName + '?' + qs.stringify(urlParams);
|
||||
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'GET',
|
||||
@ -208,7 +208,7 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call
|
||||
step(
|
||||
function createLayergroup() {
|
||||
var next = this;
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'POST',
|
||||
@ -265,7 +265,7 @@ TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, call
|
||||
}
|
||||
url = '/api/v1/map/' + layergroupId + '/0/widget/' + widgetName + '/search?' + qs.stringify(urlParams);
|
||||
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'GET',
|
||||
@ -332,7 +332,7 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) {
|
||||
step(
|
||||
function createLayergroup() {
|
||||
var next = this;
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'POST',
|
||||
@ -385,7 +385,7 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) {
|
||||
}
|
||||
url = '/api/v1/map/' + layergroupId + '/dataview/' + dataviewName + '?' + qs.stringify(urlParams);
|
||||
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'GET',
|
||||
@ -441,7 +441,7 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) {
|
||||
|
||||
params.placeholders = params.placeholders || {};
|
||||
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: urlNamed + '?' + qs.stringify({ api_key: self.apiKey }),
|
||||
method: 'POST',
|
||||
@ -473,7 +473,7 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) {
|
||||
urlNamed + '/' + templateId + '?' + qs.stringify({api_key: self.apiKey}) :
|
||||
url;
|
||||
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: path,
|
||||
method: 'POST',
|
||||
@ -569,20 +569,22 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) {
|
||||
expectedResponse.headers['Content-Type'] = 'application/json; charset=utf-8';
|
||||
}
|
||||
|
||||
assert.response(server, request, expectedResponse, function(res, err) {
|
||||
if (params.contentType) {
|
||||
expectedResponse.headers['Content-Type'] = 'application/json; charset=utf-8';
|
||||
}
|
||||
|
||||
assert.response(self.server, request, expectedResponse, function(res, err) {
|
||||
assert.ifError(err);
|
||||
var obj;
|
||||
|
||||
if (isPng) {
|
||||
obj = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
|
||||
}
|
||||
else if (isMvt) {
|
||||
} else if (isMvt) {
|
||||
if (res.body) {
|
||||
obj = new mapnik.VectorTile(z, x, y);
|
||||
obj.setDataSync(new Buffer(res.body, 'binary'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
obj = JSON.parse(res.body);
|
||||
}
|
||||
|
||||
@ -618,7 +620,7 @@ TestClient.prototype.getLayergroup = function(expectedResponse, callback) {
|
||||
url += '?' + qs.stringify({api_key: this.apiKey});
|
||||
}
|
||||
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'POST',
|
||||
@ -662,7 +664,7 @@ TestClient.prototype.getNodeStatus = function(nodeName, callback) {
|
||||
step(
|
||||
function createLayergroup() {
|
||||
var next = this;
|
||||
assert.response(server,
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'POST',
|
||||
@ -723,7 +725,7 @@ TestClient.prototype.getNodeStatus = function(nodeName, callback) {
|
||||
}
|
||||
};
|
||||
|
||||
assert.response(server, request, expectedResponse, function(res, err) {
|
||||
assert.response(self.server, request, expectedResponse, function(res, err) {
|
||||
assert.ifError(err);
|
||||
next(null, res, JSON.parse(res.body));
|
||||
});
|
||||
@ -741,6 +743,10 @@ TestClient.prototype.drain = function(callback) {
|
||||
};
|
||||
|
||||
module.exports.getStaticMap = function getStaticMap(templateName, params, callback) {
|
||||
var self = this;
|
||||
|
||||
self.server = new CartodbWindshaft(serverOptions);
|
||||
|
||||
if (!callback) {
|
||||
callback = params;
|
||||
params = null;
|
||||
@ -771,9 +777,22 @@ module.exports.getStaticMap = function getStaticMap(templateName, params, callba
|
||||
// this could be removed once named maps are invalidated, otherwise you hits the cache
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
|
||||
assert.response(server, requestOptions, expectedResponse, function (res, err) {
|
||||
assert.response(self.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')));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
TestClient.prototype.setUserRenderTimeoutLimit = function (user, userTimeoutLimit, callback) {
|
||||
const userTimeoutLimitsKey = `limits:timeout:${user}`;
|
||||
const params = [
|
||||
userTimeoutLimitsKey,
|
||||
'render', userTimeoutLimit,
|
||||
'render_public', userTimeoutLimit
|
||||
];
|
||||
|
||||
this.keysToDelete[userTimeoutLimitsKey] = 5;
|
||||
|
||||
helper.configureMetadata('hmset', params, callback);
|
||||
}
|
||||
|
@ -166,12 +166,29 @@ function rmdirRecursiveSync(dirname) {
|
||||
}
|
||||
}
|
||||
|
||||
function configureMetadata(action, params, callback) {
|
||||
redisClient.SELECT(5, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
redisClient[action](params, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
return callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
deleteRedisKeys: deleteRedisKeys,
|
||||
lzma_compress_to_base64: lzma_compress_to_base64,
|
||||
checkNoCache: checkNoCache,
|
||||
checkSurrogateKey: checkSurrogateKey,
|
||||
checkCache: checkCache,
|
||||
rmdirRecursiveSync: rmdirRecursiveSync
|
||||
rmdirRecursiveSync: rmdirRecursiveSync,
|
||||
configureMetadata
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user