File: test_coroutines.py

package info (click to toggle)
python-eliot 1.16.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 964 kB
  • sloc: python: 8,641; makefile: 151
file content (105 lines) | stat: -rw-r--r-- 3,006 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"""
Tests for coroutines.

Imported into test_coroutine.py when running tests under Python 3.5 or later;
in earlier versions of Python this code is a syntax error.
"""

import asyncio
from unittest import TestCase

from ..testing import capture_logging
from ..parse import Parser
from .. import start_action


async def standalone_coro():
    """
    Log a message inside a new coroutine.
    """
    await asyncio.sleep(0.1)
    with start_action(action_type="standalone"):
        pass


async def calling_coro():
    """
    Log an action inside a coroutine, and call another coroutine.
    """
    with start_action(action_type="calling"):
        await standalone_coro()


def run_coroutines(*async_functions):
    """
    Run a coroutine until it finishes.
    """
    loop = asyncio.get_event_loop()
    futures = [asyncio.ensure_future(f()) for f in async_functions]

    async def wait_for_futures():
        for future in futures:
            await future

    loop.run_until_complete(wait_for_futures())


class CoroutineTests(TestCase):
    """
    Tests for coroutines.
    """

    @capture_logging(None)
    def test_multiple_coroutines_contexts(self, logger):
        """
        Each top-level coroutine has its own Eliot logging context.
        """

        async def waiting_coro():
            with start_action(action_type="waiting"):
                await asyncio.sleep(0.5)

        run_coroutines(waiting_coro, standalone_coro)
        trees = Parser.parse_stream(logger.messages)
        self.assertEqual(
            sorted([(t.root().action_type, t.root().children) for t in trees]),
            [("standalone", []), ("waiting", [])],
        )

    @capture_logging(None)
    def test_await_inherits_coroutine_contexts(self, logger):
        """
        awaited coroutines inherit the logging context.
        """
        run_coroutines(calling_coro)
        [tree] = Parser.parse_stream(logger.messages)
        root = tree.root()
        [child] = root.children
        self.assertEqual(
            (root.action_type, child.action_type, child.children),
            ("calling", "standalone", []),
        )

    @capture_logging(None)
    def test_interleaved_coroutines(self, logger):
        """
        start_action() started in one coroutine doesn't impact another in a
        different coroutine.
        """

        async def coro_sleep(delay, action_type):
            with start_action(action_type=action_type):
                await asyncio.sleep(delay)

        async def main():
            with start_action(action_type="main"):
                f1 = asyncio.ensure_future(coro_sleep(1, "a"))
                f2 = asyncio.ensure_future(coro_sleep(0.5, "b"))
                await f1
                await f2

        run_coroutines(main)
        [tree] = list(Parser.parse_stream(logger.messages))
        root = tree.root()
        self.assertEqual(root.action_type, "main")
        self.assertEqual(sorted([c.action_type for c in root.children]), ["a", "b"])