PageRenderTime 28ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/tornado/test/testing_test.py

http://github.com/facebook/tornado
Python | 350 lines | 239 code | 74 blank | 37 comment | 18 complexity | 3673a5e50da2c782c4e6674e9b9c0f0a MD5 | raw file
Possible License(s): Apache-2.0
  1. from tornado import gen, ioloop
  2. from tornado.httpserver import HTTPServer
  3. from tornado.locks import Event
  4. from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, bind_unused_port, gen_test
  5. from tornado.web import Application
  6. import asyncio
  7. import contextlib
  8. import gc
  9. import os
  10. import platform
  11. import traceback
  12. import unittest
  13. import warnings
  14. @contextlib.contextmanager
  15. def set_environ(name, value):
  16. old_value = os.environ.get(name)
  17. os.environ[name] = value
  18. try:
  19. yield
  20. finally:
  21. if old_value is None:
  22. del os.environ[name]
  23. else:
  24. os.environ[name] = old_value
  25. class AsyncTestCaseTest(AsyncTestCase):
  26. def test_wait_timeout(self):
  27. time = self.io_loop.time
  28. # Accept default 5-second timeout, no error
  29. self.io_loop.add_timeout(time() + 0.01, self.stop)
  30. self.wait()
  31. # Timeout passed to wait()
  32. self.io_loop.add_timeout(time() + 1, self.stop)
  33. with self.assertRaises(self.failureException):
  34. self.wait(timeout=0.01)
  35. # Timeout set with environment variable
  36. self.io_loop.add_timeout(time() + 1, self.stop)
  37. with set_environ("ASYNC_TEST_TIMEOUT", "0.01"):
  38. with self.assertRaises(self.failureException):
  39. self.wait()
  40. def test_subsequent_wait_calls(self):
  41. """
  42. This test makes sure that a second call to wait()
  43. clears the first timeout.
  44. """
  45. self.io_loop.add_timeout(self.io_loop.time() + 0.00, self.stop)
  46. self.wait(timeout=0.02)
  47. self.io_loop.add_timeout(self.io_loop.time() + 0.03, self.stop)
  48. self.wait(timeout=0.15)
  49. class LeakTest(AsyncTestCase):
  50. def tearDown(self):
  51. super().tearDown()
  52. # Trigger a gc to make warnings more deterministic.
  53. gc.collect()
  54. def test_leaked_coroutine(self):
  55. # This test verifies that "leaked" coroutines are shut down
  56. # without triggering warnings like "task was destroyed but it
  57. # is pending". If this test were to fail, it would fail
  58. # because runtests.py detected unexpected output to stderr.
  59. event = Event()
  60. async def callback():
  61. try:
  62. await event.wait()
  63. except asyncio.CancelledError:
  64. pass
  65. self.io_loop.add_callback(callback)
  66. self.io_loop.add_callback(self.stop)
  67. self.wait()
  68. class AsyncHTTPTestCaseTest(AsyncHTTPTestCase):
  69. def setUp(self):
  70. super(AsyncHTTPTestCaseTest, self).setUp()
  71. # Bind a second port.
  72. sock, port = bind_unused_port()
  73. app = Application()
  74. server = HTTPServer(app, **self.get_httpserver_options())
  75. server.add_socket(sock)
  76. self.second_port = port
  77. self.second_server = server
  78. def get_app(self):
  79. return Application()
  80. def test_fetch_segment(self):
  81. path = "/path"
  82. response = self.fetch(path)
  83. self.assertEqual(response.request.url, self.get_url(path))
  84. def test_fetch_full_http_url(self):
  85. # Ensure that self.fetch() recognizes absolute urls and does
  86. # not transform them into references to our main test server.
  87. path = "http://localhost:%d/path" % self.second_port
  88. response = self.fetch(path)
  89. self.assertEqual(response.request.url, path)
  90. def tearDown(self):
  91. self.second_server.stop()
  92. super(AsyncHTTPTestCaseTest, self).tearDown()
  93. class AsyncTestCaseWrapperTest(unittest.TestCase):
  94. def test_undecorated_generator(self):
  95. class Test(AsyncTestCase):
  96. def test_gen(self):
  97. yield
  98. test = Test("test_gen")
  99. result = unittest.TestResult()
  100. test.run(result)
  101. self.assertEqual(len(result.errors), 1)
  102. self.assertIn("should be decorated", result.errors[0][1])
  103. @unittest.skipIf(
  104. platform.python_implementation() == "PyPy",
  105. "pypy destructor warnings cannot be silenced",
  106. )
  107. def test_undecorated_coroutine(self):
  108. class Test(AsyncTestCase):
  109. async def test_coro(self):
  110. pass
  111. test = Test("test_coro")
  112. result = unittest.TestResult()
  113. # Silence "RuntimeWarning: coroutine 'test_coro' was never awaited".
  114. with warnings.catch_warnings():
  115. warnings.simplefilter("ignore")
  116. test.run(result)
  117. self.assertEqual(len(result.errors), 1)
  118. self.assertIn("should be decorated", result.errors[0][1])
  119. def test_undecorated_generator_with_skip(self):
  120. class Test(AsyncTestCase):
  121. @unittest.skip("don't run this")
  122. def test_gen(self):
  123. yield
  124. test = Test("test_gen")
  125. result = unittest.TestResult()
  126. test.run(result)
  127. self.assertEqual(len(result.errors), 0)
  128. self.assertEqual(len(result.skipped), 1)
  129. def test_other_return(self):
  130. class Test(AsyncTestCase):
  131. def test_other_return(self):
  132. return 42
  133. test = Test("test_other_return")
  134. result = unittest.TestResult()
  135. test.run(result)
  136. self.assertEqual(len(result.errors), 1)
  137. self.assertIn("Return value from test method ignored", result.errors[0][1])
  138. class SetUpTearDownTest(unittest.TestCase):
  139. def test_set_up_tear_down(self):
  140. """
  141. This test makes sure that AsyncTestCase calls super methods for
  142. setUp and tearDown.
  143. InheritBoth is a subclass of both AsyncTestCase and
  144. SetUpTearDown, with the ordering so that the super of
  145. AsyncTestCase will be SetUpTearDown.
  146. """
  147. events = []
  148. result = unittest.TestResult()
  149. class SetUpTearDown(unittest.TestCase):
  150. def setUp(self):
  151. events.append("setUp")
  152. def tearDown(self):
  153. events.append("tearDown")
  154. class InheritBoth(AsyncTestCase, SetUpTearDown):
  155. def test(self):
  156. events.append("test")
  157. InheritBoth("test").run(result)
  158. expected = ["setUp", "test", "tearDown"]
  159. self.assertEqual(expected, events)
  160. class AsyncHTTPTestCaseSetUpTearDownTest(unittest.TestCase):
  161. def test_tear_down_releases_app_and_http_server(self):
  162. result = unittest.TestResult()
  163. class SetUpTearDown(AsyncHTTPTestCase):
  164. def get_app(self):
  165. return Application()
  166. def test(self):
  167. self.assertTrue(hasattr(self, "_app"))
  168. self.assertTrue(hasattr(self, "http_server"))
  169. test = SetUpTearDown("test")
  170. test.run(result)
  171. self.assertFalse(hasattr(test, "_app"))
  172. self.assertFalse(hasattr(test, "http_server"))
  173. class GenTest(AsyncTestCase):
  174. def setUp(self):
  175. super(GenTest, self).setUp()
  176. self.finished = False
  177. def tearDown(self):
  178. self.assertTrue(self.finished)
  179. super(GenTest, self).tearDown()
  180. @gen_test
  181. def test_sync(self):
  182. self.finished = True
  183. @gen_test
  184. def test_async(self):
  185. yield gen.moment
  186. self.finished = True
  187. def test_timeout(self):
  188. # Set a short timeout and exceed it.
  189. @gen_test(timeout=0.1)
  190. def test(self):
  191. yield gen.sleep(1)
  192. # This can't use assertRaises because we need to inspect the
  193. # exc_info triple (and not just the exception object)
  194. try:
  195. test(self)
  196. self.fail("did not get expected exception")
  197. except ioloop.TimeoutError:
  198. # The stack trace should blame the add_timeout line, not just
  199. # unrelated IOLoop/testing internals.
  200. self.assertIn("gen.sleep(1)", traceback.format_exc())
  201. self.finished = True
  202. def test_no_timeout(self):
  203. # A test that does not exceed its timeout should succeed.
  204. @gen_test(timeout=1)
  205. def test(self):
  206. yield gen.sleep(0.1)
  207. test(self)
  208. self.finished = True
  209. def test_timeout_environment_variable(self):
  210. @gen_test(timeout=0.5)
  211. def test_long_timeout(self):
  212. yield gen.sleep(0.25)
  213. # Uses provided timeout of 0.5 seconds, doesn't time out.
  214. with set_environ("ASYNC_TEST_TIMEOUT", "0.1"):
  215. test_long_timeout(self)
  216. self.finished = True
  217. def test_no_timeout_environment_variable(self):
  218. @gen_test(timeout=0.01)
  219. def test_short_timeout(self):
  220. yield gen.sleep(1)
  221. # Uses environment-variable timeout of 0.1, times out.
  222. with set_environ("ASYNC_TEST_TIMEOUT", "0.1"):
  223. with self.assertRaises(ioloop.TimeoutError):
  224. test_short_timeout(self)
  225. self.finished = True
  226. def test_with_method_args(self):
  227. @gen_test
  228. def test_with_args(self, *args):
  229. self.assertEqual(args, ("test",))
  230. yield gen.moment
  231. test_with_args(self, "test")
  232. self.finished = True
  233. def test_with_method_kwargs(self):
  234. @gen_test
  235. def test_with_kwargs(self, **kwargs):
  236. self.assertDictEqual(kwargs, {"test": "test"})
  237. yield gen.moment
  238. test_with_kwargs(self, test="test")
  239. self.finished = True
  240. def test_native_coroutine(self):
  241. @gen_test
  242. async def test(self):
  243. self.finished = True
  244. test(self)
  245. def test_native_coroutine_timeout(self):
  246. # Set a short timeout and exceed it.
  247. @gen_test(timeout=0.1)
  248. async def test(self):
  249. await gen.sleep(1)
  250. try:
  251. test(self)
  252. self.fail("did not get expected exception")
  253. except ioloop.TimeoutError:
  254. self.finished = True
  255. class GetNewIOLoopTest(AsyncTestCase):
  256. def get_new_ioloop(self):
  257. # Use the current loop instead of creating a new one here.
  258. return ioloop.IOLoop.current()
  259. def setUp(self):
  260. # This simulates the effect of an asyncio test harness like
  261. # pytest-asyncio.
  262. self.orig_loop = asyncio.get_event_loop()
  263. self.new_loop = asyncio.new_event_loop()
  264. asyncio.set_event_loop(self.new_loop)
  265. super(GetNewIOLoopTest, self).setUp()
  266. def tearDown(self):
  267. super(GetNewIOLoopTest, self).tearDown()
  268. # AsyncTestCase must not affect the existing asyncio loop.
  269. self.assertFalse(asyncio.get_event_loop().is_closed())
  270. asyncio.set_event_loop(self.orig_loop)
  271. self.new_loop.close()
  272. def test_loop(self):
  273. self.assertIs(self.io_loop.asyncio_loop, self.new_loop) # type: ignore
  274. if __name__ == "__main__":
  275. unittest.main()