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
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
|
20
Makefile
20
Makefile
@ -6,3 +6,23 @@ clean:
|
||||
|
||||
check:
|
||||
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]
|
||||
*
|
||||
*/
|
||||
var _ = require('underscore'),
|
||||
fs = require('fs'),
|
||||
path = require('path');
|
||||
var _ = require('underscore');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
if ( process.argv[2] ) ENV = process.argv[2];
|
||||
else if ( process.env['NODE_ENV'] ) ENV = process.env['NODE_ENV'];
|
||||
else ENV = 'development';
|
||||
var ENV = process.env.NODE_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
|
||||
if (ENV != 'development' && ENV != 'production' && ENV != 'test' && ENV != 'staging' ) {
|
||||
if (availableEnvironments.indexOf(ENV) === -1) {
|
||||
console.error("\nnode app.js [environment]");
|
||||
console.error("environments: development, staging, production, test");
|
||||
console.error("environments: " + availableEnvironments.join(', '));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -32,8 +36,8 @@ var env = require(__dirname + '/config/environments/' + ENV);
|
||||
env.api_hostname = require('os').hostname().split('.')[0];
|
||||
_.extend(global.settings, env);
|
||||
|
||||
global.log4js = require('log4js')
|
||||
log4js_config = {
|
||||
global.log4js = require('log4js');
|
||||
var log4js_config = {
|
||||
appenders: [],
|
||||
replaceConsole:true
|
||||
};
|
||||
@ -63,31 +67,33 @@ if ( global.settings.rollbar ) {
|
||||
});
|
||||
}
|
||||
|
||||
log4js.configure(log4js_config, { cwd: __dirname });
|
||||
global.logger = log4js.getLogger();
|
||||
global.log4js.configure(log4js_config, { cwd: __dirname });
|
||||
global.logger = global.log4js.getLogger();
|
||||
|
||||
|
||||
// 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 app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
app.listen(global.settings.node_port, global.settings.node_host, function() {
|
||||
console.log("CartoDB SQL API " + version + " listening on " +
|
||||
global.settings.node_host + ":" + global.settings.node_port +
|
||||
" with base_url " + global.settings.base_url
|
||||
+ " (" + ENV + ")");
|
||||
console.log(
|
||||
"CartoDB SQL API %s listening on %s:%s with base_url %s (%s)",
|
||||
version, global.settings.node_host, global.settings.node_port, global.settings.base_url, ENV
|
||||
);
|
||||
});
|
||||
|
||||
process.on('uncaughtException', function(err) {
|
||||
logger.error('Uncaught exception: ' + err.stack);
|
||||
global.logger.error('Uncaught exception: ' + err.stack);
|
||||
});
|
||||
|
||||
process.on('SIGHUP', function() {
|
||||
global.log4js.clearAndShutdownAppenders(function() {
|
||||
global.log4js.configure(log4js_config);
|
||||
global.logger = log4js.getLogger();
|
||||
global.logger = global.log4js.getLogger();
|
||||
console.log('Log files reloaded');
|
||||
});
|
||||
});
|
||||
|
@ -12,10 +12,8 @@ ApikeyAuth.prototype.verifyCredentials = function(options, callback) {
|
||||
};
|
||||
|
||||
ApikeyAuth.prototype.hasCredentials = function() {
|
||||
return !!(this.req.query.api_key
|
||||
|| this.req.query.map_key
|
||||
|| (this.req.body && this.req.body.api_key)
|
||||
|| (this.req.body && this.req.body.map_key));
|
||||
return !!(this.req.query.api_key || this.req.query.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;
|
||||
|
||||
if ( requiredApi ) {
|
||||
if ( requiredApi == req.query.map_key ) {
|
||||
if ( requiredApi === req.query.map_key ) {
|
||||
valid = true;
|
||||
} else if ( requiredApi == req.query.api_key ) {
|
||||
} else if ( requiredApi === req.query.api_key ) {
|
||||
valid = true;
|
||||
// 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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
// too bound to the request object, but ok for now
|
||||
var _ = require('underscore')
|
||||
, OAuthUtil = require('oauth-client')
|
||||
, url = require('url')
|
||||
, Step = require('step');
|
||||
var _ = require('underscore');
|
||||
var OAuthUtil = require('oauth-client');
|
||||
var step = require('step');
|
||||
var assert = require('assert');
|
||||
|
||||
var oAuth = function(){
|
||||
var oAuth = (function(){
|
||||
var me = {
|
||||
oauth_database: 3,
|
||||
oauth_user_key: "rails:oauth_access_tokens:<%= oauth_access_key %>",
|
||||
@ -15,7 +15,7 @@ var oAuth = function(){
|
||||
// * in GET request
|
||||
// * in header
|
||||
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 oauth_variables = ['oauth_body_hash',
|
||||
'oauth_consumer_key',
|
||||
@ -34,9 +34,10 @@ var oAuth = function(){
|
||||
var header_string = req.headers.authorization;
|
||||
if (!_.isUndefined(header_string)) {
|
||||
_.each(oauth_variables, function(oauth_key){
|
||||
var matched_string = header_string.match(new RegExp(oauth_key + '=\"([^\"]+)\"'))
|
||||
if (!_.isNull(matched_string))
|
||||
var matched_string = header_string.match(new RegExp(oauth_key + '=\"([^\"]+)\"'));
|
||||
if (!_.isNull(matched_string)) {
|
||||
header_oauth[oauth_key] = decodeURIComponent(matched_string[1]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -69,12 +70,12 @@ var oAuth = function(){
|
||||
var ohash;
|
||||
var signature;
|
||||
|
||||
Step(
|
||||
step(
|
||||
function getTokensFromURL(){
|
||||
return oAuth.parseTokens(req);
|
||||
},
|
||||
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 = !_.isEmpty(data);
|
||||
@ -87,8 +88,10 @@ var oAuth = function(){
|
||||
}
|
||||
},
|
||||
function regenerateSignature(err, data){
|
||||
if (err) throw err;
|
||||
if (!this.is_oauth_request) return null;
|
||||
assert.ifError(err);
|
||||
if (!this.is_oauth_request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ohash = data;
|
||||
var consumer = OAuthUtil.createConsumer(ohash.consumer_key, ohash.consumer_secret);
|
||||
@ -98,7 +101,7 @@ var oAuth = function(){
|
||||
var method = req.method;
|
||||
var host = req.headers.host;
|
||||
|
||||
if(!httpProto || (httpProto != 'http' && httpProto != 'https')) {
|
||||
if(!httpProto || (httpProto !== 'http' && httpProto !== 'https')) {
|
||||
var msg = "Unknown HTTP protocol " + httpProto + ".";
|
||||
err = new Error(msg);
|
||||
err.http_status = 500;
|
||||
@ -111,13 +114,13 @@ var oAuth = function(){
|
||||
|
||||
// remove signature from passed_tokens
|
||||
signature = passed_tokens.oauth_signature;
|
||||
delete passed_tokens['oauth_signature'];
|
||||
delete passed_tokens.oauth_signature;
|
||||
|
||||
var joined = {};
|
||||
|
||||
// remove oauth_signature from body
|
||||
if(req.body) {
|
||||
delete req.body['oauth_signature'];
|
||||
delete req.body.oauth_signature;
|
||||
}
|
||||
_.extend(joined, req.body ? req.body : null);
|
||||
_.extend(joined, passed_tokens);
|
||||
@ -126,7 +129,7 @@ var oAuth = function(){
|
||||
return signer.sign(method, path, joined);
|
||||
},
|
||||
function checkSignature(err, data){
|
||||
if (err) throw err;
|
||||
assert.ifError(err);
|
||||
|
||||
//console.log(data + " should equal the provided signature: " + signature);
|
||||
callback(err, (signature === data && !_.isUndefined(data)) ? true : null);
|
||||
@ -139,7 +142,7 @@ var oAuth = function(){
|
||||
};
|
||||
|
||||
return me;
|
||||
}();
|
||||
})();
|
||||
|
||||
function OAuthAuth(req) {
|
||||
this.req = req;
|
||||
|
@ -14,36 +14,47 @@
|
||||
// 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'] )
|
||||
process.env['PGAPPNAME']='cartodb_sqlapi';
|
||||
var CdbRequest = require('../models/cartodb_request');
|
||||
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() {
|
||||
|
||||
var path = require('path');
|
||||
var app = express.createServer();
|
||||
|
||||
var express = require('express')
|
||||
, 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({
|
||||
var metadataBackend = require('cartodb-redis')({
|
||||
host: global.settings.redis_host,
|
||||
port: global.settings.redis_port,
|
||||
max: global.settings.redisPool,
|
||||
@ -63,25 +74,6 @@ var tableCache = LRU({
|
||||
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 = {
|
||||
buffer: true,
|
||||
format: global.settings.log_format ||
|
||||
@ -89,7 +81,7 @@ var loggerOpts = {
|
||||
};
|
||||
|
||||
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 {
|
||||
app.use(express.logger(loggerOpts));
|
||||
}
|
||||
@ -110,7 +102,7 @@ if ( global.settings.statsd ) {
|
||||
var last_err = statsd_client.last_error;
|
||||
var last_msg = last_err.msg;
|
||||
var this_msg = ''+err;
|
||||
if ( this_msg != last_msg ) {
|
||||
if ( this_msg !== last_msg ) {
|
||||
console.error("statsd client socket error: " + err);
|
||||
statsd_client.last_error.count = 1;
|
||||
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);
|
||||
app.use(function(req, res, next) {
|
||||
req.connection.setTimeout(timeout);
|
||||
next()
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
@ -198,25 +190,27 @@ function handleVersion(req, res) {
|
||||
function handleQuery(req, res) {
|
||||
|
||||
// extract input
|
||||
var body = (req.body) ? req.body : {};
|
||||
var params = _.extend({}, req.query, body); // clone so don't modify req.params or req.body so oauth is not broken
|
||||
var sql = params.q;
|
||||
var limit = parseInt(params.rows_per_page);
|
||||
var offset = parseInt(params.page);
|
||||
var orderBy = params.order_by;
|
||||
var body = (req.body) ? req.body : {};
|
||||
var params = _.extend({}, req.query, body); // clone so don't modify req.params or req.body so oauth is not broken
|
||||
var sql = params.q;
|
||||
var limit = parseInt(params.rows_per_page);
|
||||
var offset = parseInt(params.page);
|
||||
var orderBy = params.order_by;
|
||||
var sortOrder = params.sort_order;
|
||||
var requestedFormat = params.format;
|
||||
var format = _.isArray(requestedFormat) ? _.last(requestedFormat) : requestedFormat;
|
||||
var format = _.isArray(requestedFormat) ? _.last(requestedFormat) : requestedFormat;
|
||||
var requestedFilename = params.filename;
|
||||
var filename = requestedFilename;
|
||||
var filename = requestedFilename;
|
||||
var requestedSkipfields = params.skipfields;
|
||||
var cdbUsername = cdbReq.userByReq(req);
|
||||
var skipfields;
|
||||
var dp = params.dp; // decimal point digits (defaults to 6)
|
||||
var gn = "the_geom"; // TODO: read from configuration file
|
||||
var dp = params.dp; // decimal point digits (defaults to 6)
|
||||
var gn = "the_geom"; // TODO: read from configuration file
|
||||
var tableCacheItem;
|
||||
|
||||
if ( req.profiler ) req.profiler.start('sqlapi.query');
|
||||
if ( req.profiler ) {
|
||||
req.profiler.start('sqlapi.query');
|
||||
}
|
||||
|
||||
req.aborted = false;
|
||||
req.on("close", function() {
|
||||
@ -248,8 +242,9 @@ function handleQuery(req, res) {
|
||||
|
||||
// Accept both comma-separated string or array of comma-separated strings
|
||||
if ( requestedSkipfields ) {
|
||||
if ( _.isString(requestedSkipfields) ) skipfields = requestedSkipfields.split(',');
|
||||
else if ( _.isArray(requestedSkipfields) ) {
|
||||
if ( _.isString(requestedSkipfields) ) {
|
||||
skipfields = requestedSkipfields.split(',');
|
||||
} else if ( _.isArray(requestedSkipfields) ) {
|
||||
skipfields = [];
|
||||
_.each(requestedSkipfields, function(ele) {
|
||||
skipfields = skipfields.concat(ele.split(','));
|
||||
@ -287,14 +282,16 @@ function handleQuery(req, res) {
|
||||
var authApi = new AuthApi(req, params),
|
||||
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
|
||||
// 2. Run the request through OAuth to get R/W user id if signed
|
||||
// 3. Get the list of tables affected by the query
|
||||
// 4. Setup headers
|
||||
// 5. Send formatted results back
|
||||
Step(
|
||||
step(
|
||||
function getDatabaseConnectionParams() {
|
||||
checkAborted('getDatabaseConnectionParams');
|
||||
// If the request is providing credentials it may require every DB parameters
|
||||
@ -307,12 +304,14 @@ function handleQuery(req, res) {
|
||||
function authenticate(err, userDBParams) {
|
||||
if (err) {
|
||||
err.http_status = 404;
|
||||
err.message = "Sorry, we can't find CartoDB user '" + cdbUsername
|
||||
+ "'. Please check that you have entered the correct domain.";
|
||||
err.message = "Sorry, we can't find CartoDB user '" + cdbUsername + "'. " +
|
||||
"Please check that you have entered the correct domain.";
|
||||
throw err;
|
||||
}
|
||||
|
||||
if ( req.profiler ) req.profiler.done('getDBParams');
|
||||
if ( req.profiler ) {
|
||||
req.profiler.done('getDBParams');
|
||||
}
|
||||
|
||||
dbParams = userDBParams;
|
||||
|
||||
@ -330,7 +329,9 @@ function handleQuery(req, res) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if ( req.profiler ) req.profiler.done('authenticate');
|
||||
if ( req.profiler ) {
|
||||
req.profiler.done('authenticate');
|
||||
}
|
||||
|
||||
if (_.isBoolean(isAuthenticated) && isAuthenticated) {
|
||||
authenticated = isAuthenticated;
|
||||
@ -349,9 +350,11 @@ function handleQuery(req, res) {
|
||||
function queryExplain(err){
|
||||
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');
|
||||
|
||||
@ -373,16 +376,20 @@ function handleQuery(req, res) {
|
||||
var tables = raw_tables.split(/^\{(.*)\}$/)[1].split(',');
|
||||
self(null, tables);
|
||||
} 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, []);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
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');
|
||||
|
||||
@ -410,8 +417,8 @@ function handleQuery(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
var fClass = formats[format];
|
||||
formatter = new fClass();
|
||||
var FormatClass = formats[format];
|
||||
formatter = new FormatClass();
|
||||
req.formatter = formatter;
|
||||
|
||||
|
||||
@ -454,7 +461,7 @@ function handleQuery(req, res) {
|
||||
return null;
|
||||
},
|
||||
function generateFormat(err){
|
||||
if (err) throw err;
|
||||
assert.ifError(err);
|
||||
checkAborted('generateFormat');
|
||||
|
||||
// TODO: drop this, fix UI!
|
||||
@ -493,25 +500,32 @@ function handleQuery(req, res) {
|
||||
function errorHandle(err){
|
||||
formatter = null;
|
||||
|
||||
if ( err ) handleException(err, res);
|
||||
if ( err ) {
|
||||
handleException(err, res);
|
||||
}
|
||||
if ( req.profiler ) {
|
||||
req.profiler.sendStats(); // TODO: do on nextTick ?
|
||||
}
|
||||
if (statsd_client) {
|
||||
if ( err ) statsd_client.increment('sqlapi.query.error');
|
||||
else statsd_client.increment('sqlapi.query.success');
|
||||
if ( err ) {
|
||||
statsd_client.increment('sqlapi.query.error');
|
||||
} else {
|
||||
statsd_client.increment('sqlapi.query.success');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
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){
|
||||
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;
|
||||
res.send({explain: {pid: process.pid, hits: totalExplainHits, keys : totalExplainKeys }});
|
||||
}
|
||||
@ -543,7 +557,8 @@ function handleHealthCheck(req, res) {
|
||||
function getContentDisposition(formatter, filename, inline) {
|
||||
var ext = formatter.getFileExtension();
|
||||
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){
|
||||
@ -575,13 +590,13 @@ function handleException(err, res) {
|
||||
|
||||
_.defaults(msg, pgErrorHandler.getFields());
|
||||
|
||||
if (global.settings.environment == 'development') {
|
||||
if (global.settings.environment === 'development') {
|
||||
msg.stack = err.stack;
|
||||
}
|
||||
|
||||
if (global.settings.environment !== 'test'){
|
||||
// TODO: email this Exception report
|
||||
console.error("EXCEPTION REPORT: " + err.stack)
|
||||
console.error("EXCEPTION REPORT: " + err.stack);
|
||||
}
|
||||
|
||||
// allow cross site post
|
||||
|
@ -1,6 +1,8 @@
|
||||
|
||||
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._initFunctions();
|
||||
this.headerSize = 8;
|
||||
@ -14,13 +16,14 @@ function ArrayBufferSer(type, data, options) {
|
||||
|
||||
var w = this.writeFn[type];
|
||||
|
||||
var i;
|
||||
if(!this.options.delta) {
|
||||
for(var i = 0; i < data.length; ++i) {
|
||||
for(i = 0; i < data.length; ++i) {
|
||||
this[w](data[i]);
|
||||
}
|
||||
} else {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@ -66,7 +69,7 @@ ArrayBufferSer.prototype = {
|
||||
var s = this.sizes[type];
|
||||
if(s) {
|
||||
var r = off % s;
|
||||
return r == 0 ? 0 : s - r;
|
||||
return r === 0 ? 0 : s - r;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
@ -78,7 +81,7 @@ ArrayBufferSer.prototype = {
|
||||
return s*t.length;
|
||||
}
|
||||
s = 0;
|
||||
if(this.type == ArrayBufferSer.STRING) {
|
||||
if(this.type === ArrayBufferSer.STRING) {
|
||||
// calculate size with padding
|
||||
t.forEach(function(arr) {
|
||||
var pad = self._paddingFor(offset, ArrayBufferSer.MAX_PADDING);
|
||||
@ -108,16 +111,30 @@ ArrayBufferSer.prototype = {
|
||||
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() {
|
||||
var self = this;
|
||||
this.writeFn.forEach(function(fn) {
|
||||
if(self[fn] === undefined)
|
||||
if(self[fn] === undefined) {
|
||||
self[fn] = function(d) {
|
||||
self.buffer[fn](d, self.offset);
|
||||
self.offset += self.sizes[self.type];
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -30,7 +30,9 @@ function userByHostName(host) {
|
||||
}
|
||||
|
||||
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 mat[1];
|
||||
|
@ -1,6 +1,7 @@
|
||||
var pg = require('./pg'),
|
||||
ArrayBufferSer = require("../bin_encoder"),
|
||||
_ = require('underscore');
|
||||
var _ = require('underscore');
|
||||
|
||||
var pg = require('./pg');
|
||||
var ArrayBufferSer = require("../bin_encoder");
|
||||
|
||||
function BinaryFormat() {}
|
||||
|
||||
@ -9,13 +10,14 @@ BinaryFormat.prototype = new pg('arraybuffer');
|
||||
BinaryFormat.prototype._contentType = "application/octet-stream";
|
||||
|
||||
BinaryFormat.prototype._extractTypeFromName = function(name) {
|
||||
var g = name.match(new RegExp(/.*__(uintclamp|uint|int|float)(8|16|32)/i))
|
||||
if(g && g.length == 3) {
|
||||
var g = name.match(/.*__(uintclamp|uint|int|float)(8|16|32)/i);
|
||||
if(g && g.length === 3) {
|
||||
var typeName = g[1] + g[2];
|
||||
return ArrayBufferSer.typeNames[typeName];
|
||||
}
|
||||
};
|
||||
|
||||
// jshint maxcomplexity:12
|
||||
BinaryFormat.prototype.transform = function(result, options, callback) {
|
||||
var total_rows = result.rowCount;
|
||||
var rows = result.rows;
|
||||
@ -35,27 +37,28 @@ BinaryFormat.prototype.transform = function(result, options, callback) {
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
var i;
|
||||
var t;
|
||||
// get header types (and guess from name)
|
||||
for(var i = 0; i < headersNames.length; ++i) {
|
||||
var r = rows[0];
|
||||
var n = headersNames[i];
|
||||
if(typeof(r[n]) == 'string') {
|
||||
for(i = 0; i < headersNames.length; ++i) {
|
||||
r = rows[0];
|
||||
n = headersNames[i];
|
||||
if(typeof(r[n]) === 'string') {
|
||||
headerTypes.push(ArrayBufferSer.STRING);
|
||||
} else if(typeof(r[n]) == 'object') {
|
||||
var t = this._extractTypeFromName(n);
|
||||
t = t == undefined ? ArrayBufferSer.FLOAT32: t;
|
||||
} else if(typeof(r[n]) === 'object') {
|
||||
t = this._extractTypeFromName(n);
|
||||
t = t || ArrayBufferSer.FLOAT32;
|
||||
headerTypes.push(ArrayBufferSer.BUFFER + t);
|
||||
} else {
|
||||
var t = this._extractTypeFromName(n);
|
||||
headerTypes.push(t == undefined ? ArrayBufferSer.FLOAT32: t);
|
||||
t = this._extractTypeFromName(n);
|
||||
headerTypes.push(t || ArrayBufferSer.FLOAT32);
|
||||
}
|
||||
}
|
||||
|
||||
// pack the data
|
||||
var header = new ArrayBufferSer(ArrayBufferSer.STRING, headersNames);
|
||||
var data = [header];
|
||||
for(var i = 0; i < headersNames.length; ++i) {
|
||||
for(i = 0; i < headersNames.length; ++i) {
|
||||
var d = [];
|
||||
var n = headersNames[i];
|
||||
for(var r = 0; r < total_rows; ++r) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
var _ = require('underscore'),
|
||||
pg = require('./pg');
|
||||
var _ = require('underscore');
|
||||
|
||||
var pg = require('./pg');
|
||||
|
||||
function GeoJsonFormat() {
|
||||
this.buffer = '';
|
||||
@ -40,7 +41,7 @@ GeoJsonFormat.prototype.handleQueryRow = function(row) {
|
||||
'"properties":'
|
||||
];
|
||||
delete row[this.opts.gn];
|
||||
delete row['the_geom_webmercator'];
|
||||
delete row.the_geom_webmercator;
|
||||
geojson.push(JSON.stringify(row));
|
||||
geojson.push('}');
|
||||
|
||||
@ -52,13 +53,15 @@ GeoJsonFormat.prototype.handleQueryRow = function(row) {
|
||||
}
|
||||
};
|
||||
|
||||
GeoJsonFormat.prototype.handleQueryEnd = function(result) {
|
||||
GeoJsonFormat.prototype.handleQueryEnd = function(/*result*/) {
|
||||
if (this.error) {
|
||||
this.callback(this.error);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.opts.profiler ) this.opts.profiler.done('gotRows');
|
||||
if ( this.opts.profiler ) {
|
||||
this.opts.profiler.done('gotRows');
|
||||
}
|
||||
|
||||
if ( ! this._streamingStarted ) {
|
||||
this.startStreaming();
|
||||
@ -91,7 +94,7 @@ function _toGeoJSON(data, gn, callback){
|
||||
};
|
||||
_geojson.geometry = JSON.parse(ele[gn]);
|
||||
delete ele[gn];
|
||||
delete ele["the_geom_webmercator"]; // TODO: use skipfields
|
||||
delete ele.the_geom_webmercator; // TODO: use skipfields
|
||||
_geojson.properties = ele;
|
||||
out.features.push(_geojson);
|
||||
});
|
||||
|
@ -2,9 +2,9 @@
|
||||
// load all the formats
|
||||
//
|
||||
|
||||
var formats = {},
|
||||
path = require('path'),
|
||||
folder = __dirname + "/";
|
||||
var formats = {};
|
||||
var path = require('path');
|
||||
var folder = __dirname + "/";
|
||||
|
||||
require("fs").readdirSync(folder).forEach(function(file) {
|
||||
if (path.extname(file) === '.js' && file !== 'index.js' && file !== 'ogr.js' && file !== 'pg.js' ) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
var pg = require('./pg'),
|
||||
util = require('util'),
|
||||
PgErrorHandler = require(global.settings.app_root + '/app/postgresql/error_handler'),
|
||||
_ = require('underscore');
|
||||
var _ = require('underscore');
|
||||
|
||||
var pg = require('./pg');
|
||||
var PgErrorHandler = require('../../postgresql/error_handler');
|
||||
|
||||
function JsonFormat() {
|
||||
this.buffer = '';
|
||||
@ -12,6 +12,7 @@ JsonFormat.prototype = new pg('json');
|
||||
|
||||
JsonFormat.prototype._contentType = "application/json; charset=utf-8";
|
||||
|
||||
// jshint maxcomplexity:9
|
||||
JsonFormat.prototype.formatResultFields = function(flds) {
|
||||
flds = flds || [];
|
||||
var nfields = {};
|
||||
@ -73,13 +74,16 @@ JsonFormat.prototype.handleQueryRow = function(row, result) {
|
||||
}
|
||||
};
|
||||
|
||||
// jshint maxcomplexity:13
|
||||
JsonFormat.prototype.handleQueryEnd = function(result) {
|
||||
if (this.error && !this._streamingStarted) {
|
||||
this.callback(this.error);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.opts.profiler ) this.opts.profiler.done('gotRows');
|
||||
if ( this.opts.profiler ) {
|
||||
this.opts.profiler.done('gotRows');
|
||||
}
|
||||
|
||||
if ( ! this._streamingStarted ) {
|
||||
this.startStreaming();
|
||||
@ -95,7 +99,9 @@ JsonFormat.prototype.handleQueryEnd = function(result) {
|
||||
var sf = this.opts.skipfields;
|
||||
for (var i = 0; i < result.fields.length; 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;
|
||||
}
|
||||
@ -124,7 +130,7 @@ JsonFormat.prototype.handleQueryEnd = function(result) {
|
||||
severities.push(severity);
|
||||
notices[severity] = [];
|
||||
}
|
||||
notices[severity].push(notice.message)
|
||||
notices[severity].push(notice.message);
|
||||
});
|
||||
_.each(severities, function(severity) {
|
||||
out.push(',');
|
||||
|
@ -1,9 +1,10 @@
|
||||
var crypto = require('crypto'),
|
||||
Step = require('step'),
|
||||
fs = require('fs'),
|
||||
_ = require('underscore'),
|
||||
PSQL = require('cartodb-psql'),
|
||||
spawn = require('child_process').spawn;
|
||||
var crypto = require('crypto');
|
||||
var step = require('step');
|
||||
var fs = require('fs');
|
||||
var _ = require('underscore');
|
||||
var PSQL = require('cartodb-psql');
|
||||
var spawn = require('child_process').spawn;
|
||||
var assert = require('assert');
|
||||
|
||||
// Keeps track of what's waiting baking for export
|
||||
var bakingExports = {};
|
||||
@ -18,12 +19,12 @@ OgrFormat.prototype = {
|
||||
|
||||
is_file: true,
|
||||
|
||||
getQuery: function(sql, options) {
|
||||
getQuery: function(/*sql, options*/) {
|
||||
return null; // dont execute the query
|
||||
},
|
||||
|
||||
transform: function(result, options, callback) {
|
||||
throw "should not be called for file formats"
|
||||
transform: function(/*result, options, callback*/) {
|
||||
throw "should not be called for file formats";
|
||||
},
|
||||
|
||||
getContentType: function(){ return this._contentType; },
|
||||
@ -50,7 +51,7 @@ OgrFormat.prototype = {
|
||||
// Internal function usable by all OGR-driven outputs
|
||||
OgrFormat.prototype.toOGR = function(options, out_format, out_filename, callback) {
|
||||
|
||||
var gcol = options.gn;
|
||||
//var gcol = options.gn;
|
||||
var sql = options.sql;
|
||||
var skipfields = options.skipfields;
|
||||
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)
|
||||
sql = sql.replace(/;\s*$/, '');
|
||||
|
||||
Step (
|
||||
step (
|
||||
|
||||
function fetchColumns() {
|
||||
var colsql = 'SELECT * FROM (' + sql + ') as _cartodbsqlapi LIMIT 0';
|
||||
pg = new PSQL(dbopts);
|
||||
pg.query(colsql, this);
|
||||
},
|
||||
// jshint maxcomplexity:9
|
||||
function findSRS(err, result) {
|
||||
if (err) throw err;
|
||||
assert.ifError(err);
|
||||
|
||||
//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) {
|
||||
var field = result.fields[i];
|
||||
var k = field.name;
|
||||
if ( skipfields.indexOf(k) != -1 ) continue;
|
||||
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 ( skipfields.indexOf(k) !== -1 ) {
|
||||
continue;
|
||||
}
|
||||
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 ( ! geocol && pg.typeName(field.dataTypeID) == 'geometry' ) {
|
||||
geocol = k
|
||||
if ( ! geocol && pg.typeName(field.dataTypeID) === 'geometry' ) {
|
||||
geocol = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log(columns.join(','));
|
||||
|
||||
if ( ! needSRS || ! geocol ) return null;
|
||||
if ( ! needSRS || ! geocol ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var next = this;
|
||||
|
||||
@ -124,23 +135,18 @@ OgrFormat.prototype.toOGR = function(options, out_format, out_filename, callback
|
||||
|
||||
},
|
||||
function spawnDumper(err, srid, type) {
|
||||
if (err) throw err;
|
||||
assert.ifError(err);
|
||||
|
||||
var next = this;
|
||||
|
||||
var ogrsql = 'SELECT ' + columns.join(',')
|
||||
+ ' FROM (' + sql + ') as _cartodbsqlapi';
|
||||
var ogrsql = 'SELECT ' + columns.join(',') + ' FROM (' + sql + ') as _cartodbsqlapi';
|
||||
|
||||
var ogrargs = [
|
||||
'-f', out_format,
|
||||
'-lco', 'ENCODING=UTF-8',
|
||||
'-lco', 'LINEFORMAT=CRLF',
|
||||
out_filename,
|
||||
"PG:host=" + dbhost
|
||||
+ " port=" + dbport
|
||||
+ " user=" + dbuser
|
||||
+ " dbname=" + dbname
|
||||
+ " password=" + dbpass,
|
||||
"PG:host=" + dbhost + " port=" + dbport + " user=" + dbuser + " dbname=" + dbname + " password=" + dbpass,
|
||||
'-sql', ogrsql
|
||||
];
|
||||
|
||||
@ -171,7 +177,9 @@ console.log('ogr2ogr ' + _.map(ogrargs, function(x) { return "'" + x + "'"; }).j
|
||||
child.stderr.on('data', function(data) {
|
||||
data = data.toString(); // know of a faster way ?
|
||||
// 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);
|
||||
});
|
||||
|
||||
@ -204,7 +212,14 @@ OgrFormat.prototype.toOGR_SingleFile = function(options, fmt, callback) {
|
||||
var layername = options.filename;
|
||||
|
||||
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 dumpfile = outdirpath + ':cartodb-query.' + ext;
|
||||
|
||||
@ -214,7 +229,7 @@ OgrFormat.prototype.toOGR_SingleFile = function(options, fmt, callback) {
|
||||
};
|
||||
|
||||
OgrFormat.prototype.sendResponse = function(opts, callback) {
|
||||
var next = callback;
|
||||
//var next = callback;
|
||||
var reqKey = this.getKey(opts);
|
||||
var qElem = new ExportRequest(opts.sink, callback, opts.beforeSink);
|
||||
var baking = bakingExports[reqKey];
|
||||
@ -223,8 +238,10 @@ OgrFormat.prototype.sendResponse = function(opts, callback) {
|
||||
} else {
|
||||
baking = bakingExports[reqKey] = { req: [ qElem ] };
|
||||
this.generate(opts, function(err, dumpfile) {
|
||||
if ( opts.profiler ) opts.profiler.done('generate');
|
||||
Step (
|
||||
if ( opts.profiler ) {
|
||||
opts.profiler.done('generate');
|
||||
}
|
||||
step (
|
||||
function sendResults() {
|
||||
var nextPipe = function(finish) {
|
||||
var r = baking.req.shift();
|
||||
@ -234,28 +251,29 @@ OgrFormat.prototype.sendResponse = function(opts, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
if ( ! err ) nextPipe(this);
|
||||
else {
|
||||
if ( ! err ) {
|
||||
nextPipe(this);
|
||||
} else {
|
||||
_.each(baking.req, function(r) {
|
||||
r.cb(err);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
},
|
||||
function cleanup(err) {
|
||||
function cleanup(/*err*/) {
|
||||
delete bakingExports[reqKey];
|
||||
|
||||
// unlink dump file (sync to avoid race condition)
|
||||
console.log("removing", dumpfile);
|
||||
try { fs.unlinkSync(dumpfile); }
|
||||
catch (e) {
|
||||
if ( e.code != 'ENOENT' ) {
|
||||
if ( e.code !== 'ENOENT' ) {
|
||||
console.log("Could not unlink dumpfile " + dumpfile + ": " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -284,8 +302,10 @@ ExportRequest.prototype.sendFile = function (err, filename, callback) {
|
||||
if ( ! this.canceled ) {
|
||||
//console.log("Creating readable stream out of dumpfile");
|
||||
this.istream = fs.createReadStream(filename)
|
||||
.on('open', function(fd) {
|
||||
if ( that.beforeSink ) that.beforeSink();
|
||||
.on('open', function(/*fd*/) {
|
||||
if ( that.beforeSink ) {
|
||||
that.beforeSink();
|
||||
}
|
||||
that.istream.pipe(that.ostream);
|
||||
callback();
|
||||
})
|
||||
|
@ -1,5 +1,6 @@
|
||||
var Step = require('step'),
|
||||
PSQL = require('cartodb-psql');
|
||||
var step = require('step');
|
||||
var PSQL = require('cartodb-psql');
|
||||
var assert = require('assert');
|
||||
|
||||
function PostgresFormat(id) {
|
||||
this.id = id;
|
||||
@ -7,7 +8,7 @@ function PostgresFormat(id) {
|
||||
|
||||
PostgresFormat.prototype = {
|
||||
|
||||
getQuery: function(sql, options) {
|
||||
getQuery: function(sql/*, options*/) {
|
||||
return sql;
|
||||
},
|
||||
|
||||
@ -34,7 +35,9 @@ PostgresFormat.prototype.handleQueryRowWithSkipFields = function(row, 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++) {
|
||||
result.notices.push(msg[i]);
|
||||
}
|
||||
@ -48,7 +51,9 @@ PostgresFormat.prototype.handleQueryEnd = function(result) {
|
||||
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;
|
||||
|
||||
@ -58,14 +63,16 @@ PostgresFormat.prototype.handleQueryEnd = function(result) {
|
||||
var newfields = [];
|
||||
for ( var j=0; j<result.fields.length; ++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;
|
||||
}
|
||||
|
||||
var that = this;
|
||||
|
||||
Step (
|
||||
step (
|
||||
function packageResult() {
|
||||
if ( that.opts.abortChecker ) {
|
||||
that.opts.abortChecker('packageResult');
|
||||
@ -74,11 +81,13 @@ PostgresFormat.prototype.handleQueryEnd = function(result) {
|
||||
},
|
||||
function sendResults(err, out){
|
||||
|
||||
if (err) throw err;
|
||||
assert.ifError(err);
|
||||
|
||||
// return to browser
|
||||
if ( out ) {
|
||||
if ( that.opts.beforeSink ) that.opts.beforeSink();
|
||||
if ( that.opts.beforeSink ) {
|
||||
that.opts.beforeSink();
|
||||
}
|
||||
that.opts.sink.send(out);
|
||||
} else {
|
||||
console.error("No output from transform, doing nothing ?!");
|
||||
@ -117,7 +126,9 @@ PostgresFormat.prototype.sendResponse = function(opts, callback) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if ( that.opts.profiler ) that.opts.profiler.done('eventedQuery');
|
||||
if ( that.opts.profiler ) {
|
||||
that.opts.profiler.done('eventedQuery');
|
||||
}
|
||||
|
||||
if (that.hasSkipFields) {
|
||||
query.on('row', that.handleQueryRowWithSkipFields.bind(that));
|
||||
|
@ -1,8 +1,9 @@
|
||||
var crypto = require('crypto'),
|
||||
Step = require('step'),
|
||||
fs = require('fs'),
|
||||
spawn = require('child_process').spawn,
|
||||
ogr = require('./ogr');
|
||||
var step = require('step');
|
||||
var fs = require('fs');
|
||||
var spawn = require('child_process').spawn;
|
||||
var assert = require('assert');
|
||||
|
||||
var ogr = require('./ogr');
|
||||
|
||||
function ShpFormat() {
|
||||
}
|
||||
@ -42,16 +43,17 @@ ShpFormat.prototype.toSHP = function (options, callback) {
|
||||
// TODO: following tests:
|
||||
// - fetch query with no "the_geom" column
|
||||
|
||||
Step (
|
||||
step (
|
||||
function createOutDir() {
|
||||
fs.mkdir(outdirpath, 0777, this);
|
||||
},
|
||||
function spawnDumper(err) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
|
||||
fmtObj.toOGR(options, 'ESRI Shapefile', shapefile, this);
|
||||
},
|
||||
function doZip(err) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
|
||||
var next = this;
|
||||
|
||||
@ -82,21 +84,24 @@ ShpFormat.prototype.toSHP = function (options, callback) {
|
||||
if ( err ) {
|
||||
console.log("Unlinking " + fn + ": " + err);
|
||||
finish(err);
|
||||
} else {
|
||||
unlinkall(dir, files, finish);
|
||||
}
|
||||
else unlinkall(dir, files, finish)
|
||||
});
|
||||
};
|
||||
fs.readdir(outdirpath, function(err, files) {
|
||||
if ( err ) {
|
||||
if ( err.code != 'ENOENT' ) {
|
||||
if ( err.code !== 'ENOENT' ) {
|
||||
next(new Error([topError, err].join('\n')));
|
||||
} else {
|
||||
next(topError);
|
||||
}
|
||||
} else {
|
||||
unlinkall(outdirpath, files, function(err) {
|
||||
unlinkall(outdirpath, files, 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);
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,4 @@
|
||||
var pg = require('./pg'),
|
||||
_ = require('underscore');
|
||||
var pg = require('./pg');
|
||||
|
||||
var svg_width = 1024.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) {
|
||||
var gn = options.gn;
|
||||
var dp = options.dp;
|
||||
return 'WITH source AS ( ' + sql + '), extent AS ( '
|
||||
+ ' SELECT ST_Extent(' + gn + ') AS e FROM source '
|
||||
+ '), extent_info AS ( SELECT e, '
|
||||
+ 'st_xmin(e) as ex0, st_ymax(e) as ey0, '
|
||||
+ 'st_xmax(e)-st_xmin(e) as ew, '
|
||||
+ 'st_ymax(e)-st_ymin(e) as eh FROM extent )'
|
||||
+ ', trans AS ( SELECT CASE WHEN '
|
||||
+ 'eh = 0 THEN ' + svg_width
|
||||
+ '/ COALESCE(NULLIF(ew,0),' + svg_width +') WHEN '
|
||||
+ svg_ratio + ' <= (ew / eh) THEN ('
|
||||
+ svg_width + '/ew ) ELSE ('
|
||||
+ svg_height + '/eh ) END as s '
|
||||
+ ', ex0 as x0, ey0 as y0 FROM extent_info ) '
|
||||
+ 'SELECT st_TransScale(e, -x0, -y0, s, s)::box2d as '
|
||||
+ gn + '_box, ST_Dimension(' + gn + ') as ' + gn
|
||||
+ '_dimension, ST_AsSVG(ST_TransScale(' + gn + ', '
|
||||
+ '-x0, -y0, s, s), 0, ' + dp + ') as ' + gn
|
||||
//+ ', ex0, ey0, ew, eh, s ' // DEBUG ONLY
|
||||
+ ' FROM trans, extent_info, source'
|
||||
+ ' ORDER BY the_geom_dimension ASC';
|
||||
return 'WITH source AS ( ' + sql + '), extent AS ( ' +
|
||||
' SELECT ST_Extent(' + gn + ') AS e FROM source ' +
|
||||
'), extent_info AS ( SELECT e, ' +
|
||||
'st_xmin(e) as ex0, st_ymax(e) as ey0, ' +
|
||||
'st_xmax(e)-st_xmin(e) as ew, ' +
|
||||
'st_ymax(e)-st_ymin(e) as eh FROM extent )' +
|
||||
', trans AS ( SELECT CASE WHEN ' +
|
||||
'eh = 0 THEN ' + svg_width +
|
||||
'/ COALESCE(NULLIF(ew,0),' + svg_width +') WHEN ' +
|
||||
svg_ratio + ' <= (ew / eh) THEN (' +
|
||||
svg_width + '/ew ) ELSE (' +
|
||||
svg_height + '/eh ) END as s ' +
|
||||
', ex0 as x0, ey0 as y0 FROM extent_info ) ' +
|
||||
'SELECT st_TransScale(e, -x0, -y0, s, s)::box2d as ' +
|
||||
gn + '_box, ST_Dimension(' + gn + ') as ' + gn +
|
||||
'_dimension, ST_AsSVG(ST_TransScale(' + gn + ', ' +
|
||||
'-x0, -y0, s, s), 0, ' + dp + ') as ' + gn +
|
||||
//+ ', ex0, ey0, ew, eh, s ' // DEBUG ONLY +
|
||||
' FROM trans, extent_info, source' +
|
||||
' ORDER BY the_geom_dimension ASC';
|
||||
};
|
||||
|
||||
SvgFormat.prototype.startStreaming = function() {
|
||||
@ -72,14 +71,11 @@ SvgFormat.prototype.startStreaming = function() {
|
||||
this.bbox.ymax += growby;
|
||||
this.bbox.width = this.bbox.xmax - this.bbox.xmin;
|
||||
this.bbox.height = this.bbox.ymax - this.bbox.ymin;
|
||||
rootTag += 'viewBox="' + this.bbox.xmin + ' ' + (-this.bbox.ymax) + ' '
|
||||
+ this.bbox.width + ' ' + this.bbox.height + '" ';
|
||||
rootTag += 'viewBox="' + this.bbox.xmin + ' ' + (-this.bbox.ymax) + ' ' +
|
||||
this.bbox.width + ' ' + this.bbox.height + '" ';
|
||||
}
|
||||
rootTag += 'style="fill-opacity:' + fill_opacity
|
||||
+ '; stroke:' + stroke_color
|
||||
+ '; stroke-width:' + stroke_width
|
||||
+ '; fill:' + fill_color
|
||||
+ '" ';
|
||||
rootTag += 'style="fill-opacity:' + fill_opacity + '; stroke:' + stroke_color + '; ' +
|
||||
'stroke-width:' + stroke_width + '; fill:' + fill_color + '" ';
|
||||
rootTag += 'xmlns="http://www.w3.org/2000/svg" version="1.1">\n';
|
||||
|
||||
header.push(rootTag);
|
||||
@ -89,6 +85,7 @@ SvgFormat.prototype.startStreaming = function() {
|
||||
this._streamingStarted = true;
|
||||
};
|
||||
|
||||
// jshint maxcomplexity:11
|
||||
SvgFormat.prototype.handleQueryRow = function(row) {
|
||||
this.totalRows++;
|
||||
|
||||
@ -97,8 +94,11 @@ SvgFormat.prototype.handleQueryRow = function(row) {
|
||||
}
|
||||
|
||||
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'];
|
||||
// TODO: add an identifier, if any of "cartodb_id", "oid", "id", "gid" are found
|
||||
// TODO: add "class" attribute to help with styling ?
|
||||
@ -106,10 +106,11 @@ SvgFormat.prototype.handleQueryRow = function(row) {
|
||||
this.buffer += '<circle r="' + radius + '" ' + g + ' />\n';
|
||||
} else if ( gdims == '1' ) {
|
||||
// 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' ) {
|
||||
this.buffer += '<path d="' + g + '" />\n';
|
||||
}
|
||||
// jshint ignore:end
|
||||
|
||||
if ( ! this.bbox ) {
|
||||
// Parse layer extent: "BOX(x y, X Y)"
|
||||
|
@ -1,7 +1,7 @@
|
||||
var pg = require('./pg'),
|
||||
_ = require('underscore'),
|
||||
geojson = require('./geojson'),
|
||||
TopoJSON = require('topojson');
|
||||
var pg = require('./pg');
|
||||
var _ = require('underscore');
|
||||
var geojson = require('./geojson');
|
||||
var TopoJSON = require('topojson');
|
||||
|
||||
function TopoJsonFormat() {
|
||||
this.features = [];
|
||||
@ -19,7 +19,7 @@ TopoJsonFormat.prototype.handleQueryRow = function(row) {
|
||||
};
|
||||
_geojson.geometry = JSON.parse(row[this.opts.gn]);
|
||||
delete row[this.opts.gn];
|
||||
delete row["the_geom_webmercator"];
|
||||
delete row.the_geom_webmercator;
|
||||
_geojson.properties = row;
|
||||
this.features.push(_geojson);
|
||||
};
|
||||
@ -30,7 +30,9 @@ TopoJsonFormat.prototype.handleQueryEnd = function() {
|
||||
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, {
|
||||
"quantization": 1e4,
|
||||
|
@ -34,7 +34,9 @@ For logger.trace('one','two','three'):
|
||||
//
|
||||
// We only log error and higher errors
|
||||
//
|
||||
if ( loggingEvent.level.level < 40000 ) return;
|
||||
if ( loggingEvent.level.level < 40000 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
rollbar.reportMessage(loggingEvent.data);
|
||||
};
|
||||
|
@ -1,23 +1,19 @@
|
||||
var Step = require('step'),
|
||||
_ = require('underscore'),
|
||||
var step = require('step'),
|
||||
fs = require('fs');
|
||||
|
||||
function HealthCheck(metadataBackend, psqlClass) {
|
||||
function HealthCheck(metadataBackend) {
|
||||
this.metadataBackend = metadataBackend;
|
||||
this.psqlClass = psqlClass;
|
||||
}
|
||||
|
||||
module.exports = HealthCheck;
|
||||
|
||||
HealthCheck.prototype.check = function(username, query, callback) {
|
||||
var self = this,
|
||||
startTime,
|
||||
result = {
|
||||
var result = {
|
||||
redis: {},
|
||||
postgresql: {}
|
||||
};
|
||||
|
||||
Step(
|
||||
step(
|
||||
function getManualDisable() {
|
||||
fs.readFile(global.settings.disabled_file, this);
|
||||
},
|
||||
|
11
npm-shrinkwrap.json
generated
11
npm-shrinkwrap.json
generated
@ -143,8 +143,7 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1",
|
||||
"from": "inherits@~2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||
"from": "inherits@~2.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -156,9 +155,9 @@
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "2.5.0",
|
||||
"version": "2.5.2",
|
||||
"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": {
|
||||
"version": "0.0.7",
|
||||
@ -220,9 +219,9 @@
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.5.tgz",
|
||||
"dependencies": {
|
||||
"wordwrap": {
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.3",
|
||||
"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": {
|
||||
"redis": "0.7.1",
|
||||
"mocha": "~1.21.4",
|
||||
"jshint": "~2.6.0",
|
||||
"zipfile": "~0.5.0",
|
||||
"libxmljs": "~0.8.1"
|
||||
},
|
||||
"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": {
|
||||
"node": ">=0.8 <0.11",
|
||||
|
@ -1,40 +1,37 @@
|
||||
require('../helper');
|
||||
require('../support/assert');
|
||||
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
||||
, assert = require('assert')
|
||||
, tests = module.exports = {}
|
||||
, querystring = require('querystring');
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var assert = require('../support/assert');
|
||||
|
||||
suite('app.auth', function() {
|
||||
describe('app.auth', function() {
|
||||
|
||||
var scenarios = [
|
||||
{
|
||||
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')",
|
||||
statusCode: 200
|
||||
}
|
||||
,{
|
||||
},
|
||||
{
|
||||
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'",
|
||||
statusCode: 200
|
||||
}
|
||||
,{
|
||||
},
|
||||
{
|
||||
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')",
|
||||
statusCode: 401
|
||||
}
|
||||
,{
|
||||
},
|
||||
{
|
||||
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')",
|
||||
statusCode: 401
|
||||
}
|
||||
,{
|
||||
},
|
||||
{
|
||||
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')",
|
||||
statusCode: 401
|
||||
}
|
||||
,{
|
||||
},
|
||||
{
|
||||
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')",
|
||||
statusCode: 401
|
||||
@ -42,7 +39,7 @@ suite('app.auth', function() {
|
||||
];
|
||||
|
||||
scenarios.forEach(function(scenario) {
|
||||
test(scenario.desc, function(done) {
|
||||
it(scenario.desc, function(done) {
|
||||
assert.response(app, {
|
||||
// view prepare_db.sh to find public table name and structure
|
||||
url: scenario.url,
|
||||
|
@ -13,27 +13,21 @@
|
||||
*
|
||||
*/
|
||||
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')()
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, _ = require('underscore')
|
||||
, zipfile = require('zipfile')
|
||||
, fs = require('fs')
|
||||
, libxmljs = require('libxmljs')
|
||||
, Step = require('step')
|
||||
;
|
||||
|
||||
|
||||
suite('app.test', function() {
|
||||
describe('app.test', function() {
|
||||
|
||||
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_cache_control_persist = 'public,max-age=31536000';
|
||||
|
||||
test('GET /api/v1/version', function(done){
|
||||
it('GET /api/v1/version', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/version',
|
||||
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, {
|
||||
url: '/api/v1/sql',
|
||||
method: 'GET'
|
||||
@ -62,7 +56,7 @@ test('GET /api/v1/sql', function(done){
|
||||
});
|
||||
|
||||
// Test base_url setting
|
||||
test('GET /api/whatever/sql', function(done){
|
||||
it('GET /api/whatever/sql', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/whatever/sql?q=SELECT%201',
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
@ -75,7 +69,7 @@ test('GET /api/whatever/sql', function(done){
|
||||
});
|
||||
|
||||
// Test CORS headers with GET
|
||||
test('GET /api/whatever/sql', function(done){
|
||||
it('GET /api/whatever/sql', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/whatever/sql?q=SELECT%201',
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
@ -83,14 +77,16 @@ test('GET /api/whatever/sql', function(done){
|
||||
},{
|
||||
}, function(res) {
|
||||
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'], '*');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Test that OPTIONS does not run queries
|
||||
test('OPTIONS /api/x/sql', function(done){
|
||||
it('OPTIONS /api/x/sql', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/x/sql?q=syntax%20error',
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
@ -98,7 +94,9 @@ test('OPTIONS /api/x/sql', function(done){
|
||||
},{}, function(res) {
|
||||
assert.equal(res.statusCode, 200, 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'], '*');
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&database=cartodb_test_user_1_db',
|
||||
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, {
|
||||
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'},
|
||||
@ -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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
||||
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, {
|
||||
url: '/user/vizzuality/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
||||
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
|
||||
test('SELECT from user-specific database', function(done){
|
||||
it('SELECT from user-specific database', function(done){
|
||||
var backupDBHost = global.settings.db_host;
|
||||
global.settings.db_host = '6.6.6.6';
|
||||
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
|
||||
test('SELECT with user-specific password', function(done){
|
||||
it('SELECT with user-specific password', function(done){
|
||||
var backupDBUserPass = global.settings.db_user_pass;
|
||||
global.settings.db_user_pass = '<%= user_password %>';
|
||||
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){
|
||||
assert.response(app, {
|
||||
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("paging doesn't break x-cache-channel",
|
||||
it("paging doesn't break x-cache-channel",
|
||||
function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
@ -242,13 +240,14 @@ function(done){
|
||||
});
|
||||
|
||||
// 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 pr = [ [2,3], [0,4] ]; // page and rows
|
||||
var methods = [ 'GET', 'POST' ];
|
||||
var authorized = 0;
|
||||
var testing = 0;
|
||||
var method = 0;
|
||||
// jshint maxcomplexity:7
|
||||
var testNext = function() {
|
||||
if ( testing >= pr.length ) {
|
||||
if ( method+1 >= methods.length ) {
|
||||
@ -266,9 +265,8 @@ test("paging", function(done){
|
||||
}
|
||||
}
|
||||
var prcur = pr[testing++];
|
||||
console.log("Test " + testing + "/" + pr.length
|
||||
+ " method " + methods[method] + " "
|
||||
+ ( authorized ? "authenticated" : "" ) );
|
||||
console.log("Test " + testing + "/" + pr.length + " method " + methods[method] + " " +
|
||||
( authorized ? "authenticated" : "" ) );
|
||||
var page = prcur[0];
|
||||
var nrows = prcur[1];
|
||||
var data_obj = {
|
||||
@ -276,13 +274,15 @@ test("paging", function(done){
|
||||
rows_per_page: nrows,
|
||||
page: page
|
||||
};
|
||||
if ( authorized ) data_obj['api_key'] = '1234';
|
||||
if ( authorized ) {
|
||||
data_obj.api_key = '1234';
|
||||
}
|
||||
var data = querystring.stringify(data_obj);
|
||||
var req = {
|
||||
url: '/api/v1/sql',
|
||||
headers: {host: 'vizzuality.cartodb.com'}
|
||||
};
|
||||
if ( methods[method] == 'GET' ) {
|
||||
if ( methods[method] === 'GET' ) {
|
||||
req.method = 'GET';
|
||||
req.url += '?' + data;
|
||||
} else {
|
||||
@ -306,7 +306,7 @@ test("paging", function(done){
|
||||
});
|
||||
|
||||
// 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" +
|
||||
"SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(v)";
|
||||
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, {
|
||||
url: '/api/v1/sql',
|
||||
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, {
|
||||
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'},
|
||||
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, {
|
||||
url: "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4&database=cartodb_test_user_1_db",
|
||||
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, {
|
||||
url: "/api/v1/sql?q=INSERT%20INTO%20untitle_table_4%20(id)%20VALUES%20(1)",
|
||||
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
|
||||
//
|
||||
// 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, {
|
||||
// view prepare_db.sh to see where to set api_key
|
||||
url: "/api/v1/sql?api_key=1234&"
|
||||
+ querystring.stringify({q:
|
||||
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||
"INSERT INTO private_table(name) VALUES('noret1') UNION VALUES('noret2')"
|
||||
}),
|
||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||
@ -417,11 +417,10 @@ test('INSERT returns affected rows', function(done){
|
||||
// Check results from UPDATE
|
||||
//
|
||||
// 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, {
|
||||
// view prepare_db.sh to see where to set api_key
|
||||
url: "/api/v1/sql?api_key=1234&"
|
||||
+ querystring.stringify({q:
|
||||
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||
"UPDATE private_table SET name = upper(name) WHERE name in ('noret1', 'noret2')"
|
||||
}),
|
||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||
@ -443,11 +442,10 @@ test('UPDATE returns affected rows', function(done){
|
||||
// Check results from DELETE
|
||||
//
|
||||
// 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, {
|
||||
// view prepare_db.sh to see where to set api_key
|
||||
url: "/api/v1/sql?api_key=1234&"
|
||||
+ querystring.stringify({q:
|
||||
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||
"DELETE FROM private_table WHERE name in ('NORET1', 'NORET2')"
|
||||
}),
|
||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||
@ -469,11 +467,10 @@ test('DELETE returns affected rows', function(done){
|
||||
// Check results from INSERT .. RETURNING
|
||||
//
|
||||
// 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, {
|
||||
// view prepare_db.sh to see where to set api_key
|
||||
url: "/api/v1/sql?api_key=1234&"
|
||||
+ querystring.stringify({q:
|
||||
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||
"INSERT INTO private_table(name) VALUES('test') RETURNING upper(name), reverse(name)"
|
||||
}),
|
||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||
@ -494,11 +491,10 @@ test('INSERT with RETURNING returns all results', function(done){
|
||||
// Check results from UPDATE .. RETURNING
|
||||
//
|
||||
// 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, {
|
||||
// view prepare_db.sh to see where to set api_key
|
||||
url: "/api/v1/sql?api_key=1234&"
|
||||
+ querystring.stringify({q:
|
||||
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||
"UPDATE private_table SET name = 'tost' WHERE name = 'test' RETURNING upper(name), reverse(name)"
|
||||
}),
|
||||
headers: {host: 'vizzuality.localhost.lan:8080' },
|
||||
@ -519,11 +515,10 @@ test('UPDATE with RETURNING returns all results', function(done){
|
||||
// Check results from DELETE .. RETURNING
|
||||
//
|
||||
// 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, {
|
||||
// view prepare_db.sh to see where to set api_key
|
||||
url: "/api/v1/sql?api_key=1234&"
|
||||
+ querystring.stringify({q:
|
||||
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||
"DELETE FROM private_table WHERE name = 'tost' RETURNING name"
|
||||
}),
|
||||
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, {
|
||||
url: "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4",
|
||||
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
|
||||
//
|
||||
// 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, {
|
||||
// view prepare_db.sh to see where to set api_key
|
||||
url: "/api/v1/sql?api_key=1234&"
|
||||
+ querystring.stringify({q:
|
||||
url: "/api/v1/sql?api_key=1234&" + querystring.stringify({q:
|
||||
"SELECT min(updated_at) FROM private_table"
|
||||
}),
|
||||
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, {
|
||||
url: "/api/v1/sql?" + querystring.stringify({
|
||||
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
|
||||
test('SELECT INTO with paging ', function(done){
|
||||
it('SELECT INTO with paging ', function(done){
|
||||
var esc_tabname = 'test ""select into""'; // escaped ident
|
||||
Step(
|
||||
step(
|
||||
function select_into() {
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
@ -610,7 +604,7 @@ test('SELECT INTO with paging ', function(done){
|
||||
},{}, function(res) { next(null, 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);
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
@ -624,7 +618,7 @@ test('SELECT INTO with paging ', function(done){
|
||||
},{}, function(res) { next(null, res); });
|
||||
},
|
||||
function check_res_drop_table(err, res) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
||||
var out = JSON.parse(res.body);
|
||||
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 check_drop(err, res) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
||||
return null;
|
||||
},
|
||||
function finish(err) {
|
||||
done(err)
|
||||
done(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Test effects of COPY
|
||||
// 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, {
|
||||
url: "/api/v1/sql?" + querystring.stringify({
|
||||
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, {
|
||||
url: "/api/v1/sql?" + querystring.stringify({
|
||||
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, {
|
||||
url: "/api/v1/sql?" + querystring.stringify({
|
||||
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, {
|
||||
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
|
||||
}),
|
||||
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, {
|
||||
url: "/api/v1/sql?" + querystring.stringify({
|
||||
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);
|
||||
var pbody = JSON.parse(res.body);
|
||||
assert.equal(pbody.total_rows, 1);
|
||||
assert.equal(pbody.rows[0]['count'], 0);
|
||||
assert.equal(pbody.rows[0].count, 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('REINDEX TABLE with GET and auth', function(done){
|
||||
it('REINDEX TABLE with GET and auth', function(done){
|
||||
assert.response(app, {
|
||||
url: "/api/v1/sql?" + querystring.stringify({
|
||||
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, {
|
||||
url: "/api/v1/sql?" + querystring.stringify({
|
||||
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, {
|
||||
url: "/api/v1/sql?" + querystring.stringify({
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=unknown',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
||||
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, {
|
||||
url: '/api/v1/sql',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&filename=x',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&skipfields=the_geom_webmercator,cartodb_id,unexistant',
|
||||
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, {
|
||||
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'},
|
||||
method: 'GET'
|
||||
},{ }, 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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*gadfgadfg%20FROM%20untitle_table_4',
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
@ -1013,7 +1009,7 @@ var systemQueriesSuitesToTest = [
|
||||
|
||||
function testSystemQueries(description, queries, statusErrorCode, apiKey) {
|
||||
queries.forEach(function(query) {
|
||||
test('[' + description + '] query: ' + query, function(done) {
|
||||
it('[' + description + '] query: ' + query, function(done) {
|
||||
var queryStringParams = {q: query};
|
||||
if (!!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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
||||
headers: {host: 'vizzualinot.cartodb.com'},
|
||||
method: 'GET'
|
||||
}, {}, 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-disposition'], 'inline');
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
// 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, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({q:
|
||||
'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
|
||||
test('numeric arrays are rendered as such', function(done){
|
||||
it('numeric arrays are rendered as such', function(done){
|
||||
assert.response(app, {
|
||||
url: "/api/v1/sql?"
|
||||
+ querystring.stringify({q:
|
||||
url: "/api/v1/sql?" + querystring.stringify({q:
|
||||
"SELECT ARRAY[8.7,4.3]::numeric[] as x"
|
||||
}),
|
||||
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
|
||||
test('field names and types are exposed', function(done){
|
||||
it('field names and types are exposed', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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
|
||||
test('schema response takes skipfields into account', function(done){
|
||||
it('schema response takes skipfields into account', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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
|
||||
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, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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
|
||||
// test again (new mocha run) with a different TZ
|
||||
//
|
||||
test('timezone info in JSON output', function(done){
|
||||
Step(
|
||||
it('timezone info in JSON output', function(done){
|
||||
step(
|
||||
function testEuropeRomeExplicit() {
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
@ -1213,7 +1211,7 @@ test('timezone info in JSON output', function(done){
|
||||
});
|
||||
},
|
||||
function testEuropeRomeImplicit(err) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
@ -1233,7 +1231,7 @@ test('timezone info in JSON output', function(done){
|
||||
});
|
||||
},
|
||||
function testUTCExplicit(err) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
@ -1253,7 +1251,7 @@ test('timezone info in JSON output', function(done){
|
||||
});
|
||||
},
|
||||
function testUTCImplicit(err) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
@ -1280,13 +1278,15 @@ test('timezone info in JSON output', function(done){
|
||||
|
||||
// WARNING and NOTICE in JSON output
|
||||
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/104
|
||||
test('notice and warning info in JSON output', function(done){
|
||||
Step(
|
||||
it('notice and warning info in JSON output', function(done){
|
||||
step(
|
||||
function addRaiseFunction() {
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
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'
|
||||
}),
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
@ -1300,7 +1300,7 @@ test('notice and warning info in JSON output', function(done){
|
||||
});
|
||||
},
|
||||
function raiseNotice(err) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
@ -1321,7 +1321,7 @@ test('notice and warning info in JSON output', function(done){
|
||||
});
|
||||
},
|
||||
function raiseWarning(err) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
@ -1342,11 +1342,12 @@ test('notice and warning info in JSON output', function(done){
|
||||
});
|
||||
},
|
||||
function raiseBothWarningAndNotice(err) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
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'},
|
||||
method: 'GET'
|
||||
@ -1377,7 +1378,7 @@ test('notice and warning info in JSON output', function(done){
|
||||
},{ }, function(res) {
|
||||
try {
|
||||
assert.equal(res.statusCode, 200, res.body);
|
||||
var parsedBody = JSON.parse(res.body);
|
||||
JSON.parse(res.body);
|
||||
} catch (e) { err = new Error(err + ',' + e); }
|
||||
next(err);
|
||||
});
|
||||
@ -1391,7 +1392,7 @@ test('notice and warning info in JSON output', function(done){
|
||||
/**
|
||||
* 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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&database=cartodb_test_user_1_db',
|
||||
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['cache-control'], expected_cache_control);
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&callback=foo_jsonp',
|
||||
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, {
|
||||
url: "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4&callback=foo_jsonp",
|
||||
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) {
|
||||
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
||||
var didRunJsonCallback = false;
|
||||
// jshint ignore:start
|
||||
function foo_jsonp(body) {
|
||||
assert.deepEqual(body, {"error":["must be owner of relation untitle_table_4"]});
|
||||
didRunJsonCallback = true;
|
||||
}
|
||||
eval(res.body);
|
||||
// jshint ignore:end
|
||||
assert.ok(didRunJsonCallback);
|
||||
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, {
|
||||
url: "/api/v1/sql?q=select%20pg_sleep(2.1)%20as%20sleep",
|
||||
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(
|
||||
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;
|
||||
global.settings.db_max_row_size = 4;
|
||||
|
@ -1,15 +1,10 @@
|
||||
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')
|
||||
, net = require('net')
|
||||
;
|
||||
var assert = require('../support/assert');
|
||||
var step = require('step');
|
||||
var net = require('net');
|
||||
|
||||
var sql_server_port = 5556;
|
||||
var sql_server_port = 5540;
|
||||
var sql_server = net.createServer(function(c) {
|
||||
console.log('server connected');
|
||||
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);
|
||||
});
|
||||
|
||||
// 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);
|
||||
var db_host_backup = global.settings.db_host;
|
||||
var db_port_backup = global.settings.db_port;
|
||||
global.settings.db_host = 'localhost';
|
||||
global.settings.db_port = sql_server_port;
|
||||
var app = App();
|
||||
Step(
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
step(
|
||||
function sendQuery() {
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
@ -45,7 +40,7 @@ test('does not hang server', function(done){
|
||||
});
|
||||
},
|
||||
function checkResponse(err, res) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 500, res.statusCode + ': ' + res.body);
|
||||
var parsed = JSON.parse(res.body);
|
||||
assert.ok(parsed.error);
|
||||
@ -64,7 +59,7 @@ test('does not hang server', function(done){
|
||||
});
|
||||
},
|
||||
function checkResponse(err, res) {
|
||||
if ( err ) throw err;
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 500, res.statusCode + ': ' + res.body);
|
||||
var parsed = JSON.parse(res.body);
|
||||
assert.ok(parsed.error);
|
||||
@ -80,7 +75,7 @@ test('does not hang server', function(done){
|
||||
);
|
||||
});
|
||||
|
||||
suiteTeardown(function(done) {
|
||||
after(function(done) {
|
||||
try {
|
||||
sql_server.close(done);
|
||||
} catch (er) {
|
||||
|
@ -2,34 +2,16 @@ require('../../helper');
|
||||
require('../../support/assert');
|
||||
|
||||
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, _ = require('underscore')
|
||||
, zipfile = require('zipfile')
|
||||
, fs = require('fs')
|
||||
, libxmljs = require('libxmljs')
|
||||
, Step = require('step')
|
||||
;
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var assert = require('assert');
|
||||
var querystring = require('querystring');
|
||||
|
||||
// allow lots of emitters to be set to silence warning
|
||||
app.setMaxListeners(0);
|
||||
|
||||
suite('export.arraybuffer', function() {
|
||||
describe('export.arraybuffer', function() {
|
||||
|
||||
var expected_cache_control = 'no-cache,max-age=3600,must-revalidate,public';
|
||||
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){
|
||||
it('GET /api/v1/sql as arraybuffer ', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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'
|
||||
},{ }, function(res){
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
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, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
q: 'SELECT cartodb_id, the_geom FROM untitle_table_4',
|
||||
|
@ -2,21 +2,16 @@ require('../../helper');
|
||||
require('../../support/assert');
|
||||
|
||||
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, _ = require('underscore')
|
||||
, zipfile = require('zipfile')
|
||||
, fs = require('fs')
|
||||
, libxmljs = require('libxmljs')
|
||||
;
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var assert = require('assert');
|
||||
var querystring = require('querystring');
|
||||
|
||||
// allow lots of emitters to be set to silence warning
|
||||
app.setMaxListeners(0);
|
||||
|
||||
suite('export.csv', function() {
|
||||
describe('export.csv', function() {
|
||||
|
||||
test('CSV format', function(done){
|
||||
it('CSV format', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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, {
|
||||
url: '/api/v1/sql',
|
||||
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, {
|
||||
url: '/api/v1/sql',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=csv&filename=mycsv.csv',
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
@ -89,43 +84,45 @@ test('CSV format, custom filename', function(done){
|
||||
var ct = res.header('Content-Type');
|
||||
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 checkfields = {'name':1, 'cartodb_id':1, 'the_geom':1, 'the_geom_webmercator':1};
|
||||
for ( var f in checkfields ) {
|
||||
var idx = row0.indexOf(f);
|
||||
if ( checkfields[f] ) {
|
||||
assert.ok(idx != -1, "result does not include '" + f + "'");
|
||||
} else {
|
||||
assert.ok(idx == -1, "result includes '" + f + "' ("+idx+")");
|
||||
}
|
||||
}
|
||||
var checkFields = { name: true, cartodb_id: true, the_geom: true, the_geom_webmercator: true };
|
||||
Object.keys(checkFields).forEach(function(f) {
|
||||
var idx = row0.indexOf(f);
|
||||
if ( checkFields[f] ) {
|
||||
assert.ok(idx !== -1, "result does not include '" + f + "'");
|
||||
} else {
|
||||
assert.ok(idx === -1, "result includes '" + f + "' ("+idx+")");
|
||||
}
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('skipfields controls fields included in CSV output', function(done){
|
||||
it('skipfields controls fields included in CSV output', function(done){
|
||||
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'},
|
||||
method: 'GET'
|
||||
},{ }, function(res){
|
||||
assert.equal(res.statusCode, 200, res.body);
|
||||
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};
|
||||
for ( var f in checkfields ) {
|
||||
var idx = row0.indexOf(f);
|
||||
if ( checkfields[f] ) {
|
||||
assert.ok(idx != -1, "result does not include '" + f + "'");
|
||||
} else {
|
||||
assert.ok(idx == -1, "result includes '" + f + "' ("+idx+")");
|
||||
}
|
||||
}
|
||||
var checkFields = { name: true, cartodb_id: false, the_geom: true, the_geom_webmercator: true };
|
||||
Object.keys(checkFields).forEach(function(f) {
|
||||
var idx = row0.indexOf(f);
|
||||
if ( checkFields[f] ) {
|
||||
assert.ok(idx !== -1, "result does not include '" + f + "'");
|
||||
} else {
|
||||
assert.ok(idx === -1, "result includes '" + f + "' ("+idx+")");
|
||||
}
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('GET /api/v1/sql as csv', function(done){
|
||||
it('GET /api/v1/sql as csv', function(done){
|
||||
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'},
|
||||
method: 'GET'
|
||||
},{ }, 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
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20true%20WHERE%20false&format=csv',
|
||||
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');
|
||||
assert.ok(obtained_lines.length <= 2, // may or may not have an header
|
||||
// See http://trac.osgeo.org/gdal/ticket/5234
|
||||
'Too many lines in output (' + obtained_lines.length + '): '
|
||||
+ obtained_lines.join('\n'));
|
||||
'Too many lines in output (' + obtained_lines.length + '): ' + obtained_lines.join('\n'));
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20cartodb_id,%20address%20FROM%20untitle_table_4%20LIMIT%201&format=csv',
|
||||
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 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) {
|
||||
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?q=SELECT%20cartodb_id,%20address%20FROM%20untitle_table_4%20LIMIT%201&format=csv',
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
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';
|
||||
assert.equal(res.body, expected);
|
||||
if ( ! --waiting ) done();
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{
|
||||
url: '/api/v1/sql?q=SELECT%20cartodb_id,%20address%20FROM%20untitle_table_4%20LIMIT%201&format=csv',
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
method: 'GET'
|
||||
},
|
||||
{
|
||||
status: 200
|
||||
},
|
||||
validate
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,15 +1,8 @@
|
||||
|
||||
require('../../helper');
|
||||
require('../../support/assert');
|
||||
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, _ = require('underscore')
|
||||
, zipfile = require('zipfile')
|
||||
, fs = require('fs')
|
||||
, libxmljs = require('libxmljs')
|
||||
;
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var assert = require('../../support/assert');
|
||||
var querystring = require('querystring');
|
||||
|
||||
// allow lots of emitters to be set to silence warning
|
||||
// TODO: check if still needed ...
|
||||
@ -18,17 +11,18 @@ app.setMaxListeners(0);
|
||||
// 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
|
||||
if (tmp.indexOf(dec_sep)>-1) {
|
||||
return tmp.length - tmp.indexOf(dec_sep) - 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
suite('export.geojson', function() {
|
||||
describe('export.geojson', function() {
|
||||
|
||||
// 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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
||||
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, {
|
||||
url: '/api/v1/sql',
|
||||
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, {
|
||||
url: '/api/v1/sql?format=csv&q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson&filename=x',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson&skipfields=unexistant,cartodb_id',
|
||||
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, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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'},
|
||||
method: 'GET'
|
||||
},{ }, function(res){
|
||||
console.log(res);
|
||||
assert.equal(res.statusCode, 400, res.body);
|
||||
var geoJson = JSON.parse(res.body);
|
||||
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, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
q: "SELECT 1 as gid, null::geometry as the_geom limit 0",
|
||||
|
@ -1,22 +1,16 @@
|
||||
require('../../helper');
|
||||
require('../../support/assert');
|
||||
|
||||
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, _ = require('underscore')
|
||||
, zipfile = require('zipfile')
|
||||
, fs = require('fs')
|
||||
, libxmljs = require('libxmljs')
|
||||
, http = require('http')
|
||||
, server_utils = require('../../support/server_utils')
|
||||
;
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var assert = require('../../support/assert');
|
||||
var querystring = require('querystring');
|
||||
var libxmljs = require('libxmljs');
|
||||
var http = require('http');
|
||||
var server_utils = require('../../support/server_utils');
|
||||
|
||||
// allow lots of emitters to be set to silence warning
|
||||
app.setMaxListeners(0);
|
||||
|
||||
suite('export.kml', function() {
|
||||
describe('export.kml', function() {
|
||||
|
||||
// Check if an attribute is in the KML output
|
||||
//
|
||||
@ -34,15 +28,21 @@ var hasAttribute = function(kml, att) {
|
||||
var xpath;
|
||||
|
||||
xpath = "//SimpleField[@name='" + att + "']";
|
||||
if ( doc.get(xpath) ) return true;
|
||||
if ( doc.get(xpath) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
xpath = "//Placemark/" + att;
|
||||
if ( doc.get(xpath) ) return true;
|
||||
if ( doc.get(xpath) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var lcatt = att.toLowerCase();
|
||||
if ( lcatt == 'name' || lcatt == 'description' ) {
|
||||
if ( lcatt === 'name' || lcatt === 'description' ) {
|
||||
xpath = "//Placemark/" + lcatt;
|
||||
if ( doc.get(xpath) ) return true;
|
||||
if ( doc.get(xpath) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//if ( lowerkml.indexOf('simplefield name="'+ loweratt + '"') != -1 ) return true;
|
||||
@ -59,13 +59,19 @@ var extractCoordinates = function(kml) {
|
||||
|
||||
var doc = libxmljs.parseXmlString(kml);
|
||||
//console.log("doc: " + doc);
|
||||
if ( ! doc ) return;
|
||||
if ( ! doc ) {
|
||||
return;
|
||||
}
|
||||
var coo = doc.get("//coordinates");
|
||||
//console.log("coo: " + coo);
|
||||
if ( ! coo ) return;
|
||||
if ( ! coo ) {
|
||||
return;
|
||||
}
|
||||
coo = coo.text();
|
||||
//console.log("coo: " + coo);
|
||||
if ( ! coo ) return;
|
||||
if ( ! coo ) {
|
||||
return;
|
||||
}
|
||||
coo = coo.split(' ');
|
||||
//console.log("coo: " + coo);
|
||||
for (var i=0; i<coo.length; ++i) {
|
||||
@ -84,19 +90,25 @@ var extractFolderName = function(kml) {
|
||||
|
||||
var doc = libxmljs.parseXmlString(kml);
|
||||
//console.log("doc: " + doc);
|
||||
if ( ! doc ) return;
|
||||
if ( ! doc ) {
|
||||
return;
|
||||
}
|
||||
var coo = doc.get("//Document/Folder/name");
|
||||
//console.log("coo: " + coo);
|
||||
if ( ! coo ) return;
|
||||
if ( ! coo ) {
|
||||
return;
|
||||
}
|
||||
coo = coo.text();
|
||||
//console.log("coo: " + coo);
|
||||
if ( ! coo ) return;
|
||||
if ( ! coo ) {
|
||||
return;
|
||||
}
|
||||
return coo;
|
||||
};
|
||||
|
||||
// KML tests
|
||||
|
||||
test('KML format, unauthenticated', function(done){
|
||||
it('KML format, unauthenticated', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml',
|
||||
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, {
|
||||
url: '/api/v1/sql',
|
||||
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, {
|
||||
url: '/api/v1/sql',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml&skipfields=address,cartodb_id',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml&filename=kmltest',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=kml&api_key=1234',
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
@ -205,15 +217,42 @@ 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({
|
||||
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',
|
||||
filename: 'multi'
|
||||
});
|
||||
|
||||
var concurrency = 4;
|
||||
var waiting = concurrency;
|
||||
|
||||
function onResponse(res) {
|
||||
//console.log("Response started");
|
||||
res.body = '';
|
||||
//res.setEncoding('binary');
|
||||
res.on('data', function(chunk){ res.body += chunk; });
|
||||
res.on('end', function(){
|
||||
//console.log("Response ended");
|
||||
assert.equal(res.statusCode, 200, res.body);
|
||||
assert.ok(res.body);
|
||||
var snippet = res.body.substr(0, 5);
|
||||
assert.equal(snippet, "<?xml");
|
||||
var cd = res.headers['content-disposition'];
|
||||
assert.equal(true, /^attachment/.test(cd), 'KML is not disposed as attachment: ' + cd);
|
||||
assert.equal(true, /filename=multi.kml/gi.test(cd), 'Unexpected KML filename: ' + cd);
|
||||
if ( ! --waiting ) {
|
||||
app.close();
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onError(err) {
|
||||
console.log("Response error" + err);
|
||||
}
|
||||
|
||||
server_utils.startOnNextPort(app, function() {
|
||||
var port = app.address().port;
|
||||
//console.log("Listening on port " + port);
|
||||
@ -225,34 +264,16 @@ test('KML format, unauthenticated, concurrent requests', function(done){
|
||||
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");
|
||||
res.body = '';
|
||||
//res.setEncoding('binary');
|
||||
res.on('data', function(chunk){ res.body += chunk; });
|
||||
res.on('end', function(){
|
||||
//console.log("Response ended");
|
||||
assert.equal(res.statusCode, 200, res.body);
|
||||
assert.ok(res.body);
|
||||
var snippet = res.body.substr(0, 5);
|
||||
assert.equal(snippet, "<?xml");
|
||||
var cd = res.headers['content-disposition'];
|
||||
assert.equal(true, /^attachment/.test(cd), 'KML is not disposed as attachment: ' + cd);
|
||||
assert.equal(true, /filename=multi.kml/gi.test(cd), 'Unexpected KML filename: ' + cd);
|
||||
if ( ! --waiting ) {
|
||||
app.close();
|
||||
done();
|
||||
}
|
||||
});
|
||||
}).on('error', function(err) {
|
||||
console.log("Response error" + err);
|
||||
}).end();
|
||||
})
|
||||
.on('response', onResponse)
|
||||
.on('error', onError)
|
||||
.end();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 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, {
|
||||
url: '/api/v1/sql?q=SELECT%20true%20WHERE%20false&format=kml',
|
||||
headers: {host: 'vizzuality.cartodb.com'},
|
||||
@ -260,7 +281,10 @@ test('GET /api/v1/sql as kml with no rows', function(done){
|
||||
},{ }, function(res){
|
||||
assert.equal(res.statusCode, 200, res.body);
|
||||
// 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,'');
|
||||
assert.ok(body.match(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
|
||||
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, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
q: 'SELECT true WHERE false;',
|
||||
@ -280,7 +304,10 @@ test('GET /api/v1/sql as kml with ending semicolon', function(done){
|
||||
},{ }, function(res){
|
||||
assert.equal(res.statusCode, 200, res.body);
|
||||
// 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,'');
|
||||
assert.ok(body.match(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
|
||||
test('check point coordinates, unauthenticated', function(done){
|
||||
it('check point coordinates, unauthenticated', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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
|
||||
test('check point coordinates, authenticated', function(done){
|
||||
it('check point coordinates, authenticated', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?' + querystring.stringify({
|
||||
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,
|
||||
seriesLimit = 200,
|
||||
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,
|
||||
seriesLimit = 200,
|
||||
expectedRows = numberOfRowsInPrivateTable * seriesLimit;
|
||||
|
@ -1,24 +1,20 @@
|
||||
require('../../helper');
|
||||
require('../../support/assert');
|
||||
|
||||
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, _ = require('underscore')
|
||||
, zipfile = require('zipfile')
|
||||
, fs = require('fs')
|
||||
, libxmljs = require('libxmljs')
|
||||
;
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var assert = require('../../support/assert');
|
||||
var querystring = require('querystring');
|
||||
var _ = require('underscore');
|
||||
var zipfile = require('zipfile');
|
||||
var fs = require('fs');
|
||||
|
||||
// allow lots of emitters to be set to silence warning
|
||||
app.setMaxListeners(0);
|
||||
|
||||
suite('export.shapefile', function() {
|
||||
describe('export.shapefile', function() {
|
||||
|
||||
// SHP tests
|
||||
|
||||
test('SHP format, unauthenticated', function(done){
|
||||
it('SHP format, unauthenticated', function(done){
|
||||
assert.response(app, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp',
|
||||
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));
|
||||
var tmpfile = '/tmp/myshape.zip';
|
||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||
if (err) { done(err); return }
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
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.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, {
|
||||
url: '/api/v1/sql',
|
||||
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, {
|
||||
url: '/api/v1/sql',
|
||||
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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp&filename=myshape',
|
||||
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));
|
||||
var tmpfile = '/tmp/myshape.zip';
|
||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||
if (err) { done(err); return }
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
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.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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp&filename=b;"%20()[]a',
|
||||
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);
|
||||
var tmpfile = '/tmp/myshape.zip';
|
||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||
if (err) { done(err); return }
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
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 + '.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, {
|
||||
url: '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4%20LIMIT%201&format=shp&api_key=1234',
|
||||
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));
|
||||
var tmpfile = '/tmp/myshape.zip';
|
||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||
if (err) { done(err); return }
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
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.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
|
||||
test('SHP format, unauthenticated, with utf8 data', function(done){
|
||||
it('SHP format, unauthenticated, with utf8 data', function(done){
|
||||
var query = querystring.stringify({
|
||||
q: "SELECT '♥♦♣♠' as f, st_makepoint(0,0,4326) as the_geom",
|
||||
format: 'shp',
|
||||
@ -167,7 +171,9 @@ test('SHP format, unauthenticated, with utf8 data', function(done){
|
||||
assert.equal(res.statusCode, 200, res.body);
|
||||
var tmpfile = '/tmp/myshape.zip';
|
||||
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 buffer = zf.readFileSync('myshape.dbf');
|
||||
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
|
||||
test('mixed type geometry', function(done){
|
||||
it('mixed type geometry', function(done){
|
||||
var query = querystring.stringify({
|
||||
q: "SELECT 'POINT(0 0)'::geometry as g UNION ALL "
|
||||
+ "SELECT 'LINESTRING(0 0, 1 0)'::geometry",
|
||||
q: "SELECT 'POINT(0 0)'::geometry as g UNION ALL SELECT 'LINESTRING(0 0, 1 0)'::geometry",
|
||||
format: 'shp'
|
||||
});
|
||||
assert.response(app, {
|
||||
@ -194,19 +199,19 @@ test('mixed type geometry', function(done){
|
||||
assert.deepEqual(res.headers['content-disposition'], 'inline');
|
||||
assert.equal(res.statusCode, 400, res.statusCode + ': ' +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);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// 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({
|
||||
q: "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",
|
||||
q: [
|
||||
"SELECT 'POINT(0 0)'::geometry as g, 1 as a_very_very_very_long_field_name",
|
||||
"SELECT 'LINESTRING(0 0, 1 0)'::geometry, 2"
|
||||
].join(" UNION ALL "),
|
||||
format: 'shp'
|
||||
});
|
||||
assert.response(app, {
|
||||
@ -219,13 +224,13 @@ test('errors are not confused with warnings', function(done){
|
||||
assert.deepEqual(res.headers['content-disposition'], 'inline');
|
||||
assert.equal(res.statusCode, 400, res.statusCode + ': ' +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);
|
||||
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({
|
||||
q: "SELECT 111 as skipme, 222 as keepme, 'POINT(0 0)'::geometry as g",
|
||||
format: 'shp',
|
||||
@ -241,7 +246,9 @@ test('skipfields controls fields included in SHP output', function(done){
|
||||
assert.equal(res.statusCode, 200, res.body);
|
||||
var tmpfile = '/tmp/myshape.zip';
|
||||
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 buffer = zf.readFileSync('myshape.dbf');
|
||||
fs.unlinkSync(tmpfile);
|
||||
@ -251,37 +258,48 @@ 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 waiting = concurrency;
|
||||
function validate(res){
|
||||
var cd = res.header('Content-Disposition');
|
||||
assert.equal(true, /^attachment/.test(cd), 'SHP is not disposed as attachment: ' + cd);
|
||||
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
||||
var tmpfile = '/tmp/myshape.zip';
|
||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
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.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
||||
assert.ok(_.contains(zf.names, 'cartodb-query.dbf'), 'SHP zipfile does not contain .dbf: ' + zf.names);
|
||||
assert.ok(_.contains(zf.names, 'cartodb-query.prj'), 'SHP zipfile does not contain .prj: ' + zf.names);
|
||||
// TODO: check DBF contents
|
||||
fs.unlinkSync(tmpfile);
|
||||
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'
|
||||
},{ }, function(res){
|
||||
assert.equal(res.statusCode, 200, res.body);
|
||||
var cd = res.header('Content-Disposition');
|
||||
assert.equal(true, /^attachment/.test(cd), 'SHP is not disposed as attachment: ' + cd);
|
||||
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
||||
var tmpfile = '/tmp/myshape.zip';
|
||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||
if (err) { done(err); return }
|
||||
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.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
||||
assert.ok(_.contains(zf.names, 'cartodb-query.dbf'), 'SHP zipfile does not contain .dbf: ' + zf.names);
|
||||
assert.ok(_.contains(zf.names, 'cartodb-query.prj'), 'SHP zipfile does not contain .prj: ' + zf.names);
|
||||
// TODO: check DBF contents
|
||||
fs.unlinkSync(tmpfile);
|
||||
if ( ! --waiting ) done();
|
||||
});
|
||||
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
|
||||
test('point with null first', function(done){
|
||||
it('point with null first', function(done){
|
||||
var query = querystring.stringify({
|
||||
q: "SELECT null::geometry as g UNION ALL SELECT 'SRID=4326;POINT(0 0)'::geometry",
|
||||
format: 'shp'
|
||||
@ -297,7 +315,9 @@ test('point with null first', function(done){
|
||||
assert.equal(true, /filename=cartodb-query.zip/gi.test(cd));
|
||||
var tmpfile = '/tmp/myshape.zip';
|
||||
var err = fs.writeFileSync(tmpfile, res.body, 'binary');
|
||||
if (err) { done(err); return }
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
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.shx'), 'SHP zipfile does not contain .shx: ' + zf.names);
|
||||
|
@ -1,22 +1,15 @@
|
||||
require('../../helper');
|
||||
require('../../support/assert');
|
||||
|
||||
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, _ = require('underscore')
|
||||
, zipfile = require('zipfile')
|
||||
, fs = require('fs')
|
||||
, libxmljs = require('libxmljs')
|
||||
;
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var assert = require('../../support/assert');
|
||||
var querystring = require('querystring');
|
||||
|
||||
// allow lots of emitters to be set to silence warning
|
||||
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({
|
||||
q: "SELECT 1 as cartodb_id, ST_MakeLine(ST_MakePoint(10, 10), ST_MakePoint(1034, 778)) AS the_geom ",
|
||||
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({
|
||||
q: "SELECT 1 as cartodb_id, ST_MakeLine(ST_MakePoint(10, 10), ST_MakePoint(1034, 778)) AS the_geom ",
|
||||
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({
|
||||
q: "SELECT 1 as cartodb_id, ST_MakeLine(ST_MakePoint(10, 10), ST_MakePoint(1034, 778)) AS the_geom ",
|
||||
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({
|
||||
q: "SELECT 1 as cartodb_id, ST_MakePoint(5000, -54) AS the_geom ",
|
||||
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 = {
|
||||
q: "SELECT 1 as cartodb_id, 'LINESTRING(0 0, 1024 768, 500.123456 600.98765432)'::geometry AS the_geom ",
|
||||
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
|
||||
// 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({
|
||||
q: "SELECT 1 as cartodb_id, ST_MakePoint(5000, -54) AS the_geom ",
|
||||
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({
|
||||
q: "SELECT 1 as cartodb_id, ST_MakePoint(5000, -54) AS something_else ",
|
||||
format: "svg"
|
||||
|
@ -1,21 +1,15 @@
|
||||
require('../../helper');
|
||||
require('../../support/assert');
|
||||
|
||||
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, _ = require('underscore')
|
||||
, zipfile = require('zipfile')
|
||||
, fs = require('fs')
|
||||
, libxmljs = require('libxmljs')
|
||||
;
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var assert = require('../../support/assert');
|
||||
var querystring = require('querystring');
|
||||
var _ = require('underscore');
|
||||
|
||||
// allow lots of emitters to be set to silence warning
|
||||
app.setMaxListeners(0);
|
||||
|
||||
|
||||
suite('export.topojson', function() {
|
||||
describe('export.topojson', function() {
|
||||
|
||||
// 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,
|
||||
getRequest(
|
||||
"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 */
|
||||
var props = obj.properties;
|
||||
assert.equal(_.keys(props).length, 2); // gid, name
|
||||
assert.equal(props['gid'], 1);
|
||||
assert.equal(props['name'], 'U');
|
||||
assert.equal(props.gid, 1);
|
||||
assert.equal(props.name, 'U');
|
||||
|
||||
obj = topojson.objects[1];
|
||||
//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 */
|
||||
props = obj.properties;
|
||||
assert.equal(_.keys(props).length, 2); // gid, name
|
||||
assert.equal(props['gid'], 2);
|
||||
assert.equal(props['name'], 'D');
|
||||
assert.equal(props.gid, 2);
|
||||
assert.equal(props.name, 'D');
|
||||
|
||||
// Check 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(
|
||||
"SELECT 1 as gid, 'U' as name, 'POLYGON((-5 0,5 0,0 5,-5 0))'::geometry as the_geom " +
|
||||
" UNION ALL " +
|
||||
@ -185,8 +179,8 @@ test('null geometries', function(done){
|
||||
assert.equal(shell[0], 0); /* non-shared arc */
|
||||
var props = obj.properties;
|
||||
assert.equal(_.keys(props).length, 2); // gid, name
|
||||
assert.equal(props['gid'], 1);
|
||||
assert.equal(props['name'], 'U');
|
||||
assert.equal(props.gid, 1);
|
||||
assert.equal(props.name, 'U');
|
||||
|
||||
// Check 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,
|
||||
getRequest(
|
||||
"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(
|
||||
app,
|
||||
getRequest(
|
||||
@ -233,10 +227,12 @@ test('null geometries', function(done){
|
||||
function(res) {
|
||||
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
|
||||
var didRunJsonCallback = false;
|
||||
// jshint ignore:start
|
||||
function foo_jsonp(body) {
|
||||
didRunJsonCallback = true;
|
||||
}
|
||||
eval(res.body);
|
||||
// jshint ignore:end
|
||||
assert.ok(didRunJsonCallback);
|
||||
done();
|
||||
}
|
||||
|
@ -1,14 +1,8 @@
|
||||
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')
|
||||
, net = require('net')
|
||||
, http = require('http')
|
||||
;
|
||||
var assert = require('../support/assert');
|
||||
var step = require('step');
|
||||
var net = require('net');
|
||||
|
||||
var sql_server_data_handler;
|
||||
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);
|
||||
});
|
||||
|
||||
// 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);
|
||||
var db_host_backup = global.settings.db_host;
|
||||
var db_port_backup = global.settings.db_port;
|
||||
global.settings.db_host = 'localhost';
|
||||
global.settings.db_port = sql_server_port;
|
||||
var app = App();
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var timeout;
|
||||
Step(
|
||||
step(
|
||||
function sendQuery() {
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
@ -50,7 +44,7 @@ test('aborts request', function(done){
|
||||
next(err, res);
|
||||
});
|
||||
},
|
||||
function checkResponse(err, res) {
|
||||
function checkResponse(err/*, res*/) {
|
||||
assert(err); // expect timeout
|
||||
assert.ok((''+err).match(/socket/), err);
|
||||
sql_server_data_handler = this;
|
||||
@ -74,7 +68,7 @@ test('aborts request', function(done){
|
||||
);
|
||||
});
|
||||
|
||||
suiteTeardown(function(done) {
|
||||
after(function(done) {
|
||||
try {
|
||||
sql_server.close(done);
|
||||
} catch (er) {
|
||||
|
@ -1,12 +1,10 @@
|
||||
require('../helper');
|
||||
require('../support/assert');
|
||||
|
||||
var assert = require('assert'),
|
||||
App = require(global.settings.app_root + '/app/controllers/app');
|
||||
var assert = require('assert');
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
|
||||
var app = App();
|
||||
|
||||
suite('health checks', function() {
|
||||
describe('health checks', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
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;
|
||||
|
||||
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,
|
||||
healthCheckRequest,
|
||||
{
|
||||
|
@ -13,25 +13,21 @@
|
||||
*
|
||||
*/
|
||||
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
|
||||
test('after configured milliseconds', function(done){
|
||||
it('after configured milliseconds', function(done){
|
||||
var testTimeout = 10;
|
||||
//console.log("settings:"); console.dir(global.settings);
|
||||
var timeoutBackup = global.settings.node_socket_timeout;
|
||||
global.settings.node_socket_timeout = testTimeout;
|
||||
var app = App();
|
||||
Step(
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
step(
|
||||
function sendLongQuery() {
|
||||
var next = this;
|
||||
assert.response(app, {
|
||||
@ -42,7 +38,7 @@ test('after configured milliseconds', function(done){
|
||||
next(err, res);
|
||||
});
|
||||
},
|
||||
function checkResponse(err, res) {
|
||||
function checkResponse(err/*, res*/) {
|
||||
assert.ok(err);
|
||||
assert.ok(err.message.match(/hang up/), err);
|
||||
return null;
|
||||
|
@ -1,24 +1,23 @@
|
||||
require('../helper');
|
||||
require('../support/assert');
|
||||
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')()
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, _ = require('underscore')
|
||||
;
|
||||
var app = require(global.settings.app_root + '/app/controllers/app')();
|
||||
var assert = require('../support/assert');
|
||||
var querystring = require('querystring');
|
||||
var _ = require('underscore');
|
||||
|
||||
// allow lots of emitters to be set to silence warning
|
||||
app.setMaxListeners(0);
|
||||
|
||||
suite('x_cache_channel', function() {
|
||||
describe('x_cache_channel', function() {
|
||||
|
||||
assert.contains = function(ary, elem) {
|
||||
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({
|
||||
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
|
||||
});
|
||||
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({
|
||||
q: "SELECT * FROM untitle_table_4; SELECT * FROM private_table",
|
||||
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({
|
||||
q: "BEGIN; SELECT * FROM untitle_table_4; COMMIT; BEGIN; SELECT * FROM private_table; COMMIT;",
|
||||
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({
|
||||
q: "BEGIN; SELECT * FROM untitle_table_4",
|
||||
api_key: 1234
|
||||
|
@ -1,11 +1,9 @@
|
||||
require('../helper');
|
||||
|
||||
var _ = require('underscore')
|
||||
, ApikeyAuth = require('../../app/auth/apikey')
|
||||
, assert = require('assert')
|
||||
;
|
||||
var ApikeyAuth = require('../../app/auth/apikey');
|
||||
var assert = require('assert');
|
||||
|
||||
suite('has credentials', function() {
|
||||
describe('has credentials', function() {
|
||||
|
||||
var noCredentialsRequests = [
|
||||
{
|
||||
@ -35,8 +33,8 @@ suite('has credentials', function() {
|
||||
];
|
||||
|
||||
noCredentialsRequests.forEach(function(request) {
|
||||
test('has no credentials if ' + request.des, function() {
|
||||
testCredentials(request.req, false)
|
||||
it('has no credentials if ' + request.des, function() {
|
||||
testCredentials(request.req, false);
|
||||
});
|
||||
});
|
||||
|
||||
@ -60,8 +58,8 @@ suite('has credentials', function() {
|
||||
];
|
||||
|
||||
credentialsRequests.forEach(function(request) {
|
||||
test('has credentials if ' + request.des, function() {
|
||||
testCredentials(request.req, true)
|
||||
it('has credentials if ' + request.des, function() {
|
||||
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);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
require('../helper')
|
||||
require('../helper');
|
||||
|
||||
var assert = require('assert'),
|
||||
_ = require('underscore'),
|
||||
HealthCheck = require('../../app/monitoring/health_check');
|
||||
var assert = require('assert');
|
||||
var HealthCheck = require('../../app/monitoring/health_check');
|
||||
|
||||
var metadataBackend = {};
|
||||
|
||||
@ -12,34 +11,34 @@ function PSQL(dbParams) {
|
||||
|
||||
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 readFileFn = fs.readFile;
|
||||
fs.readFile = function(filename, callback) {
|
||||
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.http_status, 503);
|
||||
done();
|
||||
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 readFileFn = fs.readFile;
|
||||
fs.readFile = function(filename, callback) {
|
||||
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);
|
||||
done();
|
||||
fs.readFile = readFileFn;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,30 +1,30 @@
|
||||
require('../../helper');
|
||||
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() {
|
||||
var b = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4])
|
||||
it('calculate size for basic types', function() {
|
||||
var b = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4]);
|
||||
assert.equal(4*2, b.getDataSize());
|
||||
|
||||
b = new ArrayBufferSer(ArrayBufferSer.INT8, [1,2,3,4])
|
||||
assert.equal(4*1, b.getDataSize());
|
||||
b = new ArrayBufferSer(ArrayBufferSer.INT8, [1,2,3,4]);
|
||||
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());
|
||||
});
|
||||
|
||||
|
||||
test('calculate size for arrays', function() {
|
||||
var b = new ArrayBufferSer(ArrayBufferSer.STRING, ["test","kease"])
|
||||
it('calculate size for arrays', function() {
|
||||
var b = new ArrayBufferSer(ArrayBufferSer.STRING, ["test","kease"]);
|
||||
assert.equal((b.headerSize + 4 + 5)*2, b.getDataSize());
|
||||
|
||||
var ba = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4])
|
||||
var bc = new ArrayBufferSer(ArrayBufferSer.INT16, [1,4])
|
||||
var ba = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,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.type, ArrayBufferSer.BUFFER);
|
||||
});
|
||||
@ -36,28 +36,28 @@ suite('ArrayBufferSer', function() {
|
||||
}
|
||||
}
|
||||
|
||||
test('binary data is ok', function() {
|
||||
var b = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2,3,4])
|
||||
it('binary data is ok', function() {
|
||||
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]);
|
||||
assert_buffer_equals(bf, b.buffer);
|
||||
});
|
||||
|
||||
test('binary data is ok with arrays', function() {
|
||||
var ba = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2, 3, 4])
|
||||
var bc = new ArrayBufferSer(ArrayBufferSer.INT16, [1,4])
|
||||
it('binary data is ok with arrays', function() {
|
||||
var ba = new ArrayBufferSer(ArrayBufferSer.INT16, [1,2, 3, 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([
|
||||
0, 0, 0, ArrayBufferSer.BUFFER, // type
|
||||
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, 4, 1, 0, 4, 0])
|
||||
0, 0, 0, ArrayBufferSer.INT16, 0, 0, 0, 4, 1, 0, 4, 0]);
|
||||
assert_buffer_equals(bf, b.buffer);
|
||||
});
|
||||
|
||||
test('binary data is ok with strings', function() {
|
||||
var s = 'test'
|
||||
var b = new ArrayBufferSer(ArrayBufferSer.STRING, [s])
|
||||
it('binary data is ok with strings', function() {
|
||||
var s = 'test';
|
||||
var b = new ArrayBufferSer(ArrayBufferSer.STRING, [s]);
|
||||
var bf = new Buffer([
|
||||
0, 0, 0, ArrayBufferSer.STRING, // type
|
||||
0, 0, 0, 16,
|
||||
|
@ -1,26 +1,39 @@
|
||||
require('../helper');
|
||||
|
||||
var _ = require('underscore')
|
||||
, OAuthAuth = require('../../app/auth/oauth')
|
||||
, MetadataDB = require('cartodb-redis')
|
||||
, oAuth = require('../../app/auth/oauth').backend
|
||||
, assert = require('assert')
|
||||
, tests = module.exports = {}
|
||||
, oauth_data_1 = {
|
||||
var _ = require('underscore');
|
||||
var OAuthAuth = require('../../app/auth/oauth');
|
||||
var MetadataDB = require('cartodb-redis');
|
||||
var oAuth = require('../../app/auth/oauth').backend;
|
||||
var assert = require('assert');
|
||||
var oauth_data_1 = {
|
||||
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_data_2 = { oauth_version:"1.0" }
|
||||
, 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"'
|
||||
, 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"'
|
||||
, full_oauth_header = 'OAuth realm="http://photos.example.net/"' + oauth_header_tokens;
|
||||
};
|
||||
var oauth_data_2 = { oauth_version:"1.0" };
|
||||
var oauth_data = _.extend(oauth_data_1, oauth_data_2);
|
||||
var 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 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,
|
||||
port: global.settings.redis_port,
|
||||
max: global.settings.redisPool,
|
||||
@ -28,44 +41,43 @@ var metadataBackend = MetadataDB({
|
||||
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);
|
||||
});
|
||||
|
||||
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 %>");
|
||||
});
|
||||
|
||||
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}};
|
||||
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:{}};
|
||||
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 tokens = oAuth.parseTokens(req);
|
||||
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 tokens = oAuth.parseTokens(req);
|
||||
|
||||
oAuth.getOAuthHash(metadataBackend, tokens.oauth_token, function(err, data){
|
||||
console.log(data);
|
||||
assert.equal(tokens.oauth_consumer_key, data.consumer_key);
|
||||
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 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:{},
|
||||
headers:{authorization:real_oauth_header, host: 'vizzuality.testhost.lan' },
|
||||
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:{},
|
||||
headers:{authorization:real_oauth_header, host: 'vizzuality.testyhost.lan' },
|
||||
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 = {
|
||||
query:{},
|
||||
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 oAuthAuth = new OAuthAuth(req);
|
||||
assert.ok(oAuthAuth.hasCredentials());
|
||||
done();
|
||||
});
|
||||
|
||||
test('OAuthAuth reports it has no credentials', function(done) {
|
||||
it('OAuthAuth reports it has no credentials', function(done) {
|
||||
var req = {query:{}, headers:{}};
|
||||
var oAuthAuth = new OAuthAuth(req);
|
||||
assert.equal(oAuthAuth.hasCredentials(), false);
|
||||
|
Loading…
Reference in New Issue
Block a user