/eliot/tests/test_coroutines.py

https://github.com/ScatterHQ/eliot · Python · 105 lines · 56 code · 17 blank · 32 comment · 6 complexity · 6fd03e492518ccddeefb1780feb97640 MD5 · raw file

  1. """
  2. Tests for coroutines.
  3. Imported into test_coroutine.py when running tests under Python 3.5 or later;
  4. in earlier versions of Python this code is a syntax error.
  5. """
  6. import asyncio
  7. from unittest import TestCase
  8. from ..testing import capture_logging
  9. from ..parse import Parser
  10. from .. import start_action
  11. async def standalone_coro():
  12. """
  13. Log a message inside a new coroutine.
  14. """
  15. await asyncio.sleep(0.1)
  16. with start_action(action_type="standalone"):
  17. pass
  18. async def calling_coro():
  19. """
  20. Log an action inside a coroutine, and call another coroutine.
  21. """
  22. with start_action(action_type="calling"):
  23. await standalone_coro()
  24. def run_coroutines(*async_functions):
  25. """
  26. Run a coroutine until it finishes.
  27. """
  28. loop = asyncio.get_event_loop()
  29. futures = [asyncio.ensure_future(f()) for f in async_functions]
  30. async def wait_for_futures():
  31. for future in futures:
  32. await future
  33. loop.run_until_complete(wait_for_futures())
  34. class CoroutineTests(TestCase):
  35. """
  36. Tests for coroutines.
  37. """
  38. @capture_logging(None)
  39. def test_multiple_coroutines_contexts(self, logger):
  40. """
  41. Each top-level coroutine has its own Eliot logging context.
  42. """
  43. async def waiting_coro():
  44. with start_action(action_type="waiting"):
  45. await asyncio.sleep(0.5)
  46. run_coroutines(waiting_coro, standalone_coro)
  47. trees = Parser.parse_stream(logger.messages)
  48. self.assertEqual(
  49. sorted([(t.root().action_type, t.root().children) for t in trees]),
  50. [("standalone", []), ("waiting", [])],
  51. )
  52. @capture_logging(None)
  53. def test_await_inherits_coroutine_contexts(self, logger):
  54. """
  55. awaited coroutines inherit the logging context.
  56. """
  57. run_coroutines(calling_coro)
  58. [tree] = Parser.parse_stream(logger.messages)
  59. root = tree.root()
  60. [child] = root.children
  61. self.assertEqual(
  62. (root.action_type, child.action_type, child.children),
  63. ("calling", "standalone", []),
  64. )
  65. @capture_logging(None)
  66. def test_interleaved_coroutines(self, logger):
  67. """
  68. start_action() started in one coroutine doesn't impact another in a
  69. different coroutine.
  70. """
  71. async def coro_sleep(delay, action_type):
  72. with start_action(action_type=action_type):
  73. await asyncio.sleep(delay)
  74. async def main():
  75. with start_action(action_type="main"):
  76. f1 = asyncio.ensure_future(coro_sleep(1, "a"))
  77. f2 = asyncio.ensure_future(coro_sleep(0.5, "b"))
  78. await f1
  79. await f2
  80. run_coroutines(main)
  81. [tree] = list(Parser.parse_stream(logger.messages))
  82. root = tree.root()
  83. self.assertEqual(root.action_type, "main")
  84. self.assertEqual(sorted([c.action_type for c in root.children]), ["a", "b"])