gen_test.py
Go to the documentation of this file.
00001 from __future__ import absolute_import, division, with_statement
00002 import functools
00003 from tornado.escape import url_escape
00004 from tornado.httpclient import AsyncHTTPClient
00005 from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, LogTrapTestCase
00006 from tornado.util import b
00007 from tornado.web import Application, RequestHandler, asynchronous
00008 
00009 from tornado import gen
00010 
00011 
00012 class GenTest(AsyncTestCase):
00013     def run_gen(self, f):
00014         f()
00015         self.wait()
00016 
00017     def delay_callback(self, iterations, callback, arg):
00018         """Runs callback(arg) after a number of IOLoop iterations."""
00019         if iterations == 0:
00020             callback(arg)
00021         else:
00022             self.io_loop.add_callback(functools.partial(
00023                     self.delay_callback, iterations - 1, callback, arg))
00024 
00025     def test_no_yield(self):
00026         @gen.engine
00027         def f():
00028             self.stop()
00029         self.run_gen(f)
00030 
00031     def test_inline_cb(self):
00032         @gen.engine
00033         def f():
00034             (yield gen.Callback("k1"))()
00035             res = yield gen.Wait("k1")
00036             assert res is None
00037             self.stop()
00038         self.run_gen(f)
00039 
00040     def test_ioloop_cb(self):
00041         @gen.engine
00042         def f():
00043             self.io_loop.add_callback((yield gen.Callback("k1")))
00044             yield gen.Wait("k1")
00045             self.stop()
00046         self.run_gen(f)
00047 
00048     def test_exception_phase1(self):
00049         @gen.engine
00050         def f():
00051             1 / 0
00052         self.assertRaises(ZeroDivisionError, self.run_gen, f)
00053 
00054     def test_exception_phase2(self):
00055         @gen.engine
00056         def f():
00057             self.io_loop.add_callback((yield gen.Callback("k1")))
00058             yield gen.Wait("k1")
00059             1 / 0
00060         self.assertRaises(ZeroDivisionError, self.run_gen, f)
00061 
00062     def test_exception_in_task_phase1(self):
00063         def fail_task(callback):
00064             1 / 0
00065 
00066         @gen.engine
00067         def f():
00068             try:
00069                 yield gen.Task(fail_task)
00070                 raise Exception("did not get expected exception")
00071             except ZeroDivisionError:
00072                 self.stop()
00073         self.run_gen(f)
00074 
00075     def test_exception_in_task_phase2(self):
00076         # This is the case that requires the use of stack_context in gen.engine
00077         def fail_task(callback):
00078             self.io_loop.add_callback(lambda: 1 / 0)
00079 
00080         @gen.engine
00081         def f():
00082             try:
00083                 yield gen.Task(fail_task)
00084                 raise Exception("did not get expected exception")
00085             except ZeroDivisionError:
00086                 self.stop()
00087         self.run_gen(f)
00088 
00089     def test_with_arg(self):
00090         @gen.engine
00091         def f():
00092             (yield gen.Callback("k1"))(42)
00093             res = yield gen.Wait("k1")
00094             self.assertEqual(42, res)
00095             self.stop()
00096         self.run_gen(f)
00097 
00098     def test_key_reuse(self):
00099         @gen.engine
00100         def f():
00101             yield gen.Callback("k1")
00102             yield gen.Callback("k1")
00103             self.stop()
00104         self.assertRaises(gen.KeyReuseError, self.run_gen, f)
00105 
00106     def test_key_mismatch(self):
00107         @gen.engine
00108         def f():
00109             yield gen.Callback("k1")
00110             yield gen.Wait("k2")
00111             self.stop()
00112         self.assertRaises(gen.UnknownKeyError, self.run_gen, f)
00113 
00114     def test_leaked_callback(self):
00115         @gen.engine
00116         def f():
00117             yield gen.Callback("k1")
00118             self.stop()
00119         self.assertRaises(gen.LeakedCallbackError, self.run_gen, f)
00120 
00121     def test_parallel_callback(self):
00122         @gen.engine
00123         def f():
00124             for k in range(3):
00125                 self.io_loop.add_callback((yield gen.Callback(k)))
00126             yield gen.Wait(1)
00127             self.io_loop.add_callback((yield gen.Callback(3)))
00128             yield gen.Wait(0)
00129             yield gen.Wait(3)
00130             yield gen.Wait(2)
00131             self.stop()
00132         self.run_gen(f)
00133 
00134     def test_bogus_yield(self):
00135         @gen.engine
00136         def f():
00137             yield 42
00138         self.assertRaises(gen.BadYieldError, self.run_gen, f)
00139 
00140     def test_reuse(self):
00141         @gen.engine
00142         def f():
00143             self.io_loop.add_callback((yield gen.Callback(0)))
00144             yield gen.Wait(0)
00145             self.stop()
00146         self.run_gen(f)
00147         self.run_gen(f)
00148 
00149     def test_task(self):
00150         @gen.engine
00151         def f():
00152             yield gen.Task(self.io_loop.add_callback)
00153             self.stop()
00154         self.run_gen(f)
00155 
00156     def test_wait_all(self):
00157         @gen.engine
00158         def f():
00159             (yield gen.Callback("k1"))("v1")
00160             (yield gen.Callback("k2"))("v2")
00161             results = yield gen.WaitAll(["k1", "k2"])
00162             self.assertEqual(results, ["v1", "v2"])
00163             self.stop()
00164         self.run_gen(f)
00165 
00166     def test_exception_in_yield(self):
00167         @gen.engine
00168         def f():
00169             try:
00170                 yield gen.Wait("k1")
00171                 raise Exception("did not get expected exception")
00172             except gen.UnknownKeyError:
00173                 pass
00174             self.stop()
00175         self.run_gen(f)
00176 
00177     def test_resume_after_exception_in_yield(self):
00178         @gen.engine
00179         def f():
00180             try:
00181                 yield gen.Wait("k1")
00182                 raise Exception("did not get expected exception")
00183             except gen.UnknownKeyError:
00184                 pass
00185             (yield gen.Callback("k2"))("v2")
00186             self.assertEqual((yield gen.Wait("k2")), "v2")
00187             self.stop()
00188         self.run_gen(f)
00189 
00190     def test_orphaned_callback(self):
00191         @gen.engine
00192         def f():
00193             self.orphaned_callback = yield gen.Callback(1)
00194         try:
00195             self.run_gen(f)
00196             raise Exception("did not get expected exception")
00197         except gen.LeakedCallbackError:
00198             pass
00199         self.orphaned_callback()
00200 
00201     def test_multi(self):
00202         @gen.engine
00203         def f():
00204             (yield gen.Callback("k1"))("v1")
00205             (yield gen.Callback("k2"))("v2")
00206             results = yield [gen.Wait("k1"), gen.Wait("k2")]
00207             self.assertEqual(results, ["v1", "v2"])
00208             self.stop()
00209         self.run_gen(f)
00210 
00211     def test_multi_delayed(self):
00212         @gen.engine
00213         def f():
00214             # callbacks run at different times
00215             responses = yield [
00216                 gen.Task(self.delay_callback, 3, arg="v1"),
00217                 gen.Task(self.delay_callback, 1, arg="v2"),
00218                 ]
00219             self.assertEqual(responses, ["v1", "v2"])
00220             self.stop()
00221         self.run_gen(f)
00222 
00223     def test_arguments(self):
00224         @gen.engine
00225         def f():
00226             (yield gen.Callback("noargs"))()
00227             self.assertEqual((yield gen.Wait("noargs")), None)
00228             (yield gen.Callback("1arg"))(42)
00229             self.assertEqual((yield gen.Wait("1arg")), 42)
00230 
00231             (yield gen.Callback("kwargs"))(value=42)
00232             result = yield gen.Wait("kwargs")
00233             self.assertTrue(isinstance(result, gen.Arguments))
00234             self.assertEqual(((), dict(value=42)), result)
00235             self.assertEqual(dict(value=42), result.kwargs)
00236 
00237             (yield gen.Callback("2args"))(42, 43)
00238             result = yield gen.Wait("2args")
00239             self.assertTrue(isinstance(result, gen.Arguments))
00240             self.assertEqual(((42, 43), {}), result)
00241             self.assertEqual((42, 43), result.args)
00242 
00243             def task_func(callback):
00244                 callback(None, error="foo")
00245             result = yield gen.Task(task_func)
00246             self.assertTrue(isinstance(result, gen.Arguments))
00247             self.assertEqual(((None,), dict(error="foo")), result)
00248 
00249             self.stop()
00250         self.run_gen(f)
00251 
00252     def test_stack_context_leak(self):
00253         # regression test: repeated invocations of a gen-based
00254         # function should not result in accumulated stack_contexts
00255         from tornado import stack_context
00256 
00257         @gen.engine
00258         def inner(callback):
00259             yield gen.Task(self.io_loop.add_callback)
00260             callback()
00261 
00262         @gen.engine
00263         def outer():
00264             for i in xrange(10):
00265                 yield gen.Task(inner)
00266             stack_increase = len(stack_context._state.contexts) - initial_stack_depth
00267             self.assertTrue(stack_increase <= 2)
00268             self.stop()
00269         initial_stack_depth = len(stack_context._state.contexts)
00270         self.run_gen(outer)
00271 
00272 
00273 class GenSequenceHandler(RequestHandler):
00274     @asynchronous
00275     @gen.engine
00276     def get(self):
00277         self.io_loop = self.request.connection.stream.io_loop
00278         self.io_loop.add_callback((yield gen.Callback("k1")))
00279         yield gen.Wait("k1")
00280         self.write("1")
00281         self.io_loop.add_callback((yield gen.Callback("k2")))
00282         yield gen.Wait("k2")
00283         self.write("2")
00284         # reuse an old key
00285         self.io_loop.add_callback((yield gen.Callback("k1")))
00286         yield gen.Wait("k1")
00287         self.finish("3")
00288 
00289 
00290 class GenTaskHandler(RequestHandler):
00291     @asynchronous
00292     @gen.engine
00293     def get(self):
00294         io_loop = self.request.connection.stream.io_loop
00295         client = AsyncHTTPClient(io_loop=io_loop)
00296         response = yield gen.Task(client.fetch, self.get_argument('url'))
00297         response.rethrow()
00298         self.finish(b("got response: ") + response.body)
00299 
00300 
00301 class GenExceptionHandler(RequestHandler):
00302     @asynchronous
00303     @gen.engine
00304     def get(self):
00305         # This test depends on the order of the two decorators.
00306         io_loop = self.request.connection.stream.io_loop
00307         yield gen.Task(io_loop.add_callback)
00308         raise Exception("oops")
00309 
00310 
00311 class GenYieldExceptionHandler(RequestHandler):
00312     @asynchronous
00313     @gen.engine
00314     def get(self):
00315         io_loop = self.request.connection.stream.io_loop
00316         # Test the interaction of the two stack_contexts.
00317 
00318         def fail_task(callback):
00319             io_loop.add_callback(lambda: 1 / 0)
00320         try:
00321             yield gen.Task(fail_task)
00322             raise Exception("did not get expected exception")
00323         except ZeroDivisionError:
00324             self.finish('ok')
00325 
00326 
00327 class GenWebTest(AsyncHTTPTestCase, LogTrapTestCase):
00328     def get_app(self):
00329         return Application([
00330                 ('/sequence', GenSequenceHandler),
00331                 ('/task', GenTaskHandler),
00332                 ('/exception', GenExceptionHandler),
00333                 ('/yield_exception', GenYieldExceptionHandler),
00334                 ])
00335 
00336     def test_sequence_handler(self):
00337         response = self.fetch('/sequence')
00338         self.assertEqual(response.body, b("123"))
00339 
00340     def test_task_handler(self):
00341         response = self.fetch('/task?url=%s' % url_escape(self.get_url('/sequence')))
00342         self.assertEqual(response.body, b("got response: 123"))
00343 
00344     def test_exception_handler(self):
00345         # Make sure we get an error and not a timeout
00346         response = self.fetch('/exception')
00347         self.assertEqual(500, response.code)
00348 
00349     def test_yield_exception_handler(self):
00350         response = self.fetch('/yield_exception')
00351         self.assertEqual(response.body, b('ok'))


rosbridge_server
Author(s): Jonathan Mace
autogenerated on Thu Jan 2 2014 11:53:55