# vi:filetype= my $ExePath; BEGIN { use FindBin; $ExePath = "$FindBin::Bin/../haskell/bin/restyscript"; if (!-f $ExePath) { $skip = "$ExePath is not found.\n"; return; } if (!-x $ExePath) { $skip = "$ExePath is not an executable.\n"; return; } }; use t::OpenResty $skip ? (skip_all => $skip) : (); plan tests => 3 * blocks(); run_tests; __DATA__ === TEST 1: Delete existing models --- request DELETE /=/model?_user=$TestAccount&_password=$TestPass&_use_cookie=1 --- response {"success":1} === TEST 2: Delete existing actions --- request DELETE /=/action --- response {"success":1,"warning":"Builtin actions were skipped."} === TEST 3: Create a model --- request POST /=/model/Carrie.js { "description": "我的书签", "columns": [ { "name": "title", "type":"text", "label": "标题" }, { "name": "url", "type":"text", "label": "网址" }, { "name": "num", "type": "integer", "label": "num" } ] } --- response {"success":1} === TEST 4: insert a record --- request POST /=/model/Carrie/~/~.js { "title":"hello carrie","url":"http://www.carriezh.cn/","num":"10"} --- response {"success":1,"rows_affected":1,"last_row":"/=/model/Carrie/id/1"} === TEST 5: insert another record --- request POST /=/model/Carrie/~/~.js { "title":"second","url":"http://zhangxiaojue.cn","num":"1"} --- response {"success":1,"rows_affected":1,"last_row":"/=/model/Carrie/id/2"} === TEST 6: create an action --- request POST /=/action/Query {"definition": "select * from Carrie where title = 'hello carrie' and num=10; select * from Carrie where title = 'hello carrie' and num=10;"} --- response {"success":1} === TEST 7: Invoke the action --- request GET /=/action/Query/~/~ --- response [ [{"num":"10","url":"http://www.carriezh.cn/","title":"hello carrie","id":"1"}], [{"num":"10","url":"http://www.carriezh.cn/","title":"hello carrie","id":"1"}] ] === TEST 8: Update the def to introduce vars --- request PUT /=/action/Query { "parameters":[{"name":"num","type":"literal"}], "definition": "select title from Carrie where num = $num; select url from Carrie where num = $num"} --- response {"error":"Unrecognized key in hash: parameters","success":0} === TEST 9: Add a parameter --- request POST /=/action/Query/~ {"name":"num","type":"literal"} --- response {"src":"/=/model/Query/num","success":1} === TEST 10: Update the definition --- request PUT /=/action/Query { "definition": "select title from Carrie where num = $num; select url from Carrie where num = $num"} --- response {"success":1} === TEST 11: Invoke the action --- request GET /=/action/Query/num/10 --- response [ [{"title":"hello carrie"}], [{"url":"http://www.carriezh.cn/"}] ] === TEST 12: Invoke the action --- request GET /=/action/Query/num/1 --- response [ [{"title":"second"}], [{"url":"http://zhangxiaojue.cn"}] ] === TEST 13: Reference nonexistent models --- request PUT /=/action/Query { "definition": "select * from BlahBlah limit 1 offset 1"} --- response {"success":0,"error":"Model \"BlahBlah\" not found."} === TEST 14: Try to reference meta models --- request PUT /=/action/Query { "definition": "select * from _models limit 1 offset 1"} --- response {"error":"\"action\" (line 1, column 15):\nunexpected \"_\"\nexpecting space or model","success":0} === TEST 15: Invalid method --- request PUT /=/action/RunAction/~/~ {"definition":""} --- response {"success":0,"error":"HTTP PUT method not supported for action exec."} === TEST 16: Empty restyscript string --- request PUT /=/action/RunAction {"definition":""} --- response {"error":"Restyscript source must be an non-empty literal string: \"\"","success":0} --- SKIP === TEST 17: GET rows --- request GET /=/model/Carrie/~/~ --- response [ {"num":"10","url":"http://www.carriezh.cn/","title":"hello carrie","id":"1"}, {"num":"1","url":"http://zhangxiaojue.cn","title":"second","id":"2"} ] === TEST 18: Add a new parameter --- request POST /=/action/Query/~ {"name":"num","type":"literal","default":"5"} --- response {"success":0,"error":"Unrecognized key in hash: default"} === TEST 19: Add a default value --- request PUT /=/action/Query/num {"default_value":"5"} --- response {"success":1} === TEST 20: Update some rows --- request PUT /=/action/Query { "definition": "update Carrie set num=$num where num=10 or num=1" } --- response {"success":1} === TEST 21: Invoke the new Query action --- request GET /=/action/Query/~/~ --- response [{"success":1,"rows_affected":2}] === TEST 22: check rows again --- request GET /=/model/Carrie/~/~ --- response [ {"num":"5","url":"http://www.carriezh.cn/","title":"hello carrie","id":"1"}, {"num":"5","url":"http://zhangxiaojue.cn","title":"second","id":"2"} ] === TEST 23: run the action again --- request GET /=/action/Query/~/~ --- response [{"success":1,"rows_affected":0}] === TEST 24: run the action again (with argument) --- request GET /=/action/Query/num/7 --- response [{"success":1,"rows_affected":0}] === TEST 25: Add a parameter --- request POST /=/action/Query/~ {"name":"col","type":"symbol"} --- response {"success":1,"src":"/=/model/Query/col"} === TEST 26: Do two updates --- request PUT /=/action/Query {"definition": "update Carrie set $col=7 where id=1; update Carrie set $col=8 where id=2"} --- response {"success":1} === TEST 27: Run the action w/o arguments --- request GET /=/action/Query/~/~ --- response {"success":0,"error":"Arguments required: col"} === TEST 28: Run the action with arguments --- request POST /=/action/Query/~/~ {"col":"_access"} --- response {"success":0,"error":"Bad value for parameter \"col\"."} === TEST 29: Run the action with arguments --- request POST /=/action/Query/~/~ {"col":"num"} --- response [{"success":1,"rows_affected":1},{"success":1,"rows_affected":1}] === TEST 30: Run the action with invalid arguments --- request POST /=/action/Query/~/~ {"col":"@#@@$^^#@"} --- response {"success":0,"error":"Bad value for parameter \"col\"."} === TEST 31: Run the action in the right way --- request POST /=/action/Query/~/~ {"col":"num"} --- response [{"rows_affected":1,"success":1},{"rows_affected":1,"success":1}] === TEST 32: check rows again --- request GET /=/model/Carrie/~/~ --- response [ {"num":"7","url":"http://www.carriezh.cn/","title":"hello carrie","id":"1"}, {"num":"8","url":"http://zhangxiaojue.cn","title":"second","id":"2"} ] === TEST 33: remove parameters --- request DELETE /=/action/Query/~ --- response {"success":0,"error":"Failed to remove parameter \"col\": it's used in the definition."} === TEST 34: remove parameters --- request PUT /=/action/Query {"definition":"select 0"} --- response {"success":1} === TEST 35: remove parameters --- request DELETE /=/action/Query/~ --- response {"success":1} === TEST 36: check the action --- request GET /=/action/Query/~ --- response [] === TEST 37: Add a new parameter --- request POST /=/action/Query/dir {"type":"keyword"} --- response {"success":1,"src":"/=/model/Query/dir"} === TEST 38: order by a var --- request PUT /=/action/Query {"definition": "select id from Carrie order by id $dir"} --- response {"success":1} === TEST 39: invoke it with dir = asc --- request GET /=/action/Query/dir/asc --- response [[ {"id":"1"}, {"id":"2"} ]] === TEST 40: invoke it with dir = desc --- request GET /=/action/Query/dir/desc --- response [[ {"id":"2"}, {"id":"1"} ]] === TEST 41: invoke with invalid dir --- request GET /=/action/Query/dir/blah' --- response {"error":"Invalid valud for parameter \"dir\".","success":0} === TEST 42: Add a new parameter --- request POST /=/action/Query/num {"type":"literal"} --- response {"success":1,"src":"/=/model/Query/num"} === TEST 43: Delete rows --- request PUT /=/action/Query {"definition":"delete from Carrie\n where num = $num;;" } --- response {"success":1} === TEST 44: Invoke the action --- request GET /=/action/Query/num/7 --- response [{"success":1,"rows_affected":1}] === TEST 45: check rows again --- request GET /=/model/Carrie/~/~ --- response [{"num":"8","url":"http://zhangxiaojue.cn","title":"second","id":"2"}] === TEST 46: Add a new parameter Yahoo --- request POST /=/action/Query/~ {"name":"Yahoo","type":"literal"} --- response {"success":1,"src":"/=/model/Query/Yahoo"} === TEST 47: Add a new parameter Yahoo (twice) --- request POST /=/action/Query/~ {"name":"Yahoo","type":"literal"} --- response {"error":"Parameter \"Yahoo\" already exists in action \"Query\".","success":0} === TEST 48: Add a new parameter Google --- request POST /=/action/Query/~ {"name":"Google","type":"literal"} --- response {"success":1,"src":"/=/model/Query/Google"} === TEST 49: Insert some more data via actions --- request PUT /=/action/Query {"definition": "POST '/=/model/Carrie' || '/~/~' [{num: 5, url: 'yahoo.cn', title: $Yahoo}, {'num': 6, url: 'google' || '.com', \"title\": $Google}]" } --- response {"success":1} === TEST 50: Invoke it --- request GET /=/action/Query/Yahoo/Yahoo?Google=Google --- response [{"success":1,"rows_affected":2,"last_row":"/=/model/Carrie/id/4"}] === TEST 51: Add a new parameter col --- request POST /=/action/Query/~ {"name":"col","type":"symbol"} --- response {"success":1,"src":"/=/model/Query/col"} === TEST 52: three GET in an action --- request PUT /=/action/Query {"definition": "GET '/=/model/Carrie' || '/' || $col || '/4'; GET '/=/model/Carrie/' || $col || '/3';\n GET '/=/model/Carrie/' || $col || '/2';" } --- response {"success":1} === TEST 53: Invoke it --- request GET /=/action/Query/col/id --- response [ [{"num":"6","url":"google.com","title":"Google","id":"4"}], [{"num":"5","url":"yahoo.cn","title":"Yahoo","id":"3"}], [{"num":"8","url":"http://zhangxiaojue.cn","title":"second","id":"2"}] ] === TEST 54: three GET in an action (with exceptions) --- request PUT /=/action/Query {"definition": "GET '/=/model/Carrie' || '/id/4'; GET '/=/blah/blah'; GET '/=/model';" } --- response {"success":1} === TEST 55: Invoke it --- request GET /=/action/Query/~/~ --- response [ [{"id":"4","num":"6","title":"Google","url":"google.com"}], {"error":"Handler for the \"blah\" category not found.","success":0}, [{"description":"我的书签","name":"Carrie","src":"/=/model/Carrie"}] ] === TEST 56: Invoke it using yaml --- request GET /=/action/Query/~/~.yml --- format: YAML --- response --- - - id: 4 num: 6 title: Google url: google.com - error: Handler for the "blah" category not found. success: 0 - - description: "\xE6\x88\x91\xE7\x9A\x84\xE4\xB9\xA6\xE7\xAD\xBE" name: Carrie src: /=/model/Carrie === TEST 57: Add a new parameter model --- request POST /=/action/Query/~ {"name":"model","type":"symbol"} --- response {"success":1,"src":"/=/model/Query/model"} === TEST 58: delete mixed in 2 GET --- request PUT /=/action/Query {"definition": "DELETE '/=/model/'||$model|| '/id/4';\n GET ('/=/model/'||$model||'/~/~') ; delete from Carrie where id = 3\n ;GET '/=/' || ('model/' || $model ||'/~/~')" } --- response {"success":1} === TEST 59: Invoke it --- request GET /=/action/Query/model/Carrie --- response [ {"rows_affected":1,"success":1}, [ {"id":"2","num":"8","title":"second","url":"http://zhangxiaojue.cn"}, {"id":"3","num":"5","title":"Yahoo","url":"yahoo.cn"} ], {"rows_affected":1,"success":1}, [{"id":"2","num":"8","title":"second","url":"http://zhangxiaojue.cn"}] ] === TEST 60: access another account --- request POST /=/action/Query2 {"definition": "DELETE '/=/model?_user=' || $user || '&_password=' || $pass;\nPOST '/=/model/Another' {\"description\":\"a model in another account\"};\n GET '/=/model';\n GET '/=/model?_user=$TestAccount2&_password=$TestPass2'", "parameters":[ {"name":"user","type":"literal"}, {"name":"pass","type":"literal"} ]} --- response {"success":1} === TEST 61: Invoke it --- request POST /=/action/Query2/user/$TestAccount2 {"pass":"$TestPass2"} --- response [ {"success":1}, {"success":1,"warning":"No 'columns' specified for model \"Another\"."}, [ {"description":"我的书签","name":"Carrie","src":"/=/model/Carrie"}, {"description":"a model in another account","name":"Another","src":"/=/model/Another"} ], [] ] === TEST 62: check Test account 2: --- request GET /=/model?_user=$TestAccount2&_password=$TestPass2 --- response [] === TEST 63: recheck Test account 1: --- request GET /=/model?_user=$TestAccount&_password=$TestPass&_use_cookie=1 --- response [ {"src":"/=/model/Carrie","name":"Carrie","description":"我的书签"}, {"src":"/=/model/Another","name":"Another","description":"a model in another account"} ] === TEST 64: NewComment --- request POST /=/action/NewComment { "description":"New comment", "parameters":[ { "name": "sender", "type": "literal" }, { "name": "email", "type": "literal" }, { "name": "url", "type": "literal" }, { "name": "body", "type": "literal" }, { "name": "post_id", "type": "literal" } ], "definition":"POST '/=/model/Comment/~/~' { sender: $sender, email: $email, url: $url, body: $body, post: $post_id }; update Carrie set num = num + 1 where id = $post_id;" } --- response {"success":1} === TEST 65: logout --- request GET /=/logout --- response {"success":1}