Merge pull request #220 from CartoDB/jshint
Add jshint linting as part of the test suite
This commit is contained in:
commit
80e485d475
3
.jshintignore
Normal file
3
.jshintignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
test/support/
|
||||||
|
test/websocket_test/
|
||||||
|
app/models/formats/topojson.js
|
98
.jshintrc
Normal file
98
.jshintrc
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
{
|
||||||
|
// // 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" : false, // 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 Globals
|
||||||
|
"globals" : { // additional predefined global variables
|
||||||
|
"suite": true,
|
||||||
|
"suiteSetup": true,
|
||||||
|
"test": true,
|
||||||
|
"suiteTeardown": true,
|
||||||
|
"beforeEach": true,
|
||||||
|
"afterEach": true,
|
||||||
|
"before": true,
|
||||||
|
"after": true,
|
||||||
|
"describe": true,
|
||||||
|
"it": true
|
||||||
|
}
|
||||||
|
}
|
@ -22,5 +22,4 @@ env:
|
|||||||
|
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "0.8"
|
|
||||||
- "0.10"
|
- "0.10"
|
||||||
|
20
Makefile
20
Makefile
@ -6,3 +6,23 @@ clean:
|
|||||||
|
|
||||||
check:
|
check:
|
||||||
npm test
|
npm test
|
||||||
|
|
||||||
|
jshint:
|
||||||
|
@echo "***jshint***"
|
||||||
|
@./node_modules/.bin/jshint app/ test/ app.js
|
||||||
|
|
||||||
|
test:
|
||||||
|
@echo "***tests***"
|
||||||
|
test/run_tests.sh ${RUNTESTFLAGS} test/unit/*.js test/unit/model/*.js test/acceptance/*.js test/acceptance/export/*.js
|
||||||
|
|
||||||
|
test-unit:
|
||||||
|
@echo "***unit tests***"
|
||||||
|
test/run_tests.sh ${RUNTESTFLAGS} test/unit/*.js test/unit/model/*.js
|
||||||
|
|
||||||
|
test-acceptance:
|
||||||
|
@echo "***acceptance tests***"
|
||||||
|
test/run_tests.sh ${RUNTESTFLAGS} test/acceptance/*.js test/acceptance/export/*.js
|
||||||
|
|
||||||
|
test-all: jshint test
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
46
app.js
46
app.js
@ -9,20 +9,24 @@
|
|||||||
* environments: [development, test, production]
|
* environments: [development, test, production]
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
var _ = require('underscore'),
|
var _ = require('underscore');
|
||||||
fs = require('fs'),
|
var fs = require('fs');
|
||||||
path = require('path');
|
var path = require('path');
|
||||||
|
|
||||||
if ( process.argv[2] ) ENV = process.argv[2];
|
var ENV = process.env.NODE_ENV || 'development';
|
||||||
else if ( process.env['NODE_ENV'] ) ENV = process.env['NODE_ENV'];
|
|
||||||
else ENV = 'development';
|
|
||||||
|
|
||||||
process.env['NODE_ENV'] = ENV;
|
if (process.argv[2]) {
|
||||||
|
ENV = process.argv[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
process.env.NODE_ENV = ENV;
|
||||||
|
|
||||||
|
var availableEnvironments = ['development', 'production', 'test', 'staging'];
|
||||||
|
|
||||||
// sanity check arguments
|
// sanity check arguments
|
||||||
if (ENV != 'development' && ENV != 'production' && ENV != 'test' && ENV != 'staging' ) {
|
if (availableEnvironments.indexOf(ENV) === -1) {
|
||||||
console.error("\nnode app.js [environment]");
|
console.error("\nnode app.js [environment]");
|
||||||
console.error("environments: development, staging, production, test");
|
console.error("environments: " + availableEnvironments.join(', '));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,8 +36,8 @@ var env = require(__dirname + '/config/environments/' + ENV);
|
|||||||
env.api_hostname = require('os').hostname().split('.')[0];
|
env.api_hostname = require('os').hostname().split('.')[0];
|
||||||
_.extend(global.settings, env);
|
_.extend(global.settings, env);
|
||||||
|
|
||||||
global.log4js = require('log4js')
|
global.log4js = require('log4js');
|
||||||
log4js_config = {
|
var log4js_config = {
|
||||||
appenders: [],
|
appenders: [],
|
||||||
replaceConsole:true
|
replaceConsole:true
|
||||||
};
|
};
|
||||||
@ -63,31 +67,33 @@ if ( global.settings.rollbar ) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
log4js.configure(log4js_config, { cwd: __dirname });
|
global.log4js.configure(log4js_config, { cwd: __dirname });
|
||||||
global.logger = log4js.getLogger();
|
global.logger = global.log4js.getLogger();
|
||||||
|
|
||||||
|
|
||||||
// kick off controller
|
// kick off controller
|
||||||
if ( ! global.settings.base_url ) global.settings.base_url = '/api/*';
|
if ( ! global.settings.base_url ) {
|
||||||
|
global.settings.base_url = '/api/*';
|
||||||
|
}
|
||||||
|
|
||||||
var version = require("./package").version;
|
var version = require("./package").version;
|
||||||
|
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
app.listen(global.settings.node_port, global.settings.node_host, function() {
|
app.listen(global.settings.node_port, global.settings.node_host, function() {
|
||||||
console.log("CartoDB SQL API " + version + " listening on " +
|
console.log(
|
||||||
global.settings.node_host + ":" + global.settings.node_port +
|
"CartoDB SQL API %s listening on %s:%s with base_url %s (%s)",
|
||||||
" with base_url " + global.settings.base_url
|
version, global.settings.node_host, global.settings.node_port, global.settings.base_url, ENV
|
||||||
+ " (" + ENV + ")");
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('uncaughtException', function(err) {
|
process.on('uncaughtException', function(err) {
|
||||||
logger.error('Uncaught exception: ' + err.stack);
|
global.logger.error('Uncaught exception: ' + err.stack);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('SIGHUP', function() {
|
process.on('SIGHUP', function() {
|
||||||
global.log4js.clearAndShutdownAppenders(function() {
|
global.log4js.clearAndShutdownAppenders(function() {
|
||||||
global.log4js.configure(log4js_config);
|
global.log4js.configure(log4js_config);
|
||||||
global.logger = log4js.getLogger();
|
global.logger = global.log4js.getLogger();
|
||||||
console.log('Log files reloaded');
|
console.log('Log files reloaded');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -12,10 +12,8 @@ ApikeyAuth.prototype.verifyCredentials = function(options, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ApikeyAuth.prototype.hasCredentials = function() {
|
ApikeyAuth.prototype.hasCredentials = function() {
|
||||||
return !!(this.req.query.api_key
|
return !!(this.req.query.api_key || this.req.query.map_key ||
|
||||||
|| this.req.query.map_key
|
(this.req.body && this.req.body.api_key) || (this.req.body && this.req.body.map_key));
|
||||||
|| (this.req.body && this.req.body.api_key)
|
|
||||||
|| (this.req.body && this.req.body.map_key));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,14 +28,14 @@ function verifyRequest(req, requiredApi, callback) {
|
|||||||
var valid = false;
|
var valid = false;
|
||||||
|
|
||||||
if ( requiredApi ) {
|
if ( requiredApi ) {
|
||||||
if ( requiredApi == req.query.map_key ) {
|
if ( requiredApi === req.query.map_key ) {
|
||||||
valid = true;
|
valid = true;
|
||||||
} else if ( requiredApi == req.query.api_key ) {
|
} else if ( requiredApi === req.query.api_key ) {
|
||||||
valid = true;
|
valid = true;
|
||||||
// check also in request body
|
// check also in request body
|
||||||
} else if ( req.body && req.body.map_key && requiredApi == req.body.map_key ) {
|
} else if ( req.body && req.body.map_key && requiredApi === req.body.map_key ) {
|
||||||
valid = true;
|
valid = true;
|
||||||
} else if ( req.body && req.body.api_key && requiredApi == req.body.api_key ) {
|
} else if ( req.body && req.body.api_key && requiredApi === req.body.api_key ) {
|
||||||
valid = true;
|
valid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// too bound to the request object, but ok for now
|
// too bound to the request object, but ok for now
|
||||||
var _ = require('underscore')
|
var _ = require('underscore');
|
||||||
, OAuthUtil = require('oauth-client')
|
var OAuthUtil = require('oauth-client');
|
||||||
, url = require('url')
|
var step = require('step');
|
||||||
, Step = require('step');
|
var assert = require('assert');
|
||||||
|
|
||||||
var oAuth = function(){
|
var oAuth = (function(){
|
||||||
var me = {
|
var me = {
|
||||||
oauth_database: 3,
|
oauth_database: 3,
|
||||||
oauth_user_key: "rails:oauth_access_tokens:<%= oauth_access_key %>",
|
oauth_user_key: "rails:oauth_access_tokens:<%= oauth_access_key %>",
|
||||||
@ -15,7 +15,7 @@ var oAuth = function(){
|
|||||||
// * in GET request
|
// * in GET request
|
||||||
// * in header
|
// * in header
|
||||||
me.parseTokens = function(req){
|
me.parseTokens = function(req){
|
||||||
var query_oauth = _.clone(req.method == "POST" ? req.body: req.query);
|
var query_oauth = _.clone(req.method === "POST" ? req.body: req.query);
|
||||||
var header_oauth = {};
|
var header_oauth = {};
|
||||||
var oauth_variables = ['oauth_body_hash',
|
var oauth_variables = ['oauth_body_hash',
|
||||||
'oauth_consumer_key',
|
'oauth_consumer_key',
|
||||||
@ -34,9 +34,10 @@ var oAuth = function(){
|
|||||||
var header_string = req.headers.authorization;
|
var header_string = req.headers.authorization;
|
||||||
if (!_.isUndefined(header_string)) {
|
if (!_.isUndefined(header_string)) {
|
||||||
_.each(oauth_variables, function(oauth_key){
|
_.each(oauth_variables, function(oauth_key){
|
||||||
var matched_string = header_string.match(new RegExp(oauth_key + '=\"([^\"]+)\"'))
|
var matched_string = header_string.match(new RegExp(oauth_key + '=\"([^\"]+)\"'));
|
||||||
if (!_.isNull(matched_string))
|
if (!_.isNull(matched_string)) {
|
||||||
header_oauth[oauth_key] = decodeURIComponent(matched_string[1]);
|
header_oauth[oauth_key] = decodeURIComponent(matched_string[1]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,12 +70,12 @@ var oAuth = function(){
|
|||||||
var ohash;
|
var ohash;
|
||||||
var signature;
|
var signature;
|
||||||
|
|
||||||
Step(
|
step(
|
||||||
function getTokensFromURL(){
|
function getTokensFromURL(){
|
||||||
return oAuth.parseTokens(req);
|
return oAuth.parseTokens(req);
|
||||||
},
|
},
|
||||||
function getOAuthHash(err, data){
|
function getOAuthHash(err, data){
|
||||||
if (err) throw err;
|
assert.ifError(err);
|
||||||
|
|
||||||
// this is oauth request only if oauth headers are present
|
// this is oauth request only if oauth headers are present
|
||||||
this.is_oauth_request = !_.isEmpty(data);
|
this.is_oauth_request = !_.isEmpty(data);
|
||||||
@ -87,8 +88,10 @@ var oAuth = function(){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
function regenerateSignature(err, data){
|
function regenerateSignature(err, data){
|
||||||
if (err) throw err;
|
assert.ifError(err);
|
||||||
if (!this.is_oauth_request) return null;
|
if (!this.is_oauth_request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ohash = data;
|
ohash = data;
|
||||||
var consumer = OAuthUtil.createConsumer(ohash.consumer_key, ohash.consumer_secret);
|
var consumer = OAuthUtil.createConsumer(ohash.consumer_key, ohash.consumer_secret);
|
||||||
@ -98,7 +101,7 @@ var oAuth = function(){
|
|||||||
var method = req.method;
|
var method = req.method;
|
||||||
var host = req.headers.host;
|
var host = req.headers.host;
|
||||||
|
|
||||||
if(!httpProto || (httpProto != 'http' && httpProto != 'https')) {
|
if(!httpProto || (httpProto !== 'http' && httpProto !== 'https')) {
|
||||||
var msg = "Unknown HTTP protocol " + httpProto + ".";
|
var msg = "Unknown HTTP protocol " + httpProto + ".";
|
||||||
err = new Error(msg);
|
err = new Error(msg);
|
||||||
err.http_status = 500;
|
err.http_status = 500;
|
||||||
@ -111,13 +114,13 @@ var oAuth = function(){
|
|||||||
|
|
||||||
// remove signature from passed_tokens
|
// remove signature from passed_tokens
|
||||||
signature = passed_tokens.oauth_signature;
|
signature = passed_tokens.oauth_signature;
|
||||||
delete passed_tokens['oauth_signature'];
|
delete passed_tokens.oauth_signature;
|
||||||
|
|
||||||
var joined = {};
|
var joined = {};
|
||||||
|
|
||||||
// remove oauth_signature from body
|
// remove oauth_signature from body
|
||||||
if(req.body) {
|
if(req.body) {
|
||||||
delete req.body['oauth_signature'];
|
delete req.body.oauth_signature;
|
||||||
}
|
}
|
||||||
_.extend(joined, req.body ? req.body : null);
|
_.extend(joined, req.body ? req.body : null);
|
||||||
_.extend(joined, passed_tokens);
|
_.extend(joined, passed_tokens);
|
||||||
@ -126,7 +129,7 @@ var oAuth = function(){
|
|||||||
return signer.sign(method, path, joined);
|
return signer.sign(method, path, joined);
|
||||||
},
|
},
|
||||||
function checkSignature(err, data){
|
function checkSignature(err, data){
|
||||||
if (err) throw err;
|
assert.ifError(err);
|
||||||
|
|
||||||
//console.log(data + " should equal the provided signature: " + signature);
|
//console.log(data + " should equal the provided signature: " + signature);
|
||||||
callback(err, (signature === data && !_.isUndefined(data)) ? true : null);
|
callback(err, (signature === data && !_.isUndefined(data)) ? true : null);
|
||||||
@ -139,7 +142,7 @@ var oAuth = function(){
|
|||||||
};
|
};
|
||||||
|
|
||||||
return me;
|
return me;
|
||||||
}();
|
})();
|
||||||
|
|
||||||
function OAuthAuth(req) {
|
function OAuthAuth(req) {
|
||||||
this.req = req;
|
this.req = req;
|
||||||
|
@ -14,36 +14,47 @@
|
|||||||
// eg. vizzuality.cartodb.com/api/v1/?sql=SELECT * from my_table
|
// eg. vizzuality.cartodb.com/api/v1/?sql=SELECT * from my_table
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
var express = require('express');
|
||||||
|
var path = require('path');
|
||||||
|
var step = require('step');
|
||||||
|
var crypto = require('crypto');
|
||||||
|
var os = require('os');
|
||||||
|
var Profiler = require('step-profiler');
|
||||||
|
var StatsD = require('node-statsd').StatsD;
|
||||||
|
var PSQL = require('cartodb-psql');
|
||||||
|
var _ = require('underscore');
|
||||||
|
var LRU = require('lru-cache');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
if ( ! process.env['PGAPPNAME'] )
|
var CdbRequest = require('../models/cartodb_request');
|
||||||
process.env['PGAPPNAME']='cartodb_sqlapi';
|
var AuthApi = require('../auth/auth_api');
|
||||||
|
var formats = require('../models/formats');
|
||||||
|
var HealthCheck = require('../monitoring/health_check');
|
||||||
|
var PgErrorHandler = require('../postgresql/error_handler');
|
||||||
|
|
||||||
|
process.env.PGAPPNAME = process.env.PGAPPNAME || 'cartodb_sqlapi';
|
||||||
|
|
||||||
|
// jshint ignore:start
|
||||||
|
function pad(n) { return n < 10 ? '0' + n : n; }
|
||||||
|
Date.prototype.toJSON = function() {
|
||||||
|
var s = this.getFullYear() + '-' + pad(this.getMonth() + 1) + '-' + pad(this.getDate()) + 'T' +
|
||||||
|
pad(this.getHours()) + ':' + pad(this.getMinutes()) + ':' + pad(this.getSeconds());
|
||||||
|
var offset = this.getTimezoneOffset();
|
||||||
|
if (offset === 0) {
|
||||||
|
s += 'Z';
|
||||||
|
} else {
|
||||||
|
s += ( offset < 0 ? '+' : '-' ) + pad(Math.abs(offset / 60)) + pad(Math.abs(offset % 60));
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
// jshint ignore:end
|
||||||
|
|
||||||
|
// jshint maxcomplexity:21
|
||||||
function App() {
|
function App() {
|
||||||
|
|
||||||
var path = require('path');
|
var app = express.createServer();
|
||||||
|
|
||||||
var express = require('express')
|
var metadataBackend = require('cartodb-redis')({
|
||||||
, app = express.createServer()
|
|
||||||
, Step = require('step')
|
|
||||||
, crypto = require('crypto')
|
|
||||||
, fs = require('fs')
|
|
||||||
, os = require('os')
|
|
||||||
, zlib = require('zlib')
|
|
||||||
, util = require('util')
|
|
||||||
, Profiler = require('step-profiler')
|
|
||||||
, StatsD = require('node-statsd').StatsD
|
|
||||||
, MetadataDB = require('cartodb-redis')
|
|
||||||
, PSQL = require('cartodb-psql')
|
|
||||||
, CdbRequest = require(global.settings.app_root + '/app/models/cartodb_request')
|
|
||||||
, AuthApi = require(global.settings.app_root + '/app/auth/auth_api')
|
|
||||||
, _ = require('underscore')
|
|
||||||
, LRU = require('lru-cache')
|
|
||||||
, formats = require(global.settings.app_root + '/app/models/formats')
|
|
||||||
, HealthCheck = require(global.settings.app_root + '/app/monitoring/health_check')
|
|
||||||
, PgErrorHandler = require(global.settings.app_root + '/app/postgresql/error_handler')
|
|
||||||
;
|
|
||||||
|
|
||||||
var metadataBackend = MetadataDB({
|
|
||||||
host: global.settings.redis_host,
|
host: global.settings.redis_host,
|
||||||
port: global.settings.redis_port,
|
port: global.settings.redis_port,
|
||||||
max: global.settings.redisPool,
|
max: global.settings.redisPool,
|
||||||
@ -63,25 +74,6 @@ var tableCache = LRU({
|
|||||||
maxAge: global.settings.tableCacheMaxAge || 1000*60*10
|
maxAge: global.settings.tableCacheMaxAge || 1000*60*10
|
||||||
});
|
});
|
||||||
|
|
||||||
function pad(n) { return n < 10 ? '0' + n : n }
|
|
||||||
Date.prototype.toJSON = function() {
|
|
||||||
var s = this.getFullYear() + '-'
|
|
||||||
+ pad(this.getMonth() + 1) + '-'
|
|
||||||
+ pad(this.getDate()) + 'T'
|
|
||||||
+ pad(this.getHours()) + ':'
|
|
||||||
+ pad(this.getMinutes()) + ':'
|
|
||||||
+ pad(this.getSeconds());
|
|
||||||
var offset = this.getTimezoneOffset();
|
|
||||||
if (offset == 0) s += 'Z';
|
|
||||||
else {
|
|
||||||
s += ( offset < 0 ? '+' : '-' )
|
|
||||||
+ pad(Math.abs(offset / 60))
|
|
||||||
+ pad(Math.abs(offset % 60))
|
|
||||||
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
};
|
|
||||||
|
|
||||||
var loggerOpts = {
|
var loggerOpts = {
|
||||||
buffer: true,
|
buffer: true,
|
||||||
format: global.settings.log_format ||
|
format: global.settings.log_format ||
|
||||||
@ -89,7 +81,7 @@ var loggerOpts = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if ( global.log4js ) {
|
if ( global.log4js ) {
|
||||||
app.use(log4js.connectLogger(log4js.getLogger(), _.defaults(loggerOpts, {level:'info'})));
|
app.use(global.log4js.connectLogger(global.log4js.getLogger(), _.defaults(loggerOpts, {level:'info'})));
|
||||||
} else {
|
} else {
|
||||||
app.use(express.logger(loggerOpts));
|
app.use(express.logger(loggerOpts));
|
||||||
}
|
}
|
||||||
@ -110,7 +102,7 @@ if ( global.settings.statsd ) {
|
|||||||
var last_err = statsd_client.last_error;
|
var last_err = statsd_client.last_error;
|
||||||
var last_msg = last_err.msg;
|
var last_msg = last_err.msg;
|
||||||
var this_msg = ''+err;
|
var this_msg = ''+err;
|
||||||
if ( this_msg != last_msg ) {
|
if ( this_msg !== last_msg ) {
|
||||||
console.error("statsd client socket error: " + err);
|
console.error("statsd client socket error: " + err);
|
||||||
statsd_client.last_error.count = 1;
|
statsd_client.last_error.count = 1;
|
||||||
statsd_client.last_error.msg = this_msg;
|
statsd_client.last_error.msg = this_msg;
|
||||||
@ -147,7 +139,7 @@ if ( global.settings.hasOwnProperty('node_socket_timeout') ) {
|
|||||||
var timeout = parseInt(global.settings.node_socket_timeout);
|
var timeout = parseInt(global.settings.node_socket_timeout);
|
||||||
app.use(function(req, res, next) {
|
app.use(function(req, res, next) {
|
||||||
req.connection.setTimeout(timeout);
|
req.connection.setTimeout(timeout);
|
||||||
next()
|
next();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +208,9 @@ function handleQuery(req, res) {
|
|||||||
var gn = "the_geom"; // TODO: read from configuration file
|
var gn = "the_geom"; // TODO: read from configuration file
|
||||||
var tableCacheItem;
|
var tableCacheItem;
|
||||||
|
|
||||||
if ( req.profiler ) req.profiler.start('sqlapi.query');
|
if ( req.profiler ) {
|
||||||
|
req.profiler.start('sqlapi.query');
|
||||||
|
}
|
||||||
|
|
||||||
req.aborted = false;
|
req.aborted = false;
|
||||||
req.on("close", function() {
|
req.on("close", function() {
|
||||||
@ -248,8 +242,9 @@ function handleQuery(req, res) {
|
|||||||
|
|
||||||
// Accept both comma-separated string or array of comma-separated strings
|
// Accept both comma-separated string or array of comma-separated strings
|
||||||
if ( requestedSkipfields ) {
|
if ( requestedSkipfields ) {
|
||||||
if ( _.isString(requestedSkipfields) ) skipfields = requestedSkipfields.split(',');
|
if ( _.isString(requestedSkipfields) ) {
|
||||||
else if ( _.isArray(requestedSkipfields) ) {
|
skipfields = requestedSkipfields.split(',');
|
||||||
|
} else if ( _.isArray(requestedSkipfields) ) {
|
||||||
skipfields = [];
|
skipfields = [];
|
||||||
_.each(requestedSkipfields, function(ele) {
|
_.each(requestedSkipfields, function(ele) {
|
||||||
skipfields = skipfields.concat(ele.split(','));
|
skipfields = skipfields.concat(ele.split(','));
|
||||||
@ -287,14 +282,16 @@ function handleQuery(req, res) {
|
|||||||
var authApi = new AuthApi(req, params),
|
var authApi = new AuthApi(req, params),
|
||||||
dbParams;
|
dbParams;
|
||||||
|
|
||||||
if ( req.profiler ) req.profiler.done('init');
|
if ( req.profiler ) {
|
||||||
|
req.profiler.done('init');
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Get database from redis via the username stored in the host header subdomain
|
// 1. Get database from redis via the username stored in the host header subdomain
|
||||||
// 2. Run the request through OAuth to get R/W user id if signed
|
// 2. Run the request through OAuth to get R/W user id if signed
|
||||||
// 3. Get the list of tables affected by the query
|
// 3. Get the list of tables affected by the query
|
||||||
// 4. Setup headers
|
// 4. Setup headers
|
||||||
// 5. Send formatted results back
|
// 5. Send formatted results back
|
||||||
Step(
|
step(
|
||||||
function getDatabaseConnectionParams() {
|
function getDatabaseConnectionParams() {
|
||||||
checkAborted('getDatabaseConnectionParams');
|
checkAborted('getDatabaseConnectionParams');
|
||||||
// If the request is providing credentials it may require every DB parameters
|
// If the request is providing credentials it may require every DB parameters
|
||||||
@ -307,12 +304,14 @@ function handleQuery(req, res) {
|
|||||||
function authenticate(err, userDBParams) {
|
function authenticate(err, userDBParams) {
|
||||||
if (err) {
|
if (err) {
|
||||||
err.http_status = 404;
|
err.http_status = 404;
|
||||||
err.message = "Sorry, we can't find CartoDB user '" + cdbUsername
|
err.message = "Sorry, we can't find CartoDB user '" + cdbUsername + "'. " +
|
||||||
+ "'. Please check that you have entered the correct domain.";
|
"Please check that you have entered the correct domain.";
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( req.profiler ) req.profiler.done('getDBParams');
|
if ( req.profiler ) {
|
||||||
|
req.profiler.done('getDBParams');
|
||||||
|
}
|
||||||
|
|
||||||
dbParams = userDBParams;
|
dbParams = userDBParams;
|
||||||
|
|
||||||
@ -330,7 +329,9 @@ function handleQuery(req, res) {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( req.profiler ) req.profiler.done('authenticate');
|
if ( req.profiler ) {
|
||||||
|
req.profiler.done('authenticate');
|
||||||
|
}
|
||||||
|
|
||||||
if (_.isBoolean(isAuthenticated) && isAuthenticated) {
|
if (_.isBoolean(isAuthenticated) && isAuthenticated) {
|
||||||
authenticated = isAuthenticated;
|
authenticated = isAuthenticated;
|
||||||
@ -349,9 +350,11 @@ function handleQuery(req, res) {
|
|||||||
function queryExplain(err){
|
function queryExplain(err){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (err) throw err;
|
assert.ifError(err);
|
||||||
|
|
||||||
if ( req.profiler ) req.profiler.done('setDBAuth');
|
if ( req.profiler ) {
|
||||||
|
req.profiler.done('setDBAuth');
|
||||||
|
}
|
||||||
|
|
||||||
checkAborted('queryExplain');
|
checkAborted('queryExplain');
|
||||||
|
|
||||||
@ -373,16 +376,20 @@ function handleQuery(req, res) {
|
|||||||
var tables = raw_tables.split(/^\{(.*)\}$/)[1].split(',');
|
var tables = raw_tables.split(/^\{(.*)\}$/)[1].split(',');
|
||||||
self(null, tables);
|
self(null, tables);
|
||||||
} else {
|
} else {
|
||||||
console.error("Unexpected result from CDB_QueryTables($quotesql$" + sql + "$quotesql$): " + result);
|
console.error(
|
||||||
|
"Unexpected result from CDB_QueryTables($quotesql$" + sql + "$quotesql$): " + result
|
||||||
|
);
|
||||||
self(null, []);
|
self(null, []);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function setHeaders(err, tables){
|
function setHeaders(err, tables){
|
||||||
if (err) throw err;
|
assert.ifError(err);
|
||||||
|
|
||||||
if ( req.profiler ) req.profiler.done('queryExplain');
|
if ( req.profiler ) {
|
||||||
|
req.profiler.done('queryExplain');
|
||||||
|
}
|
||||||
|
|
||||||
checkAborted('setHeaders');
|
checkAborted('setHeaders');
|
||||||
|
|
||||||
@ -410,8 +417,8 @@ function handleQuery(req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fClass = formats[format];
|
var FormatClass = formats[format];
|
||||||
formatter = new fClass();
|
formatter = new FormatClass();
|
||||||
req.formatter = formatter;
|
req.formatter = formatter;
|
||||||
|
|
||||||
|
|
||||||
@ -454,7 +461,7 @@ function handleQuery(req, res) {
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
function generateFormat(err){
|
function generateFormat(err){
|
||||||
if (err) throw err;
|
assert.ifError(err);
|
||||||
checkAborted('generateFormat');
|
checkAborted('generateFormat');
|
||||||
|
|
||||||
// TODO: drop this, fix UI!
|
// TODO: drop this, fix UI!
|
||||||
@ -493,25 +500,32 @@ function handleQuery(req, res) {
|
|||||||
function errorHandle(err){
|
function errorHandle(err){
|
||||||
formatter = null;
|
formatter = null;
|
||||||
|
|
||||||
if ( err ) handleException(err, res);
|
if ( err ) {
|
||||||
|
handleException(err, res);
|
||||||
|
}
|
||||||
if ( req.profiler ) {
|
if ( req.profiler ) {
|
||||||
req.profiler.sendStats(); // TODO: do on nextTick ?
|
req.profiler.sendStats(); // TODO: do on nextTick ?
|
||||||
}
|
}
|
||||||
if (statsd_client) {
|
if (statsd_client) {
|
||||||
if ( err ) statsd_client.increment('sqlapi.query.error');
|
if ( err ) {
|
||||||
else statsd_client.increment('sqlapi.query.success');
|
statsd_client.increment('sqlapi.query.error');
|
||||||
|
} else {
|
||||||
|
statsd_client.increment('sqlapi.query.success');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleException(err, res);
|
handleException(err, res);
|
||||||
if (statsd_client) statsd_client.increment('sqlapi.query.error');
|
if (statsd_client) {
|
||||||
|
statsd_client.increment('sqlapi.query.error');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCacheStatus(req, res){
|
function handleCacheStatus(req, res){
|
||||||
var tableCacheValues = tableCache.values();
|
var tableCacheValues = tableCache.values();
|
||||||
var totalExplainHits = _.reduce(tableCacheValues, function(memo, res) { return memo + res.hits}, 0);
|
var totalExplainHits = _.reduce(tableCacheValues, function(memo, res) { return memo + res.hits; }, 0);
|
||||||
var totalExplainKeys = tableCacheValues.length;
|
var totalExplainKeys = tableCacheValues.length;
|
||||||
res.send({explain: {pid: process.pid, hits: totalExplainHits, keys : totalExplainKeys }});
|
res.send({explain: {pid: process.pid, hits: totalExplainHits, keys : totalExplainKeys }});
|
||||||
}
|
}
|
||||||
@ -543,7 +557,8 @@ function handleHealthCheck(req, res) {
|
|||||||
function getContentDisposition(formatter, filename, inline) {
|
function getContentDisposition(formatter, filename, inline) {
|
||||||
var ext = formatter.getFileExtension();
|
var ext = formatter.getFileExtension();
|
||||||
var time = new Date().toUTCString();
|
var time = new Date().toUTCString();
|
||||||
return ( inline ? 'inline' : 'attachment' ) +'; filename=' + filename + '.' + ext + '; modification-date="' + time + '";';
|
return ( inline ? 'inline' : 'attachment' ) + '; filename=' + filename + '.' + ext + '; ' +
|
||||||
|
'modification-date="' + time + '";';
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCrossDomain(res){
|
function setCrossDomain(res){
|
||||||
@ -575,13 +590,13 @@ function handleException(err, res) {
|
|||||||
|
|
||||||
_.defaults(msg, pgErrorHandler.getFields());
|
_.defaults(msg, pgErrorHandler.getFields());
|
||||||
|
|
||||||
if (global.settings.environment == 'development') {
|
if (global.settings.environment === 'development') {
|
||||||
msg.stack = err.stack;
|
msg.stack = err.stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.settings.environment !== 'test'){
|
if (global.settings.environment !== 'test'){
|
||||||
// TODO: email this Exception report
|
// TODO: email this Exception report
|
||||||
console.error("EXCEPTION REPORT: " + err.stack)
|
console.error("EXCEPTION REPORT: " + err.stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow cross site post
|
// allow cross site post
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
function ArrayBufferSer(type, data, options) {
|
function ArrayBufferSer(type, data, options) {
|
||||||
if(type === undefined) throw "ArrayBufferSer should be created with a type";
|
if(type === undefined) {
|
||||||
|
throw "ArrayBufferSer should be created with a type";
|
||||||
|
}
|
||||||
this.options = options || {};
|
this.options = options || {};
|
||||||
this._initFunctions();
|
this._initFunctions();
|
||||||
this.headerSize = 8;
|
this.headerSize = 8;
|
||||||
@ -14,13 +16,14 @@ function ArrayBufferSer(type, data, options) {
|
|||||||
|
|
||||||
var w = this.writeFn[type];
|
var w = this.writeFn[type];
|
||||||
|
|
||||||
|
var i;
|
||||||
if(!this.options.delta) {
|
if(!this.options.delta) {
|
||||||
for(var i = 0; i < data.length; ++i) {
|
for(i = 0; i < data.length; ++i) {
|
||||||
this[w](data[i]);
|
this[w](data[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this[w](data[0]);
|
this[w](data[0]);
|
||||||
for(var i = 1; i < data.length; ++i) {
|
for(i = 1; i < data.length; ++i) {
|
||||||
this[w](data[i] - data[i - 1]);
|
this[w](data[i] - data[i - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,7 +69,7 @@ ArrayBufferSer.prototype = {
|
|||||||
var s = this.sizes[type];
|
var s = this.sizes[type];
|
||||||
if(s) {
|
if(s) {
|
||||||
var r = off % s;
|
var r = off % s;
|
||||||
return r == 0 ? 0 : s - r;
|
return r === 0 ? 0 : s - r;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
@ -78,7 +81,7 @@ ArrayBufferSer.prototype = {
|
|||||||
return s*t.length;
|
return s*t.length;
|
||||||
}
|
}
|
||||||
s = 0;
|
s = 0;
|
||||||
if(this.type == ArrayBufferSer.STRING) {
|
if(this.type === ArrayBufferSer.STRING) {
|
||||||
// calculate size with padding
|
// calculate size with padding
|
||||||
t.forEach(function(arr) {
|
t.forEach(function(arr) {
|
||||||
var pad = self._paddingFor(offset, ArrayBufferSer.MAX_PADDING);
|
var pad = self._paddingFor(offset, ArrayBufferSer.MAX_PADDING);
|
||||||
@ -108,15 +111,29 @@ ArrayBufferSer.prototype = {
|
|||||||
return this.headerSize + this._sizeFor(this.headerSize, this.data);
|
return this.headerSize + this._sizeFor(this.headerSize, this.data);
|
||||||
},
|
},
|
||||||
|
|
||||||
writeFn: ['', 'writeInt8', 'writeUInt8','writeUInt8Clamp', 'writeInt16LE', 'writeUInt16LE', 'writeUInt32LE', 'writeUInt32LE', 'writeFloatLE', 'writeDoubleLE', 'writeString', 'writteBuffer'],
|
writeFn: [
|
||||||
|
'',
|
||||||
|
'writeInt8',
|
||||||
|
'writeUInt8',
|
||||||
|
'writeUInt8Clamp',
|
||||||
|
'writeInt16LE',
|
||||||
|
'writeUInt16LE',
|
||||||
|
'writeUInt32LE',
|
||||||
|
'writeUInt32LE',
|
||||||
|
'writeFloatLE',
|
||||||
|
'writeDoubleLE',
|
||||||
|
'writeString',
|
||||||
|
'writteBuffer'
|
||||||
|
],
|
||||||
|
|
||||||
_initFunctions: function() {
|
_initFunctions: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.writeFn.forEach(function(fn) {
|
this.writeFn.forEach(function(fn) {
|
||||||
if(self[fn] === undefined)
|
if(self[fn] === undefined) {
|
||||||
self[fn] = function(d) {
|
self[fn] = function(d) {
|
||||||
self.buffer[fn](d, self.offset);
|
self.buffer[fn](d, self.offset);
|
||||||
self.offset += self.sizes[self.type];
|
self.offset += self.sizes[self.type];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -30,7 +30,9 @@ function userByHostName(host) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mat.length !== 2) {
|
if (mat.length !== 2) {
|
||||||
console.error("ERROR: pattern '" + re_userFromHost + "' gave unexpected matches against '" + host + "': " + mat);
|
console.error(
|
||||||
|
"ERROR: pattern '" + re_userFromHost + "' gave unexpected matches against '" + host + "': " + mat
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return mat[1];
|
return mat[1];
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
var pg = require('./pg'),
|
var _ = require('underscore');
|
||||||
ArrayBufferSer = require("../bin_encoder"),
|
|
||||||
_ = require('underscore');
|
var pg = require('./pg');
|
||||||
|
var ArrayBufferSer = require("../bin_encoder");
|
||||||
|
|
||||||
function BinaryFormat() {}
|
function BinaryFormat() {}
|
||||||
|
|
||||||
@ -9,13 +10,14 @@ BinaryFormat.prototype = new pg('arraybuffer');
|
|||||||
BinaryFormat.prototype._contentType = "application/octet-stream";
|
BinaryFormat.prototype._contentType = "application/octet-stream";
|
||||||
|
|
||||||
BinaryFormat.prototype._extractTypeFromName = function(name) {
|
BinaryFormat.prototype._extractTypeFromName = function(name) {
|
||||||
var g = name.match(new RegExp(/.*__(uintclamp|uint|int|float)(8|16|32)/i))
|
var g = name.match(/.*__(uintclamp|uint|int|float)(8|16|32)/i);
|
||||||
if(g && g.length == 3) {
|
if(g && g.length === 3) {
|
||||||
var typeName = g[1] + g[2];
|
var typeName = g[1] + g[2];
|
||||||
return ArrayBufferSer.typeNames[typeName];
|
return ArrayBufferSer.typeNames[typeName];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// jshint maxcomplexity:12
|
||||||
BinaryFormat.prototype.transform = function(result, options, callback) {
|
BinaryFormat.prototype.transform = function(result, options, callback) {
|
||||||
var total_rows = result.rowCount;
|
var total_rows = result.rowCount;
|
||||||
var rows = result.rows;
|
var rows = result.rows;
|
||||||
@ -35,27 +37,28 @@ BinaryFormat.prototype.transform = function(result, options, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
var i;
|
||||||
|
var t;
|
||||||
// get header types (and guess from name)
|
// get header types (and guess from name)
|
||||||
for(var i = 0; i < headersNames.length; ++i) {
|
for(i = 0; i < headersNames.length; ++i) {
|
||||||
var r = rows[0];
|
r = rows[0];
|
||||||
var n = headersNames[i];
|
n = headersNames[i];
|
||||||
if(typeof(r[n]) == 'string') {
|
if(typeof(r[n]) === 'string') {
|
||||||
headerTypes.push(ArrayBufferSer.STRING);
|
headerTypes.push(ArrayBufferSer.STRING);
|
||||||
} else if(typeof(r[n]) == 'object') {
|
} else if(typeof(r[n]) === 'object') {
|
||||||
var t = this._extractTypeFromName(n);
|
t = this._extractTypeFromName(n);
|
||||||
t = t == undefined ? ArrayBufferSer.FLOAT32: t;
|
t = t || ArrayBufferSer.FLOAT32;
|
||||||
headerTypes.push(ArrayBufferSer.BUFFER + t);
|
headerTypes.push(ArrayBufferSer.BUFFER + t);
|
||||||
} else {
|
} else {
|
||||||
var t = this._extractTypeFromName(n);
|
t = this._extractTypeFromName(n);
|
||||||
headerTypes.push(t == undefined ? ArrayBufferSer.FLOAT32: t);
|
headerTypes.push(t || ArrayBufferSer.FLOAT32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pack the data
|
// pack the data
|
||||||
var header = new ArrayBufferSer(ArrayBufferSer.STRING, headersNames);
|
var header = new ArrayBufferSer(ArrayBufferSer.STRING, headersNames);
|
||||||
var data = [header];
|
var data = [header];
|
||||||
for(var i = 0; i < headersNames.length; ++i) {
|
for(i = 0; i < headersNames.length; ++i) {
|
||||||
var d = [];
|
var d = [];
|
||||||
var n = headersNames[i];
|
var n = headersNames[i];
|
||||||
for(var r = 0; r < total_rows; ++r) {
|
for(var r = 0; r < total_rows; ++r) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
var _ = require('underscore'),
|
var _ = require('underscore');
|
||||||
pg = require('./pg');
|
|
||||||
|
var pg = require('./pg');
|
||||||
|
|
||||||
function GeoJsonFormat() {
|
function GeoJsonFormat() {
|
||||||
this.buffer = '';
|
this.buffer = '';
|
||||||
@ -40,7 +41,7 @@ GeoJsonFormat.prototype.handleQueryRow = function(row) {
|
|||||||
'"properties":'
|
'"properties":'
|
||||||
];
|
];
|
||||||
delete row[this.opts.gn];
|
delete row[this.opts.gn];
|
||||||
delete row['the_geom_webmercator'];
|
delete row.the_geom_webmercator;
|
||||||
geojson.push(JSON.stringify(row));
|
geojson.push(JSON.stringify(row));
|
||||||
geojson.push('}');
|
geojson.push('}');
|
||||||
|
|
||||||
@ -52,13 +53,15 @@ GeoJsonFormat.prototype.handleQueryRow = function(row) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
GeoJsonFormat.prototype.handleQueryEnd = function(result) {
|
GeoJsonFormat.prototype.handleQueryEnd = function(/*result*/) {
|
||||||
if (this.error) {
|
if (this.error) {
|
||||||
this.callback(this.error);
|
this.callback(this.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( this.opts.profiler ) this.opts.profiler.done('gotRows');
|
if ( this.opts.profiler ) {
|
||||||
|
this.opts.profiler.done('gotRows');
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! this._streamingStarted ) {
|
if ( ! this._streamingStarted ) {
|
||||||
this.startStreaming();
|
this.startStreaming();
|
||||||
@ -91,7 +94,7 @@ function _toGeoJSON(data, gn, callback){
|
|||||||
};
|
};
|
||||||
_geojson.geometry = JSON.parse(ele[gn]);
|
_geojson.geometry = JSON.parse(ele[gn]);
|
||||||
delete ele[gn];
|
delete ele[gn];
|
||||||
delete ele["the_geom_webmercator"]; // TODO: use skipfields
|
delete ele.the_geom_webmercator; // TODO: use skipfields
|
||||||
_geojson.properties = ele;
|
_geojson.properties = ele;
|
||||||
out.features.push(_geojson);
|
out.features.push(_geojson);
|
||||||
});
|
});
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
// load all the formats
|
// load all the formats
|
||||||
//
|
//
|
||||||
|
|
||||||
var formats = {},
|
var formats = {};
|
||||||
path = require('path'),
|
var path = require('path');
|
||||||
folder = __dirname + "/";
|
var folder = __dirname + "/";
|
||||||
|
|
||||||
require("fs").readdirSync(folder).forEach(function(file) {
|
require("fs").readdirSync(folder).forEach(function(file) {
|
||||||
if (path.extname(file) === '.js' && file !== 'index.js' && file !== 'ogr.js' && file !== 'pg.js' ) {
|
if (path.extname(file) === '.js' && file !== 'index.js' && file !== 'ogr.js' && file !== 'pg.js' ) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
var pg = require('./pg'),
|
var _ = require('underscore');
|
||||||
util = require('util'),
|
|
||||||
PgErrorHandler = require(global.settings.app_root + '/app/postgresql/error_handler'),
|
var pg = require('./pg');
|
||||||
_ = require('underscore');
|
var PgErrorHandler = require('../../postgresql/error_handler');
|
||||||
|
|
||||||
function JsonFormat() {
|
function JsonFormat() {
|
||||||
this.buffer = '';
|
this.buffer = '';
|
||||||
@ -12,6 +12,7 @@ JsonFormat.prototype = new pg('json');
|
|||||||
|
|
||||||
JsonFormat.prototype._contentType = "application/json; charset=utf-8";
|
JsonFormat.prototype._contentType = "application/json; charset=utf-8";
|
||||||
|
|
||||||
|
// jshint maxcomplexity:9
|
||||||
JsonFormat.prototype.formatResultFields = function(flds) {
|
JsonFormat.prototype.formatResultFields = function(flds) {
|
||||||
flds = flds || [];
|
flds = flds || [];
|
||||||
var nfields = {};
|
var nfields = {};
|
||||||
@ -73,13 +74,16 @@ JsonFormat.prototype.handleQueryRow = function(row, result) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// jshint maxcomplexity:13
|
||||||
JsonFormat.prototype.handleQueryEnd = function(result) {
|
JsonFormat.prototype.handleQueryEnd = function(result) {
|
||||||
if (this.error && !this._streamingStarted) {
|
if (this.error && !this._streamingStarted) {
|
||||||
this.callback(this.error);
|
this.callback(this.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( this.opts.profiler ) this.opts.profiler.done('gotRows');
|
if ( this.opts.profiler ) {
|
||||||
|
this.opts.profiler.done('gotRows');
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! this._streamingStarted ) {
|
if ( ! this._streamingStarted ) {
|
||||||
this.startStreaming();
|
this.startStreaming();
|
||||||
@ -95,7 +99,9 @@ JsonFormat.prototype.handleQueryEnd = function(result) {
|
|||||||
var sf = this.opts.skipfields;
|
var sf = this.opts.skipfields;
|
||||||
for (var i = 0; i < result.fields.length; i++) {
|
for (var i = 0; i < result.fields.length; i++) {
|
||||||
var f = result.fields[i];
|
var f = result.fields[i];
|
||||||
if ( sf.indexOf(f.name) == -1 ) newfields.push(f);
|
if ( sf.indexOf(f.name) === -1 ) {
|
||||||
|
newfields.push(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.fields = newfields;
|
result.fields = newfields;
|
||||||
}
|
}
|
||||||
@ -124,7 +130,7 @@ JsonFormat.prototype.handleQueryEnd = function(result) {
|
|||||||
severities.push(severity);
|
severities.push(severity);
|
||||||
notices[severity] = [];
|
notices[severity] = [];
|
||||||
}
|
}
|
||||||
notices[severity].push(notice.message)
|
notices[severity].push(notice.message);
|
||||||
});
|
});
|
||||||
_.each(severities, function(severity) {
|
_.each(severities, function(severity) {
|
||||||
out.push(',');
|
out.push(',');
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
var crypto = require('crypto'),
|
var crypto = require('crypto');
|
||||||
Step = require('step'),
|
var step = require('step');
|
||||||
fs = require('fs'),
|
var fs = require('fs');
|
||||||
_ = require('underscore'),
|
var _ = require('underscore');
|
||||||
PSQL = require('cartodb-psql'),
|
var PSQL = require('cartodb-psql');
|
||||||
spawn = require('child_process').spawn;
|
var spawn = require('child_process').spawn;
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
// Keeps track of what's waiting baking for export
|
// Keeps track of what's waiting baking for export
|
||||||
var bakingExports = {};
|
var bakingExports = {};
|
||||||
@ -18,12 +19,12 @@ OgrFormat.prototype = {
|
|||||||
|
|
||||||
is_file: true,
|
is_file: true,
|
||||||
|
|
||||||
getQuery: function(sql, options) {
|
getQuery: function(/*sql, options*/) {
|
||||||
return null; // dont execute the query
|
return null; // dont execute the query
|
||||||
},
|
},
|
||||||
|
|
||||||
transform: function(result, options, callback) {
|
transform: function(/*result, options, callback*/) {
|
||||||
throw "should not be called for file formats"
|
throw "should not be called for file formats";
|
||||||
},
|
},
|
||||||
|
|
||||||
getContentType: function(){ return this._contentType; },
|
getContentType: function(){ return this._contentType; },
|
||||||
@ -50,7 +51,7 @@ OgrFormat.prototype = {
|
|||||||
// Internal function usable by all OGR-driven outputs
|
// Internal function usable by all OGR-driven outputs
|
||||||
OgrFormat.prototype.toOGR = function(options, out_format, out_filename, callback) {
|
OgrFormat.prototype.toOGR = function(options, out_format, out_filename, callback) {
|
||||||
|
|
||||||
var gcol = options.gn;
|
//var gcol = options.gn;
|
||||||
var sql = options.sql;
|
var sql = options.sql;
|
||||||
var skipfields = options.skipfields;
|
var skipfields = options.skipfields;
|
||||||
var out_layername = options.filename;
|
var out_layername = options.filename;
|
||||||
@ -73,15 +74,16 @@ OgrFormat.prototype.toOGR = function(options, out_format, out_filename, callback
|
|||||||
// Drop ending semicolon (ogr doens't like it)
|
// Drop ending semicolon (ogr doens't like it)
|
||||||
sql = sql.replace(/;\s*$/, '');
|
sql = sql.replace(/;\s*$/, '');
|
||||||
|
|
||||||
Step (
|
step (
|
||||||
|
|
||||||
function fetchColumns() {
|
function fetchColumns() {
|
||||||
var colsql = 'SELECT * FROM (' + sql + ') as _cartodbsqlapi LIMIT 0';
|
var colsql = 'SELECT * FROM (' + sql + ') as _cartodbsqlapi LIMIT 0';
|
||||||
pg = new PSQL(dbopts);
|
pg = new PSQL(dbopts);
|
||||||
pg.query(colsql, this);
|
pg.query(colsql, this);
|
||||||
},
|
},
|
||||||
|
// jshint maxcomplexity:9
|
||||||
function findSRS(err, result) {
|
function findSRS(err, result) {
|
||||||
if (err) throw err;
|
assert.ifError(err);
|
||||||
|
|
||||||
//if ( ! result.rows.length ) throw new Error("Query returns no rows");
|
//if ( ! result.rows.length ) throw new Error("Query returns no rows");
|
||||||
|
|
||||||
@ -91,20 +93,29 @@ OgrFormat.prototype.toOGR = function(options, out_format, out_filename, callback
|
|||||||
for (var i=0; i<result.fields.length; ++i) {
|
for (var i=0; i<result.fields.length; ++i) {
|
||||||
var field = result.fields[i];
|
var field = result.fields[i];
|
||||||
var k = field.name;
|
var k = field.name;
|
||||||
if ( skipfields.indexOf(k) != -1 ) continue;
|
if ( skipfields.indexOf(k) !== -1 ) {
|
||||||
if ( out_format != 'CSV' && k == "the_geom_webmercator" ) continue; // TODO: drop ?
|
continue;
|
||||||
if ( out_format == 'CSV' ) columns.push(pg.quoteIdentifier(k)+'::text');
|
}
|
||||||
else columns.push(pg.quoteIdentifier(k));
|
if ( out_format !== 'CSV' && k === "the_geom_webmercator" ) {
|
||||||
|
continue;
|
||||||
|
} // TODO: drop ?
|
||||||
|
if ( out_format === 'CSV' ) {
|
||||||
|
columns.push(pg.quoteIdentifier(k)+'::text');
|
||||||
|
} else {
|
||||||
|
columns.push(pg.quoteIdentifier(k));
|
||||||
|
}
|
||||||
|
|
||||||
if ( needSRS ) {
|
if ( needSRS ) {
|
||||||
if ( ! geocol && pg.typeName(field.dataTypeID) == 'geometry' ) {
|
if ( ! geocol && pg.typeName(field.dataTypeID) === 'geometry' ) {
|
||||||
geocol = k
|
geocol = k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//console.log(columns.join(','));
|
//console.log(columns.join(','));
|
||||||
|
|
||||||
if ( ! needSRS || ! geocol ) return null;
|
if ( ! needSRS || ! geocol ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var next = this;
|
var next = this;
|
||||||
|
|
||||||
@ -124,23 +135,18 @@ OgrFormat.prototype.toOGR = function(options, out_format, out_filename, callback
|
|||||||
|
|
||||||
},
|
},
|
||||||
function spawnDumper(err, srid, type) {
|
function spawnDumper(err, srid, type) {
|
||||||
if (err) throw err;
|
assert.ifError(err);
|
||||||
|
|
||||||
var next = this;
|
var next = this;
|
||||||
|
|
||||||
var ogrsql = 'SELECT ' + columns.join(',')
|
var ogrsql = 'SELECT ' + columns.join(',') + ' FROM (' + sql + ') as _cartodbsqlapi';
|
||||||
+ ' FROM (' + sql + ') as _cartodbsqlapi';
|
|
||||||
|
|
||||||
var ogrargs = [
|
var ogrargs = [
|
||||||
'-f', out_format,
|
'-f', out_format,
|
||||||
'-lco', 'ENCODING=UTF-8',
|
'-lco', 'ENCODING=UTF-8',
|
||||||
'-lco', 'LINEFORMAT=CRLF',
|
'-lco', 'LINEFORMAT=CRLF',
|
||||||
out_filename,
|
out_filename,
|
||||||
"PG:host=" + dbhost
|
"PG:host=" + dbhost + " port=" + dbport + " user=" + dbuser + " dbname=" + dbname + " password=" + dbpass,
|
||||||
+ " port=" + dbport
|
|
||||||
+ " user=" + dbuser
|
|
||||||
+ " dbname=" + dbname
|
|
||||||
+ " password=" + dbpass,
|
|
||||||
'-sql', ogrsql
|
'-sql', ogrsql
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -171,7 +177,9 @@ console.log('ogr2ogr ' + _.map(ogrargs, function(x) { return "'" + x + "'"; }).j
|
|||||||
child.stderr.on('data', function(data) {
|
child.stderr.on('data', function(data) {
|
||||||
data = data.toString(); // know of a faster way ?
|
data = data.toString(); // know of a faster way ?
|
||||||
// Store only the first ERROR line
|
// Store only the first ERROR line
|
||||||
if ( ! stderr && data.match(logErrPat) ) stderr = data;
|
if ( ! stderr && data.match(logErrPat) ) {
|
||||||
|
stderr = data;
|
||||||
|
}
|
||||||
console.log('ogr2ogr stderr: ' + data);
|
console.log('ogr2ogr stderr: ' + data);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -204,7 +212,14 @@ OgrFormat.prototype.toOGR_SingleFile = function(options, fmt, callback) {
|
|||||||
var layername = options.filename;
|
var layername = options.filename;
|
||||||
|
|
||||||
var tmpdir = global.settings.tmpDir || '/tmp';
|
var tmpdir = global.settings.tmpDir || '/tmp';
|
||||||
var reqKey = [ fmt, dbname, user_id, gcol, this.generateMD5(layername), this.generateMD5(sql) ].concat(skipfields).join(':');
|
var reqKey = [
|
||||||
|
fmt,
|
||||||
|
dbname,
|
||||||
|
user_id,
|
||||||
|
gcol,
|
||||||
|
this.generateMD5(layername),
|
||||||
|
this.generateMD5(sql)
|
||||||
|
].concat(skipfields).join(':');
|
||||||
var outdirpath = tmpdir + '/sqlapi-' + process.pid + '-' + reqKey;
|
var outdirpath = tmpdir + '/sqlapi-' + process.pid + '-' + reqKey;
|
||||||
var dumpfile = outdirpath + ':cartodb-query.' + ext;
|
var dumpfile = outdirpath + ':cartodb-query.' + ext;
|
||||||
|
|
||||||
@ -214,7 +229,7 @@ OgrFormat.prototype.toOGR_SingleFile = function(options, fmt, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
OgrFormat.prototype.sendResponse = function(opts, callback) {
|
OgrFormat.prototype.sendResponse = function(opts, callback) {
|
||||||
var next = callback;
|
//var next = callback;
|
||||||
var reqKey = this.getKey(opts);
|
var reqKey = this.getKey(opts);
|
||||||
var qElem = new ExportRequest(opts.sink, callback, opts.beforeSink);
|
var qElem = new ExportRequest(opts.sink, callback, opts.beforeSink);
|
||||||
var baking = bakingExports[reqKey];
|
var baking = bakingExports[reqKey];
|
||||||
@ -223,8 +238,10 @@ OgrFormat.prototype.sendResponse = function(opts, callback) {
|
|||||||
} else {
|
} else {
|
||||||
baking = bakingExports[reqKey] = { req: [ qElem ] };
|
baking = bakingExports[reqKey] = { req: [ qElem ] };
|
||||||
this.generate(opts, function(err, dumpfile) {
|
this.generate(opts, function(err, dumpfile) {
|
||||||
if ( opts.profiler ) opts.profiler.done('generate');
|
if ( opts.profiler ) {
|
||||||
Step (
|
opts.profiler.done('generate');
|
||||||
|
}
|
||||||
|
step (
|
||||||
function sendResults() {
|
function sendResults() {
|
||||||
var nextPipe = function(finish) {
|
var nextPipe = function(finish) {
|
||||||
var r = baking.req.shift();
|
var r = baking.req.shift();
|
||||||
@ -234,28 +251,29 @@ OgrFormat.prototype.sendResponse = function(opts, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( ! err ) nextPipe(this);
|
if ( ! err ) {
|
||||||
else {
|
nextPipe(this);
|
||||||
|
} else {
|
||||||
_.each(baking.req, function(r) {
|
_.each(baking.req, function(r) {
|
||||||
r.cb(err);
|
r.cb(err);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function cleanup(err) {
|
function cleanup(/*err*/) {
|
||||||
delete bakingExports[reqKey];
|
delete bakingExports[reqKey];
|
||||||
|
|
||||||
// unlink dump file (sync to avoid race condition)
|
// unlink dump file (sync to avoid race condition)
|
||||||
console.log("removing", dumpfile);
|
console.log("removing", dumpfile);
|
||||||
try { fs.unlinkSync(dumpfile); }
|
try { fs.unlinkSync(dumpfile); }
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if ( e.code != 'ENOENT' ) {
|
if ( e.code !== 'ENOENT' ) {
|
||||||
console.log("Could not unlink dumpfile " + dumpfile + ": " + e);
|
console.log("Could not unlink dumpfile " + dumpfile + ": " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -284,8 +302,10 @@ ExportRequest.prototype.sendFile = function (err, filename, callback) {
|
|||||||
if ( ! this.canceled ) {
|
if ( ! this.canceled ) {
|
||||||
//console.log("Creating readable stream out of dumpfile");
|
//console.log("Creating readable stream out of dumpfile");
|
||||||
this.istream = fs.createReadStream(filename)
|
this.istream = fs.createReadStream(filename)
|
||||||
.on('open', function(fd) {
|
.on('open', function(/*fd*/) {
|
||||||
if ( that.beforeSink ) that.beforeSink();
|
if ( that.beforeSink ) {
|
||||||
|
that.beforeSink();
|
||||||
|
}
|
||||||
that.istream.pipe(that.ostream);
|
that.istream.pipe(that.ostream);
|
||||||
callback();
|
callback();
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
var Step = require('step'),
|
var step = require('step');
|
||||||
PSQL = require('cartodb-psql');
|
var PSQL = require('cartodb-psql');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
function PostgresFormat(id) {
|
function PostgresFormat(id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -7,7 +8,7 @@ function PostgresFormat(id) {
|
|||||||
|
|
||||||
PostgresFormat.prototype = {
|
PostgresFormat.prototype = {
|
||||||
|
|
||||||
getQuery: function(sql, options) {
|
getQuery: function(sql/*, options*/) {
|
||||||
return sql;
|
return sql;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -34,7 +35,9 @@ PostgresFormat.prototype.handleQueryRowWithSkipFields = function(row, result) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
PostgresFormat.prototype.handleNotice = function(msg, result) {
|
PostgresFormat.prototype.handleNotice = function(msg, result) {
|
||||||
if ( ! result.notices ) result.notices = [];
|
if ( ! result.notices ) {
|
||||||
|
result.notices = [];
|
||||||
|
}
|
||||||
for (var i=0; i<msg.length; i++) {
|
for (var i=0; i<msg.length; i++) {
|
||||||
result.notices.push(msg[i]);
|
result.notices.push(msg[i]);
|
||||||
}
|
}
|
||||||
@ -48,7 +51,9 @@ PostgresFormat.prototype.handleQueryEnd = function(result) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( this.opts.profiler ) this.opts.profiler.done('gotRows');
|
if ( this.opts.profiler ) {
|
||||||
|
this.opts.profiler.done('gotRows');
|
||||||
|
}
|
||||||
|
|
||||||
this.opts.total_time = (Date.now() - this.start_time)/1000;
|
this.opts.total_time = (Date.now() - this.start_time)/1000;
|
||||||
|
|
||||||
@ -58,14 +63,16 @@ PostgresFormat.prototype.handleQueryEnd = function(result) {
|
|||||||
var newfields = [];
|
var newfields = [];
|
||||||
for ( var j=0; j<result.fields.length; ++j ) {
|
for ( var j=0; j<result.fields.length; ++j ) {
|
||||||
var f = result.fields[j];
|
var f = result.fields[j];
|
||||||
if ( sf.indexOf(f.name) == -1 ) newfields.push(f);
|
if ( sf.indexOf(f.name) === -1 ) {
|
||||||
|
newfields.push(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.fields = newfields;
|
result.fields = newfields;
|
||||||
}
|
}
|
||||||
|
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
Step (
|
step (
|
||||||
function packageResult() {
|
function packageResult() {
|
||||||
if ( that.opts.abortChecker ) {
|
if ( that.opts.abortChecker ) {
|
||||||
that.opts.abortChecker('packageResult');
|
that.opts.abortChecker('packageResult');
|
||||||
@ -74,11 +81,13 @@ PostgresFormat.prototype.handleQueryEnd = function(result) {
|
|||||||
},
|
},
|
||||||
function sendResults(err, out){
|
function sendResults(err, out){
|
||||||
|
|
||||||
if (err) throw err;
|
assert.ifError(err);
|
||||||
|
|
||||||
// return to browser
|
// return to browser
|
||||||
if ( out ) {
|
if ( out ) {
|
||||||
if ( that.opts.beforeSink ) that.opts.beforeSink();
|
if ( that.opts.beforeSink ) {
|
||||||
|
that.opts.beforeSink();
|
||||||
|
}
|
||||||
that.opts.sink.send(out);
|
that.opts.sink.send(out);
|
||||||
} else {
|
} else {
|
||||||
console.error("No output from transform, doing nothing ?!");
|
console.error("No output from transform, doing nothing ?!");
|
||||||
@ -117,7 +126,9 @@ PostgresFormat.prototype.sendResponse = function(opts, callback) {
|
|||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( that.opts.profiler ) that.opts.profiler.done('eventedQuery');
|
if ( that.opts.profiler ) {
|
||||||
|
that.opts.profiler.done('eventedQuery');
|
||||||
|
}
|
||||||
|
|
||||||
if (that.hasSkipFields) {
|
if (that.hasSkipFields) {
|
||||||
query.on('row', that.handleQueryRowWithSkipFields.bind(that));
|
query.on('row', that.handleQueryRowWithSkipFields.bind(that));
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
var crypto = require('crypto'),
|
var step = require('step');
|
||||||
Step = require('step'),
|
var fs = require('fs');
|
||||||
fs = require('fs'),
|
var spawn = require('child_process').spawn;
|
||||||
spawn = require('child_process').spawn,
|
var assert = require('assert');
|
||||||
ogr = require('./ogr');
|
|
||||||
|
var ogr = require('./ogr');
|
||||||
|
|
||||||
function ShpFormat() {
|
function ShpFormat() {
|
||||||
}
|
}
|
||||||
@ -42,16 +43,17 @@ ShpFormat.prototype.toSHP = function (options, callback) {
|
|||||||
// TODO: following tests:
|
// TODO: following tests:
|
||||||
// - fetch query with no "the_geom" column
|
// - fetch query with no "the_geom" column
|
||||||
|
|
||||||
Step (
|
step (
|
||||||
function createOutDir() {
|
function createOutDir() {
|
||||||
fs.mkdir(outdirpath, 0777, this);
|
fs.mkdir(outdirpath, 0777, this);
|
||||||
},
|
},
|
||||||
function spawnDumper(err) {
|
function spawnDumper(err) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
|
|
||||||
fmtObj.toOGR(options, 'ESRI Shapefile', shapefile, this);
|
fmtObj.toOGR(options, 'ESRI Shapefile', shapefile, this);
|
||||||
},
|
},
|
||||||
function doZip(err) {
|
function doZip(err) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
|
|
||||||
var next = this;
|
var next = this;
|
||||||
|
|
||||||
@ -82,21 +84,24 @@ ShpFormat.prototype.toSHP = function (options, callback) {
|
|||||||
if ( err ) {
|
if ( err ) {
|
||||||
console.log("Unlinking " + fn + ": " + err);
|
console.log("Unlinking " + fn + ": " + err);
|
||||||
finish(err);
|
finish(err);
|
||||||
|
} else {
|
||||||
|
unlinkall(dir, files, finish);
|
||||||
}
|
}
|
||||||
else unlinkall(dir, files, finish)
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
fs.readdir(outdirpath, function(err, files) {
|
fs.readdir(outdirpath, function(err, files) {
|
||||||
if ( err ) {
|
if ( err ) {
|
||||||
if ( err.code != 'ENOENT' ) {
|
if ( err.code !== 'ENOENT' ) {
|
||||||
next(new Error([topError, err].join('\n')));
|
next(new Error([topError, err].join('\n')));
|
||||||
} else {
|
} else {
|
||||||
next(topError);
|
next(topError);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unlinkall(outdirpath, files, function(err) {
|
unlinkall(outdirpath, files, function(/*err*/) {
|
||||||
fs.rmdir(outdirpath, function(err) {
|
fs.rmdir(outdirpath, function(err) {
|
||||||
if ( err ) console.log("Removing dir " + path + ": " + err);
|
if ( err ) {
|
||||||
|
console.log("Removing dir " + outdirpath + ": " + err);
|
||||||
|
}
|
||||||
next(topError, zipfile);
|
next(topError, zipfile);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
var pg = require('./pg'),
|
var pg = require('./pg');
|
||||||
_ = require('underscore');
|
|
||||||
|
|
||||||
var svg_width = 1024.0;
|
var svg_width = 1024.0;
|
||||||
var svg_height = 768.0;
|
var svg_height = 768.0;
|
||||||
@ -29,26 +28,26 @@ SvgFormat.prototype._contentType = "image/svg+xml; charset=utf-8";
|
|||||||
SvgFormat.prototype.getQuery = function(sql, options) {
|
SvgFormat.prototype.getQuery = function(sql, options) {
|
||||||
var gn = options.gn;
|
var gn = options.gn;
|
||||||
var dp = options.dp;
|
var dp = options.dp;
|
||||||
return 'WITH source AS ( ' + sql + '), extent AS ( '
|
return 'WITH source AS ( ' + sql + '), extent AS ( ' +
|
||||||
+ ' SELECT ST_Extent(' + gn + ') AS e FROM source '
|
' SELECT ST_Extent(' + gn + ') AS e FROM source ' +
|
||||||
+ '), extent_info AS ( SELECT e, '
|
'), extent_info AS ( SELECT e, ' +
|
||||||
+ 'st_xmin(e) as ex0, st_ymax(e) as ey0, '
|
'st_xmin(e) as ex0, st_ymax(e) as ey0, ' +
|
||||||
+ 'st_xmax(e)-st_xmin(e) as ew, '
|
'st_xmax(e)-st_xmin(e) as ew, ' +
|
||||||
+ 'st_ymax(e)-st_ymin(e) as eh FROM extent )'
|
'st_ymax(e)-st_ymin(e) as eh FROM extent )' +
|
||||||
+ ', trans AS ( SELECT CASE WHEN '
|
', trans AS ( SELECT CASE WHEN ' +
|
||||||
+ 'eh = 0 THEN ' + svg_width
|
'eh = 0 THEN ' + svg_width +
|
||||||
+ '/ COALESCE(NULLIF(ew,0),' + svg_width +') WHEN '
|
'/ COALESCE(NULLIF(ew,0),' + svg_width +') WHEN ' +
|
||||||
+ svg_ratio + ' <= (ew / eh) THEN ('
|
svg_ratio + ' <= (ew / eh) THEN (' +
|
||||||
+ svg_width + '/ew ) ELSE ('
|
svg_width + '/ew ) ELSE (' +
|
||||||
+ svg_height + '/eh ) END as s '
|
svg_height + '/eh ) END as s ' +
|
||||||
+ ', ex0 as x0, ey0 as y0 FROM extent_info ) '
|
', ex0 as x0, ey0 as y0 FROM extent_info ) ' +
|
||||||
+ 'SELECT st_TransScale(e, -x0, -y0, s, s)::box2d as '
|
'SELECT st_TransScale(e, -x0, -y0, s, s)::box2d as ' +
|
||||||
+ gn + '_box, ST_Dimension(' + gn + ') as ' + gn
|
gn + '_box, ST_Dimension(' + gn + ') as ' + gn +
|
||||||
+ '_dimension, ST_AsSVG(ST_TransScale(' + gn + ', '
|
'_dimension, ST_AsSVG(ST_TransScale(' + gn + ', ' +
|
||||||
+ '-x0, -y0, s, s), 0, ' + dp + ') as ' + gn
|
'-x0, -y0, s, s), 0, ' + dp + ') as ' + gn +
|
||||||
//+ ', ex0, ey0, ew, eh, s ' // DEBUG ONLY
|
//+ ', ex0, ey0, ew, eh, s ' // DEBUG ONLY +
|
||||||
+ ' FROM trans, extent_info, source'
|
' FROM trans, extent_info, source' +
|
||||||
+ ' ORDER BY the_geom_dimension ASC';
|
' ORDER BY the_geom_dimension ASC';
|
||||||
};
|
};
|
||||||
|
|
||||||
SvgFormat.prototype.startStreaming = function() {
|
SvgFormat.prototype.startStreaming = function() {
|
||||||
@ -72,14 +71,11 @@ SvgFormat.prototype.startStreaming = function() {
|
|||||||
this.bbox.ymax += growby;
|
this.bbox.ymax += growby;
|
||||||
this.bbox.width = this.bbox.xmax - this.bbox.xmin;
|
this.bbox.width = this.bbox.xmax - this.bbox.xmin;
|
||||||
this.bbox.height = this.bbox.ymax - this.bbox.ymin;
|
this.bbox.height = this.bbox.ymax - this.bbox.ymin;
|
||||||
rootTag += 'viewBox="' + this.bbox.xmin + ' ' + (-this.bbox.ymax) + ' '
|
rootTag += 'viewBox="' + this.bbox.xmin + ' ' + (-this.bbox.ymax) + ' ' +
|
||||||
+ this.bbox.width + ' ' + this.bbox.height + '" ';
|
this.bbox.width + ' ' + this.bbox.height + '" ';
|
||||||
}
|
}
|
||||||
rootTag += 'style="fill-opacity:' + fill_opacity
|
rootTag += 'style="fill-opacity:' + fill_opacity + '; stroke:' + stroke_color + '; ' +
|
||||||
+ '; stroke:' + stroke_color
|
'stroke-width:' + stroke_width + '; fill:' + fill_color + '" ';
|
||||||
+ '; stroke-width:' + stroke_width
|
|
||||||
+ '; fill:' + fill_color
|
|
||||||
+ '" ';
|
|
||||||
rootTag += 'xmlns="http://www.w3.org/2000/svg" version="1.1">\n';
|
rootTag += 'xmlns="http://www.w3.org/2000/svg" version="1.1">\n';
|
||||||
|
|
||||||
header.push(rootTag);
|
header.push(rootTag);
|
||||||
@ -89,6 +85,7 @@ SvgFormat.prototype.startStreaming = function() {
|
|||||||
this._streamingStarted = true;
|
this._streamingStarted = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// jshint maxcomplexity:11
|
||||||
SvgFormat.prototype.handleQueryRow = function(row) {
|
SvgFormat.prototype.handleQueryRow = function(row) {
|
||||||
this.totalRows++;
|
this.totalRows++;
|
||||||
|
|
||||||
@ -97,8 +94,11 @@ SvgFormat.prototype.handleQueryRow = function(row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var g = row[this.opts.gn];
|
var g = row[this.opts.gn];
|
||||||
if ( ! g ) return; // null or empty
|
if ( ! g ) {
|
||||||
|
return;
|
||||||
|
} // null or empty
|
||||||
|
|
||||||
|
// jshint ignore:start
|
||||||
var gdims = row[this.opts.gn + '_dimension'];
|
var gdims = row[this.opts.gn + '_dimension'];
|
||||||
// TODO: add an identifier, if any of "cartodb_id", "oid", "id", "gid" are found
|
// TODO: add an identifier, if any of "cartodb_id", "oid", "id", "gid" are found
|
||||||
// TODO: add "class" attribute to help with styling ?
|
// TODO: add "class" attribute to help with styling ?
|
||||||
@ -106,10 +106,11 @@ SvgFormat.prototype.handleQueryRow = function(row) {
|
|||||||
this.buffer += '<circle r="' + radius + '" ' + g + ' />\n';
|
this.buffer += '<circle r="' + radius + '" ' + g + ' />\n';
|
||||||
} else if ( gdims == '1' ) {
|
} else if ( gdims == '1' ) {
|
||||||
// Avoid filling closed linestrings
|
// Avoid filling closed linestrings
|
||||||
this.buffer += '<path ' + ( fill_color != 'none' ? 'fill="none" ' : '' ) + 'd="' + g + '" />\n';
|
this.buffer += '<path ' + ( fill_color !== 'none' ? 'fill="none" ' : '' ) + 'd="' + g + '" />\n';
|
||||||
} else if ( gdims == '2' ) {
|
} else if ( gdims == '2' ) {
|
||||||
this.buffer += '<path d="' + g + '" />\n';
|
this.buffer += '<path d="' + g + '" />\n';
|
||||||
}
|
}
|
||||||
|
// jshint ignore:end
|
||||||
|
|
||||||
if ( ! this.bbox ) {
|
if ( ! this.bbox ) {
|
||||||
// Parse layer extent: "BOX(x y, X Y)"
|
// Parse layer extent: "BOX(x y, X Y)"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
var pg = require('./pg'),
|
var pg = require('./pg');
|
||||||
_ = require('underscore'),
|
var _ = require('underscore');
|
||||||
geojson = require('./geojson'),
|
var geojson = require('./geojson');
|
||||||
TopoJSON = require('topojson');
|
var TopoJSON = require('topojson');
|
||||||
|
|
||||||
function TopoJsonFormat() {
|
function TopoJsonFormat() {
|
||||||
this.features = [];
|
this.features = [];
|
||||||
@ -19,7 +19,7 @@ TopoJsonFormat.prototype.handleQueryRow = function(row) {
|
|||||||
};
|
};
|
||||||
_geojson.geometry = JSON.parse(row[this.opts.gn]);
|
_geojson.geometry = JSON.parse(row[this.opts.gn]);
|
||||||
delete row[this.opts.gn];
|
delete row[this.opts.gn];
|
||||||
delete row["the_geom_webmercator"];
|
delete row.the_geom_webmercator;
|
||||||
_geojson.properties = row;
|
_geojson.properties = row;
|
||||||
this.features.push(_geojson);
|
this.features.push(_geojson);
|
||||||
};
|
};
|
||||||
@ -30,7 +30,9 @@ TopoJsonFormat.prototype.handleQueryEnd = function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( this.opts.profiler ) this.opts.profiler.done('gotRows');
|
if ( this.opts.profiler ) {
|
||||||
|
this.opts.profiler.done('gotRows');
|
||||||
|
}
|
||||||
|
|
||||||
var topology = TopoJSON.topology(this.features, {
|
var topology = TopoJSON.topology(this.features, {
|
||||||
"quantization": 1e4,
|
"quantization": 1e4,
|
||||||
|
@ -34,7 +34,9 @@ For logger.trace('one','two','three'):
|
|||||||
//
|
//
|
||||||
// We only log error and higher errors
|
// We only log error and higher errors
|
||||||
//
|
//
|
||||||
if ( loggingEvent.level.level < 40000 ) return;
|
if ( loggingEvent.level.level < 40000 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rollbar.reportMessage(loggingEvent.data);
|
rollbar.reportMessage(loggingEvent.data);
|
||||||
};
|
};
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
var Step = require('step'),
|
var step = require('step'),
|
||||||
_ = require('underscore'),
|
|
||||||
fs = require('fs');
|
fs = require('fs');
|
||||||
|
|
||||||
function HealthCheck(metadataBackend, psqlClass) {
|
function HealthCheck(metadataBackend) {
|
||||||
this.metadataBackend = metadataBackend;
|
this.metadataBackend = metadataBackend;
|
||||||
this.psqlClass = psqlClass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = HealthCheck;
|
module.exports = HealthCheck;
|
||||||
|
|
||||||
HealthCheck.prototype.check = function(username, query, callback) {
|
HealthCheck.prototype.check = function(username, query, callback) {
|
||||||
var self = this,
|
var result = {
|
||||||
startTime,
|
|
||||||
result = {
|
|
||||||
redis: {},
|
redis: {},
|
||||||
postgresql: {}
|
postgresql: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
Step(
|
step(
|
||||||
function getManualDisable() {
|
function getManualDisable() {
|
||||||
fs.readFile(global.settings.disabled_file, this);
|
fs.readFile(global.settings.disabled_file, this);
|
||||||
},
|
},
|
||||||
|
11
npm-shrinkwrap.json
generated
11
npm-shrinkwrap.json
generated
@ -143,8 +143,7 @@
|
|||||||
},
|
},
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"from": "inherits@~2.0.1",
|
"from": "inherits@~2.0.1"
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -156,9 +155,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lru-cache": {
|
"lru-cache": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.2",
|
||||||
"from": "lru-cache@~2.5.0",
|
"from": "lru-cache@~2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz"
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.2.tgz"
|
||||||
},
|
},
|
||||||
"node-statsd": {
|
"node-statsd": {
|
||||||
"version": "0.0.7",
|
"version": "0.0.7",
|
||||||
@ -220,9 +219,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.5.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"wordwrap": {
|
"wordwrap": {
|
||||||
"version": "0.0.2",
|
"version": "0.0.3",
|
||||||
"from": "wordwrap@~0.0.2",
|
"from": "wordwrap@~0.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
|
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,11 +32,12 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"redis": "0.7.1",
|
"redis": "0.7.1",
|
||||||
"mocha": "~1.21.4",
|
"mocha": "~1.21.4",
|
||||||
|
"jshint": "~2.6.0",
|
||||||
"zipfile": "~0.5.0",
|
"zipfile": "~0.5.0",
|
||||||
"libxmljs": "~0.8.1"
|
"libxmljs": "~0.8.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "test/run_tests.sh ${RUNTESTFLAGS} test/unit/*.js test/unit/model/*.js test/acceptance/*.js test/acceptance/export/*.js"
|
"test": "make test-all"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8 <0.11",
|
"node": ">=0.8 <0.11",
|
||||||
|
@ -1,40 +1,37 @@
|
|||||||
require('../helper');
|
require('../helper');
|
||||||
require('../support/assert');
|
|
||||||
|
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
, assert = require('assert')
|
var assert = require('../support/assert');
|
||||||
, tests = module.exports = {}
|
|
||||||
, querystring = require('querystring');
|
|
||||||
|
|
||||||
suite('app.auth', function() {
|
describe('app.auth', function() {
|
||||||
|
|
||||||
var scenarios = [
|
var scenarios = [
|
||||||
{
|
{
|
||||||
desc: 'valid api key should allow insert in protected tables',
|
desc: 'valid api key should allow insert in protected tables',
|
||||||
url: "/api/v1/sql?api_key=1234&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('app_auth_test1')",
|
url: "/api/v1/sql?api_key=1234&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('app_auth_test1')",
|
||||||
statusCode: 200
|
statusCode: 200
|
||||||
}
|
},
|
||||||
,{
|
{
|
||||||
desc: 'valid api key should allow delete in protected tables',
|
desc: 'valid api key should allow delete in protected tables',
|
||||||
url: "/api/v1/sql?api_key=1234&q=DELETE%20FROM%20private_table%20WHERE%20name%3d'app_auth_test1'",
|
url: "/api/v1/sql?api_key=1234&q=DELETE%20FROM%20private_table%20WHERE%20name%3d'app_auth_test1'",
|
||||||
statusCode: 200
|
statusCode: 200
|
||||||
}
|
},
|
||||||
,{
|
{
|
||||||
desc: 'invalid api key should NOT allow insert in protected tables',
|
desc: 'invalid api key should NOT allow insert in protected tables',
|
||||||
url: "/api/v1/sql?api_key=RAMBO&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('RAMBO')",
|
url: "/api/v1/sql?api_key=RAMBO&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('RAMBO')",
|
||||||
statusCode: 401
|
statusCode: 401
|
||||||
}
|
},
|
||||||
,{
|
{
|
||||||
desc: 'invalid api key (old redis location) should NOT allow insert in protected tables',
|
desc: 'invalid api key (old redis location) should NOT allow insert in protected tables',
|
||||||
url: "/api/v1/sql?api_key=1235&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('RAMBO')",
|
url: "/api/v1/sql?api_key=1235&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('RAMBO')",
|
||||||
statusCode: 401
|
statusCode: 401
|
||||||
}
|
},
|
||||||
,{
|
{
|
||||||
desc: 'no api key should NOT allow insert in protected tables',
|
desc: 'no api key should NOT allow insert in protected tables',
|
||||||
url: "/api/v1/sql?q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('RAMBO')",
|
url: "/api/v1/sql?q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('RAMBO')",
|
||||||
statusCode: 401
|
statusCode: 401
|
||||||
}
|
},
|
||||||
,{
|
{
|
||||||
desc: 'no api key should NOT allow insert in public tables',
|
desc: 'no api key should NOT allow insert in public tables',
|
||||||
url: "/api/v1/sql?q=INSERT%20INTO%20untitle_table_4%20(name)%20VALUES%20('RAMBO')",
|
url: "/api/v1/sql?q=INSERT%20INTO%20untitle_table_4%20(name)%20VALUES%20('RAMBO')",
|
||||||
statusCode: 401
|
statusCode: 401
|
||||||
@ -42,7 +39,7 @@ suite('app.auth', function() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
scenarios.forEach(function(scenario) {
|
scenarios.forEach(function(scenario) {
|
||||||
test(scenario.desc, function(done) {
|
it(scenario.desc, function(done) {
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
// view prepare_db.sh to find public table name and structure
|
// view prepare_db.sh to find public table name and structure
|
||||||
url: scenario.url,
|
url: scenario.url,
|
||||||
|
@ -13,27 +13,21 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
require('../helper');
|
require('../helper');
|
||||||
require('../support/assert');
|
|
||||||
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
|
var assert = require('../support/assert');
|
||||||
|
var querystring = require('querystring');
|
||||||
|
var _ = require('underscore');
|
||||||
|
var step = require('step');
|
||||||
|
|
||||||
|
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
describe('app.test', function() {
|
||||||
, assert = require('assert')
|
|
||||||
, querystring = require('querystring')
|
|
||||||
, _ = require('underscore')
|
|
||||||
, zipfile = require('zipfile')
|
|
||||||
, fs = require('fs')
|
|
||||||
, libxmljs = require('libxmljs')
|
|
||||||
, Step = require('step')
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
suite('app.test', function() {
|
|
||||||
|
|
||||||
var expected_cache_control = 'no-cache,max-age=31536000,must-revalidate,public';
|
var expected_cache_control = 'no-cache,max-age=31536000,must-revalidate,public';
|
||||||
var expected_rw_cache_control = 'no-cache,max-age=0,must-revalidate,public';
|
var expected_rw_cache_control = 'no-cache,max-age=0,must-revalidate,public';
|
||||||
var expected_cache_control_persist = 'public,max-age=31536000';
|
var expected_cache_control_persist = 'public,max-age=31536000';
|
||||||
|
|
||||||
test('GET /api/v1/version', function(done){
|
it('GET /api/v1/version', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/version',
|
url: '/api/v1/version',
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
@ -47,7 +41,7 @@ test('GET /api/v1/version', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql', function(done){
|
it('GET /api/v1/sql', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
@ -62,7 +56,7 @@ test('GET /api/v1/sql', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Test base_url setting
|
// Test base_url setting
|
||||||
test('GET /api/whatever/sql', function(done){
|
it('GET /api/whatever/sql', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/whatever/sql?q=SELECT%201',
|
url: '/api/whatever/sql?q=SELECT%201',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -75,7 +69,7 @@ test('GET /api/whatever/sql', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Test CORS headers with GET
|
// Test CORS headers with GET
|
||||||
test('GET /api/whatever/sql', function(done){
|
it('GET /api/whatever/sql', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/whatever/sql?q=SELECT%201',
|
url: '/api/whatever/sql?q=SELECT%201',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -83,14 +77,16 @@ test('GET /api/whatever/sql', function(done){
|
|||||||
},{
|
},{
|
||||||
}, function(res) {
|
}, function(res) {
|
||||||
assert.equal(res.statusCode, 200, res.body);
|
assert.equal(res.statusCode, 200, res.body);
|
||||||
assert.equal(res.headers['access-control-allow-headers'], 'X-Requested-With, X-Prototype-Version, X-CSRF-Token');
|
assert.equal(
|
||||||
|
res.headers['access-control-allow-headers'], 'X-Requested-With, X-Prototype-Version, X-CSRF-Token'
|
||||||
|
);
|
||||||
assert.equal(res.headers['access-control-allow-origin'], '*');
|
assert.equal(res.headers['access-control-allow-origin'], '*');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test that OPTIONS does not run queries
|
// Test that OPTIONS does not run queries
|
||||||
test('OPTIONS /api/x/sql', function(done){
|
it('OPTIONS /api/x/sql', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/x/sql?q=syntax%20error',
|
url: '/api/x/sql?q=syntax%20error',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -98,7 +94,9 @@ test('OPTIONS /api/x/sql', function(done){
|
|||||||
},{}, function(res) {
|
},{}, function(res) {
|
||||||
assert.equal(res.statusCode, 200, res.body);
|
assert.equal(res.statusCode, 200, res.body);
|
||||||
assert.equal(res.body, '');
|
assert.equal(res.body, '');
|
||||||
assert.equal(res.headers['access-control-allow-headers'], 'X-Requested-With, X-Prototype-Version, X-CSRF-Token');
|
assert.equal(
|
||||||
|
res.headers['access-control-allow-headers'], 'X-Requested-With, X-Prototype-Version, X-CSRF-Token'
|
||||||
|
);
|
||||||
assert.equal(res.headers['access-control-allow-origin'], '*');
|
assert.equal(res.headers['access-control-allow-origin'], '*');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -106,7 +104,7 @@ test('OPTIONS /api/x/sql', function(done){
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
test('GET /api/v1/sql with SQL parameter on SELECT only. No oAuth included ', function(done){
|
it('GET /api/v1/sql with SQL parameter on SELECT only. No oAuth included ', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&database=cartodb_test_user_1_db',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&database=cartodb_test_user_1_db',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -120,7 +118,7 @@ test('GET /api/v1/sql with SQL parameter on SELECT only. No oAuth included ', fu
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cache_policy=persist', function(done){
|
it('cache_policy=persist', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&database=cartodb_test_user_1_db&cache_policy=persist',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&database=cartodb_test_user_1_db&cache_policy=persist',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -136,7 +134,7 @@ test('cache_policy=persist', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with SQL parameter on SELECT only. no database param, just id using headers', function(done){
|
it('GET /api/v1/sql with SQL parameter on SELECT only. no database param, just id using headers', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -147,7 +145,7 @@ test('GET /api/v1/sql with SQL parameter on SELECT only. no database param, just
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /user/vizzuality/api/v1/sql with SQL parameter on SELECT only', function(done){
|
it('GET /user/vizzuality/api/v1/sql with SQL parameter on SELECT only', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/user/vizzuality/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
url: '/user/vizzuality/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
@ -159,7 +157,7 @@ test('GET /user/vizzuality/api/v1/sql with SQL parameter on SELECT only', functi
|
|||||||
|
|
||||||
|
|
||||||
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/121
|
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/121
|
||||||
test('SELECT from user-specific database', function(done){
|
it('SELECT from user-specific database', function(done){
|
||||||
var backupDBHost = global.settings.db_host;
|
var backupDBHost = global.settings.db_host;
|
||||||
global.settings.db_host = '6.6.6.6';
|
global.settings.db_host = '6.6.6.6';
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -182,7 +180,7 @@ test('SELECT from user-specific database', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/120
|
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/120
|
||||||
test('SELECT with user-specific password', function(done){
|
it('SELECT with user-specific password', function(done){
|
||||||
var backupDBUserPass = global.settings.db_user_pass;
|
var backupDBUserPass = global.settings.db_user_pass;
|
||||||
global.settings.db_user_pass = '<%= user_password %>';
|
global.settings.db_user_pass = '<%= user_password %>';
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -204,7 +202,7 @@ test('SELECT with user-specific password', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with SQL parameter on SELECT only. no database param, just id using headers. Authenticated.',
|
it('GET /api/v1/sql with SQL parameter on SELECT only. no database param, just id using headers. Authenticated.',
|
||||||
function(done){
|
function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20cartodb_id*2%20FROM%20untitle_table_4&api_key=1234',
|
url: '/api/v1/sql?q=SELECT%20cartodb_id*2%20FROM%20untitle_table_4&api_key=1234',
|
||||||
@ -220,7 +218,7 @@ function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Test for https://github.com/Vizzuality/CartoDB-SQL-API/issues/85
|
// Test for https://github.com/Vizzuality/CartoDB-SQL-API/issues/85
|
||||||
test("paging doesn't break x-cache-channel",
|
it("paging doesn't break x-cache-channel",
|
||||||
function(done){
|
function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
@ -242,13 +240,14 @@ function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Test page and rows_per_page params
|
// Test page and rows_per_page params
|
||||||
test("paging", function(done){
|
it("paging", function(done){
|
||||||
var sql = 'SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(v)';
|
var sql = 'SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(v)';
|
||||||
var pr = [ [2,3], [0,4] ]; // page and rows
|
var pr = [ [2,3], [0,4] ]; // page and rows
|
||||||
var methods = [ 'GET', 'POST' ];
|
var methods = [ 'GET', 'POST' ];
|
||||||
var authorized = 0;
|
var authorized = 0;
|
||||||
var testing = 0;
|
var testing = 0;
|
||||||
var method = 0;
|
var method = 0;
|
||||||
|
// jshint maxcomplexity:7
|
||||||
var testNext = function() {
|
var testNext = function() {
|
||||||
if ( testing >= pr.length ) {
|
if ( testing >= pr.length ) {
|
||||||
if ( method+1 >= methods.length ) {
|
if ( method+1 >= methods.length ) {
|
||||||
@ -266,9 +265,8 @@ test("paging", function(done){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var prcur = pr[testing++];
|
var prcur = pr[testing++];
|
||||||
console.log("Test " + testing + "/" + pr.length
|
console.log("Test " + testing + "/" + pr.length + " method " + methods[method] + " " +
|
||||||
+ " method " + methods[method] + " "
|
( authorized ? "authenticated" : "" ) );
|
||||||
+ ( authorized ? "authenticated" : "" ) );
|
|
||||||
var page = prcur[0];
|
var page = prcur[0];
|
||||||
var nrows = prcur[1];
|
var nrows = prcur[1];
|
||||||
var data_obj = {
|
var data_obj = {
|
||||||
@ -276,13 +274,15 @@ test("paging", function(done){
|
|||||||
rows_per_page: nrows,
|
rows_per_page: nrows,
|
||||||
page: page
|
page: page
|
||||||
};
|
};
|
||||||
if ( authorized ) data_obj['api_key'] = '1234';
|
if ( authorized ) {
|
||||||
|
data_obj.api_key = '1234';
|
||||||
|
}
|
||||||
var data = querystring.stringify(data_obj);
|
var data = querystring.stringify(data_obj);
|
||||||
var req = {
|
var req = {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
headers: {host: 'vizzuality.cartodb.com'}
|
headers: {host: 'vizzuality.cartodb.com'}
|
||||||
};
|
};
|
||||||
if ( methods[method] == 'GET' ) {
|
if ( methods[method] === 'GET' ) {
|
||||||
req.method = 'GET';
|
req.method = 'GET';
|
||||||
req.url += '?' + data;
|
req.url += '?' + data;
|
||||||
} else {
|
} else {
|
||||||
@ -306,7 +306,7 @@ test("paging", function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Test paging with WITH queries
|
// Test paging with WITH queries
|
||||||
test("paging starting with comment", function(done){
|
it("paging starting with comment", function(done){
|
||||||
var sql = "-- this is a comment\n" +
|
var sql = "-- this is a comment\n" +
|
||||||
"SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(v)";
|
"SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(v)";
|
||||||
var nrows = 3;
|
var nrows = 3;
|
||||||
@ -332,7 +332,7 @@ test("paging starting with comment", function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /api/v1/sql with SQL parameter on SELECT only. no database param, just id using headers', function(done){
|
it('POST /api/v1/sql with SQL parameter on SELECT only. no database param, just id using headers', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
data: querystring.stringify({q: "SELECT * FROM untitle_table_4"}),
|
data: querystring.stringify({q: "SELECT * FROM untitle_table_4"}),
|
||||||
@ -344,9 +344,10 @@ test('POST /api/v1/sql with SQL parameter on SELECT only. no database param, jus
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with INSERT. oAuth not used, so public user - should fail', function(done){
|
it('GET /api/v1/sql with INSERT. oAuth not used, so public user - should fail', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?q=INSERT%20INTO%20untitle_table_4%20(cartodb_id)%20VALUES%20(1e4)&database=cartodb_test_user_1_db",
|
url: "/api/v1/sql?q=INSERT%20INTO%20untitle_table_4%20(cartodb_id)%20VALUES%20(1e4)" +
|
||||||
|
"&database=cartodb_test_user_1_db",
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
},{
|
},{
|
||||||
@ -361,7 +362,7 @@ test('GET /api/v1/sql with INSERT. oAuth not used, so public user - should fail'
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with DROP TABLE. oAuth not used, so public user - should fail', function(done){
|
it('GET /api/v1/sql with DROP TABLE. oAuth not used, so public user - should fail', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4&database=cartodb_test_user_1_db",
|
url: "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4&database=cartodb_test_user_1_db",
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -378,7 +379,7 @@ test('GET /api/v1/sql with DROP TABLE. oAuth not used, so public user - should f
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with INSERT. header based db - should fail', function(){
|
it('GET /api/v1/sql with INSERT. header based db - should fail', function(){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?q=INSERT%20INTO%20untitle_table_4%20(id)%20VALUES%20(1)",
|
url: "/api/v1/sql?q=INSERT%20INTO%20untitle_table_4%20(id)%20VALUES%20(1)",
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -391,11 +392,10 @@ test('GET /api/v1/sql with INSERT. header based db - should fail', function(){
|
|||||||
// Check results from INSERT
|
// Check results from INSERT
|
||||||
//
|
//
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/13
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/13
|
||||||
test('INSERT returns affected rows', function(done){
|
it('INSERT returns affected rows', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
// view prepare_db.sh to see where to set api_key
|
// view prepare_db.sh to see where to set api_key
|
||||||
url: "/api/v1/sql?api_key=1234&"
|
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||||
+ querystring.stringify({q:
|
|
||||||
"INSERT INTO private_table(name) VALUES('noret1') UNION VALUES('noret2')"
|
"INSERT INTO private_table(name) VALUES('noret1') UNION VALUES('noret2')"
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||||
@ -417,11 +417,10 @@ test('INSERT returns affected rows', function(done){
|
|||||||
// Check results from UPDATE
|
// Check results from UPDATE
|
||||||
//
|
//
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/13
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/13
|
||||||
test('UPDATE returns affected rows', function(done){
|
it('UPDATE returns affected rows', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
// view prepare_db.sh to see where to set api_key
|
// view prepare_db.sh to see where to set api_key
|
||||||
url: "/api/v1/sql?api_key=1234&"
|
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||||
+ querystring.stringify({q:
|
|
||||||
"UPDATE private_table SET name = upper(name) WHERE name in ('noret1', 'noret2')"
|
"UPDATE private_table SET name = upper(name) WHERE name in ('noret1', 'noret2')"
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||||
@ -443,11 +442,10 @@ test('UPDATE returns affected rows', function(done){
|
|||||||
// Check results from DELETE
|
// Check results from DELETE
|
||||||
//
|
//
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/13
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/13
|
||||||
test('DELETE returns affected rows', function(done){
|
it('DELETE returns affected rows', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
// view prepare_db.sh to see where to set api_key
|
// view prepare_db.sh to see where to set api_key
|
||||||
url: "/api/v1/sql?api_key=1234&"
|
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||||
+ querystring.stringify({q:
|
|
||||||
"DELETE FROM private_table WHERE name in ('NORET1', 'NORET2')"
|
"DELETE FROM private_table WHERE name in ('NORET1', 'NORET2')"
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||||
@ -469,11 +467,10 @@ test('DELETE returns affected rows', function(done){
|
|||||||
// Check results from INSERT .. RETURNING
|
// Check results from INSERT .. RETURNING
|
||||||
//
|
//
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/50
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/50
|
||||||
test('INSERT with RETURNING returns all results', function(done){
|
it('INSERT with RETURNING returns all results', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
// view prepare_db.sh to see where to set api_key
|
// view prepare_db.sh to see where to set api_key
|
||||||
url: "/api/v1/sql?api_key=1234&"
|
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||||
+ querystring.stringify({q:
|
|
||||||
"INSERT INTO private_table(name) VALUES('test') RETURNING upper(name), reverse(name)"
|
"INSERT INTO private_table(name) VALUES('test') RETURNING upper(name), reverse(name)"
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||||
@ -494,11 +491,10 @@ test('INSERT with RETURNING returns all results', function(done){
|
|||||||
// Check results from UPDATE .. RETURNING
|
// Check results from UPDATE .. RETURNING
|
||||||
//
|
//
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/50
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/50
|
||||||
test('UPDATE with RETURNING returns all results', function(done){
|
it('UPDATE with RETURNING returns all results', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
// view prepare_db.sh to see where to set api_key
|
// view prepare_db.sh to see where to set api_key
|
||||||
url: "/api/v1/sql?api_key=1234&"
|
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||||
+ querystring.stringify({q:
|
|
||||||
"UPDATE private_table SET name = 'tost' WHERE name = 'test' RETURNING upper(name), reverse(name)"
|
"UPDATE private_table SET name = 'tost' WHERE name = 'test' RETURNING upper(name), reverse(name)"
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||||
@ -519,11 +515,10 @@ test('UPDATE with RETURNING returns all results', function(done){
|
|||||||
// Check results from DELETE .. RETURNING
|
// Check results from DELETE .. RETURNING
|
||||||
//
|
//
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/50
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/50
|
||||||
test('DELETE with RETURNING returns all results', function(done){
|
it('DELETE with RETURNING returns all results', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
// view prepare_db.sh to see where to set api_key
|
// view prepare_db.sh to see where to set api_key
|
||||||
url: "/api/v1/sql?api_key=1234&"
|
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||||
+ querystring.stringify({q:
|
|
||||||
"DELETE FROM private_table WHERE name = 'tost' RETURNING name"
|
"DELETE FROM private_table WHERE name = 'tost' RETURNING name"
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||||
@ -540,7 +535,7 @@ test('DELETE with RETURNING returns all results', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with SQL parameter on DROP TABLE. should fail', function(done){
|
it('GET /api/v1/sql with SQL parameter on DROP TABLE. should fail', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4",
|
url: "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4",
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -559,11 +554,10 @@ test('GET /api/v1/sql with SQL parameter on DROP TABLE. should fail', function(d
|
|||||||
// Check X-Cache-Channel when querying "updated_at" fields
|
// Check X-Cache-Channel when querying "updated_at" fields
|
||||||
//
|
//
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/99
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/99
|
||||||
test('Field name is not confused with UPDATE operation', function(done){
|
it('Field name is not confused with UPDATE operation', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
// view prepare_db.sh to see where to set api_key
|
// view prepare_db.sh to see where to set api_key
|
||||||
url: "/api/v1/sql?api_key=1234&"
|
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||||
+ querystring.stringify({q:
|
|
||||||
"SELECT min(updated_at) FROM private_table"
|
"SELECT min(updated_at) FROM private_table"
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||||
@ -575,7 +569,7 @@ test('Field name is not confused with UPDATE operation', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('CREATE TABLE with GET and auth', function(done){
|
it('CREATE TABLE with GET and auth', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?" + querystring.stringify({
|
url: "/api/v1/sql?" + querystring.stringify({
|
||||||
q: 'CREATE TABLE test_table(a int)',
|
q: 'CREATE TABLE test_table(a int)',
|
||||||
@ -594,9 +588,9 @@ test('CREATE TABLE with GET and auth', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See http://github.com/CartoDB/CartoDB-SQL-API/issues/127
|
// See http://github.com/CartoDB/CartoDB-SQL-API/issues/127
|
||||||
test('SELECT INTO with paging ', function(done){
|
it('SELECT INTO with paging ', function(done){
|
||||||
var esc_tabname = 'test ""select into""'; // escaped ident
|
var esc_tabname = 'test ""select into""'; // escaped ident
|
||||||
Step(
|
step(
|
||||||
function select_into() {
|
function select_into() {
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -610,7 +604,7 @@ test('SELECT INTO with paging ', function(done){
|
|||||||
},{}, function(res) { next(null, res); });
|
},{}, function(res) { next(null, res); });
|
||||||
},
|
},
|
||||||
function check_res_test_fake_into_1(err, res) {
|
function check_res_test_fake_into_1(err, res) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -624,7 +618,7 @@ test('SELECT INTO with paging ', function(done){
|
|||||||
},{}, function(res) { next(null, res); });
|
},{}, function(res) { next(null, res); });
|
||||||
},
|
},
|
||||||
function check_res_drop_table(err, res) {
|
function check_res_drop_table(err, res) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
||||||
var out = JSON.parse(res.body);
|
var out = JSON.parse(res.body);
|
||||||
assert.equal(out.total_rows, 1); // windowing works
|
assert.equal(out.total_rows, 1); // windowing works
|
||||||
@ -639,19 +633,19 @@ test('SELECT INTO with paging ', function(done){
|
|||||||
},{}, function(res) { next(null, res); });
|
},{}, function(res) { next(null, res); });
|
||||||
},
|
},
|
||||||
function check_drop(err, res) {
|
function check_drop(err, res) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
function finish(err) {
|
function finish(err) {
|
||||||
done(err)
|
done(err);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test effects of COPY
|
// Test effects of COPY
|
||||||
// See https://github.com/Vizzuality/cartodb-management/issues/1502
|
// See https://github.com/Vizzuality/cartodb-management/issues/1502
|
||||||
test('COPY TABLE with GET and auth', function(done){
|
it('COPY TABLE with GET and auth', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?" + querystring.stringify({
|
url: "/api/v1/sql?" + querystring.stringify({
|
||||||
q: 'COPY test_table FROM stdin;',
|
q: 'COPY test_table FROM stdin;',
|
||||||
@ -669,7 +663,7 @@ test('COPY TABLE with GET and auth', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('COPY TABLE with GET and auth', function(done){
|
it('COPY TABLE with GET and auth', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?" + querystring.stringify({
|
url: "/api/v1/sql?" + querystring.stringify({
|
||||||
q: "COPY test_table to '/tmp/x';",
|
q: "COPY test_table to '/tmp/x';",
|
||||||
@ -690,7 +684,7 @@ test('COPY TABLE with GET and auth', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ALTER TABLE with GET and auth', function(done){
|
it('ALTER TABLE with GET and auth', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?" + querystring.stringify({
|
url: "/api/v1/sql?" + querystring.stringify({
|
||||||
q: 'ALTER TABLE test_table ADD b int',
|
q: 'ALTER TABLE test_table ADD b int',
|
||||||
@ -708,10 +702,11 @@ test('ALTER TABLE with GET and auth', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('multistatement insert, alter, select, begin, commit', function(done){
|
it('multistatement insert, alter, select, begin, commit', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?" + querystring.stringify({
|
url: "/api/v1/sql?" + querystring.stringify({
|
||||||
q: 'BEGIN; DELETE FROM test_table; COMMIT; BEGIN; INSERT INTO test_table(b) values (5); COMMIT; ALTER TABLE test_table ALTER b TYPE float USING b::float/2; SELECT b FROM test_table;',
|
q: 'BEGIN; DELETE FROM test_table; COMMIT; BEGIN; INSERT INTO test_table(b) values (5); COMMIT; ' +
|
||||||
|
'ALTER TABLE test_table ALTER b TYPE float USING b::float/2; SELECT b FROM test_table;',
|
||||||
api_key: 1234
|
api_key: 1234
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -725,7 +720,7 @@ test('multistatement insert, alter, select, begin, commit', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('TRUNCATE TABLE with GET and auth', function(done){
|
it('TRUNCATE TABLE with GET and auth', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?" + querystring.stringify({
|
url: "/api/v1/sql?" + querystring.stringify({
|
||||||
q: 'TRUNCATE TABLE test_table',
|
q: 'TRUNCATE TABLE test_table',
|
||||||
@ -752,13 +747,13 @@ test('TRUNCATE TABLE with GET and auth', function(done){
|
|||||||
assert.equal(res.headers['cache-control'], expected_cache_control);
|
assert.equal(res.headers['cache-control'], expected_cache_control);
|
||||||
var pbody = JSON.parse(res.body);
|
var pbody = JSON.parse(res.body);
|
||||||
assert.equal(pbody.total_rows, 1);
|
assert.equal(pbody.total_rows, 1);
|
||||||
assert.equal(pbody.rows[0]['count'], 0);
|
assert.equal(pbody.rows[0].count, 0);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('REINDEX TABLE with GET and auth', function(done){
|
it('REINDEX TABLE with GET and auth', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?" + querystring.stringify({
|
url: "/api/v1/sql?" + querystring.stringify({
|
||||||
q: ' ReINdEX TABLE test_table',
|
q: ' ReINdEX TABLE test_table',
|
||||||
@ -776,7 +771,7 @@ test('REINDEX TABLE with GET and auth', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DROP TABLE with GET and auth', function(done){
|
it('DROP TABLE with GET and auth', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?" + querystring.stringify({
|
url: "/api/v1/sql?" + querystring.stringify({
|
||||||
q: 'DROP TABLE test_table',
|
q: 'DROP TABLE test_table',
|
||||||
@ -812,7 +807,7 @@ test('CREATE FUNCTION with GET and auth', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DROP FUNCTION with GET and auth', function(done){
|
it('DROP FUNCTION with GET and auth', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?" + querystring.stringify({
|
url: "/api/v1/sql?" + querystring.stringify({
|
||||||
q: 'DROP FUNCTION create_func_test(a int)',
|
q: 'DROP FUNCTION create_func_test(a int)',
|
||||||
@ -830,7 +825,7 @@ test('DROP FUNCTION with GET and auth', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sends a 400 when an unsupported format is requested', function(done){
|
it('sends a 400 when an unsupported format is requested', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=unknown',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=unknown',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -844,7 +839,7 @@ test('sends a 400 when an unsupported format is requested', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with SQL parameter and no format, ensuring content-disposition set to json', function(done){
|
it('GET /api/v1/sql with SQL parameter and no format, ensuring content-disposition set to json', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -860,7 +855,7 @@ test('GET /api/v1/sql with SQL parameter and no format, ensuring content-disposi
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /api/v1/sql with SQL parameter and no format, ensuring content-disposition set to json', function(done){
|
it('POST /api/v1/sql with SQL parameter and no format, ensuring content-disposition set to json', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
data: querystring.stringify({q: "SELECT * FROM untitle_table_4" }),
|
data: querystring.stringify({q: "SELECT * FROM untitle_table_4" }),
|
||||||
@ -877,7 +872,7 @@ test('POST /api/v1/sql with SQL parameter and no format, ensuring content-dispos
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with SQL parameter and no format, but a filename', function(done){
|
it('GET /api/v1/sql with SQL parameter and no format, but a filename', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&filename=x',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&filename=x',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -893,7 +888,7 @@ test('GET /api/v1/sql with SQL parameter and no format, but a filename', functio
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('field named "the_geom_webmercator" is not skipped by default', function(done){
|
it('field named "the_geom_webmercator" is not skipped by default', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -913,7 +908,7 @@ test('field named "the_geom_webmercator" is not skipped by default', function(do
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('skipfields controls included fields', function(done){
|
it('skipfields controls included fields', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&skipfields=the_geom_webmercator,cartodb_id,unexistant',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&skipfields=the_geom_webmercator,cartodb_id,unexistant',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -933,9 +928,10 @@ test('skipfields controls included fields', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('multiple skipfields parameter do not kill the backend', function(done){
|
it('multiple skipfields parameter do not kill the backend', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&skipfields=unexistent,the_geom_webmercator&skipfields=cartodb_id,unexistant',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&skipfields=unexistent,the_geom_webmercator' +
|
||||||
|
'&skipfields=cartodb_id,unexistant',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
},{ }, function(res){
|
},{ }, function(res){
|
||||||
@ -953,7 +949,7 @@ test('multiple skipfields parameter do not kill the backend', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql ensure cross domain set on errors', function(done){
|
it('GET /api/v1/sql ensure cross domain set on errors', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*gadfgadfg%20FROM%20untitle_table_4',
|
url: '/api/v1/sql?q=SELECT%20*gadfgadfg%20FROM%20untitle_table_4',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -1013,7 +1009,7 @@ var systemQueriesSuitesToTest = [
|
|||||||
|
|
||||||
function testSystemQueries(description, queries, statusErrorCode, apiKey) {
|
function testSystemQueries(description, queries, statusErrorCode, apiKey) {
|
||||||
queries.forEach(function(query) {
|
queries.forEach(function(query) {
|
||||||
test('[' + description + '] query: ' + query, function(done) {
|
it('[' + description + '] query: ' + query, function(done) {
|
||||||
var queryStringParams = {q: query};
|
var queryStringParams = {q: query};
|
||||||
if (!!apiKey) {
|
if (!!apiKey) {
|
||||||
queryStringParams.api_key = apiKey;
|
queryStringParams.api_key = apiKey;
|
||||||
@ -1031,23 +1027,26 @@ function testSystemQueries(description, queries, statusErrorCode, apiKey) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
test('GET decent error if domain is incorrect', function(done){
|
it('GET decent error if domain is incorrect', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
||||||
headers: {host: 'vizzualinot.cartodb.com'},
|
headers: {host: 'vizzualinot.cartodb.com'},
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
}, {}, function(res){
|
}, {}, function(res){
|
||||||
assert.equal(res.statusCode, 404, res.statusCode + ( res.statusCode != 200 ? ( ': ' + res.body ) : ''));
|
assert.equal(res.statusCode, 404, res.statusCode + ( res.statusCode !== 200 ? ( ': ' + res.body ) : ''));
|
||||||
assert.deepEqual(res.headers['content-type'], 'application/json; charset=utf-8');
|
assert.deepEqual(res.headers['content-type'], 'application/json; charset=utf-8');
|
||||||
assert.deepEqual(res.headers['content-disposition'], 'inline');
|
assert.deepEqual(res.headers['content-disposition'], 'inline');
|
||||||
var result = JSON.parse(res.body);
|
var result = JSON.parse(res.body);
|
||||||
assert.equal(result.error[0],"Sorry, we can't find CartoDB user 'vizzualinot'. Please check that you have entered the correct domain.");
|
assert.equal(
|
||||||
|
result.error[0],
|
||||||
|
"Sorry, we can't find CartoDB user 'vizzualinot'. Please check that you have entered the correct domain."
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// this test does not make sense with the current CDB_QueryTables implementation
|
// this test does not make sense with the current CDB_QueryTables implementation
|
||||||
test('GET decent error if SQL is broken', function(done){
|
it('GET decent error if SQL is broken', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({q:
|
url: '/api/v1/sql?' + querystring.stringify({q:
|
||||||
'SELECT star FROM this and that'
|
'SELECT star FROM this and that'
|
||||||
@ -1066,10 +1065,9 @@ test('GET decent error if SQL is broken', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/88
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/88
|
||||||
test('numeric arrays are rendered as such', function(done){
|
it('numeric arrays are rendered as such', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?"
|
url: "/api/v1/sql?" + querystring.stringify({q:
|
||||||
+ querystring.stringify({q:
|
|
||||||
"SELECT ARRAY[8.7,4.3]::numeric[] as x"
|
"SELECT ARRAY[8.7,4.3]::numeric[] as x"
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||||
@ -1090,7 +1088,7 @@ test('numeric arrays are rendered as such', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/97
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/97
|
||||||
test('field names and types are exposed', function(done){
|
it('field names and types are exposed', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: "SELECT 1::int as a, 2::float8 as b, 3::varchar as c, " +
|
q: "SELECT 1::int as a, 2::float8 as b, 3::varchar as c, " +
|
||||||
@ -1123,7 +1121,7 @@ test('field names and types are exposed', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/109
|
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/109
|
||||||
test('schema response takes skipfields into account', function(done){
|
it('schema response takes skipfields into account', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: "SELECT 1 as a, 2 as b, 3 as c ",
|
q: "SELECT 1 as a, 2 as b, 3 as c ",
|
||||||
@ -1143,7 +1141,7 @@ test('schema response takes skipfields into account', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/100
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/100
|
||||||
test('numeric fields are rendered as numbers in JSON', function(done){
|
it('numeric fields are rendered as numbers in JSON', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: "WITH inp AS ( SELECT 1::int2 as a, 2::int4 as b, " +
|
q: "WITH inp AS ( SELECT 1::int2 as a, 2::int4 as b, " +
|
||||||
@ -1191,8 +1189,8 @@ test('numeric fields are rendered as numbers in JSON', function(done){
|
|||||||
// numbers, but it'd currently take running the
|
// numbers, but it'd currently take running the
|
||||||
// test again (new mocha run) with a different TZ
|
// test again (new mocha run) with a different TZ
|
||||||
//
|
//
|
||||||
test('timezone info in JSON output', function(done){
|
it('timezone info in JSON output', function(done){
|
||||||
Step(
|
step(
|
||||||
function testEuropeRomeExplicit() {
|
function testEuropeRomeExplicit() {
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -1213,7 +1211,7 @@ test('timezone info in JSON output', function(done){
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function testEuropeRomeImplicit(err) {
|
function testEuropeRomeImplicit(err) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
@ -1233,7 +1231,7 @@ test('timezone info in JSON output', function(done){
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function testUTCExplicit(err) {
|
function testUTCExplicit(err) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
@ -1253,7 +1251,7 @@ test('timezone info in JSON output', function(done){
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function testUTCImplicit(err) {
|
function testUTCImplicit(err) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
@ -1280,13 +1278,15 @@ test('timezone info in JSON output', function(done){
|
|||||||
|
|
||||||
// WARNING and NOTICE in JSON output
|
// WARNING and NOTICE in JSON output
|
||||||
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/104
|
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/104
|
||||||
test('notice and warning info in JSON output', function(done){
|
it('notice and warning info in JSON output', function(done){
|
||||||
Step(
|
step(
|
||||||
function addRaiseFunction() {
|
function addRaiseFunction() {
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: "create or replace function raise(lvl text, msg text) returns void as $$ begin if lvl = 'notice' then raise notice '%', msg; elsif lvl = 'warning' then raise warning '%', msg; else raise exception '%', msg; end if; end; $$ language plpgsql;",
|
q: "create or replace function raise(lvl text, msg text) returns void as $$ begin if lvl = 'notice' " +
|
||||||
|
"then raise notice '%', msg; elsif lvl = 'warning' then raise warning '%', msg; " +
|
||||||
|
"else raise exception '%', msg; end if; end; $$ language plpgsql;",
|
||||||
api_key: '1234'
|
api_key: '1234'
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -1300,7 +1300,7 @@ test('notice and warning info in JSON output', function(done){
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function raiseNotice(err) {
|
function raiseNotice(err) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
@ -1321,7 +1321,7 @@ test('notice and warning info in JSON output', function(done){
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function raiseWarning(err) {
|
function raiseWarning(err) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
@ -1342,11 +1342,12 @@ test('notice and warning info in JSON output', function(done){
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function raiseBothWarningAndNotice(err) {
|
function raiseBothWarningAndNotice(err) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: "SET client_min_messages TO 'notice'; select raise('warning', 'hello again warning'), raise('notice', 'hello again notice');"
|
q: "SET client_min_messages TO 'notice'; select raise('warning', 'hello again warning'), " +
|
||||||
|
"raise('notice', 'hello again notice');"
|
||||||
}),
|
}),
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
@ -1377,7 +1378,7 @@ test('notice and warning info in JSON output', function(done){
|
|||||||
},{ }, function(res) {
|
},{ }, function(res) {
|
||||||
try {
|
try {
|
||||||
assert.equal(res.statusCode, 200, res.body);
|
assert.equal(res.statusCode, 200, res.body);
|
||||||
var parsedBody = JSON.parse(res.body);
|
JSON.parse(res.body);
|
||||||
} catch (e) { err = new Error(err + ',' + e); }
|
} catch (e) { err = new Error(err + ',' + e); }
|
||||||
next(err);
|
next(err);
|
||||||
});
|
});
|
||||||
@ -1391,7 +1392,7 @@ test('notice and warning info in JSON output', function(done){
|
|||||||
/**
|
/**
|
||||||
* CORS
|
* CORS
|
||||||
*/
|
*/
|
||||||
test('GET /api/v1/sql with SQL parameter on SELECT only should return CORS headers ', function(done){
|
it('GET /api/v1/sql with SQL parameter on SELECT only should return CORS headers ', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&database=cartodb_test_user_1_db',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&database=cartodb_test_user_1_db',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -1402,12 +1403,15 @@ test('GET /api/v1/sql with SQL parameter on SELECT only should return CORS heade
|
|||||||
assert.equal(res.headers['x-cache-channel'], 'cartodb_test_user_1_db:public.untitle_table_4');
|
assert.equal(res.headers['x-cache-channel'], 'cartodb_test_user_1_db:public.untitle_table_4');
|
||||||
assert.equal(res.headers['cache-control'], expected_cache_control);
|
assert.equal(res.headers['cache-control'], expected_cache_control);
|
||||||
assert.equal(res.headers['access-control-allow-origin'], '*');
|
assert.equal(res.headers['access-control-allow-origin'], '*');
|
||||||
assert.equal(res.headers['access-control-allow-headers'], "X-Requested-With, X-Prototype-Version, X-CSRF-Token");
|
assert.equal(
|
||||||
|
res.headers['access-control-allow-headers'],
|
||||||
|
"X-Requested-With, X-Prototype-Version, X-CSRF-Token"
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET with callback param returns wrapped result set with callback as jsonp', function(done) {
|
it('GET with callback param returns wrapped result set with callback as jsonp', function(done) {
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&callback=foo_jsonp',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&callback=foo_jsonp',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -1419,7 +1423,7 @@ test('GET with callback param returns wrapped result set with callback as jsonp'
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET with callback must return 200 status error even if it is an error', function(done){
|
it('GET with callback must return 200 status error even if it is an error', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4&callback=foo_jsonp",
|
url: "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4&callback=foo_jsonp",
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -1427,17 +1431,19 @@ test('GET with callback must return 200 status error even if it is an error', fu
|
|||||||
},{}, function(res) {
|
},{}, function(res) {
|
||||||
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
||||||
var didRunJsonCallback = false;
|
var didRunJsonCallback = false;
|
||||||
|
// jshint ignore:start
|
||||||
function foo_jsonp(body) {
|
function foo_jsonp(body) {
|
||||||
assert.deepEqual(body, {"error":["must be owner of relation untitle_table_4"]});
|
assert.deepEqual(body, {"error":["must be owner of relation untitle_table_4"]});
|
||||||
didRunJsonCallback = true;
|
didRunJsonCallback = true;
|
||||||
}
|
}
|
||||||
eval(res.body);
|
eval(res.body);
|
||||||
|
// jshint ignore:end
|
||||||
assert.ok(didRunJsonCallback);
|
assert.ok(didRunJsonCallback);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET with slow query exceeding statement timeout returns proper error message', function(done){
|
it('GET with slow query exceeding statement timeout returns proper error message', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: "/api/v1/sql?q=select%20pg_sleep(2.1)%20as%20sleep",
|
url: "/api/v1/sql?q=select%20pg_sleep(2.1)%20as%20sleep",
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -1452,7 +1458,7 @@ test('GET with callback must return 200 status error even if it is an error', fu
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('stream response is closed on error and error message is part of the response', function(done){
|
it('stream response is closed on error and error message is part of the response', function(done){
|
||||||
assert.response(
|
assert.response(
|
||||||
app,
|
app,
|
||||||
{
|
{
|
||||||
@ -1475,7 +1481,7 @@ test('GET with callback must return 200 status error even if it is an error', fu
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('too large rows get into error log', function(done){
|
it('too large rows get into error log', function(done){
|
||||||
|
|
||||||
var dbMaxRowSize = global.settings.db_max_row_size;
|
var dbMaxRowSize = global.settings.db_max_row_size;
|
||||||
global.settings.db_max_row_size = 4;
|
global.settings.db_max_row_size = 4;
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
require('../helper');
|
require('../helper');
|
||||||
require('../support/assert');
|
|
||||||
|
|
||||||
var assert = require('assert')
|
var assert = require('../support/assert');
|
||||||
, App = require(global.settings.app_root + '/app/controllers/app')
|
var step = require('step');
|
||||||
, querystring = require('querystring')
|
var net = require('net');
|
||||||
, _ = require('underscore')
|
|
||||||
, Step = require('step')
|
|
||||||
, net = require('net')
|
|
||||||
;
|
|
||||||
|
|
||||||
var sql_server_port = 5556;
|
var sql_server_port = 5540;
|
||||||
var sql_server = net.createServer(function(c) {
|
var sql_server = net.createServer(function(c) {
|
||||||
console.log('server connected');
|
console.log('server connected');
|
||||||
c.destroy();
|
c.destroy();
|
||||||
@ -19,21 +14,21 @@ var sql_server = net.createServer(function(c) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('backend crash', function() {
|
describe('backend crash', function() {
|
||||||
|
|
||||||
suiteSetup(function(done){
|
before(function(done){
|
||||||
sql_server.listen(sql_server_port, done);
|
sql_server.listen(sql_server_port, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/135
|
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/135
|
||||||
test('does not hang server', function(done){
|
it('does not hang server', function(done){
|
||||||
//console.log("settings:"); console.dir(global.settings);
|
//console.log("settings:"); console.dir(global.settings);
|
||||||
var db_host_backup = global.settings.db_host;
|
var db_host_backup = global.settings.db_host;
|
||||||
var db_port_backup = global.settings.db_port;
|
var db_port_backup = global.settings.db_port;
|
||||||
global.settings.db_host = 'localhost';
|
global.settings.db_host = 'localhost';
|
||||||
global.settings.db_port = sql_server_port;
|
global.settings.db_port = sql_server_port;
|
||||||
var app = App();
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
Step(
|
step(
|
||||||
function sendQuery() {
|
function sendQuery() {
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -45,7 +40,7 @@ test('does not hang server', function(done){
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function checkResponse(err, res) {
|
function checkResponse(err, res) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
assert.equal(res.statusCode, 500, res.statusCode + ': ' + res.body);
|
assert.equal(res.statusCode, 500, res.statusCode + ': ' + res.body);
|
||||||
var parsed = JSON.parse(res.body);
|
var parsed = JSON.parse(res.body);
|
||||||
assert.ok(parsed.error);
|
assert.ok(parsed.error);
|
||||||
@ -64,7 +59,7 @@ test('does not hang server', function(done){
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function checkResponse(err, res) {
|
function checkResponse(err, res) {
|
||||||
if ( err ) throw err;
|
assert.ifError(err);
|
||||||
assert.equal(res.statusCode, 500, res.statusCode + ': ' + res.body);
|
assert.equal(res.statusCode, 500, res.statusCode + ': ' + res.body);
|
||||||
var parsed = JSON.parse(res.body);
|
var parsed = JSON.parse(res.body);
|
||||||
assert.ok(parsed.error);
|
assert.ok(parsed.error);
|
||||||
@ -80,7 +75,7 @@ test('does not hang server', function(done){
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
suiteTeardown(function(done) {
|
after(function(done) {
|
||||||
try {
|
try {
|
||||||
sql_server.close(done);
|
sql_server.close(done);
|
||||||
} catch (er) {
|
} catch (er) {
|
||||||
|
@ -2,34 +2,16 @@ require('../../helper');
|
|||||||
require('../../support/assert');
|
require('../../support/assert');
|
||||||
|
|
||||||
|
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
, assert = require('assert')
|
var assert = require('assert');
|
||||||
, querystring = require('querystring')
|
var querystring = require('querystring');
|
||||||
, _ = require('underscore')
|
|
||||||
, zipfile = require('zipfile')
|
|
||||||
, fs = require('fs')
|
|
||||||
, libxmljs = require('libxmljs')
|
|
||||||
, Step = require('step')
|
|
||||||
;
|
|
||||||
|
|
||||||
// allow lots of emitters to be set to silence warning
|
// allow lots of emitters to be set to silence warning
|
||||||
app.setMaxListeners(0);
|
app.setMaxListeners(0);
|
||||||
|
|
||||||
suite('export.arraybuffer', function() {
|
describe('export.arraybuffer', function() {
|
||||||
|
|
||||||
var expected_cache_control = 'no-cache,max-age=3600,must-revalidate,public';
|
it('GET /api/v1/sql as arraybuffer ', function(done){
|
||||||
var expected_cache_control_persist = 'public,max-age=31536000';
|
|
||||||
|
|
||||||
// use dec_sep for internationalization
|
|
||||||
var checkDecimals = function(x, dec_sep){
|
|
||||||
var tmp='' + x;
|
|
||||||
if (tmp.indexOf(dec_sep)>-1)
|
|
||||||
return tmp.length-tmp.indexOf(dec_sep)-1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
test('GET /api/v1/sql as arraybuffer ', function(done){
|
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: 'SELECT cartodb_id,name,1::integer,187.9 FROM untitle_table_4',
|
q: 'SELECT cartodb_id,name,1::integer,187.9 FROM untitle_table_4',
|
||||||
@ -39,12 +21,12 @@ test('GET /api/v1/sql as arraybuffer ', function(done){
|
|||||||
method: 'GET'
|
method: 'GET'
|
||||||
},{ }, function(res){
|
},{ }, function(res){
|
||||||
assert.equal(res.statusCode, 200, res.body);
|
assert.equal(res.statusCode, 200, res.body);
|
||||||
assert.equal(res.headers['content-type'], "application/octet-stream")
|
assert.equal(res.headers['content-type'], "application/octet-stream");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql as arraybuffer does not support geometry types ', function(done){
|
it('GET /api/v1/sql as arraybuffer does not support geometry types ', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: 'SELECT cartodb_id, the_geom FROM untitle_table_4',
|
q: 'SELECT cartodb_id, the_geom FROM untitle_table_4',
|
||||||
|
@ -2,21 +2,16 @@ require('../../helper');
|
|||||||
require('../../support/assert');
|
require('../../support/assert');
|
||||||
|
|
||||||
|
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
, assert = require('assert')
|
var assert = require('assert');
|
||||||
, querystring = require('querystring')
|
var querystring = require('querystring');
|
||||||
, _ = require('underscore')
|
|
||||||
, zipfile = require('zipfile')
|
|
||||||
, fs = require('fs')
|
|
||||||
, libxmljs = require('libxmljs')
|
|
||||||
;
|
|
||||||
|
|
||||||
// allow lots of emitters to be set to silence warning
|
// allow lots of emitters to be set to silence warning
|
||||||
app.setMaxListeners(0);
|
app.setMaxListeners(0);
|
||||||
|
|
||||||
suite('export.csv', function() {
|
describe('export.csv', function() {
|
||||||
|
|
||||||
test('CSV format', function(done){
|
it('CSV format', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: 'SELECT * FROM untitle_table_4 WHERE cartodb_id = 1',
|
q: 'SELECT * FROM untitle_table_4 WHERE cartodb_id = 1',
|
||||||
@ -43,7 +38,7 @@ test('CSV format', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('CSV format, bigger than 81920 bytes', function(done){
|
it('CSV format, bigger than 81920 bytes', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
data: querystring.stringify({
|
data: querystring.stringify({
|
||||||
@ -59,7 +54,7 @@ test('CSV format, bigger than 81920 bytes', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('CSV format from POST', function(done){
|
it('CSV format from POST', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
data: querystring.stringify({q: "SELECT * FROM untitle_table_4 LIMIT 1", format: 'csv'}),
|
data: querystring.stringify({q: "SELECT * FROM untitle_table_4 LIMIT 1", format: 'csv'}),
|
||||||
@ -76,7 +71,7 @@ test('CSV format from POST', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('CSV format, custom filename', function(done){
|
it('CSV format, custom filename', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=csv&filename=mycsv.csv',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=csv&filename=mycsv.csv',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -89,43 +84,45 @@ test('CSV format, custom filename', function(done){
|
|||||||
var ct = res.header('Content-Type');
|
var ct = res.header('Content-Type');
|
||||||
assert.equal(true, /header=present/.test(ct), "CSV doesn't advertise header presence: " + ct);
|
assert.equal(true, /header=present/.test(ct), "CSV doesn't advertise header presence: " + ct);
|
||||||
var row0 = res.body.substring(0, res.body.search(/[\n\r]/)).split(',');
|
var row0 = res.body.substring(0, res.body.search(/[\n\r]/)).split(',');
|
||||||
var checkfields = {'name':1, 'cartodb_id':1, 'the_geom':1, 'the_geom_webmercator':1};
|
var checkFields = { name: true, cartodb_id: true, the_geom: true, the_geom_webmercator: true };
|
||||||
for ( var f in checkfields ) {
|
Object.keys(checkFields).forEach(function(f) {
|
||||||
var idx = row0.indexOf(f);
|
var idx = row0.indexOf(f);
|
||||||
if ( checkfields[f] ) {
|
if ( checkFields[f] ) {
|
||||||
assert.ok(idx != -1, "result does not include '" + f + "'");
|
assert.ok(idx !== -1, "result does not include '" + f + "'");
|
||||||
} else {
|
} else {
|
||||||
assert.ok(idx == -1, "result includes '" + f + "' ("+idx+")");
|
assert.ok(idx === -1, "result includes '" + f + "' ("+idx+")");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('skipfields controls fields included in CSV output', function(done){
|
it('skipfields controls fields included in CSV output', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=csv&skipfields=unexistant,cartodb_id',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=csv' +
|
||||||
|
'&skipfields=unexistant,cartodb_id',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
},{ }, function(res){
|
},{ }, function(res){
|
||||||
assert.equal(res.statusCode, 200, res.body);
|
assert.equal(res.statusCode, 200, res.body);
|
||||||
var row0 = res.body.substring(0, res.body.search(/[\n\r]/)).split(',');
|
var row0 = res.body.substring(0, res.body.search(/[\n\r]/)).split(',');
|
||||||
var checkfields = {'name':1, 'cartodb_id':0, 'the_geom':1, 'the_geom_webmercator':1};
|
var checkFields = { name: true, cartodb_id: false, the_geom: true, the_geom_webmercator: true };
|
||||||
for ( var f in checkfields ) {
|
Object.keys(checkFields).forEach(function(f) {
|
||||||
var idx = row0.indexOf(f);
|
var idx = row0.indexOf(f);
|
||||||
if ( checkfields[f] ) {
|
if ( checkFields[f] ) {
|
||||||
assert.ok(idx != -1, "result does not include '" + f + "'");
|
assert.ok(idx !== -1, "result does not include '" + f + "'");
|
||||||
} else {
|
} else {
|
||||||
assert.ok(idx == -1, "result includes '" + f + "' ("+idx+")");
|
assert.ok(idx === -1, "result includes '" + f + "' ("+idx+")");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql as csv', function(done){
|
it('GET /api/v1/sql as csv', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20cartodb_id,ST_AsEWKT(the_geom)%20as%20geom%20FROM%20untitle_table_4%20LIMIT%201&format=csv',
|
url: '/api/v1/sql?q=SELECT%20cartodb_id,ST_AsEWKT(the_geom)%20as%20geom%20FROM%20untitle_table_4%20LIMIT%201' +
|
||||||
|
'&format=csv',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
},{ }, function(res){
|
},{ }, function(res){
|
||||||
@ -137,7 +134,7 @@ test('GET /api/v1/sql as csv', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/60
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/60
|
||||||
test('GET /api/v1/sql as csv with no rows', function(done){
|
it('GET /api/v1/sql as csv with no rows', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20true%20WHERE%20false&format=csv',
|
url: '/api/v1/sql?q=SELECT%20true%20WHERE%20false&format=csv',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -147,13 +144,12 @@ test('GET /api/v1/sql as csv with no rows', function(done){
|
|||||||
var obtained_lines = res.body.split('\r\n');
|
var obtained_lines = res.body.split('\r\n');
|
||||||
assert.ok(obtained_lines.length <= 2, // may or may not have an header
|
assert.ok(obtained_lines.length <= 2, // may or may not have an header
|
||||||
// See http://trac.osgeo.org/gdal/ticket/5234
|
// See http://trac.osgeo.org/gdal/ticket/5234
|
||||||
'Too many lines in output (' + obtained_lines.length + '): '
|
'Too many lines in output (' + obtained_lines.length + '): ' + obtained_lines.join('\n'));
|
||||||
+ obtained_lines.join('\n'));
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql as csv, properly escaped', function(done){
|
it('GET /api/v1/sql as csv, properly escaped', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20cartodb_id,%20address%20FROM%20untitle_table_4%20LIMIT%201&format=csv',
|
url: '/api/v1/sql?q=SELECT%20cartodb_id,%20address%20FROM%20untitle_table_4%20LIMIT%201&format=csv',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -166,23 +162,29 @@ test('GET /api/v1/sql as csv, properly escaped', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql as csv, concurrently', function(done){
|
it('GET /api/v1/sql as csv, concurrently', function(done){
|
||||||
|
|
||||||
var concurrency = 4;
|
var concurrency = 4;
|
||||||
var waiting = concurrency;
|
var waiting = concurrency;
|
||||||
|
function validate(res){
|
||||||
|
var expected = 'cartodb_id,address\r\n1,"Calle de Pérez Galdós 9, Madrid, Spain"\r\n';
|
||||||
|
assert.equal(res.body, expected);
|
||||||
|
if ( ! --waiting ) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
for (var i=0; i<concurrency; ++i) {
|
for (var i=0; i<concurrency; ++i) {
|
||||||
|
assert.response(app,
|
||||||
assert.response(app, {
|
{
|
||||||
url: '/api/v1/sql?q=SELECT%20cartodb_id,%20address%20FROM%20untitle_table_4%20LIMIT%201&format=csv',
|
url: '/api/v1/sql?q=SELECT%20cartodb_id,%20address%20FROM%20untitle_table_4%20LIMIT%201&format=csv',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
},{ }, function(res){
|
},
|
||||||
assert.equal(res.statusCode, 200, res.body);
|
{
|
||||||
var expected = 'cartodb_id,address\r\n1,"Calle de Pérez Galdós 9, Madrid, Spain"\r\n';
|
status: 200
|
||||||
assert.equal(res.body, expected);
|
},
|
||||||
if ( ! --waiting ) done();
|
validate
|
||||||
});
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
|
|
||||||
require('../../helper');
|
require('../../helper');
|
||||||
require('../../support/assert');
|
|
||||||
|
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
, assert = require('assert')
|
var assert = require('../../support/assert');
|
||||||
, querystring = require('querystring')
|
var querystring = require('querystring');
|
||||||
, _ = require('underscore')
|
|
||||||
, zipfile = require('zipfile')
|
|
||||||
, fs = require('fs')
|
|
||||||
, libxmljs = require('libxmljs')
|
|
||||||
;
|
|
||||||
|
|
||||||
// allow lots of emitters to be set to silence warning
|
// allow lots of emitters to be set to silence warning
|
||||||
// TODO: check if still needed ...
|
// TODO: check if still needed ...
|
||||||
@ -18,17 +11,18 @@ app.setMaxListeners(0);
|
|||||||
// use dec_sep for internationalization
|
// use dec_sep for internationalization
|
||||||
var checkDecimals = function(x, dec_sep){
|
var checkDecimals = function(x, dec_sep){
|
||||||
var tmp='' + x;
|
var tmp='' + x;
|
||||||
if (tmp.indexOf(dec_sep)>-1)
|
if (tmp.indexOf(dec_sep)>-1) {
|
||||||
return tmp.length-tmp.indexOf(dec_sep)-1;
|
return tmp.length - tmp.indexOf(dec_sep) - 1;
|
||||||
else
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
suite('export.geojson', function() {
|
describe('export.geojson', function() {
|
||||||
|
|
||||||
// GEOJSON tests
|
// GEOJSON tests
|
||||||
|
|
||||||
test('GET /api/v1/sql with SQL parameter and geojson format, ensuring content-disposition set to geojson', function(done){
|
it('GET /api/v1/sql with SQL parameter, ensuring content-disposition set to geojson', function(done) {
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -42,7 +36,7 @@ test('GET /api/v1/sql with SQL parameter and geojson format, ensuring content-di
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /api/v1/sql with SQL parameter and geojson format, ensuring content-disposition set to geojson', function(done){
|
it('POST /api/v1/sql with SQL parameter, ensuring content-disposition set to geojson', function(done) {
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
data: querystring.stringify({q: "SELECT * FROM untitle_table_4", format: 'geojson' }),
|
data: querystring.stringify({q: "SELECT * FROM untitle_table_4", format: 'geojson' }),
|
||||||
@ -57,7 +51,7 @@ test('POST /api/v1/sql with SQL parameter and geojson format, ensuring content-d
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('uses the last format parameter when multiple are used', function(done){
|
it('uses the last format parameter when multiple are used', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?format=csv&q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
url: '/api/v1/sql?format=csv&q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -70,7 +64,7 @@ test('uses the last format parameter when multiple are used', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('uses custom filename', function(done){
|
it('uses custom filename', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson&filename=x',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson&filename=x',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -83,7 +77,7 @@ test('uses custom filename', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not include the_geom and the_geom_webmercator properties by default', function(done){
|
it('does not include the_geom and the_geom_webmercator properties by default', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -104,7 +98,7 @@ test('does not include the_geom and the_geom_webmercator properties by default',
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('skipfields controls fields included in GeoJSON output', function(done){
|
it('skipfields controls fields included in GeoJSON output', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson&skipfields=unexistant,cartodb_id',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson&skipfields=unexistant,cartodb_id',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -126,7 +120,7 @@ test('skipfields controls fields included in GeoJSON output', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('GET /api/v1/sql as geojson limiting decimal places', function(done){
|
it('GET /api/v1/sql as geojson limiting decimal places', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: 'SELECT ST_MakePoint(0.123,2.3456) as the_geom',
|
q: 'SELECT ST_MakePoint(0.123,2.3456) as the_geom',
|
||||||
@ -142,7 +136,7 @@ test('GET /api/v1/sql as geojson limiting decimal places', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql as geojson with default dp as 6', function(done){
|
it('GET /api/v1/sql as geojson with default dp as 6', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: 'SELECT ST_MakePoint(0.12345678,2.3456787654) as the_geom',
|
q: 'SELECT ST_MakePoint(0.12345678,2.3456787654) as the_geom',
|
||||||
@ -157,7 +151,7 @@ test('GET /api/v1/sql as geojson with default dp as 6', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('null geometries in geojson output', function(done){
|
it('null geometries in geojson output', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: "SELECT 1 as gid, 'U' as name, null::geometry as the_geom ",
|
q: "SELECT 1 as gid, 'U' as name, null::geometry as the_geom ",
|
||||||
@ -182,7 +176,7 @@ test('null geometries in geojson output', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('stream response handle errors', function(done) {
|
it('stream response handle errors', function(done) {
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: "SELECTT 1 as gid, null::geometry as the_geom ",
|
q: "SELECTT 1 as gid, null::geometry as the_geom ",
|
||||||
@ -191,7 +185,6 @@ test('stream response handle errors', function(done) {
|
|||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
},{ }, function(res){
|
},{ }, function(res){
|
||||||
console.log(res);
|
|
||||||
assert.equal(res.statusCode, 400, res.body);
|
assert.equal(res.statusCode, 400, res.body);
|
||||||
var geoJson = JSON.parse(res.body);
|
var geoJson = JSON.parse(res.body);
|
||||||
assert.ok(geoJson.error);
|
assert.ok(geoJson.error);
|
||||||
@ -201,7 +194,7 @@ test('stream response handle errors', function(done) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('stream response with empty result set has valid output', function(done) {
|
it('stream response with empty result set has valid output', function(done) {
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: "SELECT 1 as gid, null::geometry as the_geom limit 0",
|
q: "SELECT 1 as gid, null::geometry as the_geom limit 0",
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
require('../../helper');
|
require('../../helper');
|
||||||
require('../../support/assert');
|
|
||||||
|
|
||||||
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
var assert = require('../../support/assert');
|
||||||
, assert = require('assert')
|
var querystring = require('querystring');
|
||||||
, querystring = require('querystring')
|
var libxmljs = require('libxmljs');
|
||||||
, _ = require('underscore')
|
var http = require('http');
|
||||||
, zipfile = require('zipfile')
|
var server_utils = require('../../support/server_utils');
|
||||||
, fs = require('fs')
|
|
||||||
, libxmljs = require('libxmljs')
|
|
||||||
, http = require('http')
|
|
||||||
, server_utils = require('../../support/server_utils')
|
|
||||||
;
|
|
||||||
|
|
||||||
// allow lots of emitters to be set to silence warning
|
// allow lots of emitters to be set to silence warning
|
||||||
app.setMaxListeners(0);
|
app.setMaxListeners(0);
|
||||||
|
|
||||||
suite('export.kml', function() {
|
describe('export.kml', function() {
|
||||||
|
|
||||||
// Check if an attribute is in the KML output
|
// Check if an attribute is in the KML output
|
||||||
//
|
//
|
||||||
@ -34,15 +28,21 @@ var hasAttribute = function(kml, att) {
|
|||||||
var xpath;
|
var xpath;
|
||||||
|
|
||||||
xpath = "//SimpleField[@name='" + att + "']";
|
xpath = "//SimpleField[@name='" + att + "']";
|
||||||
if ( doc.get(xpath) ) return true;
|
if ( doc.get(xpath) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
xpath = "//Placemark/" + att;
|
xpath = "//Placemark/" + att;
|
||||||
if ( doc.get(xpath) ) return true;
|
if ( doc.get(xpath) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
var lcatt = att.toLowerCase();
|
var lcatt = att.toLowerCase();
|
||||||
if ( lcatt == 'name' || lcatt == 'description' ) {
|
if ( lcatt === 'name' || lcatt === 'description' ) {
|
||||||
xpath = "//Placemark/" + lcatt;
|
xpath = "//Placemark/" + lcatt;
|
||||||
if ( doc.get(xpath) ) return true;
|
if ( doc.get(xpath) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if ( lowerkml.indexOf('simplefield name="'+ loweratt + '"') != -1 ) return true;
|
//if ( lowerkml.indexOf('simplefield name="'+ loweratt + '"') != -1 ) return true;
|
||||||
@ -59,13 +59,19 @@ var extractCoordinates = function(kml) {
|
|||||||
|
|
||||||
var doc = libxmljs.parseXmlString(kml);
|
var doc = libxmljs.parseXmlString(kml);
|
||||||
//console.log("doc: " + doc);
|
//console.log("doc: " + doc);
|
||||||
if ( ! doc ) return;
|
if ( ! doc ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var coo = doc.get("//coordinates");
|
var coo = doc.get("//coordinates");
|
||||||
//console.log("coo: " + coo);
|
//console.log("coo: " + coo);
|
||||||
if ( ! coo ) return;
|
if ( ! coo ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
coo = coo.text();
|
coo = coo.text();
|
||||||
//console.log("coo: " + coo);
|
//console.log("coo: " + coo);
|
||||||
if ( ! coo ) return;
|
if ( ! coo ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
coo = coo.split(' ');
|
coo = coo.split(' ');
|
||||||
//console.log("coo: " + coo);
|
//console.log("coo: " + coo);
|
||||||
for (var i=0; i<coo.length; ++i) {
|
for (var i=0; i<coo.length; ++i) {
|
||||||
@ -84,19 +90,25 @@ var extractFolderName = function(kml) {
|
|||||||
|
|
||||||
var doc = libxmljs.parseXmlString(kml);
|
var doc = libxmljs.parseXmlString(kml);
|
||||||
//console.log("doc: " + doc);
|
//console.log("doc: " + doc);
|
||||||
if ( ! doc ) return;
|
if ( ! doc ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var coo = doc.get("//Document/Folder/name");
|
var coo = doc.get("//Document/Folder/name");
|
||||||
//console.log("coo: " + coo);
|
//console.log("coo: " + coo);
|
||||||
if ( ! coo ) return;
|
if ( ! coo ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
coo = coo.text();
|
coo = coo.text();
|
||||||
//console.log("coo: " + coo);
|
//console.log("coo: " + coo);
|
||||||
if ( ! coo ) return;
|
if ( ! coo ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
return coo;
|
return coo;
|
||||||
};
|
};
|
||||||
|
|
||||||
// KML tests
|
// KML tests
|
||||||
|
|
||||||
test('KML format, unauthenticated', function(done){
|
it('KML format, unauthenticated', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -119,7 +131,7 @@ test('KML format, unauthenticated', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('KML format, unauthenticated, POST', function(done){
|
it('KML format, unauthenticated, POST', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
data: 'q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml',
|
data: 'q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml',
|
||||||
@ -134,7 +146,7 @@ test('KML format, unauthenticated, POST', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('KML format, bigger than 81920 bytes', function(done){
|
it('KML format, bigger than 81920 bytes', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
data: querystring.stringify({
|
data: querystring.stringify({
|
||||||
@ -153,7 +165,7 @@ test('KML format, bigger than 81920 bytes', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('KML format, skipfields', function(done){
|
it('KML format, skipfields', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml&skipfields=address,cartodb_id',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml&skipfields=address,cartodb_id',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -176,7 +188,7 @@ test('KML format, skipfields', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('KML format, unauthenticated, custom filename', function(done){
|
it('KML format, unauthenticated, custom filename', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml&filename=kmltest',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml&filename=kmltest',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -192,7 +204,7 @@ test('KML format, unauthenticated, custom filename', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('KML format, authenticated', function(done){
|
it('KML format, authenticated', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml&api_key=1234',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml&api_key=1234',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -205,27 +217,18 @@ test('KML format, authenticated', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('KML format, unauthenticated, concurrent requests', function(done){
|
it('KML format, unauthenticated, concurrent requests', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 'val', x, y, st_setsrid(st_makepoint(x,y),4326) as the_geom FROM generate_series(-180, 180) as x, generate_series(-90,90) y",
|
q: "SELECT 'val', x, y, st_setsrid(st_makepoint(x,y),4326) as the_geom " +
|
||||||
|
"FROM generate_series(-180, 180) as x, generate_series(-90,90) y",
|
||||||
format: 'kml',
|
format: 'kml',
|
||||||
filename: 'multi'
|
filename: 'multi'
|
||||||
});
|
});
|
||||||
|
|
||||||
var concurrency = 4;
|
var concurrency = 4;
|
||||||
var waiting = concurrency;
|
var waiting = concurrency;
|
||||||
server_utils.startOnNextPort(app, function() {
|
|
||||||
var port = app.address().port;
|
function onResponse(res) {
|
||||||
//console.log("Listening on port " + port);
|
|
||||||
for (var i=0; i<concurrency; ++i) {
|
|
||||||
//console.log("Sending request");
|
|
||||||
http.request({
|
|
||||||
host: 'localhost',
|
|
||||||
port: port,
|
|
||||||
path: '/api/v1/sql?' + query,
|
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
|
||||||
agent: false // or should this be true ?
|
|
||||||
}).on('response', function(res) {
|
|
||||||
//console.log("Response started");
|
//console.log("Response started");
|
||||||
res.body = '';
|
res.body = '';
|
||||||
//res.setEncoding('binary');
|
//res.setEncoding('binary');
|
||||||
@ -244,15 +247,33 @@ test('KML format, unauthenticated, concurrent requests', function(done){
|
|||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).on('error', function(err) {
|
}
|
||||||
|
|
||||||
|
function onError(err) {
|
||||||
console.log("Response error" + err);
|
console.log("Response error" + err);
|
||||||
}).end();
|
}
|
||||||
|
|
||||||
|
server_utils.startOnNextPort(app, function() {
|
||||||
|
var port = app.address().port;
|
||||||
|
//console.log("Listening on port " + port);
|
||||||
|
for (var i=0; i<concurrency; ++i) {
|
||||||
|
//console.log("Sending request");
|
||||||
|
http.request({
|
||||||
|
host: 'localhost',
|
||||||
|
port: port,
|
||||||
|
path: '/api/v1/sql?' + query,
|
||||||
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
|
agent: false // or should this be true ?
|
||||||
|
})
|
||||||
|
.on('response', onResponse)
|
||||||
|
.on('error', onError)
|
||||||
|
.end();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/60
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/60
|
||||||
test('GET /api/v1/sql as kml with no rows', function(done){
|
it('GET /api/v1/sql as kml with no rows', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20true%20WHERE%20false&format=kml',
|
url: '/api/v1/sql?q=SELECT%20true%20WHERE%20false&format=kml',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -260,7 +281,10 @@ test('GET /api/v1/sql as kml with no rows', function(done){
|
|||||||
},{ }, function(res){
|
},{ }, function(res){
|
||||||
assert.equal(res.statusCode, 200, res.body);
|
assert.equal(res.statusCode, 200, res.body);
|
||||||
// NOTE: GDAL-1.11+ added 'id="root_doc"' attribute to the output
|
// NOTE: GDAL-1.11+ added 'id="root_doc"' attribute to the output
|
||||||
var pat = new RegExp('^<\\?xml version="1.0" encoding="utf-8" \\?><kml xmlns="http://www.opengis.net/kml/2.2"><Document( id="root_doc")?><Folder><name>cartodb_query</name></Folder></Document></kml>$');
|
var pat = new RegExp('^<\\?xml version="1.0" encoding="utf-8" \\?>' +
|
||||||
|
'<kml xmlns="http://www.opengis.net/kml/2.2">' +
|
||||||
|
'<Document( id="root_doc")?><Folder><name>cartodb_query</name></Folder></Document>' +
|
||||||
|
'</kml>$');
|
||||||
var body = res.body.replace(/\n/g,'');
|
var body = res.body.replace(/\n/g,'');
|
||||||
assert.ok(body.match(pat),
|
assert.ok(body.match(pat),
|
||||||
"Response:\n" + body + '\ndoes not match pattern:\n' + pat);
|
"Response:\n" + body + '\ndoes not match pattern:\n' + pat);
|
||||||
@ -269,7 +293,7 @@ test('GET /api/v1/sql as kml with no rows', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/90
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/90
|
||||||
test('GET /api/v1/sql as kml with ending semicolon', function(done){
|
it('GET /api/v1/sql as kml with ending semicolon', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: 'SELECT true WHERE false;',
|
q: 'SELECT true WHERE false;',
|
||||||
@ -280,7 +304,10 @@ test('GET /api/v1/sql as kml with ending semicolon', function(done){
|
|||||||
},{ }, function(res){
|
},{ }, function(res){
|
||||||
assert.equal(res.statusCode, 200, res.body);
|
assert.equal(res.statusCode, 200, res.body);
|
||||||
// NOTE: GDAL-1.11+ added 'id="root_doc"' attribute to the output
|
// NOTE: GDAL-1.11+ added 'id="root_doc"' attribute to the output
|
||||||
var pat = new RegExp('^<\\?xml version="1.0" encoding="utf-8" \\?><kml xmlns="http://www.opengis.net/kml/2.2"><Document( id="root_doc")?><Folder><name>cartodb_query</name></Folder></Document></kml>$');
|
var pat = new RegExp('^<\\?xml version="1.0" encoding="utf-8" \\?>' +
|
||||||
|
'<kml xmlns="http://www.opengis.net/kml/2.2">' +
|
||||||
|
'<Document( id="root_doc")?><Folder><name>cartodb_query</name></Folder></Document>' +
|
||||||
|
'</kml>$');
|
||||||
var body = res.body.replace(/\n/g,'');
|
var body = res.body.replace(/\n/g,'');
|
||||||
assert.ok(body.match(pat),
|
assert.ok(body.match(pat),
|
||||||
"Response:\n" + body + '\ndoes not match pattern:\n' + pat);
|
"Response:\n" + body + '\ndoes not match pattern:\n' + pat);
|
||||||
@ -289,7 +316,7 @@ test('GET /api/v1/sql as kml with ending semicolon', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/CartoDB/cartodb/issues/276
|
// See https://github.com/CartoDB/cartodb/issues/276
|
||||||
test('check point coordinates, unauthenticated', function(done){
|
it('check point coordinates, unauthenticated', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: 'SELECT * from untitle_table_4 WHERE cartodb_id = -1',
|
q: 'SELECT * from untitle_table_4 WHERE cartodb_id = -1',
|
||||||
@ -307,7 +334,7 @@ test('check point coordinates, unauthenticated', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/CartoDB/cartodb/issues/276
|
// See https://github.com/CartoDB/cartodb/issues/276
|
||||||
test('check point coordinates, authenticated', function(done){
|
it('check point coordinates, authenticated', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?' + querystring.stringify({
|
url: '/api/v1/sql?' + querystring.stringify({
|
||||||
q: 'SELECT * from untitle_table_4 WHERE cartodb_id = -1',
|
q: 'SELECT * from untitle_table_4 WHERE cartodb_id = -1',
|
||||||
@ -325,7 +352,7 @@ test('check point coordinates, authenticated', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('expects 1000 placemarks in public table', function(done){
|
it('expects 1000 placemarks in public table', function(done){
|
||||||
var numberOfRowsInPublicTable = 6,
|
var numberOfRowsInPublicTable = 6,
|
||||||
seriesLimit = 200,
|
seriesLimit = 200,
|
||||||
expectedRows = numberOfRowsInPublicTable * seriesLimit;
|
expectedRows = numberOfRowsInPublicTable * seriesLimit;
|
||||||
@ -349,7 +376,7 @@ test('check point coordinates, authenticated', function(done){
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('expects 1000 placemarks in private table using the API KEY', function(done){
|
it('expects 1000 placemarks in private table using the API KEY', function(done){
|
||||||
var numberOfRowsInPrivateTable = 5,
|
var numberOfRowsInPrivateTable = 5,
|
||||||
seriesLimit = 200,
|
seriesLimit = 200,
|
||||||
expectedRows = numberOfRowsInPrivateTable * seriesLimit;
|
expectedRows = numberOfRowsInPrivateTable * seriesLimit;
|
||||||
|
@ -1,24 +1,20 @@
|
|||||||
require('../../helper');
|
require('../../helper');
|
||||||
require('../../support/assert');
|
|
||||||
|
|
||||||
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
var assert = require('../../support/assert');
|
||||||
, assert = require('assert')
|
var querystring = require('querystring');
|
||||||
, querystring = require('querystring')
|
var _ = require('underscore');
|
||||||
, _ = require('underscore')
|
var zipfile = require('zipfile');
|
||||||
, zipfile = require('zipfile')
|
var fs = require('fs');
|
||||||
, fs = require('fs')
|
|
||||||
, libxmljs = require('libxmljs')
|
|
||||||
;
|
|
||||||
|
|
||||||
// allow lots of emitters to be set to silence warning
|
// allow lots of emitters to be set to silence warning
|
||||||
app.setMaxListeners(0);
|
app.setMaxListeners(0);
|
||||||
|
|
||||||
suite('export.shapefile', function() {
|
describe('export.shapefile', function() {
|
||||||
|
|
||||||
// SHP tests
|
// SHP tests
|
||||||
|
|
||||||
test('SHP format, unauthenticated', function(done){
|
it('SHP format, unauthenticated', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -31,7 +27,9 @@ test('SHP format, unauthenticated', function(done){
|
|||||||
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
||||||
var tmpfile = '/tmp/myshape.zip';
|
var tmpfile = '/tmp/myshape.zip';
|
||||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||||
if (err) { done(err); return }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var zf = new zipfile.ZipFile(tmpfile);
|
var zf = new zipfile.ZipFile(tmpfile);
|
||||||
assert.ok(_.contains(zf.names, 'cartodb-query.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'cartodb-query.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
||||||
assert.ok(_.contains(zf.names, 'cartodb-query.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'cartodb-query.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
||||||
@ -43,7 +41,7 @@ test('SHP format, unauthenticated', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('SHP format, unauthenticated, POST', function(done){
|
it('SHP format, unauthenticated, POST', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
data: 'q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp',
|
data: 'q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp',
|
||||||
@ -58,7 +56,7 @@ test('SHP format, unauthenticated, POST', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('SHP format, big size, POST', function(done){
|
it('SHP format, big size, POST', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
data: querystring.stringify({
|
data: querystring.stringify({
|
||||||
@ -77,7 +75,7 @@ test('SHP format, big size, POST', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('SHP format, unauthenticated, with custom filename', function(done){
|
it('SHP format, unauthenticated, with custom filename', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp&filename=myshape',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp&filename=myshape',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -90,7 +88,9 @@ test('SHP format, unauthenticated, with custom filename', function(done){
|
|||||||
assert.equal(true, /filename=myshape.zip/gi.test(cd));
|
assert.equal(true, /filename=myshape.zip/gi.test(cd));
|
||||||
var tmpfile = '/tmp/myshape.zip';
|
var tmpfile = '/tmp/myshape.zip';
|
||||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||||
if (err) { done(err); return }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var zf = new zipfile.ZipFile(tmpfile);
|
var zf = new zipfile.ZipFile(tmpfile);
|
||||||
assert.ok(_.contains(zf.names, 'myshape.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'myshape.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
||||||
assert.ok(_.contains(zf.names, 'myshape.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'myshape.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
||||||
@ -101,7 +101,7 @@ test('SHP format, unauthenticated, with custom filename', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('SHP format, unauthenticated, with custom, dangerous filename', function(done){
|
it('SHP format, unauthenticated, with custom, dangerous filename', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp&filename=b;"%20()[]a',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp&filename=b;"%20()[]a',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -115,7 +115,9 @@ test('SHP format, unauthenticated, with custom, dangerous filename', function(do
|
|||||||
assert.equal(true, /filename=b_______a.zip/gi.test(cd), 'Unexpected SHP filename: ' + cd);
|
assert.equal(true, /filename=b_______a.zip/gi.test(cd), 'Unexpected SHP filename: ' + cd);
|
||||||
var tmpfile = '/tmp/myshape.zip';
|
var tmpfile = '/tmp/myshape.zip';
|
||||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||||
if (err) { done(err); return }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var zf = new zipfile.ZipFile(tmpfile);
|
var zf = new zipfile.ZipFile(tmpfile);
|
||||||
assert.ok(_.contains(zf.names, fname + '.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
assert.ok(_.contains(zf.names, fname + '.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
||||||
assert.ok(_.contains(zf.names, fname + '.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
assert.ok(_.contains(zf.names, fname + '.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
||||||
@ -126,7 +128,7 @@ test('SHP format, unauthenticated, with custom, dangerous filename', function(do
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('SHP format, authenticated', function(done){
|
it('SHP format, authenticated', function(done){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp&api_key=1234',
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp&api_key=1234',
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
@ -138,7 +140,9 @@ test('SHP format, authenticated', function(done){
|
|||||||
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
||||||
var tmpfile = '/tmp/myshape.zip';
|
var tmpfile = '/tmp/myshape.zip';
|
||||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||||
if (err) { done(err); return }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var zf = new zipfile.ZipFile(tmpfile);
|
var zf = new zipfile.ZipFile(tmpfile);
|
||||||
assert.ok(_.contains(zf.names, 'cartodb-query.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'cartodb-query.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
||||||
assert.ok(_.contains(zf.names, 'cartodb-query.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'cartodb-query.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
||||||
@ -152,7 +156,7 @@ test('SHP format, authenticated', function(done){
|
|||||||
|
|
||||||
|
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/66
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/66
|
||||||
test('SHP format, unauthenticated, with utf8 data', function(done){
|
it('SHP format, unauthenticated, with utf8 data', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT '♥♦♣♠' as f, st_makepoint(0,0,4326) as the_geom",
|
q: "SELECT '♥♦♣♠' as f, st_makepoint(0,0,4326) as the_geom",
|
||||||
format: 'shp',
|
format: 'shp',
|
||||||
@ -167,7 +171,9 @@ test('SHP format, unauthenticated, with utf8 data', function(done){
|
|||||||
assert.equal(res.statusCode, 200, res.body);
|
assert.equal(res.statusCode, 200, res.body);
|
||||||
var tmpfile = '/tmp/myshape.zip';
|
var tmpfile = '/tmp/myshape.zip';
|
||||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||||
if (err) { done(err); return }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var zf = new zipfile.ZipFile(tmpfile);
|
var zf = new zipfile.ZipFile(tmpfile);
|
||||||
var buffer = zf.readFileSync('myshape.dbf');
|
var buffer = zf.readFileSync('myshape.dbf');
|
||||||
fs.unlinkSync(tmpfile);
|
fs.unlinkSync(tmpfile);
|
||||||
@ -178,10 +184,9 @@ test('SHP format, unauthenticated, with utf8 data', function(done){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/66
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/66
|
||||||
test('mixed type geometry', function(done){
|
it('mixed type geometry', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 'POINT(0 0)'::geometry as g UNION ALL "
|
q: "SELECT 'POINT(0 0)'::geometry as g UNION ALL SELECT 'LINESTRING(0 0, 1 0)'::geometry",
|
||||||
+ "SELECT 'LINESTRING(0 0, 1 0)'::geometry",
|
|
||||||
format: 'shp'
|
format: 'shp'
|
||||||
});
|
});
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -194,19 +199,19 @@ test('mixed type geometry', function(done){
|
|||||||
assert.deepEqual(res.headers['content-disposition'], 'inline');
|
assert.deepEqual(res.headers['content-disposition'], 'inline');
|
||||||
assert.equal(res.statusCode, 400, res.statusCode + ': ' +res.body);
|
assert.equal(res.statusCode, 400, res.statusCode + ': ' +res.body);
|
||||||
var parsedBody = JSON.parse(res.body);
|
var parsedBody = JSON.parse(res.body);
|
||||||
var expectedBody = {"error":["ERROR 1: Attempt to write non-point (LINESTRING) geometry to point shapefile."]}
|
var expectedBody = {"error":["ERROR 1: Attempt to write non-point (LINESTRING) geometry to point shapefile."]};
|
||||||
assert.deepEqual(parsedBody, expectedBody);
|
assert.deepEqual(parsedBody, expectedBody);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/87
|
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/87
|
||||||
test('errors are not confused with warnings', function(done){
|
it('errors are not confused with warnings', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 'POINT(0 0)'::geometry as g"
|
q: [
|
||||||
+ ", 1 as a_very_very_very_long_field_name"
|
"SELECT 'POINT(0 0)'::geometry as g, 1 as a_very_very_very_long_field_name",
|
||||||
+ " UNION ALL "
|
"SELECT 'LINESTRING(0 0, 1 0)'::geometry, 2"
|
||||||
+ "SELECT 'LINESTRING(0 0, 1 0)'::geometry, 2",
|
].join(" UNION ALL "),
|
||||||
format: 'shp'
|
format: 'shp'
|
||||||
});
|
});
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -219,13 +224,13 @@ test('errors are not confused with warnings', function(done){
|
|||||||
assert.deepEqual(res.headers['content-disposition'], 'inline');
|
assert.deepEqual(res.headers['content-disposition'], 'inline');
|
||||||
assert.equal(res.statusCode, 400, res.statusCode + ': ' +res.body);
|
assert.equal(res.statusCode, 400, res.statusCode + ': ' +res.body);
|
||||||
var parsedBody = JSON.parse(res.body);
|
var parsedBody = JSON.parse(res.body);
|
||||||
var expectedBody = {"error":["ERROR 1: Attempt to write non-point (LINESTRING) geometry to point shapefile."]}
|
var expectedBody = {"error":["ERROR 1: Attempt to write non-point (LINESTRING) geometry to point shapefile."]};
|
||||||
assert.deepEqual(parsedBody, expectedBody);
|
assert.deepEqual(parsedBody, expectedBody);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('skipfields controls fields included in SHP output', function(done){
|
it('skipfields controls fields included in SHP output', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 111 as skipme, 222 as keepme, 'POINT(0 0)'::geometry as g",
|
q: "SELECT 111 as skipme, 222 as keepme, 'POINT(0 0)'::geometry as g",
|
||||||
format: 'shp',
|
format: 'shp',
|
||||||
@ -241,7 +246,9 @@ test('skipfields controls fields included in SHP output', function(done){
|
|||||||
assert.equal(res.statusCode, 200, res.body);
|
assert.equal(res.statusCode, 200, res.body);
|
||||||
var tmpfile = '/tmp/myshape.zip';
|
var tmpfile = '/tmp/myshape.zip';
|
||||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||||
if (err) { done(err); return }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var zf = new zipfile.ZipFile(tmpfile);
|
var zf = new zipfile.ZipFile(tmpfile);
|
||||||
var buffer = zf.readFileSync('myshape.dbf');
|
var buffer = zf.readFileSync('myshape.dbf');
|
||||||
fs.unlinkSync(tmpfile);
|
fs.unlinkSync(tmpfile);
|
||||||
@ -251,23 +258,18 @@ test('skipfields controls fields included in SHP output', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('SHP format, concurrently', function(done){
|
it('SHP format, concurrently', function(done){
|
||||||
var concurrency = 1;
|
var concurrency = 1;
|
||||||
var waiting = concurrency;
|
var waiting = concurrency;
|
||||||
for (var i=0; i<concurrency; ++i) {
|
function validate(res){
|
||||||
assert.response(app, {
|
|
||||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp',
|
|
||||||
headers: {host: 'vizzuality.cartodb.com'},
|
|
||||||
encoding: 'binary',
|
|
||||||
method: 'GET'
|
|
||||||
},{ }, function(res){
|
|
||||||
assert.equal(res.statusCode, 200, res.body);
|
|
||||||
var cd = res.header('Content-Disposition');
|
var cd = res.header('Content-Disposition');
|
||||||
assert.equal(true, /^attachment/.test(cd), 'SHP is not disposed as attachment: ' + cd);
|
assert.equal(true, /^attachment/.test(cd), 'SHP is not disposed as attachment: ' + cd);
|
||||||
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
||||||
var tmpfile = '/tmp/myshape.zip';
|
var tmpfile = '/tmp/myshape.zip';
|
||||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||||
if (err) { done(err); return }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var zf = new zipfile.ZipFile(tmpfile);
|
var zf = new zipfile.ZipFile(tmpfile);
|
||||||
assert.ok(_.contains(zf.names, 'cartodb-query.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'cartodb-query.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
||||||
assert.ok(_.contains(zf.names, 'cartodb-query.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'cartodb-query.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
||||||
@ -275,13 +277,29 @@ test('SHP format, concurrently', function(done){
|
|||||||
assert.ok(_.contains(zf.names, 'cartodb-query.prj'), 'SHP zipfile does not contain .prj: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'cartodb-query.prj'), 'SHP zipfile does not contain .prj: ' + zf.names);
|
||||||
// TODO: check DBF contents
|
// TODO: check DBF contents
|
||||||
fs.unlinkSync(tmpfile);
|
fs.unlinkSync(tmpfile);
|
||||||
if ( ! --waiting ) done();
|
if ( ! --waiting ) {
|
||||||
});
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i=0; i<concurrency; ++i) {
|
||||||
|
assert.response(
|
||||||
|
app,
|
||||||
|
{
|
||||||
|
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp',
|
||||||
|
headers: {host: 'vizzuality.cartodb.com'},
|
||||||
|
encoding: 'binary',
|
||||||
|
method: 'GET'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 200
|
||||||
|
},
|
||||||
|
validate
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/111
|
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/111
|
||||||
test('point with null first', function(done){
|
it('point with null first', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT null::geometry as g UNION ALL SELECT 'SRID=4326;POINT(0 0)'::geometry",
|
q: "SELECT null::geometry as g UNION ALL SELECT 'SRID=4326;POINT(0 0)'::geometry",
|
||||||
format: 'shp'
|
format: 'shp'
|
||||||
@ -297,7 +315,9 @@ test('point with null first', function(done){
|
|||||||
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
||||||
var tmpfile = '/tmp/myshape.zip';
|
var tmpfile = '/tmp/myshape.zip';
|
||||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||||
if (err) { done(err); return }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
var zf = new zipfile.ZipFile(tmpfile);
|
var zf = new zipfile.ZipFile(tmpfile);
|
||||||
assert.ok(_.contains(zf.names, 'cartodb-query.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'cartodb-query.shp'), 'SHP zipfile does not contain .shp: ' + zf.names);
|
||||||
assert.ok(_.contains(zf.names, 'cartodb-query.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
assert.ok(_.contains(zf.names, 'cartodb-query.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
||||||
|
@ -1,22 +1,15 @@
|
|||||||
require('../../helper');
|
require('../../helper');
|
||||||
require('../../support/assert');
|
|
||||||
|
|
||||||
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
var assert = require('../../support/assert');
|
||||||
, assert = require('assert')
|
var querystring = require('querystring');
|
||||||
, querystring = require('querystring')
|
|
||||||
, _ = require('underscore')
|
|
||||||
, zipfile = require('zipfile')
|
|
||||||
, fs = require('fs')
|
|
||||||
, libxmljs = require('libxmljs')
|
|
||||||
;
|
|
||||||
|
|
||||||
// allow lots of emitters to be set to silence warning
|
// allow lots of emitters to be set to silence warning
|
||||||
app.setMaxListeners(0);
|
app.setMaxListeners(0);
|
||||||
|
|
||||||
suite('export.svg', function() {
|
describe('export.svg', function() {
|
||||||
|
|
||||||
test('GET /api/v1/sql with SVG format', function(done){
|
it('GET /api/v1/sql with SVG format', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 1 as cartodb_id, ST_MakeLine(ST_MakePoint(10, 10), ST_MakePoint(1034, 778)) AS the_geom ",
|
q: "SELECT 1 as cartodb_id, ST_MakeLine(ST_MakePoint(10, 10), ST_MakePoint(1034, 778)) AS the_geom ",
|
||||||
format: "svg"
|
format: "svg"
|
||||||
@ -36,7 +29,7 @@ test('GET /api/v1/sql with SVG format', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /api/v1/sql with SVG format', function(done){
|
it('POST /api/v1/sql with SVG format', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 1 as cartodb_id, ST_MakeLine(ST_MakePoint(10, 10), ST_MakePoint(1034, 778)) AS the_geom ",
|
q: "SELECT 1 as cartodb_id, ST_MakeLine(ST_MakePoint(10, 10), ST_MakePoint(1034, 778)) AS the_geom ",
|
||||||
format: "svg"
|
format: "svg"
|
||||||
@ -58,7 +51,7 @@ test('POST /api/v1/sql with SVG format', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with SVG format and custom filename', function(done){
|
it('GET /api/v1/sql with SVG format and custom filename', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 1 as cartodb_id, ST_MakeLine(ST_MakePoint(10, 10), ST_MakePoint(1034, 778)) AS the_geom ",
|
q: "SELECT 1 as cartodb_id, ST_MakeLine(ST_MakePoint(10, 10), ST_MakePoint(1034, 778)) AS the_geom ",
|
||||||
format: "svg",
|
format: "svg",
|
||||||
@ -79,7 +72,7 @@ test('GET /api/v1/sql with SVG format and custom filename', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with SVG format and centered point', function(done){
|
it('GET /api/v1/sql with SVG format and centered point', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 1 as cartodb_id, ST_MakePoint(5000, -54) AS the_geom ",
|
q: "SELECT 1 as cartodb_id, ST_MakePoint(5000, -54) AS the_geom ",
|
||||||
format: "svg"
|
format: "svg"
|
||||||
@ -100,7 +93,7 @@ test('GET /api/v1/sql with SVG format and centered point', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/v1/sql with SVG format and trimmed decimals', function(done){
|
it('GET /api/v1/sql with SVG format and trimmed decimals', function(done){
|
||||||
var queryobj = {
|
var queryobj = {
|
||||||
q: "SELECT 1 as cartodb_id, 'LINESTRING(0 0, 1024 768, 500.123456 600.98765432)'::geometry AS the_geom ",
|
q: "SELECT 1 as cartodb_id, 'LINESTRING(0 0, 1024 768, 500.123456 600.98765432)'::geometry AS the_geom ",
|
||||||
format: "svg",
|
format: "svg",
|
||||||
@ -138,7 +131,7 @@ test('GET /api/v1/sql with SVG format and trimmed decimals', function(done){
|
|||||||
|
|
||||||
// Test adding "the_geom" to skipfields
|
// Test adding "the_geom" to skipfields
|
||||||
// See http://github.com/Vizzuality/CartoDB-SQL-API/issues/73
|
// See http://github.com/Vizzuality/CartoDB-SQL-API/issues/73
|
||||||
test('SVG format with "the_geom" in skipfields', function(done){
|
it('SVG format with "the_geom" in skipfields', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 1 as cartodb_id, ST_MakePoint(5000, -54) AS the_geom ",
|
q: "SELECT 1 as cartodb_id, ST_MakePoint(5000, -54) AS the_geom ",
|
||||||
format: "svg",
|
format: "svg",
|
||||||
@ -159,7 +152,7 @@ test('SVG format with "the_geom" in skipfields', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('SVG format with missing "the_geom" field', function(done){
|
it('SVG format with missing "the_geom" field', function(done){
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT 1 as cartodb_id, ST_MakePoint(5000, -54) AS something_else ",
|
q: "SELECT 1 as cartodb_id, ST_MakePoint(5000, -54) AS something_else ",
|
||||||
format: "svg"
|
format: "svg"
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
require('../../helper');
|
require('../../helper');
|
||||||
require('../../support/assert');
|
|
||||||
|
|
||||||
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
var assert = require('../../support/assert');
|
||||||
, assert = require('assert')
|
var querystring = require('querystring');
|
||||||
, querystring = require('querystring')
|
var _ = require('underscore');
|
||||||
, _ = require('underscore')
|
|
||||||
, zipfile = require('zipfile')
|
|
||||||
, fs = require('fs')
|
|
||||||
, libxmljs = require('libxmljs')
|
|
||||||
;
|
|
||||||
|
|
||||||
// allow lots of emitters to be set to silence warning
|
// allow lots of emitters to be set to silence warning
|
||||||
app.setMaxListeners(0);
|
app.setMaxListeners(0);
|
||||||
|
|
||||||
|
|
||||||
suite('export.topojson', function() {
|
describe('export.topojson', function() {
|
||||||
|
|
||||||
// TOPOJSON tests
|
// TOPOJSON tests
|
||||||
|
|
||||||
@ -34,7 +28,7 @@ suite('export.topojson', function() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test('GET two polygons sharing an edge as topojson', function(done){
|
it('GET two polygons sharing an edge as topojson', function(done){
|
||||||
assert.response(app,
|
assert.response(app,
|
||||||
getRequest(
|
getRequest(
|
||||||
"SELECT 1 as gid, 'U' as name, 'POLYGON((-5 0,5 0,0 5,-5 0))'::geometry as the_geom " +
|
"SELECT 1 as gid, 'U' as name, 'POLYGON((-5 0,5 0,0 5,-5 0))'::geometry as the_geom " +
|
||||||
@ -81,8 +75,8 @@ test('GET two polygons sharing an edge as topojson', function(done){
|
|||||||
assert.equal(shell[1], 1); /* non-shared arc */
|
assert.equal(shell[1], 1); /* non-shared arc */
|
||||||
var props = obj.properties;
|
var props = obj.properties;
|
||||||
assert.equal(_.keys(props).length, 2); // gid, name
|
assert.equal(_.keys(props).length, 2); // gid, name
|
||||||
assert.equal(props['gid'], 1);
|
assert.equal(props.gid, 1);
|
||||||
assert.equal(props['name'], 'U');
|
assert.equal(props.name, 'U');
|
||||||
|
|
||||||
obj = topojson.objects[1];
|
obj = topojson.objects[1];
|
||||||
//console.dir(obj);
|
//console.dir(obj);
|
||||||
@ -99,8 +93,8 @@ test('GET two polygons sharing an edge as topojson', function(done){
|
|||||||
assert.equal(shell[1], 2); /* non-shared arc */
|
assert.equal(shell[1], 2); /* non-shared arc */
|
||||||
props = obj.properties;
|
props = obj.properties;
|
||||||
assert.equal(_.keys(props).length, 2); // gid, name
|
assert.equal(_.keys(props).length, 2); // gid, name
|
||||||
assert.equal(props['gid'], 2);
|
assert.equal(props.gid, 2);
|
||||||
assert.equal(props['name'], 'D');
|
assert.equal(props.name, 'D');
|
||||||
|
|
||||||
// Check arcs
|
// Check arcs
|
||||||
assert.ok(topojson.hasOwnProperty('arcs'));
|
assert.ok(topojson.hasOwnProperty('arcs'));
|
||||||
@ -140,7 +134,7 @@ test('GET two polygons sharing an edge as topojson', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('null geometries', function(done){
|
it('null geometries', function(done){
|
||||||
assert.response(app, getRequest(
|
assert.response(app, getRequest(
|
||||||
"SELECT 1 as gid, 'U' as name, 'POLYGON((-5 0,5 0,0 5,-5 0))'::geometry as the_geom " +
|
"SELECT 1 as gid, 'U' as name, 'POLYGON((-5 0,5 0,0 5,-5 0))'::geometry as the_geom " +
|
||||||
" UNION ALL " +
|
" UNION ALL " +
|
||||||
@ -185,8 +179,8 @@ test('null geometries', function(done){
|
|||||||
assert.equal(shell[0], 0); /* non-shared arc */
|
assert.equal(shell[0], 0); /* non-shared arc */
|
||||||
var props = obj.properties;
|
var props = obj.properties;
|
||||||
assert.equal(_.keys(props).length, 2); // gid, name
|
assert.equal(_.keys(props).length, 2); // gid, name
|
||||||
assert.equal(props['gid'], 1);
|
assert.equal(props.gid, 1);
|
||||||
assert.equal(props['name'], 'U');
|
assert.equal(props.name, 'U');
|
||||||
|
|
||||||
// Check arcs
|
// Check arcs
|
||||||
assert.ok(topojson.hasOwnProperty('arcs'));
|
assert.ok(topojson.hasOwnProperty('arcs'));
|
||||||
@ -198,7 +192,7 @@ test('null geometries', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('skipped fields are not returned', function(done) {
|
it('skipped fields are not returned', function(done) {
|
||||||
assert.response(app,
|
assert.response(app,
|
||||||
getRequest(
|
getRequest(
|
||||||
"SELECT 1 as gid, 'U' as name, 'POLYGON((-5 0,5 0,0 5,-5 0))'::geometry as the_geom",
|
"SELECT 1 as gid, 'U' as name, 'POLYGON((-5 0,5 0,0 5,-5 0))'::geometry as the_geom",
|
||||||
@ -218,7 +212,7 @@ test('null geometries', function(done){
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('jsonp callback is invoked', function(done){
|
it('jsonp callback is invoked', function(done){
|
||||||
assert.response(
|
assert.response(
|
||||||
app,
|
app,
|
||||||
getRequest(
|
getRequest(
|
||||||
@ -233,10 +227,12 @@ test('null geometries', function(done){
|
|||||||
function(res) {
|
function(res) {
|
||||||
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
||||||
var didRunJsonCallback = false;
|
var didRunJsonCallback = false;
|
||||||
|
// jshint ignore:start
|
||||||
function foo_jsonp(body) {
|
function foo_jsonp(body) {
|
||||||
didRunJsonCallback = true;
|
didRunJsonCallback = true;
|
||||||
}
|
}
|
||||||
eval(res.body);
|
eval(res.body);
|
||||||
|
// jshint ignore:end
|
||||||
assert.ok(didRunJsonCallback);
|
assert.ok(didRunJsonCallback);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
require('../helper');
|
require('../helper');
|
||||||
require('../support/assert');
|
|
||||||
|
|
||||||
var assert = require('assert')
|
var assert = require('../support/assert');
|
||||||
, App = require(global.settings.app_root + '/app/controllers/app')
|
var step = require('step');
|
||||||
, querystring = require('querystring')
|
var net = require('net');
|
||||||
, _ = require('underscore')
|
|
||||||
, Step = require('step')
|
|
||||||
, net = require('net')
|
|
||||||
, http = require('http')
|
|
||||||
;
|
|
||||||
|
|
||||||
var sql_server_data_handler;
|
var sql_server_data_handler;
|
||||||
var sql_server_port = 5556;
|
var sql_server_port = 5556;
|
||||||
@ -23,22 +17,22 @@ var sql_server = net.createServer(function(c) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('frontend abort', function() {
|
describe('frontend abort', function() {
|
||||||
|
|
||||||
suiteSetup(function(done){
|
before(function(done){
|
||||||
sql_server.listen(sql_server_port, done);
|
sql_server.listen(sql_server_port, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/129
|
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/129
|
||||||
test('aborts request', function(done){
|
it('aborts request', function(done){
|
||||||
//console.log("settings:"); console.dir(global.settings);
|
//console.log("settings:"); console.dir(global.settings);
|
||||||
var db_host_backup = global.settings.db_host;
|
var db_host_backup = global.settings.db_host;
|
||||||
var db_port_backup = global.settings.db_port;
|
var db_port_backup = global.settings.db_port;
|
||||||
global.settings.db_host = 'localhost';
|
global.settings.db_host = 'localhost';
|
||||||
global.settings.db_port = sql_server_port;
|
global.settings.db_port = sql_server_port;
|
||||||
var app = App();
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
var timeout;
|
var timeout;
|
||||||
Step(
|
step(
|
||||||
function sendQuery() {
|
function sendQuery() {
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -50,7 +44,7 @@ test('aborts request', function(done){
|
|||||||
next(err, res);
|
next(err, res);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function checkResponse(err, res) {
|
function checkResponse(err/*, res*/) {
|
||||||
assert(err); // expect timeout
|
assert(err); // expect timeout
|
||||||
assert.ok((''+err).match(/socket/), err);
|
assert.ok((''+err).match(/socket/), err);
|
||||||
sql_server_data_handler = this;
|
sql_server_data_handler = this;
|
||||||
@ -74,7 +68,7 @@ test('aborts request', function(done){
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
suiteTeardown(function(done) {
|
after(function(done) {
|
||||||
try {
|
try {
|
||||||
sql_server.close(done);
|
sql_server.close(done);
|
||||||
} catch (er) {
|
} catch (er) {
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
require('../helper');
|
require('../helper');
|
||||||
require('../support/assert');
|
require('../support/assert');
|
||||||
|
|
||||||
var assert = require('assert'),
|
var assert = require('assert');
|
||||||
App = require(global.settings.app_root + '/app/controllers/app');
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
|
|
||||||
var app = App();
|
describe('health checks', function() {
|
||||||
|
|
||||||
suite('health checks', function() {
|
|
||||||
|
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
global.settings.health = {
|
global.settings.health = {
|
||||||
@ -25,7 +23,7 @@ suite('health checks', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
test('returns 200 and ok=true with disabled configuration', function(done) {
|
it('returns 200 and ok=true with disabled configuration', function(done) {
|
||||||
global.settings.health.enabled = false;
|
global.settings.health.enabled = false;
|
||||||
|
|
||||||
assert.response(app,
|
assert.response(app,
|
||||||
@ -46,7 +44,7 @@ suite('health checks', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns 200 and ok=true with enabled configuration', function(done) {
|
it('returns 200 and ok=true with enabled configuration', function(done) {
|
||||||
assert.response(app,
|
assert.response(app,
|
||||||
healthCheckRequest,
|
healthCheckRequest,
|
||||||
{
|
{
|
||||||
|
@ -13,25 +13,21 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
require('../helper');
|
require('../helper');
|
||||||
require('../support/assert');
|
|
||||||
|
|
||||||
var assert = require('assert')
|
|
||||||
, App = require(global.settings.app_root + '/app/controllers/app')
|
|
||||||
, querystring = require('querystring')
|
|
||||||
, _ = require('underscore')
|
|
||||||
, Step = require('step')
|
|
||||||
;
|
|
||||||
|
|
||||||
suite('timeout', function() {
|
var assert = require('../support/assert');
|
||||||
|
var step = require('step');
|
||||||
|
|
||||||
|
describe('timeout', function() {
|
||||||
|
|
||||||
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/128
|
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/128
|
||||||
test('after configured milliseconds', function(done){
|
it('after configured milliseconds', function(done){
|
||||||
var testTimeout = 10;
|
var testTimeout = 10;
|
||||||
//console.log("settings:"); console.dir(global.settings);
|
//console.log("settings:"); console.dir(global.settings);
|
||||||
var timeoutBackup = global.settings.node_socket_timeout;
|
var timeoutBackup = global.settings.node_socket_timeout;
|
||||||
global.settings.node_socket_timeout = testTimeout;
|
global.settings.node_socket_timeout = testTimeout;
|
||||||
var app = App();
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
Step(
|
step(
|
||||||
function sendLongQuery() {
|
function sendLongQuery() {
|
||||||
var next = this;
|
var next = this;
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -42,7 +38,7 @@ test('after configured milliseconds', function(done){
|
|||||||
next(err, res);
|
next(err, res);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function checkResponse(err, res) {
|
function checkResponse(err/*, res*/) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.ok(err.message.match(/hang up/), err);
|
assert.ok(err.message.match(/hang up/), err);
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
require('../helper');
|
require('../helper');
|
||||||
require('../support/assert');
|
|
||||||
|
|
||||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||||
, assert = require('assert')
|
var assert = require('../support/assert');
|
||||||
, querystring = require('querystring')
|
var querystring = require('querystring');
|
||||||
, _ = require('underscore')
|
var _ = require('underscore');
|
||||||
;
|
|
||||||
|
|
||||||
// allow lots of emitters to be set to silence warning
|
// allow lots of emitters to be set to silence warning
|
||||||
app.setMaxListeners(0);
|
app.setMaxListeners(0);
|
||||||
|
|
||||||
suite('x_cache_channel', function() {
|
describe('x_cache_channel', function() {
|
||||||
|
|
||||||
assert.contains = function(ary, elem) {
|
assert.contains = function(ary, elem) {
|
||||||
assert.ok(_.contains(ary,elem), 'missing "' + elem +'" from x-cache-channel: '+ ary);
|
assert.ok(_.contains(ary,elem), 'missing "' + elem +'" from x-cache-channel: '+ ary);
|
||||||
};
|
};
|
||||||
|
|
||||||
test('supports joins', function(done) {
|
it('supports joins', function(done) {
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT a.name as an, b.name as bn FROM untitle_table_4 a left join private_table b ON (a.cartodb_id = b.cartodb_id)",
|
q: "SELECT a.name as an, b.name as bn FROM untitle_table_4 a " +
|
||||||
|
"left join private_table b ON (a.cartodb_id = b.cartodb_id)",
|
||||||
api_key: 1234
|
api_key: 1234
|
||||||
});
|
});
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
@ -38,7 +37,7 @@ test('supports joins', function(done) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('supports multistatements', function(done) {
|
it('supports multistatements', function(done) {
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "SELECT * FROM untitle_table_4; SELECT * FROM private_table",
|
q: "SELECT * FROM untitle_table_4; SELECT * FROM private_table",
|
||||||
api_key: 1234
|
api_key: 1234
|
||||||
@ -60,7 +59,7 @@ test('supports multistatements', function(done) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('supports explicit transactions', function(done) {
|
it('supports explicit transactions', function(done) {
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "BEGIN; SELECT * FROM untitle_table_4; COMMIT; BEGIN; SELECT * FROM private_table; COMMIT;",
|
q: "BEGIN; SELECT * FROM untitle_table_4; COMMIT; BEGIN; SELECT * FROM private_table; COMMIT;",
|
||||||
api_key: 1234
|
api_key: 1234
|
||||||
@ -82,7 +81,7 @@ test('supports explicit transactions', function(done) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('survives partial transactions', function(done) {
|
it('survives partial transactions', function(done) {
|
||||||
var query = querystring.stringify({
|
var query = querystring.stringify({
|
||||||
q: "BEGIN; SELECT * FROM untitle_table_4",
|
q: "BEGIN; SELECT * FROM untitle_table_4",
|
||||||
api_key: 1234
|
api_key: 1234
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
require('../helper');
|
require('../helper');
|
||||||
|
|
||||||
var _ = require('underscore')
|
var ApikeyAuth = require('../../app/auth/apikey');
|
||||||
, ApikeyAuth = require('../../app/auth/apikey')
|
var assert = require('assert');
|
||||||
, assert = require('assert')
|
|
||||||
;
|
|
||||||
|
|
||||||
suite('has credentials', function() {
|
describe('has credentials', function() {
|
||||||
|
|
||||||
var noCredentialsRequests = [
|
var noCredentialsRequests = [
|
||||||
{
|
{
|
||||||
@ -35,8 +33,8 @@ suite('has credentials', function() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
noCredentialsRequests.forEach(function(request) {
|
noCredentialsRequests.forEach(function(request) {
|
||||||
test('has no credentials if ' + request.des, function() {
|
it('has no credentials if ' + request.des, function() {
|
||||||
testCredentials(request.req, false)
|
testCredentials(request.req, false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -60,8 +58,8 @@ suite('has credentials', function() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
credentialsRequests.forEach(function(request) {
|
credentialsRequests.forEach(function(request) {
|
||||||
test('has credentials if ' + request.des, function() {
|
it('has credentials if ' + request.des, function() {
|
||||||
testCredentials(request.req, true)
|
testCredentials(request.req, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -72,13 +70,13 @@ suite('has credentials', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('verify credentials', function() {
|
describe('verifyCredentials', function() {
|
||||||
|
|
||||||
test('verifyCredentials callbacks with true value when request api_key is the same', function(done) {
|
it('callbacks with true value when request api_key is the same', function(done) {
|
||||||
testVerifyCredentials({query:{api_key: 'foo'}}, {apiKey: 'foo'}, true, done);
|
testVerifyCredentials({query:{api_key: 'foo'}}, {apiKey: 'foo'}, true, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('verifyCredentials callbacks with true value when request api_key is different', function(done) {
|
it('callbacks with false value when request api_key is different', function(done) {
|
||||||
testVerifyCredentials({query:{api_key: 'foo'}}, {apiKey: 'bar'}, false, done);
|
testVerifyCredentials({query:{api_key: 'foo'}}, {apiKey: 'bar'}, false, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
require('../helper')
|
require('../helper');
|
||||||
|
|
||||||
var assert = require('assert'),
|
var assert = require('assert');
|
||||||
_ = require('underscore'),
|
var HealthCheck = require('../../app/monitoring/health_check');
|
||||||
HealthCheck = require('../../app/monitoring/health_check');
|
|
||||||
|
|
||||||
var metadataBackend = {};
|
var metadataBackend = {};
|
||||||
|
|
||||||
@ -12,34 +11,34 @@ function PSQL(dbParams) {
|
|||||||
|
|
||||||
var healthCheck = new HealthCheck(metadataBackend, PSQL);
|
var healthCheck = new HealthCheck(metadataBackend, PSQL);
|
||||||
|
|
||||||
suite('health checks', function() {
|
describe('health checks', function() {
|
||||||
|
|
||||||
test('error if disabled file exists', function(done) {
|
it('errors if disabled file exists', function(done) {
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
var readFileFn = fs.readFile;
|
var readFileFn = fs.readFile;
|
||||||
fs.readFile = function(filename, callback) {
|
fs.readFile = function(filename, callback) {
|
||||||
callback(null, "Maintenance");
|
callback(null, "Maintenance");
|
||||||
}
|
};
|
||||||
healthCheck.check('fake', 'select 1', function(err, result) {
|
healthCheck.check('fake', 'select 1', function(err/*, result*/) {
|
||||||
assert.equal(err.message, "Maintenance");
|
assert.equal(err.message, "Maintenance");
|
||||||
assert.equal(err.http_status, 503);
|
assert.equal(err.http_status, 503);
|
||||||
done();
|
|
||||||
fs.readFile = readFileFn;
|
fs.readFile = readFileFn;
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('not err if disabled file does not exists', function(done) {
|
it('does not err if disabled file does not exists', function(done) {
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
var readFileFn = fs.readFile;
|
var readFileFn = fs.readFile;
|
||||||
fs.readFile = function(filename, callback) {
|
fs.readFile = function(filename, callback) {
|
||||||
callback(new Error("ENOENT"), null);
|
callback(new Error("ENOENT"), null);
|
||||||
}
|
};
|
||||||
healthCheck.check('fake', 'select 1', function(err, result) {
|
healthCheck.check('fake', 'select 1', function(err/*, result*/) {
|
||||||
assert.equal(err, null);
|
assert.equal(err, null);
|
||||||
done();
|
|
||||||
fs.readFile = readFileFn;
|
fs.readFile = readFileFn;
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
require('../../helper');
|
require('../../helper');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
|
|
||||||
var ArrayBufferSer = require('../../../app/models/bin_encoder')
|
var ArrayBufferSer = require('../../../app/models/bin_encoder');
|
||||||
|
|
||||||
suite('ArrayBufferSer', function() {
|
describe('ArrayBufferSer', function() {
|
||||||
|
|
||||||
test('calculate size for basic types', function() {
|
it('calculate size for basic types', function() {
|
||||||
var b = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4])
|
var b = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4]);
|
||||||
assert.equal(4*2, b.getDataSize());
|
assert.equal(4*2, b.getDataSize());
|
||||||
|
|
||||||
b = new ArrayBufferSer(ArrayBufferSer.INT8, [1,2,3,4])
|
b = new ArrayBufferSer(ArrayBufferSer.INT8, [1,2,3,4]);
|
||||||
assert.equal(4*1, b.getDataSize());
|
assert.equal(4, b.getDataSize());
|
||||||
|
|
||||||
b = new ArrayBufferSer(ArrayBufferSer.INT32, [1,2,3,4])
|
b = new ArrayBufferSer(ArrayBufferSer.INT32, [1,2,3,4]);
|
||||||
assert.equal(4*4, b.getDataSize());
|
assert.equal(4*4, b.getDataSize());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('calculate size for arrays', function() {
|
it('calculate size for arrays', function() {
|
||||||
var b = new ArrayBufferSer(ArrayBufferSer.STRING, ["test","kease"])
|
var b = new ArrayBufferSer(ArrayBufferSer.STRING, ["test","kease"]);
|
||||||
assert.equal((b.headerSize + 4 + 5)*2, b.getDataSize());
|
assert.equal((b.headerSize + 4 + 5)*2, b.getDataSize());
|
||||||
|
|
||||||
var ba = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4])
|
var ba = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4]);
|
||||||
var bc = new ArrayBufferSer(ArrayBufferSer.INT16, [1,4])
|
var bc = new ArrayBufferSer(ArrayBufferSer.INT16, [1,4]);
|
||||||
|
|
||||||
b = new ArrayBufferSer(ArrayBufferSer.BUFFER, [ba, bc])
|
b = new ArrayBufferSer(ArrayBufferSer.BUFFER, [ba, bc]);
|
||||||
assert.equal((b.headerSize + 4 + 2)*2, b.getDataSize());
|
assert.equal((b.headerSize + 4 + 2)*2, b.getDataSize());
|
||||||
assert.equal(b.type, ArrayBufferSer.BUFFER);
|
assert.equal(b.type, ArrayBufferSer.BUFFER);
|
||||||
});
|
});
|
||||||
@ -36,28 +36,28 @@ suite('ArrayBufferSer', function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test('binary data is ok', function() {
|
it('binary data is ok', function() {
|
||||||
var b = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4])
|
var b = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4]);
|
||||||
var bf = new Buffer([0, 0, 0, ArrayBufferSer.INT16, 0, 0, 0, 8, 1, 0, 2, 0, 3, 0, 4, 0]);
|
var bf = new Buffer([0, 0, 0, ArrayBufferSer.INT16, 0, 0, 0, 8, 1, 0, 2, 0, 3, 0, 4, 0]);
|
||||||
assert_buffer_equals(bf, b.buffer);
|
assert_buffer_equals(bf, b.buffer);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('binary data is ok with arrays', function() {
|
it('binary data is ok with arrays', function() {
|
||||||
var ba = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2, 3, 4])
|
var ba = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2, 3, 4]);
|
||||||
var bc = new ArrayBufferSer(ArrayBufferSer.INT16, [1,4])
|
var bc = new ArrayBufferSer(ArrayBufferSer.INT16, [1,4]);
|
||||||
|
|
||||||
var b = new ArrayBufferSer(ArrayBufferSer.BUFFER, [ba, bc])
|
var b = new ArrayBufferSer(ArrayBufferSer.BUFFER, [ba, bc]);
|
||||||
var bf = new Buffer([
|
var bf = new Buffer([
|
||||||
0, 0, 0, ArrayBufferSer.BUFFER, // type
|
0, 0, 0, ArrayBufferSer.BUFFER, // type
|
||||||
0, 0, 0, 28,
|
0, 0, 0, 28,
|
||||||
0, 0, 0, ArrayBufferSer.INT16, 0, 0, 0, 8, 1, 0, 2, 0, 3, 0, 4, 0,
|
0, 0, 0, ArrayBufferSer.INT16, 0, 0, 0, 8, 1, 0, 2, 0, 3, 0, 4, 0,
|
||||||
0, 0, 0, ArrayBufferSer.INT16, 0, 0, 0, 4, 1, 0, 4, 0])
|
0, 0, 0, ArrayBufferSer.INT16, 0, 0, 0, 4, 1, 0, 4, 0]);
|
||||||
assert_buffer_equals(bf, b.buffer);
|
assert_buffer_equals(bf, b.buffer);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('binary data is ok with strings', function() {
|
it('binary data is ok with strings', function() {
|
||||||
var s = 'test'
|
var s = 'test';
|
||||||
var b = new ArrayBufferSer(ArrayBufferSer.STRING, [s])
|
var b = new ArrayBufferSer(ArrayBufferSer.STRING, [s]);
|
||||||
var bf = new Buffer([
|
var bf = new Buffer([
|
||||||
0, 0, 0, ArrayBufferSer.STRING, // type
|
0, 0, 0, ArrayBufferSer.STRING, // type
|
||||||
0, 0, 0, 16,
|
0, 0, 0, 16,
|
||||||
|
@ -1,26 +1,39 @@
|
|||||||
require('../helper');
|
require('../helper');
|
||||||
|
|
||||||
var _ = require('underscore')
|
var _ = require('underscore');
|
||||||
, OAuthAuth = require('../../app/auth/oauth')
|
var OAuthAuth = require('../../app/auth/oauth');
|
||||||
, MetadataDB = require('cartodb-redis')
|
var MetadataDB = require('cartodb-redis');
|
||||||
, oAuth = require('../../app/auth/oauth').backend
|
var oAuth = require('../../app/auth/oauth').backend;
|
||||||
, assert = require('assert')
|
var assert = require('assert');
|
||||||
, tests = module.exports = {}
|
var oauth_data_1 = {
|
||||||
, oauth_data_1 = {
|
|
||||||
oauth_consumer_key: "dpf43f3p2l4k3l03",
|
oauth_consumer_key: "dpf43f3p2l4k3l03",
|
||||||
oauth_token: "nnch734d00sl2jdk",
|
oauth_token: "nnch734d00sl2jdk",
|
||||||
oauth_signature_method: "HMAC-SHA1",
|
oauth_signature_method: "HMAC-SHA1",
|
||||||
oauth_signature: "tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D",
|
oauth_signature: "tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D",
|
||||||
oauth_timestamp:"1191242096",
|
oauth_timestamp:"1191242096",
|
||||||
oauth_nonce:"kllo9940pd9333jh"
|
oauth_nonce:"kllo9940pd9333jh"
|
||||||
}
|
};
|
||||||
, oauth_data_2 = { oauth_version:"1.0" }
|
var oauth_data_2 = { oauth_version:"1.0" };
|
||||||
, oauth_data = _.extend(oauth_data_1, oauth_data_2)
|
var oauth_data = _.extend(oauth_data_1, oauth_data_2);
|
||||||
, real_oauth_header = 'OAuth realm="http://vizzuality.testhost.lan/",oauth_consumer_key="fZeNGv5iYayvItgDYHUbot1Ukb5rVyX6QAg8GaY2",oauth_token="l0lPbtP68ao8NfStCiA3V3neqfM03JKhToxhUQTR",oauth_signature_method="HMAC-SHA1", oauth_signature="o4hx4hWP6KtLyFwggnYB4yPK8xI%3D",oauth_timestamp="1313581372",oauth_nonce="W0zUmvyC4eVL8cBd4YwlH1nnPTbxW0QBYcWkXTwe4",oauth_version="1.0"'
|
var real_oauth_header = 'OAuth ' +
|
||||||
, oauth_header_tokens = 'oauth_consumer_key="dpf43f3p2l4k3l03",oauth_token="nnch734d00sl2jdk",oauth_signature_method="HMAC-SHA1", oauth_signature="tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D",oauth_timestamp="1191242096",oauth_nonce="kllo9940pd9333jh",oauth_version="1.0"'
|
'realm="http://vizzuality.testhost.lan/",' +
|
||||||
, full_oauth_header = 'OAuth realm="http://photos.example.net/"' + oauth_header_tokens;
|
'oauth_consumer_key="fZeNGv5iYayvItgDYHUbot1Ukb5rVyX6QAg8GaY2",' +
|
||||||
|
'oauth_token="l0lPbtP68ao8NfStCiA3V3neqfM03JKhToxhUQTR",' +
|
||||||
|
'oauth_signature_method="HMAC-SHA1", ' +
|
||||||
|
'oauth_signature="o4hx4hWP6KtLyFwggnYB4yPK8xI%3D",' +
|
||||||
|
'oauth_timestamp="1313581372",' +
|
||||||
|
'oauth_nonce="W0zUmvyC4eVL8cBd4YwlH1nnPTbxW0QBYcWkXTwe4",' +
|
||||||
|
'oauth_version="1.0"';
|
||||||
|
var oauth_header_tokens = 'oauth_consumer_key="dpf43f3p2l4k3l03",' +
|
||||||
|
'oauth_token="nnch734d00sl2jdk",' +
|
||||||
|
'oauth_signature_method="HMAC-SHA1", ' +
|
||||||
|
'oauth_signature="tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D",' +
|
||||||
|
'oauth_timestamp="1191242096",' +
|
||||||
|
'oauth_nonce="kllo9940pd9333jh",' +
|
||||||
|
'oauth_version="1.0"';
|
||||||
|
var full_oauth_header = 'OAuth realm="http://photos.example.net/"' + oauth_header_tokens;
|
||||||
|
|
||||||
var metadataBackend = MetadataDB({
|
var metadataBackend = new MetadataDB({
|
||||||
host: global.settings.redis_host,
|
host: global.settings.redis_host,
|
||||||
port: global.settings.redis_port,
|
port: global.settings.redis_port,
|
||||||
max: global.settings.redisPool,
|
max: global.settings.redisPool,
|
||||||
@ -28,44 +41,43 @@ var metadataBackend = MetadataDB({
|
|||||||
reapIntervalMillis: global.settings.redisReapIntervalMillis
|
reapIntervalMillis: global.settings.redisReapIntervalMillis
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('oauth', function() {
|
describe('oauth', function() {
|
||||||
|
|
||||||
test('test database number', function(){
|
it('test database number', function(){
|
||||||
assert.equal(oAuth.oauth_database, 3);
|
assert.equal(oAuth.oauth_database, 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('test oauth database key', function(){
|
it('test oauth database key', function(){
|
||||||
assert.equal(oAuth.oauth_user_key, "rails:oauth_access_tokens:<%= oauth_access_key %>");
|
assert.equal(oAuth.oauth_user_key, "rails:oauth_access_tokens:<%= oauth_access_key %>");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('test parse tokens from full headers does not raise exception', function(){
|
it('test parse tokens from full headers does not raise exception', function(){
|
||||||
var req = {query:{}, headers:{authorization:full_oauth_header}};
|
var req = {query:{}, headers:{authorization:full_oauth_header}};
|
||||||
assert.doesNotThrow(function(){ oAuth.parseTokens(req) }, /incomplete oauth tokens in request/);
|
assert.doesNotThrow(function(){ oAuth.parseTokens(req); }, /incomplete oauth tokens in request/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('test parse all normal tokens raises no exception', function(){
|
it('test parse all normal tokens raises no exception', function(){
|
||||||
var req = {query:oauth_data, headers:{}};
|
var req = {query:oauth_data, headers:{}};
|
||||||
assert.doesNotThrow(function(){ oAuth.parseTokens(req) }, /incomplete oauth tokens in request/);
|
assert.doesNotThrow(function(){ oAuth.parseTokens(req); }, /incomplete oauth tokens in request/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('test headers take presedence over query parameters', function(){
|
it('test headers take presedence over query parameters', function(){
|
||||||
var req = {query:{oauth_signature_method: "MY_HASH"}, headers:{authorization:full_oauth_header}};
|
var req = {query:{oauth_signature_method: "MY_HASH"}, headers:{authorization:full_oauth_header}};
|
||||||
var tokens = oAuth.parseTokens(req);
|
var tokens = oAuth.parseTokens(req);
|
||||||
assert.equal(tokens.oauth_signature_method, "HMAC-SHA1");
|
assert.equal(tokens.oauth_signature_method, "HMAC-SHA1");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('test can access oauth hash for a user based on access token (oauth_token)', function(done){
|
it('test can access oauth hash for a user based on access token (oauth_token)', function(done){
|
||||||
var req = {query:{}, headers:{authorization:real_oauth_header}};
|
var req = {query:{}, headers:{authorization:real_oauth_header}};
|
||||||
var tokens = oAuth.parseTokens(req);
|
var tokens = oAuth.parseTokens(req);
|
||||||
|
|
||||||
oAuth.getOAuthHash(metadataBackend, tokens.oauth_token, function(err, data){
|
oAuth.getOAuthHash(metadataBackend, tokens.oauth_token, function(err, data){
|
||||||
console.log(data);
|
|
||||||
assert.equal(tokens.oauth_consumer_key, data.consumer_key);
|
assert.equal(tokens.oauth_consumer_key, data.consumer_key);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('test non existant oauth hash for a user based on oauth_token returns empty hash', function(done){
|
it('test non existant oauth hash for a user based on oauth_token returns empty hash', function(done){
|
||||||
var req = {query:{}, headers:{authorization:full_oauth_header}};
|
var req = {query:{}, headers:{authorization:full_oauth_header}};
|
||||||
var tokens = oAuth.parseTokens(req);
|
var tokens = oAuth.parseTokens(req);
|
||||||
|
|
||||||
@ -76,7 +88,7 @@ test('test non existant oauth hash for a user based on oauth_token returns empty
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can return user for verified signature', function(done){
|
it('can return user for verified signature', function(done){
|
||||||
var req = {query:{},
|
var req = {query:{},
|
||||||
headers:{authorization:real_oauth_header, host: 'vizzuality.testhost.lan' },
|
headers:{authorization:real_oauth_header, host: 'vizzuality.testhost.lan' },
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
@ -91,7 +103,7 @@ test('can return user for verified signature', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns null user for unverified signatures', function(done){
|
it('returns null user for unverified signatures', function(done){
|
||||||
var req = {query:{},
|
var req = {query:{},
|
||||||
headers:{authorization:real_oauth_header, host: 'vizzuality.testyhost.lan' },
|
headers:{authorization:real_oauth_header, host: 'vizzuality.testyhost.lan' },
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
@ -105,7 +117,7 @@ test('returns null user for unverified signatures', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns null user for no oauth', function(done){
|
it('returns null user for no oauth', function(done){
|
||||||
var req = {
|
var req = {
|
||||||
query:{},
|
query:{},
|
||||||
headers:{},
|
headers:{},
|
||||||
@ -120,14 +132,14 @@ test('returns null user for no oauth', function(done){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('OAuthAuth reports it has credentials', function(done) {
|
it('OAuthAuth reports it has credentials', function(done) {
|
||||||
var req = {query:{}, headers:{authorization:real_oauth_header}};
|
var req = {query:{}, headers:{authorization:real_oauth_header}};
|
||||||
var oAuthAuth = new OAuthAuth(req);
|
var oAuthAuth = new OAuthAuth(req);
|
||||||
assert.ok(oAuthAuth.hasCredentials());
|
assert.ok(oAuthAuth.hasCredentials());
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('OAuthAuth reports it has no credentials', function(done) {
|
it('OAuthAuth reports it has no credentials', function(done) {
|
||||||
var req = {query:{}, headers:{}};
|
var req = {query:{}, headers:{}};
|
||||||
var oAuthAuth = new OAuthAuth(req);
|
var oAuthAuth = new OAuthAuth(req);
|
||||||
assert.equal(oAuthAuth.hasCredentials(), false);
|
assert.equal(oAuthAuth.hasCredentials(), false);
|
||||||
|
Loading…
Reference in New Issue
Block a user