From: A. Jesse Jiryu Davis Date: Sat, 13 Apr 2013 18:31:07 +0000 (-0400) Subject: Configurable timeout for gen_test and AsyncTestCase.wait() X-Git-Tag: v3.1.0~106^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=62dde35e3f5329c65db55dde42bf4c065e2605ef;p=thirdparty%2Ftornado.git Configurable timeout for gen_test and AsyncTestCase.wait() --- diff --git a/tornado/test/testing_test.py b/tornado/test/testing_test.py index 81455dfe0..64e5683e4 100644 --- a/tornado/test/testing_test.py +++ b/tornado/test/testing_test.py @@ -10,6 +10,20 @@ import contextlib import os +@contextlib.contextmanager +def set_environ(name, value): + old_value = os.environ.get('name') + os.environ[name] = value + + try: + yield + finally: + if old_value is None: + del os.environ[name] + else: + os.environ[name] = old_value + + class AsyncTestCaseTest(AsyncTestCase): def test_exception_in_callback(self): self.io_loop.add_callback(lambda: 1 / 0) @@ -19,6 +33,24 @@ class AsyncTestCaseTest(AsyncTestCase): except ZeroDivisionError: pass + def test_wait_timeout(self): + time = self.io_loop.time + + # Accept default 5-second timeout, no error + self.io_loop.add_timeout(time() + 0.01, self.stop) + self.wait() + + # Timeout passed to wait() + self.io_loop.add_timeout(time() + 1, self.stop) + with self.assertRaises(self.failureException): + self.wait(timeout=0.01) + + # Timeout set with environment variable + self.io_loop.add_timeout(time() + 1, self.stop) + with set_environ('ASYNC_TEST_TIMEOUT', '0.01'): + with self.assertRaises(self.failureException): + self.wait() + def test_subsequent_wait_calls(self): """ This test makes sure that a second call to wait() @@ -59,20 +91,6 @@ class SetUpTearDownTest(unittest.TestCase): self.assertEqual(expected, events) -@contextlib.contextmanager -def set_environ(name, value): - old_value = os.environ.get('name') - os.environ[name] = value - - try: - yield - finally: - if old_value is None: - del os.environ[name] - else: - os.environ[name] = old_value - - class GenTest(AsyncTestCase): def setUp(self): super(GenTest, self).setUp() @@ -106,7 +124,8 @@ class GenTest(AsyncTestCase): # A test that does not exceed its timeout should succeed. @gen_test(timeout=1) def test(self): - yield gen.Task(self.io_loop.add_timeout, self.io_loop.time() + 0.1) + time = self.io_loop.time + yield gen.Task(self.io_loop.add_timeout, time() + 0.1) test(self) self.finished = True @@ -118,7 +137,7 @@ class GenTest(AsyncTestCase): yield gen.Task(self.io_loop.add_timeout, time() + 0.25) # Uses provided timeout of 0.5 seconds, doesn't time out. - with set_environ('TIMEOUT', '0.1'): + with set_environ('ASYNC_TEST_TIMEOUT', '0.1'): test_long_timeout(self) self.finished = True @@ -129,8 +148,8 @@ class GenTest(AsyncTestCase): time = self.io_loop.time yield gen.Task(self.io_loop.add_timeout, time() + 1) - # Uses environment TIMEOUT of 0.1, times out. - with set_environ('TIMEOUT', '0.1'): + # Uses environment-variable timeout of 0.1, times out. + with set_environ('ASYNC_TEST_TIMEOUT', '0.1'): with self.assertRaises(ioloop.TimeoutError): test_short_timeout(self) diff --git a/tornado/testing.py b/tornado/testing.py index 67bab88e5..ba75a27d3 100644 --- a/tornado/testing.py +++ b/tornado/testing.py @@ -82,6 +82,17 @@ def bind_unused_port(): return sock, port +def get_async_test_timeout(): + """Get the global timeout setting for async tests. + + Returns a float, the timeout in seconds. + """ + try: + return float(os.environ.get('ASYNC_TEST_TIMEOUT')) + except (ValueError, TypeError): + return 5 + + class AsyncTestCase(unittest.TestCase): """`~unittest.TestCase` subclass for testing `.IOLoop`-based asynchronous code. @@ -202,14 +213,19 @@ class AsyncTestCase(unittest.TestCase): self.__running = False self.__stopped = True - def wait(self, condition=None, timeout=5): + def wait(self, condition=None, timeout=None): """Runs the `.IOLoop` until stop is called or timeout has passed. - In the event of a timeout, an exception will be thrown. + In the event of a timeout, an exception will be thrown. The default + timeout is 5 seconds; it may be overridden with a ``timeout`` keyword + argument or globally with the ASYNC_TEST_TIMEOUT environment variable. If ``condition`` is not None, the `.IOLoop` will be restarted after `stop()` until ``condition()`` returns true. """ + if timeout is None: + timeout = get_async_test_timeout() + if not self.__stopped: if timeout: def timeout_func(): @@ -369,8 +385,8 @@ def gen_test(func=None, timeout=None): response = yield gen.Task(self.fetch('/')) By default, ``@gen_test`` times out after 5 seconds. The timeout may be - overridden globally with the TIMEOUT environment variable, or for each - test with the ``timeout`` keyword argument: + overridden globally with the ASYNC_TEST_TIMEOUT environment variable, + or for each test with the ``timeout`` keyword argument: class MyTest(AsyncHTTPTestCase): @gen_test(timeout=10) @@ -380,10 +396,8 @@ def gen_test(func=None, timeout=None): If both the environment variable and the parameter are set, ``gen_test`` uses the maximum of the two. """ - try: - env_timeout = float(os.environ.get('TIMEOUT')) - except (ValueError, TypeError): - env_timeout = None + if timeout is None: + timeout = get_async_test_timeout() def wrap(f): f = gen.coroutine(f) @@ -399,11 +413,9 @@ def gen_test(func=None, timeout=None): # @gen_test # def f(self): # pass - timeout = env_timeout or 5 return wrap(func) else: # Used like @gen_test(timeout=10) - timeout = float(timeout) return wrap