all: bin/restful_annot
mkdir -p bin/
- ../../../bin/nitc --dir bin src/nitcorn_hello_world.nit src/simple_file_server.nit
+ nitc --dir bin src/nitcorn_hello_world.nit src/simple_file_server.nit
pre-build: src/restful_annot_gen.nit
src/restful_annot_gen.nit:
- ../../../bin/nitrestful -o $@ src/restful_annot.nit
+ nitrestful -o $@ src/restful_annot.nit
bin/restful_annot: src/restful_annot_gen.nit
mkdir -p bin/
- ../../../bin/nitc -o $@ src/restful_annot_gen.nit
+ nitc -o $@ src/restful_annot_gen.nit
+
+check: src/restful_annot_gen.nit
+ mkdir -p bin/ out/
+ nitc -o bin/test_restful_annot src/test_restful_annot.nit -m src/restful_annot_gen.nit
+ bin/test_restful_annot > out/test_restful_annot.res 2>&1
+ diff sav/test_restful_annot.res out/test_restful_annot.res
--- /dev/null
+[Client] curl -s 'localhost:*****/rest_path/async_service?str=thread_0'
+[Client] curl -s 'localhost:*****/rest_path/async_service?str=thread_1'
+[Client] curl -s 'localhost:*****/rest_path/async_service?str=thread_2'
+[Client] curl -s 'localhost:*****/rest_path/async_service?str=thread_3'
+[Client] curl -s 'localhost:*****/rest_path/foo?s=s&i=12&b=true'
+foo s 12 true
+[Client] curl -s 'localhost:*****/rest_path/foo?s=s&i=-4&b=false'
+foo s -4 false
+[Client] curl -s 'localhost:*****/rest_path/foo' --data 's=s&i=12&b=true'
+foo s 12 true
+[Client] curl -s 'localhost:*****/rest_path/api_name?s=s'
+bar s null null
+[Client] curl -s 'localhost:*****/rest_path/alt_name?s=s'
+bar s null null
+[Client] curl -s 'localhost:*****/rest_path/api_name?i=4&b=false'
+bar null 4 false
+[Client] curl -s 'localhost:*****/rest_path/complex_args?array=["a","b"]&data={"str":"asdf"}' -g
+complex_args [a,b] <MyData str:asdf more:null>
+[Client] curl -s 'localhost:*****/rest_path/complex_args?array=["a","b"]&data={"__class":"MyOtherData","str":"asdf","i":1234}' -g
+complex_args [a,b] <MyOtherData str:asdf more:null i:1234>
+[Client] curl -s 'localhost:*****/rest_path/non_existent_service'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/foo'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/foo?b=WrongDataType'
+Bad JSON character
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/bar?s=s'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/api_name' --data s=DoesNotAcceptPOST
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/complex_args?array=["a","b"]&data={"str":"as' -g
+Malformed JSON string
+Fallback answer
+async_service thread_0
+async_service thread_1
+async_service thread_2
+async_service thread_3
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import nitcorn::restful_annot
+
+import pthreads
+
+redef class Sys
+ var iface: String is lazy do
+ var testid = "NIT_TESTING_ID".environ
+ if testid.is_empty then testid = "1"
+ return "localhost:{10000+testid.to_i}"
+ end
+
+ var host_re: Regex is lazy do return "localhost:\[0-9\]+".to_re
+end
+
+class ServerThread
+ super Thread
+
+ redef fun main
+ do
+ # Hide testing concept to force nitcorn to actually run
+ "NIT_TESTING".setenv("false")
+
+ # Setup
+ var vh = new VirtualHost(iface)
+ vh.routes.add new Route("rest_path", new MyAction)
+
+ # Launch
+ var factory = new HttpFactory.and_libevent
+ factory.config.virtual_hosts.add vh
+ factory.run
+
+ return null
+ end
+end
+
+class ClientParallelThread
+ super Thread
+
+ var i: Int
+
+ redef fun main
+ do
+ system "curl -s '{iface}/rest_path/async_service?str=thread_{i}'"
+ return null
+ end
+end
+
+redef fun system(cmd)
+do
+ print "[Client] {cmd.replace(host_re, "localhost:*****")}"
+ var r = super(cmd)
+ print ""
+ return r
+end
+
+# First, launch a server in the background
+var server = new ServerThread
+server.start
+0.1.sleep
+
+# Launch 4 parallel requests to the async method
+for i in 4.times do
+ var client = new ClientParallelThread(i)
+ client.start
+ 0.1.sleep
+end
+
+# Successes
+system "curl -s '{iface}/rest_path/foo?s=s&i=12&b=true'"
+system "curl -s '{iface}/rest_path/foo?s=s&i=-4&b=false'"
+system "curl -s '{iface}/rest_path/foo' --data 's=s&i=12&b=true'"
+
+system "curl -s '{iface}/rest_path/api_name?s=s'"
+system "curl -s '{iface}/rest_path/alt_name?s=s'"
+system "curl -s '{iface}/rest_path/api_name?i=4&b=false'"
+
+system """curl -s '{{{iface}}}/rest_path/complex_args?array=["a","b"]&data={"str":"asdf"}' -g"""
+system """curl -s '{{{iface}}}/rest_path/complex_args?array=["a","b"]&data={"__class":"MyOtherData","str":"asdf","i":1234}' -g"""
+
+# Errors falling back to `answer`
+system "curl -s '{iface}/rest_path/non_existent_service'"
+system "curl -s '{iface}/rest_path/foo'" # Missing args
+system "curl -s '{iface}/rest_path/foo?b=WrongDataType'"
+system "curl -s '{iface}/rest_path/bar?s=s'" # Renamed
+system "curl -s '{iface}/rest_path/api_name' --data s=DoesNotAcceptPOST"
+system """curl -s '{{{iface}}}/rest_path/complex_args?array=["a","b"]&data={"str":"as' -g""" # Truncated JSON
+
+2.5.sleep
+exit 0
--- /dev/null
+[Client] curl -s 'localhost:*****/rest_path/async_service?str=thread_0'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/async_service?str=thread_1'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/async_service?str=thread_2'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/async_service?str=thread_3'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/foo?s=s&i=12&b=true'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/foo?s=s&i=-4&b=false'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/foo' --data 's=s&i=12&b=true'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/api_name?s=s'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/alt_name?s=s'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/api_name?i=4&b=false'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/complex_args?array=["a","b"]&data={"str":"asdf"}' -g
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/complex_args?array=["a","b"]&data={"__class":"MyOtherData","str":"asdf","i":1234}' -g
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/non_existent_service'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/foo'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/foo?b=WrongDataType'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/bar?s=s'
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/api_name' --data s=DoesNotAcceptPOST
+Fallback answer
+[Client] curl -s 'localhost:*****/rest_path/complex_args?array=["a","b"]&data={"str":"as' -g
+Fallback answer