From f857bfb1af6535371a2f2b77ff0b1ac6c24e0a52 Mon Sep 17 00:00:00 2001 From: "V. Soshnikov" Date: Wed, 10 Jan 2018 04:01:37 +0300 Subject: [PATCH] #110 and #110 were not bugs. It was urlencoded issue. I updated tests and updated readme . Also I added few good examples. --- README.md | 162 ++++++++++++------------------- examples/simple_rest_client.py | 131 +++++++++++++++++++++++++ examples/simple_rest_client.sh | 67 +++++++++++++ src/ngx_http_tnt_module.c | 54 +++++++++-- src/ngx_http_tnt_version.h | 2 +- t/http_utils.py | 112 ++++++++++++++++----- t/ngx_confs/nginx.dev.conf | 16 +-- t/ngx_confs/tnt_server_test.conf | 24 +++++ t/parallel_clients.sh | 2 +- t/test.lua | 3 + t/v23_features.py | 4 +- t/v25_features.py | 24 +++-- t/v26_features.py | 108 +++++++++++++++++---- 13 files changed, 540 insertions(+), 169 deletions(-) create mode 100755 examples/simple_rest_client.py create mode 100755 examples/simple_rest_client.sh diff --git a/README.md b/README.md index 705399e..4c3714b 100644 --- a/README.md +++ b/README.md @@ -901,6 +901,8 @@ a query string and MsgPack without losing type information or value. The syntax is: `{QUERY_ARG_NAME}=%{FMT_TYPE}` +Please look carefully for yours url encoding! + A good example is (also see examples [tnt_update](#tnt_update) and [tnt_upsert](#tnt_upsert)): ``` HTTP GET ... /url?space_id=512&value=some+string @@ -949,8 +951,8 @@ Operations (for [tnt_upsert](#tnt_upsert)) Examples can be found at: -* `./t/ngx_confs/tnt_server_test.conf:342` -* `./t/v26_features.py` +* `examples/simple_rest_client.py` +* `examples/simple_rest_client.sh` [Back to contents](#contents) @@ -962,6 +964,10 @@ tnt_insert **context:** *location, location if* +**HTTP methods** *GET, POST, PUT, PATCH, DELETE* + +**Content-Typer** *default, application/x-www-form-urlencoded* + This directive allows executing an insert query with Tarantool. * The first argument is a space id. @@ -989,6 +995,11 @@ Here is a description: See "message"/"code" fields for details. +Examples can be found at: + +* `simple_rest_client.py` +* `simple_rest_client.sh` + [Back to contents](#contents) @@ -1000,6 +1011,10 @@ tnt_replace **context:** *location, location if* +**HTTP methods** *GET, POST, PUT, PATCH, DELETE* + +**Content-Typer** *default, application/x-www-form-urlencoded* + This directive allows executing a replace query with Tarantool. * The first argument is a space id. @@ -1027,6 +1042,11 @@ Here is a description: See "message"/"code" fields for details. +Examples can be found at: + +* `examples/simple_rest_client.py` +* `examples/simple_rest_client.sh` + [Back to contents](#contents) tnt_delete @@ -1037,6 +1057,10 @@ tnt_delete **context:** *location, location if* +**HTTP methods** *GET, POST, PUT, PATCH, DELETE* + +**Content-Typer** *default, application/x-www-form-urlencoded* + This directive allows executing a delete query with Tarantool. * The first argument is a space id. @@ -1065,6 +1089,11 @@ Here is a description: See "message"/"code" fields for details. +Examples can be found at: + +* `examples/simple_rest_client.py` +* `examples/simple_rest_client.sh` + [Back to contents](#contents) @@ -1076,6 +1105,10 @@ tnt_select **context:** *location, location if* +**HTTP methods** *GET, POST, PUT, PATCH, DELETE* + +**Content-Typer** *default, application/x-www-form-urlencoded* + This directive allows executing a select query with Tarantool. * The first argument is a space id. @@ -1109,6 +1142,11 @@ Here is a description: See "message"/"code" fields for details. +Examples can be found at: + +* `examples/simple_rest_client.py` +* `examples/simple_rest_client.sh` + [Back to contents](#contents) tnt_select_limit_max @@ -1119,6 +1157,10 @@ tnt_select_limit_max **context:** *server, location, location if* +**HTTP methods** *GET, POST, PUT, PATCH, DELETE* + +**Content-Typer** *default, application/x-www-form-urlencoded* + This is a constraint to avoid *large selects*. This is the maximum number of returned tuples per select operation. If the client reaches this limit, then the client gets an error on its side. @@ -1145,6 +1187,11 @@ Here is a description: See "message"/"code" fields for details. +Examples can be found at: + +* `examples/simple_rest_client.py` +* `examples/simple_rest_client.sh` + [Back to contents](#contents) tnt_allowed_spaces @@ -1204,6 +1251,10 @@ tnt_update **context:** *location, location if* +**HTTP methods** *GET, POST, PUT, PATCH, DELETE* + +**Content-Typer** *default, application/x-www-form-urlencoded* + This directive allows executing an update query with Tarantool. * The first argument is a space id. @@ -1233,72 +1284,10 @@ section [1]. * The third argument is a [format](#format) string. -[1] Example - -it is just an example, it does not contain any tuning settings and -additinitional validation! - -* nginx.conf -```nginx.conf -# ... -upstrean backend { - server 127.0.0.1:3113; -} - -# ... -location /delete { - tnt_delete 512 0 "id=%n"; - tnt_pass tnt; -} -location /select { - tnt_select 512 0 0 100 ge "id=%n"; - tnt_pass tnt; -} -location /update { - tnt_update 512 "id=%kn" "value=%s,value1=%f"; - tnt_pass tnt; -} -location /insert { - tnt_insert 512 "id=%kn" "value=%s,value1=%f"; - tnt_pass backend; -} - -``` - -* Tarantool -```lua --- ... - -box.cfg{listen=3113} - --- ... -t = box.schema.space.create('t1', {if_not_exists=true}) -t:create_index('pk', {if_not_exists=true}) -``` - -* Client request -```bash -$ curl -X POST -d id=3113 http://127.0.0.1:8081/insert -{"id":0,"result":[[3113]]} - -$ curl 'http://127.0.0.1:8081/select?id=3113' -{"id":0,"result":[[3113]]} - -$ curl -X POST -d id=3113 -d 'value==,1,Delta compression using up to 4 threads.' -d value1==,2,3.14 http://127.0.0.1:8081/update_post -{"id":0,"result":[[3113,"Delta compression using up to 4 threads.",3.140000]]}+ - -### NOTICE! %2B is urlescaped('+') -$ curl -X POST -d id=3113 -d value1=%2B,2,5.14 http://127.0.0.1:8081/update {"id":0,"result":[[3113,"Delta compression using up to 4 threads.",8.280000]]} - -$ curl 'http://127.0.0.1:8081/select?id=3113' -{"id":0,"result":[[3113,"Delta compression using up to 4 threads.",8.280000]]} - -curl -X POST -d id=3113 http://127.0.0.1:8081/delete -{"id":0,"result":[[3113,"Delta compression using up to 4 threads.",8.280000]]} +Examples can be found at: -curl 'http://127.0.0.1:8081/select?id=3113' -{"id":0,"result":[]} -``` +* `examples/simple_rest_client.py` +* `examples/simple_rest_client.sh` Returns HTTP code 4XX if client's request doesn't well formatted. It means, that this error raised if some of values missed or has wrong type. @@ -1332,6 +1321,10 @@ tnt_upsert **context:** *location, location if* +**HTTP methods** *GET, POST, PUT, PATCH, DELETE* + +**Content-Typer** *default, application/x-www-form-urlencoded* + This directive allows executing an upsert query with Tarantool. * The first argument is a space id. @@ -1363,39 +1356,10 @@ section [1]. [1] Example -it is just an example, it does not contain any tuning settings and -additinitional validation! - -* nginx.conf -```nginx.conf -# ... -upstrean backend { - server 127.0.0.1:3113; -} - -# ... -location /upsert { - tnt_delete 512 0 "new_id=%n,new_value=%s" "updated_value=%os"; - tnt_pass tnt; -} -``` - -* Tarantool -```lua --- ... - -box.cfg{listen=3113} - --- ... -local t = box.schema.space.create('t1', {if_not_exists=true}) -t:create_index('pk', {if_not_exists=true}) -``` +Examples can be found at: -* Client request -```bash -$ curl -X POST -d new_id=3113 -d new_value=str -d updated_value==,2,ustr http://127.0.0.1:8081/upsert -{"id":0,"result":[[3113, "ustr"]]} -``` +* `examples/simple_rest_client.py` +* `examples/simple_rest_client.sh` Returns HTTP code 4XX if client's request doesn't well formatted. It means, that this error raised if some of values missed or has wrong type. diff --git a/examples/simple_rest_client.py b/examples/simple_rest_client.py new file mode 100755 index 0000000..d957661 --- /dev/null +++ b/examples/simple_rest_client.py @@ -0,0 +1,131 @@ +#!/usr/bin/python + +import json +import urllib +import urllib2 + +# +# Notice +# +# 1. Tarantool conf {{{ +# box.cfg {listen = 3113} +# tester = box.schema.space.create('tester', {if_not_exist=true}) +# index = tester:create_index('pk', {parts{1, 'str'}}) +# print ('SPACE_ID = ', tester.id) +# print ('INDEX_ID = ', index.id) +# }}} +# +# 2. nginx.conf {{{ +# +# upstream tnt { +# server 127.0.0.1:3113; +#} +# +# location /api/v1/kv { +# +# tnt_http_rest_methods get post put delete patch; +# +# if ($request_method = GET) { +# tnt_select {SPACE_ID} {INDEX_ID} 0 100 all "key=%s"; +# } +# if ($request_method = POST) { +# tnt_insert {SPACE_ID} "key=%s,value=%n"; +# } +# if ($request_method = PUT) { +# tnt_update {SPACE_ID} "key=%ks" "value=%n"; +# } +# if ($request_method = DELETE) { +# tnt_delete {SPACE_ID} {INDEX_ID} "key=%s"; +# } +# if ($request_method = PATCH) { +# tnt_upsert {SPACE_ID} "key=%s,new_value=%n" "updated_value=%on"; +# tnt_pass tnt; +# } +# +# tnt_pass tnt; +# } + +# Helpers {{{ +def request(req_url, args, req_type): + try: + url = req_url + '?' + urllib.urlencode(args) + + req = urllib2.Request(url) + req.get_method = lambda: req_type + res = urllib2.urlopen(req) + + out = res.read() + out = out + res.read() + + return json.loads(out) + except urllib2.HTTPError as e: + return (e.code, json.loads(e.read())) + +def select_eq(url, data): + return request(url, data, 'GET') + +def update(url, data): + return request(url, data, 'PUT') + +def insert(url, data): + return request(url, data, 'POST') + +def upsert(url, data): + return request(url, data, 'PATCH') + +def delete(url, data): + return request(url, data, 'DELETE') +# }}} + + +# +# Test starts here +# +req_url = 'http://127.0.0.1:8081/api/v1/kv' + +# === +# insert into the 'tester' +inserted = insert(req_url, { 'key': 'my_key', 'value': 10}) +# should be {"restul": [[{list of insterted values}]] }, if okay +print ('inserted = ', inserted) + + +# === +# upsert (insert in this case) into the 'tester' +upserted = upsert(req_url, { 'key': 'my_key_1', 'new_value': 100, + "updated_value": "+,1,10"}) + +# should be {"result": []}, if okay +print ('upserted = ', upserted) + +# === +# add 10 to the value into the 'tester' +upserted = upsert(req_url, { 'key': 'my_key_1', 'new_value': 1000, + "updated_value": "+,1,10"}) +# should be {"result": []}, if okay +print ('upserted = ', upserted) + +# === +# - 10 to the value into the 'tester' +updated = update(req_url, { 'key': 'my_key', 'value': "-,1,10"}) +# should be {"result": [[{list of updated values}]]}, if okay +print ('updated = ', updated) + +# === +# Select by key +selected_1 = select_eq(req_url, {'key': 'my_key'}) +selected_2 = select_eq(req_url, {'key': 'my_key_1'}) +# should be {"result": [[{list of updated values}]]}, if okay +print ('selected_1 = ', selected_1) +print ('selected_2 = ', selected_2) + +# === +# Delete by key +deleted = delete(req_url, {'key': 'my_key'}) +# should be {"result": [[{list of deleted values}]]}, if okay +print ('deleted = ', deleted) + +deleted = delete(req_url, {'key': 'my_key_1'}) +# should be {"result": [[{list of deleted values}]]}, if okay +print ('deleted = ', deleted) + diff --git a/examples/simple_rest_client.sh b/examples/simple_rest_client.sh new file mode 100755 index 0000000..9fef5bf --- /dev/null +++ b/examples/simple_rest_client.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# +# Notice +# +# 1. Tarantool conf {{{ +# box.cfg {listen = 3113} +# tester = box.schema.space.create('tester', {if_not_exist=true}) +# index = tester:create_index('pk', {parts{1, 'str'}}) +# print ('SPACE_ID = ', tester.id) +# print ('INDEX_ID = ', index.id) +# }}} +# +# 2. nginx.conf {{{ +# +# upstream tnt { +# server 127.0.0.1:3113; +#} +# +# location /api/v1/kv { +# +# tnt_http_rest_methods get post put delete patch; +# +# if ($request_method = GET) { +# tnt_select {SPACE_ID} {INDEX_ID} 0 100 all "key=%s"; +# } +# if ($request_method = POST) { +# tnt_insert {SPACE_ID} "key=%s,value=%n"; +# } +# if ($request_method = PUT) { +# tnt_update {SPACE_ID} "key=%ks" "value=%n"; +# } +# if ($request_method = DELETE) { +# tnt_delete {SPACE_ID} {INDEX_ID} "key=%s"; +# } +# if ($request_method = PATCH) { +# tnt_upsert {SPACE_ID} "key=%s,new_value=%n" "updated_value=%on"; +# tnt_pass tnt; +# } +# +# tnt_pass tnt; +# } + +req_url='http://127.0.0.1:8081/api/v1/kv' + +# Insert values into the tester +echo Inserted = `curl -s -X POST -d 'key=my_key_5' -d 'value=1' $req_url` +echo inserted = `curl -s -X POST $req_url?"key=my_key_6&value=2"` + +# Update values into the tester + +# %23 is urencode('#'). Delete field from the tuple +echo Updated = `curl -s -X PUT $req_url?"key=my_key_5&value=%23,1,10"` +# %2B is urencode('+') +echo Updated = `curl -s -X PUT -d 'key=my_key_6' -d "value=%2B,1,999" $req_url` + +# %3D is urencode('='). +echo Upserted = `curl -s -X PATCH $req_url?"key=my_key_5&new_value=10&updated_value=%3D,1,10"` + +# Select values from the tester +echo Selected = `curl -s $req_url?key=my_key_5` +echo Selected = `curl -s -X GET -d 'key=my_key_6' $req_url` + +# Delete values from the tester +echo Deleted = `curl -s -X DELETE $req_url?key=my_key_5` +echo Deleted = `curl -s -X DELETE -d 'key=my_key_6' $req_url` + diff --git a/src/ngx_http_tnt_module.c b/src/ngx_http_tnt_module.c index e6ab41f..c8ca6f6 100644 --- a/src/ngx_http_tnt_module.c +++ b/src/ngx_http_tnt_module.c @@ -342,6 +342,8 @@ static void ngx_http_tnt_abort_request(ngx_http_request_t *r); static void ngx_http_tnt_finalize_request(ngx_http_request_t *r, ngx_int_t rc); /** Some helpers */ +static ngx_int_t ngx_http_tnt_str_match(ngx_str_t *a, const char *b, + size_t len); static ngx_int_t ngx_http_tnt_set_err(ngx_http_request_t *r, int errcode, const u_char *msg, size_t msglen); #define ngx_http_tnt_set_err_str(r, code, str) \ @@ -1775,6 +1777,7 @@ ngx_http_tnt_format_prepare(ngx_http_tnt_loc_conf_t *conf, for (; arg.it < end; ) { + arg = ngx_http_tnt_get_next_arg(arg.it, end); if (arg.value != NULL) { @@ -1851,6 +1854,7 @@ ngx_http_tnt_format_prepare(ngx_http_tnt_loc_conf_t *conf, rc = ngx_http_tnt_format_prepare_kv(r, prepared_result, &key, &value); + if (rc != NGX_OK) { return rc; } @@ -2008,15 +2012,16 @@ ngx_http_tnt_format_bind_operation(ngx_http_request_t *r, struct tp *tp, switch (*update_operation) { case '=': - case '!': - case '+': - case '-': - case '&': - case '^': - case '|': - break; - default: - goto no_operation_type; + case '!': + case '+': + case '-': + case '&': + case '^': + case '|': + case '#': + break; + default: + goto no_operation_type; } filedno_pt = ngx_http_tnt_read_next(val, ','); @@ -3450,6 +3455,22 @@ ngx_http_tnt_init_handlers(ngx_http_request_t *r, ngx_http_upstream_t *u, u->create_request = ngx_http_tnt_query_handler; if (tlcf->req_type > 0) { + + if (r->headers_in.content_type != NULL && + r->headers_in.content_type->value.len > 0) + { + + if (!ngx_http_tnt_str_match(&r->headers_in.content_type->value, + "application/x-www-form-urlencoded", + sizeof("application/x-www-form-urlencoded") - 1) || + !ngx_http_tnt_str_match(&r->headers_in.content_type->value, + "application/x-www-form-urlencoded", + sizeof("application/x-www-form-urlencoded") - 1)) + { + return NGX_HTTP_NOT_ALLOWED; + } + } + u->create_request = ngx_http_tnt_dml_handler; return NGX_OK; } @@ -3788,6 +3809,7 @@ ngx_http_tnt_dml_handler(ngx_http_request_t *r) } break; case TP_DELETE: + if (tp_delete(&tp, (uint32_t) prepared_result.space_id, (uint32_t) prepared_result.index_id) == NULL || tp_key(&tp, prepared_result.tuples_count) == NULL) @@ -3964,6 +3986,20 @@ ngx_http_tnt_finalize_request(ngx_http_request_t *r, ngx_int_t rc) } +static ngx_int_t +ngx_http_tnt_str_match(ngx_str_t *a, const char *b, + size_t len) +{ + if (a->len != len) { + return 0; + } + if (ngx_strncmp(a->data, (const u_char *) b, len) == 0) { + return 1; + } + return 0; +} + + static ngx_int_t ngx_http_tnt_set_err(ngx_http_request_t *r, int errcode, const u_char *msg, size_t len) diff --git a/src/ngx_http_tnt_version.h b/src/ngx_http_tnt_version.h index 9ae8014..29f1e75 100644 --- a/src/ngx_http_tnt_version.h +++ b/src/ngx_http_tnt_version.h @@ -34,6 +34,6 @@ #ifndef NGX_HTTP_TNT_VERSION_H #define NGX_HTTP_TNT_VERSION_H 1 -#define NGX_HTTP_TNT_MODULE_VERSION_STRING "v2.6-rc2" +#define NGX_HTTP_TNT_MODULE_VERSION_STRING "v2.5-rc3" #endif diff --git a/t/http_utils.py b/t/http_utils.py index 9a07c77..64f71c0 100644 --- a/t/http_utils.py +++ b/t/http_utils.py @@ -112,18 +112,30 @@ def request_raw(url, data, headers): def request(url, data, headers = None): return request_raw(url, json.dumps(data), headers) -def put(url, data, headers): +def put(url, data, headers, dont_use_json = False): out = '{}' + res = None try: - req = urllib2.Request(url) - req.get_method = lambda: 'PUT' - if headers: - for header in headers: - req.add_header(header, headers[header]) - if data: - req.add_header('Content-Type', 'application/json') - res = urllib2.urlopen(req, json.dumps(data)) + if not dont_use_json: + req = urllib2.Request(url) + req.get_method = lambda: 'PUT' + if headers: + for header in headers: + req.add_header(header, headers[header]) + if data: + req.add_header('Content-Type', 'application/json') + res = urllib2.urlopen(req, json.dumps(data)) + else: + res = urllib2.urlopen(req) else: + full_url = url + if data and type(data) == type([]): + full_url = url + '?' + arr_of_dicts_to_string(data) + elif data: + full_url = url + '?' + urllib.urlencode(data) + + req = urllib2.Request(full_url) + req.get_method = lambda: 'PUT' res = urllib2.urlopen(req) out = res.read() @@ -149,6 +161,43 @@ def put(url, data, headers): print(traceback.format_exc()) return (False, e) +def patch(url, data): + out = '{}' + res = None + try: + full_url = url + if data and type(data) == type([]): + full_url = url + '?' + arr_of_dicts_to_string(data) + elif data: + full_url = url + '?' + urllib.urlencode(data) + + req = urllib2.Request(full_url) + req.get_method = lambda: 'PATCH' + res = urllib2.urlopen(req) + + out = res.read() + out = out + res.read() + rc = res.getcode() + + if VERBOSE: + print("code: ", rc, " recv: '", out, "'") + + if rc != 500: + return (rc, json.loads(out)) + + return (rc, False) + except urllib2.HTTPError as e: + if e.code == 400: + out = e.read(); + + if VERBOSE: + print("code: ", e.code, " recv: '", out, "'") + + return (e.code, json.loads(out)) + except Exception as e: + print(traceback.format_exc()) + return (False, e) + def arr_of_dicts_to_string(arr_of_dicts): res = "" @@ -245,31 +294,48 @@ def post_success_pure(url, data, headers=None): assert(code == 200), 'expected 200' return msg -def put_success(url, data, headers): - (code, msg) = put(url, data, headers) +def put_success(url, data, headers, dont_use_json = False): + (code, msg) = put(url, data, headers, dont_use_json) assert(code == 200), 'expected 200' result = get_result(msg) return result def put_fail(url, data, headers): - return put(url, data, headers) + return put(url, data, headers, False) + +def patch_success(url, data): + (code, msg) = patch(url, data) + assert(code == 200), 'expected 200' + result = get_result(msg) + return result def get_fail(url, data, headers): (code, msg) = get(url, data, headers) return (code, msg) -def delete(url, data, headers): +def delete(url, data, headers, dont_use_json = False): out = '{}' try: - req = urllib2.Request(url) - req.get_method = lambda: 'DELETE' - if headers: - for header in headers: - req.add_header(header, headers[header]) - if data: - req.add_header('Content-Type', 'application/json') - res = urllib2.urlopen(req, json.dumps(data)) + if not dont_use_json: + req = urllib2.Request(url) + req.get_method = lambda: 'DELETE' + if headers: + for header in headers: + req.add_header(header, headers[header]) + if data: + req.add_header('Content-Type', 'application/json') + res = urllib2.urlopen(req, json.dumps(data)) + else: + res = urllib2.urlopen(req) else: + full_url = url + if data and type(data) == type([]): + full_url = url + '?' + arr_of_dicts_to_string(data) + elif data: + full_url = url + '?' + urllib.urlencode(data) + + req = urllib2.Request(full_url) + req.get_method = lambda: 'DELETE' res = urllib2.urlopen(req) out = res.read() @@ -295,8 +361,8 @@ def delete(url, data, headers): print(traceback.format_exc()) return (False, e) -def delete_success(url, data, headers): - (code, msg) = delete(url, data, headers) +def delete_success(url, data, headers, dont_use_json = False): + (code, msg) = delete(url, data, headers, dont_use_json) assert(code == 200), 'expected 200' result = get_result(msg) return result diff --git a/t/ngx_confs/nginx.dev.conf b/t/ngx_confs/nginx.dev.conf index 7cfcdce..997ac71 100644 --- a/t/ngx_confs/nginx.dev.conf +++ b/t/ngx_confs/nginx.dev.conf @@ -1,15 +1,15 @@ -daemon off; -master_process off; -#worker_processes 4; +daemon off; #on; +master_process off; #on; +worker_processes 1; #2; + +#daemon on; +#master_process on; +#worker_processes 1; pid logs/nginx.pid; -error_log logs/notice.log notice; -error_log logs/info.log info; -error_log logs/crit.log crit; -error_log logs/debug.log debug; error_log stderr; -events {} +events {worker_connections 4000; multi_accept on;} include tnt_server_test.conf; diff --git a/t/ngx_confs/tnt_server_test.conf b/t/ngx_confs/tnt_server_test.conf index b2fbba4..b025879 100644 --- a/t/ngx_confs/tnt_server_test.conf +++ b/t/ngx_confs/tnt_server_test.conf @@ -431,5 +431,29 @@ http { tnt_pass tnt; } + # https://github.com/tarantool/nginx_upstream_module/issues/111 + # https://github.com/tarantool/nginx_upstream_module/issues/110 + location /issue_110_and_111 { + + tnt_http_rest_methods get post put delete patch; + + if ($request_method = GET) { + tnt_select 516 0 0 100 all "key=%s"; + } + if ($request_method = POST) { + tnt_insert 516 "key=%s,value=%n"; + } + if ($request_method = PUT) { + tnt_update 516 "key=%ks" "value=%n"; + } + if ($request_method = DELETE) { + tnt_delete 516 0 "key=%s"; + } + if ($request_method = PATCH) { + tnt_upsert 516 "key=%s,new_value=%n" "updated_value=%on"; + tnt_pass tnt; + } + tnt_pass tnt; + } } } diff --git a/t/parallel_clients.sh b/t/parallel_clients.sh index dab87a1..c8cc1e1 100755 --- a/t/parallel_clients.sh +++ b/t/parallel_clients.sh @@ -7,7 +7,7 @@ for i in {1..10}; do ./t/v24_features.py & # ./t/lua.py & ./t/v25_features.py & - ./t/v26_features.py & + ./t/v26_features.py done for i in `jobs -p`; do diff --git a/t/test.lua b/t/test.lua index 945a3fa..92db5b7 100755 --- a/t/test.lua +++ b/t/test.lua @@ -217,3 +217,6 @@ i = t:create_index('sk', {parts={1,'unsigned', 2, 'str'}, if_not_exists=true}) t = box.schema.space.create('t4', {if_not_exists=true}) t:create_index('pk', {if_not_exists=true}) + +t = box.schema.space.create('t5', {if_not_exists=true}) +t:create_index('pk', {if_not_exists=true, parts={1, 'str'}}) diff --git a/t/v23_features.py b/t/v23_features.py index c7bc8c8..df266a6 100755 --- a/t/v23_features.py +++ b/t/v23_features.py @@ -30,10 +30,10 @@ # ============ # print('[+] Parse query args overflow test') -for i in range(1, 100): +for i in range(1, 1000): args['arg' + str(i)] = 'some_string_plus_' + str(i) (code, msg) = get_fail(preset_method_location, args, {}) -assert(code == 414), 'expected http code 414' +assert(code == 500), 'expected http code 500' # ============ diff --git a/t/v25_features.py b/t/v25_features.py index aea438c..8b7f451 100755 --- a/t/v25_features.py +++ b/t/v25_features.py @@ -10,7 +10,8 @@ default_headers = {"Content-Type": "application/x-www-form-urlencoded"} preset_method_location = BASE_URL + '/url_encoded' - +# ============ +# print ('[+] Post form - 0 param') rc, out = post_form(preset_method_location, default_headers) assert rc == 200, "rc != 200" @@ -19,7 +20,8 @@ default_headers["Content-Type"], "Content-Type not equals" print ('[+] OK') - +# ============ +# print ('[+] Post form - 1 param') rc, out = post_form(preset_method_location, {"a": "b"}, default_headers) assert rc == 200, "rc != 200" @@ -29,7 +31,8 @@ assert out['result'][0]['body'][0] == {"a": "b"}, "not expected result" print ('[+] OK') - +# ============ +# print ('[+] Post form - N param') args = {} expected = [] @@ -56,7 +59,8 @@ count = count + 1 print ('[+] OK') - +# ============ +# print ('[+] Method ccv') for m in {"method_1", "method_2", "method_3"}: preset_method_location = BASE_URL + '/method_ccv/' + m + '/comming' @@ -66,7 +70,8 @@ 'not expected URL' print ('[+] OK') - +# ============ +# print ('[+] Headers ccv') preset_method_location = BASE_URL + '/headers_ccv' rc, out = get(preset_method_location, None, None) @@ -79,7 +84,8 @@ 'X-Uri is not expected' print ('[+] OK') - +# ============ +# print ('[+] Post form - identical params') preset_method_location = BASE_URL + '/url_encoded' rc, out = post_form(preset_method_location, "a=b&a=b&a=b&a=b", @@ -90,7 +96,8 @@ assert k['a'] == 'b', 'not expected' print ('[+] OK') - +# ============ +# print ('[+] Post - skip_count_1') preset_method_location = BASE_URL + '/skip_count_1' rc, out = post(preset_method_location, {'params': [{"arg1": 1}], 'id': 1}, @@ -100,7 +107,8 @@ assert out['result'][0]['arg1'] == 1, 'arg1 != 1' print ('[+] OK') - +# ============ +# print ('[+] Post - skip_count_2') preset_method_location = BASE_URL + '/skip_count_2' rc, out = post(preset_method_location, {'params': [{"arg1": 1}], 'id': 1}, diff --git a/t/v26_features.py b/t/v26_features.py index f2d403e..d4e303d 100755 --- a/t/v26_features.py +++ b/t/v26_features.py @@ -13,7 +13,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): res.append(k.values()[0]) return res[start_from:] - +# ============ +# print ('[+] basic insert') result = get_success(BASE_URL + '/delete', {'index': 1}, None, False) assert 'result' in result and 'id' in result, 'expected: result and id' @@ -45,7 +46,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): assert result == arr_of_dicts_to_arr(insert_2), "Expected != result" print ('[+] OK') - +# ============ +# print ('[+] basic select') result = get_success(BASE_URL + '/select', {'index': 0}, None, False) assert arr_of_dicts_to_arr(insert_1) == result['result'][0], \ @@ -54,7 +56,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): "Expected != result" print ('[+] OK') - +# ============ +# print ('[+] basic replace') insert_1[5]['int'] = 1000000 result = get_success(BASE_URL + '/replace', insert_1, None) @@ -62,7 +65,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): "Expected != result" print ('[+] OK') - +# ============ +# print ('[+] basic delete') result = get_success(BASE_URL + '/delete', {'index': 1}, None) assert arr_of_dicts_to_arr(insert_1) == result, \ @@ -72,13 +76,15 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): "Expected != result" print ('[+] OK') - +# ============ +# print ('[+] https://github.com/tarantool/nginx_upstream_module/issues/98') result = get_success(BASE_URL + '/error_if_escaped', {'getArg': 'a b'}, None) assert result == True, 'Expected True' print ('[+] OK') - +# ============ +# print ('[+] insert + extented format') data = [ @@ -101,7 +107,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): assert arr_of_dicts_to_arr(data, 2) == result, 'Expected != result' print ('[+] OK') - +# ============ +# print ('[+] select + extented format') data = [ @@ -147,7 +154,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): assert result == arr_of_dicts_to_arr(data, 2), "Expected != result" print ('[+] OK') - +# ============ +# print ('[+] select + extented format w/o FMT args') rc, result = get(BASE_URL + '/select_ext_fmt',[ @@ -172,7 +180,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): print ('[+] OK') - +# ============ +# print ('[+] select will reach a limit') rc, result = get(BASE_URL + '/select_ext_fmt',[ {'space_id': 10}, {'index_id': 10}, {'iter': 'ge'}, {'limit': 1000 }, @@ -180,7 +189,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): assert rc == 400, 'Expected 400' print ('[+] OK') - +# ============ +# print ('[+] insert + extented format w/o space_id') data = [ @@ -232,7 +242,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): print ('[+] OK') - +# ============ +# print ('[+] Allowed spaces and indexes') rc, result = get(BASE_URL + '/dml_allowed_sp', [ @@ -249,7 +260,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): print ('[+] OK') - +# ============ +# print ('[+] Wrong order') data = [ @@ -279,7 +291,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): print ('[+] OK') - +# ============ +# print ('[+] Format validation') data = [ {'space_id': 513}, @@ -329,7 +342,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): print ('[+] OK') - +# ============ +# print ('[+] Update multipart index') result = get_success(BASE_URL + '/delete_mt_fmt', { @@ -371,7 +385,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): print ('[+] OK') - +# ============ +# print ('[+] Upsert') upsert = [ @@ -405,7 +420,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): print ('[+] OK') - +# ============ +# print ('[+] Issue - https://github.com/tarantool/nginx_upstream_module/issues/108') data = [] @@ -418,7 +434,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): print ('[+] OK') - +# ============ +# print ('[+] Post urlencoded') post_form_success(BASE_URL + '/delete_post', {'id': 11}, None) @@ -435,7 +452,8 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): print ('[+] OK') - +# ============ +# print ('[+] Update format validation') _, result = post_form(BASE_URL + '/update_post', {'id': 12, 'value': '=,TEXT', @@ -453,3 +471,57 @@ def arr_of_dicts_to_arr(arr_of_dicts, start_from = 0): assert _ == 400 and 'error' in result, 'Expected != result' print ('[+] OK') + +# ============ +# +print (''' [+] Issues + https://github.com/tarantool/nginx_upstream_module/issues/110 and + https://github.com/tarantool/nginx_upstream_module/issues/111 + ''') + +## Issue 111 +_, result = delete(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc'}, None, True) +assert _ == 200 and 'result' in result and 'id' in result, 'expected: result and id' + +post_form_success(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc', 'value': '10'}, + None) + +result = put_success(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc', 'value': '#,1,10'}, None, True) +assert result[0] == 'test_inc', "Expected != Result" + +result = get_success(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc'}, None) +assert result[0] == 'test_inc', "Expected != Result" + + +## Issue 110 +_, result = delete(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc_2'}, None, True) +assert _ == 200 and 'result' in result and 'id' in result, \ + 'expected: result and id' + +post_form_success(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc_2', 'value': '1'}, + None) + +_, result = patch(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc_2', 'new_value' : 1, 'updated_value': '+,1,5'}) +assert _ == 200 and 'result' in result and 'id' in result, \ + 'expected: result and id' + +result = get_success(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc_2'}, None) +assert result[1] == 6, "Expected != Result" + +_, result = patch(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc_2', 'new_value' : 1, 'updated_value': '=,1,5'}) +assert _ == 200 and 'result' in result and 'id' in result, \ + 'expected: result and id' +result = get_success(BASE_URL + '/issue_110_and_111', \ + {'key': 'test_inc_2'}, None) +assert result[1] == 5, "Expected != Result" + +print ('[+] OK')