File: test_run_process.py

package info (click to toggle)
python-watchgod 0.8.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 220 kB
  • sloc: python: 1,040; makefile: 55
file content (94 lines) | stat: -rw-r--r-- 3,207 bytes parent folder | download
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
import sys

import pytest

from watchgod import arun_process, run_process
from watchgod.main import _start_process


class FakeWatcher:
    def __init__(self, path):
        self._async = 'async' in path
        self._check = 0
        self.files = [1, 2, 3]

    def check(self):
        self._check += 1
        if self._check == 1:
            return {'x'}
        elif self._check == 2:
            return set()
        elif self._async:
            raise StopAsyncIteration
        else:
            raise KeyboardInterrupt


class FakeProcess:
    def __init__(self, is_alive=True, exitcode=1, pid=123):
        self._is_alive = is_alive
        self.exitcode = exitcode
        self.pid = pid

    def is_alive(self):
        return self._is_alive

    def join(self, wait):
        pass


def test_alive_terminates(mocker):
    mock_start_process = mocker.patch('watchgod.main._start_process')
    mock_start_process.return_value = FakeProcess()
    mock_kill = mocker.patch('watchgod.main.os.kill')

    assert run_process('/x/y/z', object(), watcher_cls=FakeWatcher, debounce=5, min_sleep=1) == 1
    assert mock_start_process.call_count == 2
    assert mock_kill.call_count == 2  # kill in loop + final kill


def test_dead_callback(mocker):
    mock_start_process = mocker.patch('watchgod.main._start_process')
    mock_start_process.return_value = FakeProcess(is_alive=False)
    mock_kill = mocker.patch('watchgod.main.os.kill')
    c = mocker.MagicMock()

    assert run_process('/x/y/z', object(), watcher_cls=FakeWatcher, callback=c, debounce=5, min_sleep=1) == 1
    assert mock_start_process.call_count == 2
    assert mock_kill.call_count == 0
    assert c.call_count == 1
    c.assert_called_with({'x'})


@pytest.mark.skipif(sys.platform == 'win32', reason='fails on windows')
def test_alive_doesnt_terminate(mocker):
    mock_start_process = mocker.patch('watchgod.main._start_process')
    mock_start_process.return_value = FakeProcess(exitcode=None)
    mock_kill = mocker.patch('watchgod.main.os.kill')

    assert run_process('/x/y/z', object(), watcher_cls=FakeWatcher, debounce=5, min_sleep=1) == 1
    assert mock_start_process.call_count == 2
    assert mock_kill.call_count == 4  # 2 kills in loop (graceful and termination) + 2 final kills


def test_start_process(mocker):
    mock_process = mocker.patch('watchgod.main.spawn_context.Process')
    v = object()
    _start_process(v, (1, 2, 3), {})
    assert mock_process.call_count == 1
    mock_process.assert_called_with(target=v, args=(1, 2, 3), kwargs={})


@pytest.mark.skipif(sys.version_info < (3, 8), reason='AsyncMock unavailable')
async def test_async_alive_terminates(mocker):
    mock_start_process = mocker.patch('watchgod.main._start_process')
    mock_start_process.return_value = FakeProcess()
    mock_kill = mocker.patch('watchgod.main.os.kill')
    c = mocker.AsyncMock(return_value=1)

    reloads = await arun_process('/x/y/async', object(), watcher_cls=FakeWatcher, callback=c, debounce=5, min_sleep=1)
    assert reloads == 1
    assert mock_start_process.call_count == 2
    assert mock_kill.call_count == 2  # kill in loop + final kill
    assert c.call_count == 1
    c.assert_called_with({'x'})