2011-08-25 03:47:10 +08:00
/ * *
*
* Requires the database and tables setup in config / environments / test . js to exist
* Ensure the user is present in the pgbouncer auth file too
* TODO : Add OAuth tests .
*
2013-07-25 00:43:38 +08:00
* To run this test , ensure that cartodb _test _user _1 _db metadata exists
* in Redis for the vizzuality . cartodb . com domain
2011-08-25 03:47:10 +08:00
*
* SELECT 5
* HSET rails : users : vizzuality id 1
2013-04-11 19:35:11 +08:00
* HSET rails : users : vizzuality database _name cartodb _test _user _1 _db
2011-08-25 03:47:10 +08:00
*
* /
2011-06-13 11:23:02 +08:00
require ( '../helper' ) ;
2012-07-13 04:54:12 +08:00
require ( '../support/assert' ) ;
2011-09-07 19:05:10 +08:00
2012-11-12 19:37:34 +08:00
2014-01-31 17:55:30 +08:00
var app = require ( global . settings . app _root + '/app/controllers/app' ) ( )
2011-08-25 03:47:10 +08:00
, assert = require ( 'assert' )
2012-09-17 17:50:19 +08:00
, querystring = require ( 'querystring' )
2012-11-12 19:37:34 +08:00
, _ = require ( 'underscore' )
, zipfile = require ( 'zipfile' )
, fs = require ( 'fs' )
2012-11-13 00:10:16 +08:00
, libxmljs = require ( 'libxmljs' )
2013-04-09 17:49:05 +08:00
, Step = require ( 'step' )
2012-11-12 19:37:34 +08:00
;
2011-06-13 11:23:02 +08:00
2012-03-16 20:50:07 +08:00
2012-07-13 04:54:12 +08:00
suite ( 'app.test' , function ( ) {
2013-07-22 23:21:38 +08:00
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' ;
2012-11-13 02:14:20 +08:00
var expected _cache _control _persist = 'public,max-age=31536000' ;
2011-06-20 21:39:12 +08:00
2012-07-16 23:16:28 +08:00
test ( 'GET /api/v1/sql' , function ( done ) {
2011-08-25 03:47:10 +08:00
assert . response ( app , {
2011-09-07 19:05:10 +08:00
url : '/api/v1/sql' ,
2011-08-25 03:47:10 +08:00
method : 'GET'
} , {
2011-11-22 08:06:14 +08:00
status : 400
2012-07-16 23:16:28 +08:00
} , function ( res ) {
2013-02-13 20:32:34 +08:00
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
2013-05-23 17:49:23 +08:00
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
assert . deepEqual ( JSON . parse ( res . body ) , { "error" : [ "You must indicate a sql query" ] } ) ;
done ( ) ;
} ) ;
} ) ;
// Test base_url setting
test ( 'GET /api/whatever/sql' , function ( done ) {
assert . response ( app , {
2013-05-24 19:51:39 +08:00
url : '/api/whatever/sql?q=SELECT%201' ,
headers : { host : 'vizzuality.cartodb.com' } ,
2013-05-23 17:49:23 +08:00
method : 'GET'
} , {
} , function ( res ) {
2013-05-24 19:51:39 +08:00
assert . equal ( res . statusCode , 200 , res . body ) ;
2012-07-16 23:16:28 +08:00
done ( ) ;
2011-08-25 03:47:10 +08:00
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;
2011-06-10 00:34:02 +08:00
2013-05-24 20:21:13 +08:00
// Test CORS headers with GET
test ( 'GET /api/whatever/sql' , function ( done ) {
assert . response ( app , {
url : '/api/whatever/sql?q=SELECT%201' ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , {
} , 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-origin' ] , '*' ) ;
done ( ) ;
} ) ;
} ) ;
// Test that OPTIONS does not run queries
test ( 'OPTIONS /api/x/sql' , function ( done ) {
assert . response ( app , {
url : '/api/x/sql?q=syntax%20error' ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'OPTIONS'
} , { } , 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-origin' ] , '*' ) ;
done ( ) ;
} ) ;
} ) ;
2011-10-05 23:49:54 +08:00
2012-07-13 17:01:32 +08:00
test ( 'GET /api/v1/sql with SQL parameter on SELECT only. No oAuth included ' , function ( done ) {
2011-08-25 03:47:10 +08:00
assert . response ( app , {
2011-10-05 23:49:54 +08:00
url : '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&database=cartodb_test_user_1_db' ,
2011-08-25 03:47:10 +08:00
method : 'GET'
2012-07-13 17:01:32 +08:00
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
2012-10-15 19:20:37 +08:00
// Check cache headers
assert . equal ( res . headers [ 'x-cache-channel' ] , 'cartodb_test_user_1_db:untitle_table_4' ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _cache _control ) ;
2012-07-13 17:01:32 +08:00
done ( ) ;
2011-08-25 03:47:10 +08:00
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;
2011-08-18 00:27:45 +08:00
2012-11-13 02:14:20 +08:00
test ( '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' ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
// Check cache headers
2013-07-22 23:21:38 +08:00
assert . ok ( res . headers . hasOwnProperty ( 'x-cache-channel' ) ) ;
2013-10-18 19:29:06 +08:00
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/105
assert . equal ( res . headers [ 'x-cache-channel' ] , 'cartodb_test_user_1_db:untitle_table_4' ) ;
2012-11-13 02:14:20 +08:00
assert . equal ( res . headers [ 'cache-control' ] , expected _cache _control _persist ) ;
done ( ) ;
} ) ;
} ) ;
2012-07-13 17:01:32 +08:00
test ( 'GET /api/v1/sql with SQL parameter on SELECT only. no database param, just id using headers' , function ( done ) {
2011-08-25 03:47:10 +08:00
assert . response ( app , {
2011-09-07 19:05:10 +08:00
url : '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4' ,
2011-08-25 03:47:10 +08:00
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
2012-07-13 17:01:32 +08:00
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
done ( ) ;
2011-08-25 03:47:10 +08:00
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;
2011-08-25 03:47:10 +08:00
2013-11-18 20:31:11 +08:00
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/121
2013-11-18 19:21:30 +08:00
test ( 'SELECT from user-specific database' , function ( done ) {
var backupDBHost = global . settings . db _host ;
global . settings . db _host = '6.6.6.6' ;
assert . response ( app , {
url : '/api/v1/sql?q=SELECT+2+as+n' ,
headers : { host : 'cartodb250user.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
global . settings . db _host = backupDBHost ;
var err = null ;
try {
assert . equal ( res . statusCode , 200 , res . statusCode + ": " + res . body ) ;
var parsed = JSON . parse ( res . body ) ;
assert . equal ( parsed . rows . length , 1 ) ;
assert . equal ( parsed . rows [ 0 ] . n , 2 ) ;
} catch ( e ) {
err = e ;
}
done ( err ) ;
} ) ;
} ) ;
2013-11-18 20:31:11 +08:00
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/120
test ( 'SELECT with user-specific password' , function ( done ) {
var backupDBUserPass = global . settings . db _user _pass ;
global . settings . db _user _pass = '<%= user_password %>' ;
assert . response ( app , {
url : '/api/v1/sql?q=SELECT+2+as+n&api_key=1234' ,
headers : { host : 'cartodb250user.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
global . settings . db _user _pass = backupDBUserPass ;
var err = null ;
try {
assert . equal ( res . statusCode , 200 , res . statusCode + ": " + res . body ) ;
var parsed = JSON . parse ( res . body ) ;
assert . equal ( parsed . rows . length , 1 ) ;
assert . equal ( parsed . rows [ 0 ] . n , 2 ) ;
} catch ( e ) {
err = e ;
}
done ( err ) ;
} ) ;
} ) ;
2012-10-15 19:20:37 +08:00
test ( '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' ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
// Check cache headers
assert . equal ( res . headers [ 'x-cache-channel' ] , 'cartodb_test_user_1_db:untitle_table_4' ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _cache _control ) ;
done ( ) ;
} ) ;
} ) ;
2013-02-18 23:14:15 +08:00
// Test for https://github.com/Vizzuality/CartoDB-SQL-API/issues/85
test ( "paging doesn't break x-cache-channel" ,
function ( done ) {
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
2013-05-24 16:22:17 +08:00
// note: select casing intentionally mixed
q : 'selECT cartodb_id*3 FROM untitle_table_4' ,
2013-02-18 23:14:15 +08:00
api _key : '1234' ,
rows _per _page : 1 ,
page : 2
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
assert . equal ( res . headers [ 'x-cache-channel' ] , 'cartodb_test_user_1_db:untitle_table_4' ) ;
2013-06-06 21:24:57 +08:00
var parsed = JSON . parse ( res . body ) ;
assert . equal ( parsed . rows . length , 1 ) ;
2013-02-18 23:14:15 +08:00
done ( ) ;
} ) ;
} ) ;
2013-12-03 23:52:55 +08:00
// Test page and rows_per_page params
test ( "paging" , function ( done ) {
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
// note: select casing intentionally mixed
q : 'SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(v)' ,
rows _per _page : 3 ,
page : 2
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsed = JSON . parse ( res . body ) ;
assert . equal ( parsed . rows . length , 3 ) ;
assert . equal ( parsed . rows [ 0 ] . v , 7 ) ;
assert . equal ( parsed . rows [ 1 ] . v , 8 ) ;
assert . equal ( parsed . rows [ 2 ] . v , 9 ) ;
done ( ) ;
} ) ;
} ) ;
2012-07-13 17:01:32 +08:00
test ( 'POST /api/v1/sql with SQL parameter on SELECT only. no database param, just id using headers' , function ( done ) {
2011-09-07 19:05:10 +08:00
assert . response ( app , {
url : '/api/v1/sql' ,
data : querystring . stringify ( { q : "SELECT * FROM untitle_table_4" } ) ,
headers : { host : 'vizzuality.cartodb.com' , 'Content-Type' : 'application/x-www-form-urlencoded' } ,
method : 'POST'
2012-07-13 17:01:32 +08:00
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
done ( ) ;
2011-09-07 19:05:10 +08:00
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;
2011-09-07 19:05:10 +08:00
2013-02-13 20:32:34 +08:00
test ( 'GET /api/v1/sql with INSERT. oAuth not used, so public user - should fail' , function ( done ) {
2011-08-25 03:47:10 +08:00
assert . response ( app , {
2013-04-11 19:35:11 +08:00
url : "/api/v1/sql?q=INSERT%20INTO%20untitle_table_4%20(cartodb_id)%20VALUES%20(1e4)&database=cartodb_test_user_1_db" ,
2011-08-25 03:47:10 +08:00
method : 'GET'
} , {
2013-02-13 20:32:34 +08:00
} , function ( res ) {
assert . equal ( res . statusCode , 400 , res . statusCode + ': ' + res . body ) ;
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
assert . deepEqual ( JSON . parse ( res . body ) ,
2013-04-11 19:35:11 +08:00
{ "error" : [ "permission denied for relation untitle_table_4" ] }
2013-02-13 20:32:34 +08:00
) ;
done ( ) ;
2011-08-25 03:47:10 +08:00
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;
2011-08-18 00:27:45 +08:00
2013-04-11 19:00:13 +08:00
test ( 'GET /api/v1/sql with DROP TABLE. oAuth not used, so public user - should fail' , function ( done ) {
2011-06-21 00:03:29 +08:00
assert . response ( app , {
2013-04-11 19:35:11 +08:00
url : "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4&database=cartodb_test_user_1_db" ,
2011-08-25 03:47:10 +08:00
method : 'GET'
2011-06-21 00:03:29 +08:00
} , {
2013-02-13 20:32:34 +08:00
} , function ( res ) {
assert . equal ( res . statusCode , 400 , res . statusCode + ': ' + res . body ) ;
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
assert . deepEqual ( JSON . parse ( res . body ) ,
2013-04-11 19:35:11 +08:00
{ "error" : [ "must be owner of relation untitle_table_4" ] }
2013-02-13 20:32:34 +08:00
) ;
done ( ) ;
2011-06-21 00:03:29 +08:00
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;
2011-08-25 03:47:10 +08:00
2013-02-13 20:32:34 +08:00
test ( 'GET /api/v1/sql with INSERT. header based db - should fail' , function ( ) {
2011-06-21 00:22:46 +08:00
assert . response ( app , {
2011-09-07 19:05:10 +08:00
url : "/api/v1/sql?q=INSERT%20INTO%20untitle_table_4%20(id)%20VALUES%20(1)" ,
2011-08-25 03:47:10 +08:00
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
2011-06-21 00:22:46 +08:00
} , {
2011-11-22 08:06:14 +08:00
status : 400
2011-06-21 00:22:46 +08:00
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;
2011-08-25 03:47:10 +08:00
2012-09-17 22:56:25 +08:00
// Check results from INSERT
//
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/13
test ( '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 :
"INSERT INTO private_table(name) VALUES('noret1') UNION VALUES('noret2')"
} ) ,
headers : { host : 'vizzuality.localhost.lan:8080' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var out = JSON . parse ( res . body ) ;
assert . ok ( out . hasOwnProperty ( 'time' ) ) ;
assert . equal ( out . total _rows , 2 ) ;
assert . equal ( out . rows . length , 0 ) ;
2012-10-15 19:20:37 +08:00
// Check cache headers
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/43
2013-07-22 23:21:38 +08:00
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
2012-09-17 22:56:25 +08:00
done ( ) ;
} ) ;
} ) ;
// Check results from UPDATE
//
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/13
test ( '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 :
"UPDATE private_table SET name = upper(name) WHERE name in ('noret1', 'noret2')"
} ) ,
headers : { host : 'vizzuality.localhost.lan:8080' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var out = JSON . parse ( res . body ) ;
assert . ok ( out . hasOwnProperty ( 'time' ) ) ;
assert . equal ( out . total _rows , 2 ) ;
assert . equal ( out . rows . length , 0 ) ;
2012-10-15 19:20:37 +08:00
// Check cache headers
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/43
2013-07-22 23:21:38 +08:00
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
2012-09-17 22:56:25 +08:00
done ( ) ;
} ) ;
} ) ;
// Check results from DELETE
//
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/13
test ( '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 :
"DELETE FROM private_table WHERE name in ('NORET1', 'NORET2')"
} ) ,
headers : { host : 'vizzuality.localhost.lan:8080' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var out = JSON . parse ( res . body ) ;
assert . ok ( out . hasOwnProperty ( 'time' ) ) ;
assert . equal ( out . total _rows , 2 ) ;
assert . equal ( out . rows . length , 0 ) ;
2012-10-15 19:20:37 +08:00
// Check cache headers
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/43
2013-07-22 23:21:38 +08:00
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
2012-09-17 22:56:25 +08:00
done ( ) ;
} ) ;
} ) ;
2012-09-17 17:50:19 +08:00
// Check results from INSERT .. RETURNING
//
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/50
test ( '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 :
"INSERT INTO private_table(name) VALUES('test') RETURNING upper(name), reverse(name)"
} ) ,
headers : { host : 'vizzuality.localhost.lan:8080' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var out = JSON . parse ( res . body ) ;
assert . ok ( out . hasOwnProperty ( 'time' ) ) ;
assert . equal ( out . total _rows , 1 ) ;
assert . equal ( out . rows . length , 1 ) ;
assert . equal ( _ . keys ( out . rows [ 0 ] ) . length , 2 ) ;
assert . equal ( out . rows [ 0 ] . upper , 'TEST' ) ;
assert . equal ( out . rows [ 0 ] . reverse , 'tset' ) ;
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 ) {
assert . response ( app , {
// view prepare_db.sh to see where to set api_key
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' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var out = JSON . parse ( res . body ) ;
assert . ok ( out . hasOwnProperty ( 'time' ) ) ;
assert . equal ( out . total _rows , 1 ) ;
assert . equal ( out . rows . length , 1 ) ;
assert . equal ( _ . keys ( out . rows [ 0 ] ) . length , 2 ) ;
assert . equal ( out . rows [ 0 ] . upper , 'TOST' ) ;
assert . equal ( out . rows [ 0 ] . reverse , 'tsot' ) ;
done ( ) ;
} ) ;
} ) ;
2012-09-17 22:50:15 +08:00
// Check results from DELETE .. RETURNING
//
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/50
test ( '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 :
"DELETE FROM private_table WHERE name = 'tost' RETURNING name"
} ) ,
headers : { host : 'vizzuality.localhost.lan:8080' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var out = JSON . parse ( res . body ) ;
assert . ok ( out . hasOwnProperty ( 'time' ) ) ;
assert . equal ( out . total _rows , 1 ) ;
assert . equal ( out . rows . length , 1 ) ;
assert . equal ( _ . keys ( out . rows [ 0 ] ) . length , 1 ) ;
assert . equal ( out . rows [ 0 ] . name , 'tost' ) ;
done ( ) ;
} ) ;
} ) ;
2013-02-13 20:32:34 +08:00
test ( 'GET /api/v1/sql with SQL parameter on DROP TABLE. should fail' , function ( done ) {
2011-08-25 03:47:10 +08:00
assert . response ( app , {
2011-09-07 19:05:10 +08:00
url : "/api/v1/sql?q=DROP%20TABLE%20untitle_table_4" ,
2011-08-25 03:47:10 +08:00
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
2013-02-13 20:32:34 +08:00
} , { } , function ( res ) {
assert . equal ( res . statusCode , 400 , res . statusCode + ': ' + res . body ) ;
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
assert . deepEqual ( JSON . parse ( res . body ) ,
{ "error" : [ "must be owner of relation untitle_table_4" ] }
) ;
done ( ) ;
2011-08-25 03:47:10 +08:00
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;
2011-10-05 23:49:54 +08:00
2013-07-08 23:36:53 +08:00
// 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 ) {
assert . response ( app , {
// view prepare_db.sh to see where to set api_key
url : "/api/v1/sql?api_key=1234&"
+ querystring . stringify ( { q :
"SELECT min(updated_at) FROM private_table"
} ) ,
headers : { host : 'vizzuality.localhost.lan:8080' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
assert . equal ( res . headers [ 'x-cache-channel' ] , 'cartodb_test_user_1_db:private_table' ) ;
done ( ) ;
} ) ;
} ) ;
2012-10-15 19:20:37 +08:00
test ( 'CREATE TABLE with GET and auth' , function ( done ) {
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
2012-10-15 19:40:04 +08:00
q : 'CREATE TABLE test_table(a int)' ,
2012-10-15 19:20:37 +08:00
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
// Check cache headers
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/43
2013-07-22 23:21:38 +08:00
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
2012-10-15 19:20:37 +08:00
done ( ) ;
} ) ;
} ) ;
2014-01-10 00:24:48 +08:00
// See http://github.com/CartoDB/CartoDB-SQL-API/issues/127
test ( 'SELECT INTO with paging ' , function ( done ) {
var esc _tabname = 'test ""select into""' ; // escaped ident
Step (
function select _into ( ) {
var next = this ;
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
q : 'SELECT generate_series(1,10) InTO "' + esc _tabname + '"' ,
rows _per _page : 1 , page : 1 ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) { next ( null , res ) ; } ) ;
} ,
function check _res _test _fake _into _1 ( err , res ) {
if ( err ) throw err ;
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var next = this ;
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
q : 'SELECT \' INTO "c"\' FROM "' + esc _tabname + '"' ,
rows _per _page : 1 , page : 1 ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) { next ( null , res ) ; } ) ;
} ,
function check _res _drop _table ( err , res ) {
if ( err ) throw err ;
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var out = JSON . parse ( res . body ) ;
assert . equal ( out . total _rows , 1 ) ; // windowing works
var next = this ;
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
q : 'DROP TABLE "' + esc _tabname + '"' ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) { next ( null , res ) ; } ) ;
} ,
function check _drop ( err , res ) {
if ( err ) throw err ;
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
return null ;
} ,
function finish ( err ) {
done ( err )
}
) ;
} ) ;
2013-01-17 16:59:48 +08:00
// Test effects of COPY
// See https://github.com/Vizzuality/cartodb-management/issues/1502
test ( 'COPY TABLE with GET and auth' , function ( done ) {
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
q : 'COPY test_table FROM stdin;' ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
// We expect a problem, actually
assert . equal ( res . statusCode , 400 , res . statusCode + ': ' + res . body ) ;
2013-02-13 20:32:34 +08:00
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
2013-01-17 16:59:48 +08:00
assert . deepEqual ( JSON . parse ( res . body ) , { "error" : [ "COPY from stdin failed: No source stream defined" ] } ) ;
done ( ) ;
} ) ;
} ) ;
2012-10-15 19:20:37 +08:00
2013-01-22 00:39:07 +08:00
test ( 'COPY TABLE with GET and auth' , function ( done ) {
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
q : "COPY test_table to '/tmp/x';" ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
// We expect a problem, actually
assert . equal ( res . statusCode , 400 , res . statusCode + ': ' + res . body ) ;
2013-02-13 20:32:34 +08:00
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
2013-01-22 00:39:07 +08:00
assert . deepEqual ( JSON . parse ( res . body ) , { "error" : [ "must be superuser to COPY to or from a file" ] } ) ;
done ( ) ;
} ) ;
} ) ;
2012-10-15 19:40:04 +08:00
test ( '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' ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
// Check cache headers
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/43
2013-07-22 23:21:38 +08:00
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
2012-10-15 19:40:04 +08:00
done ( ) ;
} ) ;
} ) ;
2013-02-19 01:39:09 +08:00
test ( 'multistatement insert, alter, select, begin, commit' , function ( done ) {
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
2013-06-06 23:06:06 +08:00
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;' ,
2013-02-19 01:39:09 +08:00
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
assert . equal ( parsedBody . total _rows , 1 ) ;
assert . deepEqual ( parsedBody . rows [ 0 ] , { b : 2.5 } ) ;
done ( ) ;
} ) ;
} ) ;
2013-05-07 00:21:22 +08:00
test ( 'TRUNCATE TABLE with GET and auth' , function ( done ) {
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
q : 'TRUNCATE TABLE test_table' ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
2013-07-22 23:21:38 +08:00
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
2013-05-07 00:21:22 +08:00
var pbody = JSON . parse ( res . body ) ;
assert . equal ( pbody . rows . length , 0 ) ;
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
q : 'SELECT count(*) FROM test_table' ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
assert . equal ( res . headers [ 'x-cache-channel' ] , 'cartodb_test_user_1_db:test_table' ) ;
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 ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
2013-07-25 00:43:38 +08:00
test ( 'REINDEX TABLE with GET and auth' , function ( done ) {
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
q : ' ReINdEX TABLE test_table' ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
var pbody = JSON . parse ( res . body ) ;
assert . equal ( pbody . rows . length , 0 ) ;
done ( ) ;
} ) ;
} ) ;
2012-10-15 19:20:37 +08:00
test ( 'DROP TABLE with GET and auth' , function ( done ) {
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
2012-10-15 19:40:04 +08:00
q : 'DROP TABLE test_table' ,
2012-10-15 19:20:37 +08:00
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
// Check cache headers
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/43
2013-07-22 23:21:38 +08:00
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
2012-10-15 19:20:37 +08:00
done ( ) ;
} ) ;
} ) ;
test ( 'CREATE FUNCTION with GET and auth' , function ( done ) {
assert . response ( app , {
url : "/api/v1/sql?" + querystring . stringify ( {
q : 'CREATE FUNCTION create_func_test(a int) RETURNS INT AS \'SELECT 1\' LANGUAGE \'sql\'' ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
// Check cache headers
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/43
2013-07-22 23:21:38 +08:00
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
2012-10-15 19:20:37 +08:00
done ( ) ;
} ) ;
} ) ;
test ( '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)' ,
api _key : 1234
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
// Check cache headers
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/43
2013-07-22 23:21:38 +08:00
assert . ok ( ! res . hasOwnProperty ( 'x-cache-channel' ) ) ;
assert . equal ( res . headers [ 'cache-control' ] , expected _rw _cache _control ) ;
2012-10-15 19:20:37 +08:00
done ( ) ;
} ) ;
} ) ;
2012-10-25 19:34:06 +08:00
test ( 'sends a 400 when an unsupported format is requested' , function ( done ) {
2011-10-28 19:11:18 +08:00
assert . response ( app , {
2012-10-25 19:34:06 +08:00
url : '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=unknown' ,
2012-10-12 17:42:03 +08:00
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
2012-10-25 19:34:06 +08:00
assert . equal ( res . statusCode , 400 , res . body ) ;
2013-02-13 20:32:34 +08:00
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
2012-10-25 19:34:06 +08:00
assert . deepEqual ( JSON . parse ( res . body ) , { "error" : [ "Invalid format: unknown" ] } ) ;
2012-10-12 17:42:03 +08:00
done ( ) ;
} ) ;
} ) ;
2012-10-25 19:34:06 +08:00
test ( 'GET /api/v1/sql with SQL parameter and no format, ensuring content-disposition set to json' , function ( done ) {
2012-10-12 17:42:03 +08:00
assert . response ( app , {
2012-10-25 19:34:06 +08:00
url : '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4' ,
2011-10-28 19:11:18 +08:00
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
2012-07-13 17:01:32 +08:00
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
2012-11-13 02:44:16 +08:00
var ct = res . header ( 'Content-Type' ) ;
assert . ok ( /json/ . test ( ct ) , 'Default format is not JSON: ' + ct ) ;
2011-10-28 19:11:18 +08:00
var cd = res . header ( 'Content-Disposition' ) ;
2012-11-13 02:44:16 +08:00
assert . equal ( true , /^inline/ . test ( cd ) , 'Default format is not disposed inline: ' + cd ) ;
2012-11-12 19:37:34 +08:00
assert . equal ( true , /filename=cartodb-query.json/gi . test ( cd ) , 'Unexpected JSON filename: ' + cd ) ;
2012-07-13 04:54:12 +08:00
done ( ) ;
2011-10-28 19:11:18 +08:00
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;
2011-10-28 19:11:18 +08:00
2012-11-14 02:26:36 +08:00
test ( '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" } ) ,
headers : { host : 'vizzuality.cartodb.com' , 'Content-Type' : 'application/x-www-form-urlencoded' } ,
method : 'POST'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
var ct = res . header ( 'Content-Type' ) ;
assert . ok ( /json/ . test ( ct ) , 'Default format is not JSON: ' + ct ) ;
var cd = res . header ( 'Content-Disposition' ) ;
2012-11-14 23:30:18 +08:00
assert . equal ( true , /^inline/ . test ( cd ) , 'Default format is not disposed inline: ' + cd ) ;
2012-11-14 02:26:36 +08:00
assert . equal ( true , /filename=cartodb-query.json/gi . test ( cd ) , 'Unexpected JSON filename: ' + cd ) ;
done ( ) ;
} ) ;
} ) ;
2012-11-13 02:44:16 +08:00
test ( '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' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
var ct = res . header ( 'Content-Type' ) ;
assert . ok ( /json/ . test ( ct ) , 'Default format is not JSON: ' + ct ) ;
var cd = res . header ( 'Content-Disposition' ) ;
assert . equal ( true , /^attachment/ . test ( cd ) , 'Format with filename is not disposed as attachment: ' + cd ) ;
assert . equal ( true , /filename=x.json/gi . test ( cd ) , 'Unexpected JSON filename: ' + cd ) ;
done ( ) ;
} ) ;
} ) ;
2012-11-13 00:10:16 +08:00
test ( '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' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
var row0 = JSON . parse ( res . body ) . rows [ 0 ] ;
var checkfields = { 'name' : 1 , 'cartodb_id' : 1 , 'the_geom' : 1 , 'the_geom_webmercator' : 1 } ;
for ( var f in checkfields ) {
if ( checkfields [ f ] ) {
assert . ok ( row0 . hasOwnProperty ( f ) , "result does not include '" + f + "'" ) ;
} else {
assert . ok ( ! row0 . hasOwnProperty ( f ) , "result includes '" + f + "'" ) ;
}
}
done ( ) ;
} ) ;
} ) ;
test ( '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' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
var row0 = JSON . parse ( res . body ) . rows [ 0 ] ;
var checkfields = { 'name' : 1 , 'cartodb_id' : 0 , 'the_geom' : 1 , 'the_geom_webmercator' : 0 } ;
for ( var f in checkfields ) {
if ( checkfields [ f ] ) {
assert . ok ( row0 . hasOwnProperty ( f ) , "result does not include '" + f + "'" ) ;
} else {
assert . ok ( ! row0 . hasOwnProperty ( f ) , "result includes '" + f + "'" ) ;
}
}
done ( ) ;
} ) ;
} ) ;
2013-05-06 18:30:32 +08:00
test ( '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' ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
var row0 = JSON . parse ( res . body ) . rows [ 0 ] ;
var checkfields = { 'name' : 1 , 'cartodb_id' : 0 , 'the_geom' : 1 , 'the_geom_webmercator' : 0 } ;
for ( var f in checkfields ) {
if ( checkfields [ f ] ) {
assert . ok ( row0 . hasOwnProperty ( f ) , "result does not include '" + f + "'" ) ;
} else {
assert . ok ( ! row0 . hasOwnProperty ( f ) , "result includes '" + f + "'" ) ;
}
}
done ( ) ;
} ) ;
} ) ;
2012-10-25 19:34:06 +08:00
test ( 'GET /api/v1/sql ensure cross domain set on errors' , function ( done ) {
2012-10-12 18:17:35 +08:00
assert . response ( app , {
2012-10-25 19:34:06 +08:00
url : '/api/v1/sql?q=SELECT%20*gadfgadfg%20FROM%20untitle_table_4' ,
2012-10-12 18:17:35 +08:00
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
2012-10-25 19:34:06 +08:00
} , {
status : 400
} , function ( res ) {
var cd = res . header ( 'Access-Control-Allow-Origin' ) ;
2013-02-13 20:32:34 +08:00
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
2012-10-25 19:34:06 +08:00
assert . equal ( cd , '*' ) ;
2012-10-12 18:17:35 +08:00
done ( ) ;
} ) ;
} ) ;
2012-10-25 19:34:06 +08:00
test ( 'cannot GET system tables' , function ( done ) {
2013-04-09 17:49:05 +08:00
var req = { headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET' } ;
var pre = '/api/v1/sql?' ;
Step (
function trySysTable1 ( ) {
req . url = pre + querystring . stringify ( { q : 'SELECT * FROM pg_attribute' } ) ;
var next = this ;
assert . response ( app , req , function ( res ) { next ( null , res ) ; } ) ;
} ,
function chkSysTable1 _trySysTable2 ( err , res ) {
if ( err ) throw err ;
var next = this ;
assert . equal ( res . statusCode , 403 ) ;
req . url = pre + querystring . stringify ( { q : 'SELECT * FROM PG_attribute' } ) ;
assert . response ( app , req , function ( res ) { next ( null , res ) ; } ) ;
} ,
function chkSysTable2 _trySysTable3 ( err , res ) {
if ( err ) throw err ;
var next = this ;
assert . equal ( res . statusCode , 403 ) ;
req . url = pre + querystring . stringify ( { q : 'SELECT * FROM "pg_attribute"' } ) ;
assert . response ( app , req , function ( res ) { next ( null , res ) ; } ) ;
} ,
2013-04-09 18:20:27 +08:00
function chkSysTable3 _trySysTable4 ( err , res ) {
if ( err ) throw err ;
var next = this ;
assert . equal ( res . statusCode , 403 ) ;
req . url = pre + querystring . stringify ( { q : 'SELECT a.* FROM untitle_table_4 a,pg_attribute' } ) ;
assert . response ( app , req , function ( res ) { next ( null , res ) ; } ) ;
} ,
2013-04-09 18:36:37 +08:00
function chkSysTable4 _tryValidPg1 ( err , res ) {
2013-04-09 17:49:05 +08:00
if ( err ) throw err ;
var next = this ;
assert . equal ( res . statusCode , 403 ) ;
2013-04-09 18:36:37 +08:00
req . url = pre + querystring . stringify ( { q : "SELECT 'pg_'" } ) ;
assert . response ( app , req , function ( res ) { next ( null , res ) ; } ) ;
} ,
function chkValidPg1 _tryValidPg2 ( err , res ) {
if ( err ) throw err ;
var next = this ;
assert . equal ( res . statusCode , 200 ) ;
req . url = pre + querystring . stringify ( { q : "SELECT pg_attribute FROM ( select 1 as pg_attribute ) as f" } ) ;
assert . response ( app , req , function ( res ) { next ( null , res ) ; } ) ;
} ,
2013-11-07 17:16:58 +08:00
// See http://github.com/CartoDB/CartoDB-SQL-API/issues/118
function chkValidPg1 _tryValidPg3 _b ( err , res ) {
if ( err ) throw err ;
var next = this ;
assert . equal ( res . statusCode , 200 , res . statusCode + ':' + res . body ) ;
req . url = pre + querystring . stringify ( { q : "SELECT * FROM cpg_test" } ) ;
assert . response ( app , req , function ( res ) { next ( null , res ) ; } ) ;
} ,
2013-04-09 18:36:37 +08:00
function chkValidPg2 _trySet1 ( err , res ) {
if ( err ) throw err ;
var next = this ;
2013-11-07 17:16:58 +08:00
assert . equal ( res . statusCode , 200 , res . statusCode + ':' + res . body ) ;
2013-04-09 17:49:05 +08:00
req . url = pre + querystring . stringify ( { q : ' set statement_timeout TO 400' } ) ;
assert . response ( app , req , function ( res ) { next ( null , res ) ; } ) ;
} ,
function chkSet1 _trySet2 ( err , res ) {
if ( err ) throw err ;
var next = this ;
assert . equal ( res . statusCode , 403 ) ;
req . url = pre + querystring . stringify ( { q : ' SET work_mem TO 80000' } ) ;
assert . response ( app , req , function ( res ) { next ( null , res ) ; } ) ;
} ,
function chkSet2 ( err , res ) {
if ( err ) throw err ;
var next = this ;
return true ;
} ,
function finish ( err ) {
done ( err ) ;
}
) ;
2012-09-11 18:22:27 +08:00
} ) ;
2012-10-25 19:34:06 +08:00
test ( 'GET decent error if domain is incorrect' , function ( done ) {
2012-09-11 18:22:27 +08:00
assert . response ( app , {
2012-10-25 19:34:06 +08:00
url : '/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4&format=geojson' ,
headers : { host : 'vizzualinot.cartodb.com' } ,
2012-09-11 18:22:27 +08:00
method : 'GET'
2013-11-16 01:36:49 +08:00
} , { } , function ( res ) {
assert . equal ( res . statusCode , 404 , res . statusCode + ( res . statusCode != 200 ? ( ': ' + res . body ) : '' ) ) ;
2013-02-13 20:32:34 +08:00
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
2012-10-25 19:34:06 +08:00
var result = JSON . parse ( res . body ) ;
2013-12-18 19:02:51 +08:00
assert . equal ( result . error [ 0 ] , "Sorry, we can't find CartoDB user 'vizzualinot'. Please check that you have entered the correct domain." ) ;
2012-09-11 18:22:27 +08:00
done ( ) ;
} ) ;
} ) ;
2012-10-25 19:34:06 +08:00
test ( 'GET decent error if SQL is broken' , function ( done ) {
2012-09-11 18:22:27 +08:00
assert . response ( app , {
2012-10-25 19:34:06 +08:00
url : '/api/v1/sql?' + querystring . stringify ( { q :
'SELECT star FROM this and that'
} ) ,
2012-09-11 18:22:27 +08:00
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
2012-10-25 19:34:06 +08:00
} , { } , function ( res ) {
assert . equal ( res . statusCode , 400 , res . statusCode + ': ' + res . body ) ;
2013-02-13 20:32:34 +08:00
assert . deepEqual ( res . headers [ 'content-type' ] , 'application/json; charset=utf-8' ) ;
assert . deepEqual ( res . headers [ 'content-disposition' ] , 'inline' ) ;
2012-10-25 19:34:06 +08:00
var result = JSON . parse ( res . body ) ;
// NOTE: actual error message may be slighly different, possibly worth a regexp here
assert . equal ( result . error [ 0 ] , 'syntax error at or near "and"' ) ;
done ( ) ;
2012-09-11 18:22:27 +08:00
} ) ;
} ) ;
2013-03-14 18:41:07 +08:00
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/88
test ( 'numeric arrays are rendered as such' , function ( done ) {
assert . response ( app , {
url : "/api/v1/sql?"
+ querystring . stringify ( { q :
"SELECT ARRAY[8.7,4.3]::numeric[] as x"
} ) ,
headers : { host : 'vizzuality.localhost.lan:8080' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
var out = JSON . parse ( res . body ) ;
assert . ok ( out . hasOwnProperty ( 'time' ) ) ;
assert . equal ( out . total _rows , 1 ) ;
assert . equal ( out . rows . length , 1 ) ;
assert . ok ( out . rows [ 0 ] . hasOwnProperty ( 'x' ) ) ;
assert . equal ( out . rows [ 0 ] . x . length , 2 ) ;
assert . equal ( out . rows [ 0 ] . x [ 0 ] , '8.7' ) ;
assert . equal ( out . rows [ 0 ] . x [ 1 ] , '4.3' ) ;
assert . equal ( res . headers [ 'x-cache-channel' ] , 'cartodb_test_user_1_db:' ) ; // keep forever
done ( ) ;
} ) ;
} ) ;
2013-06-15 00:35:04 +08:00
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/97
test ( '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, " +
2013-11-06 18:43:56 +08:00
"4::char as d, now() as e, 'a'::text as f" +
", 1::bool as g" +
", 'POINT(0 0)'::geometry as h" +
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/117
", now()::date as i" +
2013-11-09 23:55:40 +08:00
", '1'::numeric as j" +
2013-11-06 18:43:56 +08:00
" LIMIT 0"
2013-06-15 00:35:04 +08:00
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
2013-11-09 23:55:40 +08:00
assert . equal ( _ . keys ( parsedBody . fields ) . length , 10 ) ;
2013-06-15 00:35:04 +08:00
assert . equal ( parsedBody . fields . a . type , 'number' ) ;
assert . equal ( parsedBody . fields . b . type , 'number' ) ;
assert . equal ( parsedBody . fields . c . type , 'string' ) ;
assert . equal ( parsedBody . fields . d . type , 'string' ) ;
assert . equal ( parsedBody . fields . e . type , 'date' ) ;
2013-07-04 22:03:05 +08:00
assert . equal ( parsedBody . fields . f . type , 'string' ) ;
2013-08-22 19:44:21 +08:00
assert . equal ( parsedBody . fields . g . type , 'boolean' ) ;
2013-10-02 16:22:13 +08:00
assert . equal ( parsedBody . fields . h . type , 'geometry' ) ;
2013-11-06 18:43:56 +08:00
assert . equal ( parsedBody . fields . i . type , 'date' ) ;
2013-11-09 23:55:40 +08:00
assert . equal ( parsedBody . fields . j . type , 'number' ) ;
2013-06-15 00:35:04 +08:00
done ( ) ;
} ) ;
} ) ;
2013-09-26 19:26:45 +08:00
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/109
test ( '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 " ,
skipfields : 'b'
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
assert . equal ( _ . keys ( parsedBody . fields ) . length , 2 ) ;
assert . ok ( parsedBody . fields . hasOwnProperty ( 'a' ) ) ;
assert . ok ( ! parsedBody . fields . hasOwnProperty ( 'b' ) ) ;
assert . ok ( parsedBody . fields . hasOwnProperty ( 'c' ) ) ;
done ( ) ;
} ) ;
} ) ;
2013-07-10 03:50:28 +08:00
// See https://github.com/Vizzuality/CartoDB-SQL-API/issues/100
test ( '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, " +
"3::int8 as c, 4::float4 as d, " +
"5::float8 as e, 6::numeric as f" +
") SELECT a,b,c,d,e,f," +
" ARRAY[a] AS _a, " +
" ARRAY[b] AS _b, " +
" ARRAY[c] AS _c, " +
" ARRAY[d] AS _d, " +
" ARRAY[e] AS _e, " +
" ARRAY[f] AS _f " +
"FROM inp"
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
var row = parsedBody . rows [ 0 ] ;
assert . equal ( typeof ( row . a ) , 'number' ) ;
assert . equal ( typeof ( row . b ) , 'number' ) ;
assert . equal ( typeof ( row . c ) , 'number' ) ;
assert . equal ( typeof ( row . d ) , 'number' ) ;
assert . equal ( typeof ( row . e ) , 'number' ) ;
assert . equal ( typeof ( row . f ) , 'number' ) ;
assert . equal ( typeof ( row . _a [ 0 ] ) , 'number' ) ;
assert . equal ( typeof ( row . _b [ 0 ] ) , 'number' ) ;
assert . equal ( typeof ( row . _c [ 0 ] ) , 'number' ) ;
assert . equal ( typeof ( row . _d [ 0 ] ) , 'number' ) ;
assert . equal ( typeof ( row . _e [ 0 ] ) , 'number' ) ;
assert . equal ( typeof ( row . _f [ 0 ] ) , 'number' ) ;
done ( ) ;
} ) ;
} ) ;
2013-06-19 18:24:04 +08:00
// Timezone information is retained with JSON output
//
// NOTE: results of these tests rely on the TZ env variable
// being set to 'Europe/Rome'. The env variable cannot
// be set within this test in a reliable way, see
// https://github.com/joyent/node/issues/3286
//
// FIXME: we'd like to also test UTC outputs of these
// 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 (
function testEuropeRomeExplicit ( ) {
var next = this ;
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
q : "SET timezone TO 'Europe/Rome'; SELECT '2000-01-01T00:00:00+01'::timestamptz as d"
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
try {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
assert . equal ( parsedBody . rows [ 0 ] . d , '2000-01-01T00:00:00+0100' ) ;
next ( ) ;
} catch ( err ) {
next ( err ) ;
}
} ) ;
} ,
function testEuropeRomeImplicit ( err ) {
if ( err ) throw err ;
var next = this ;
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
q : "SET timezone TO 'Europe/Rome'; SELECT '2000-01-01T00:00:00'::timestamp as d"
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
try {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
assert . equal ( parsedBody . rows [ 0 ] . d , '2000-01-01T00:00:00+0100' ) ;
next ( ) ;
} catch ( err ) {
next ( err ) ;
}
} ) ;
} ,
function testUTCExplicit ( err ) {
if ( err ) throw err ;
var next = this ;
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
q : "SET timezone TO 'UTC'; SELECT '2000-01-01T00:00:00+00'::timestamptz as d"
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
try {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
assert . equal ( parsedBody . rows [ 0 ] . d , '2000-01-01T01:00:00+0100' ) ;
next ( ) ;
} catch ( err ) {
next ( err ) ;
}
} ) ;
} ,
function testUTCImplicit ( err ) {
if ( err ) throw err ;
var next = this ;
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
q : "SET timezone TO 'UTC'; SELECT '2000-01-01T00:00:00'::timestamp as d"
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
try {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
assert . equal ( parsedBody . rows [ 0 ] . d , '2000-01-01T00:00:00+0100' ) ;
next ( ) ;
} catch ( err ) {
next ( err ) ;
}
} ) ;
} ,
function finish ( err ) {
done ( err ) ;
}
) ;
} ) ;
2013-11-19 00:01:06 +08:00
// 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 (
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;" ,
api _key : '1234'
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
var err = null ;
try {
assert . equal ( res . statusCode , 200 , res . statusCode + ': ' + res . body ) ;
} catch ( e ) { err = e ; }
next ( err ) ;
} ) ;
} ,
function raiseNotice ( err ) {
if ( err ) throw err ;
var next = this ;
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
2013-11-19 00:09:27 +08:00
q : "SET client_min_messages TO 'notice'; select raise('notice', 'hello notice')"
2013-11-19 00:01:06 +08:00
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
var err = null ;
try {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
assert . ok ( parsedBody . hasOwnProperty ( 'notices' ) , 'Missing notices from result' ) ;
assert . equal ( parsedBody . notices . length , 1 ) ;
assert . equal ( parsedBody . notices [ 0 ] , 'hello notice' ) ;
} catch ( e ) { err = e ; }
next ( err ) ;
} ) ;
} ,
function raiseWarning ( err ) {
if ( err ) throw err ;
var next = this ;
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
2013-11-19 00:09:27 +08:00
q : "SET client_min_messages TO 'notice'; select raise('warning', 'hello warning')"
2013-11-19 00:01:06 +08:00
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
var err = null ;
try {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
assert . ok ( parsedBody . hasOwnProperty ( 'warnings' ) , 'Missing warnings from result' ) ;
assert . equal ( parsedBody . warnings . length , 1 ) ;
assert . equal ( parsedBody . warnings [ 0 ] , 'hello warning' ) ;
} catch ( e ) { err = e ; }
next ( err ) ;
} ) ;
} ,
function raiseBothWarningAndNotice ( err ) {
if ( err ) throw err ;
var next = this ;
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
2013-11-19 00:09:27 +08:00
q : "SET client_min_messages TO 'notice'; select raise('warning', 'hello again warning'), raise('notice', 'hello again notice');"
2013-11-19 00:01:06 +08:00
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
var err = null ;
try {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
assert . ok ( parsedBody . hasOwnProperty ( 'warnings' ) , 'Missing warnings from result' ) ;
assert . equal ( parsedBody . warnings . length , 1 ) ;
assert . equal ( parsedBody . warnings [ 0 ] , 'hello again warning' ) ;
assert . ok ( parsedBody . hasOwnProperty ( 'notices' ) , 'Missing notices from result' ) ;
assert . equal ( parsedBody . notices . length , 1 ) ;
assert . equal ( parsedBody . notices [ 0 ] , 'hello again notice' ) ;
} catch ( e ) { err = e ; }
next ( err ) ;
} ) ;
} ,
function delRaiseFunction ( err ) {
var next = this ;
assert . response ( app , {
url : '/api/v1/sql?' + querystring . stringify ( {
q : "DROP function raise(text, text)" ,
api _key : '1234'
} ) ,
headers : { host : 'vizzuality.cartodb.com' } ,
method : 'GET'
} , { } , function ( res ) {
try {
assert . equal ( res . statusCode , 200 , res . body ) ;
var parsedBody = JSON . parse ( res . body ) ;
} catch ( e ) { err = new Error ( err + ',' + e ) ; }
next ( err ) ;
} ) ;
} ,
function finish ( err ) {
done ( err ) ;
}
) ;
} ) ;
2013-06-15 00:35:04 +08:00
2012-11-01 20:16:46 +08:00
/ * *
* CORS
* /
test ( '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' ,
method : 'GET'
} , { } , function ( res ) {
assert . equal ( res . statusCode , 200 , res . body ) ;
// Check cache headers
assert . equal ( res . headers [ 'x-cache-channel' ] , 'cartodb_test_user_1_db: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" ) ;
done ( ) ;
} ) ;
} ) ;
2012-07-13 04:54:12 +08:00
} ) ;