-
Notifications
You must be signed in to change notification settings - Fork 27
/
test_executor_kill.py
125 lines (97 loc) · 3.91 KB
/
test_executor_kill.py
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# mypy: no-strict-optional
"""Tests that check various kill behaviours."""
import signal
import time
import sys
from typing import NoReturn, Set
import errno
import os
from unittest.mock import patch
import pytest
from mirakuru import SimpleExecutor, HTTPExecutor
from mirakuru.compat import SIGKILL
from mirakuru.exceptions import ProcessFinishedWithError
from tests import SAMPLE_DAEMON_PATH, ps_aux, TEST_SERVER_PATH
SLEEP_300 = "sleep 300"
def test_custom_signal_kill() -> None:
"""Start process and shuts it down using signal SIGQUIT."""
executor = SimpleExecutor(SLEEP_300, kill_signal=signal.SIGQUIT)
executor.start()
assert executor.running() is True
executor.kill()
assert executor.running() is False
def test_kill_custom_signal_kill() -> None:
"""Start process and shuts it down using signal SIGQUIT passed to kill."""
executor = SimpleExecutor(SLEEP_300)
executor.start()
assert executor.running() is True
executor.kill(sig=signal.SIGQUIT)
assert executor.running() is False
def test_already_closed() -> None:
"""Check that the executor cleans after itself after it exited earlier."""
with pytest.raises(ProcessFinishedWithError) as excinfo:
with SimpleExecutor("python") as executor:
assert executor.running()
os.killpg(executor.process.pid, SIGKILL)
def process_stopped() -> bool:
"""Return True only only when self.process is not running."""
return executor.running() is False
executor.wait_for(process_stopped)
assert executor.process
assert excinfo.value.exit_code == -9
assert not executor.process
def test_daemons_killing() -> None:
"""
Test if all subprocesses of SimpleExecutor can be killed.
The most problematic subprocesses are daemons or other services that
change the process group ID. This test verifies that daemon process
is killed after executor's kill().
"""
executor = SimpleExecutor(("python", SAMPLE_DAEMON_PATH), shell=True)
executor.start()
time.sleep(2)
assert (
executor.running() is not True
), "Executor should not have subprocess running as it started a daemon."
assert SAMPLE_DAEMON_PATH in ps_aux()
executor.kill()
assert SAMPLE_DAEMON_PATH not in ps_aux()
def test_stopping_brutally() -> None:
"""
Test if SimpleExecutor is stopping insubordinate process.
Check if the process that doesn't react to SIGTERM signal will be killed
by executor with SIGKILL automatically.
"""
host_port = "127.0.0.1:8000"
cmd = f"{sys.executable} {TEST_SERVER_PATH} {host_port} True"
executor = HTTPExecutor(cmd, f"http://{host_port!s}/", timeout=20)
executor.start()
assert executor.running() is True
stop_at = time.time() + 10
executor.stop()
assert executor.running() is False
assert stop_at <= time.time(), "Subprocess killed earlier than in 10 secs"
def test_stopping_children_of_stopped_process() -> None:
"""
Check that children exiting between listing and killing are ignored.
Given:
Executor is running and it's process spawn children,
and we requested it's stop, and it's stopped
When:
At the time of the check for subprocesses they're still active,
but before we start killing them, they are already dead.
Then:
We ignore and skip OsError indicates there's no such process.
"""
# pylint: disable=protected-access, missing-docstring
def raise_os_error(*_: int, **__: int) -> NoReturn:
os_error = OSError()
os_error.errno = errno.ESRCH
raise os_error
def processes_with_env_mock(*_: str, **__: str) -> Set[int]:
return {1}
with patch(
"mirakuru.base.processes_with_env", new=processes_with_env_mock
), patch("os.kill", new=raise_os_error):
executor = SimpleExecutor(SLEEP_300)
executor._kill_all_kids(executor._stop_signal)