-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tests for reaping-on-signal behavior
- Loading branch information
Showing
2 changed files
with
89 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
""" | ||
Start a child process that prints signals it receives | ||
""" | ||
import asyncio | ||
import signal | ||
import os | ||
from functools import partial | ||
import sys | ||
from simpervisor import SupervisedProcess | ||
|
||
signal_printer = os.path.join( | ||
os.path.dirname(os.path.abspath(__file__)), | ||
'signalprinter.py' | ||
) | ||
|
||
async def main(): | ||
count = int(sys.argv[1]) | ||
pids = [] | ||
for i in range(count): | ||
proc = SupervisedProcess(f'signalprinter-{i}', *[ | ||
sys.executable, | ||
signal_printer, '1' | ||
]) | ||
|
||
await proc.start() | ||
pids.append(proc.pid) | ||
|
||
print(' '.join([str(pid) for pid in pids]), flush=True) | ||
|
||
|
||
|
||
loop = asyncio.get_event_loop() | ||
asyncio.ensure_future(main()) | ||
try: | ||
loop.run_forever() | ||
finally: | ||
# Cleanup properly so we get a clean exit | ||
loop.run_until_complete(asyncio.gather(*asyncio.Task.all_tasks())) | ||
print('supervisor exiting cleanly') | ||
loop.close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import sys | ||
import signal | ||
import os | ||
import pytest | ||
from simpervisor import SupervisedProcess | ||
import subprocess | ||
import time | ||
import errno | ||
|
||
|
||
@pytest.mark.parametrize('childcount', [1, 5]) | ||
@pytest.mark.asyncio | ||
async def test_sigtermreap(childcount): | ||
""" | ||
Test reaping subprocess after SIGTERM. | ||
- Start a supervisor process that supervises a child. | ||
- Send supervisor a SIGTERM | ||
- Make sure child receives it & exits first before supervisor exiting | ||
""" | ||
signalsupervisor_file = os.path.join( | ||
os.path.dirname(os.path.abspath(__file__)), | ||
'child_scripts', | ||
'signalsupervisor.py' | ||
) | ||
|
||
proc = subprocess.Popen([sys.executable, signalsupervisor_file, str(childcount)], stdout=subprocess.PIPE) | ||
|
||
# Give the signal handlers a bit of time to set up | ||
time.sleep(0.5) | ||
|
||
# Read the child's PID from signalsupervisor | ||
child_pids = [int(l) for l in proc.stdout.readline().decode().split(' ')] | ||
|
||
proc.send_signal(signal.SIGTERM) | ||
proc.wait() | ||
|
||
stdout, stderr = proc.communicate() | ||
|
||
# Make sure the children are dead | ||
for child_pid in child_pids: | ||
with pytest.raises(OSError) as e: | ||
os.kill(child_pid, 0) | ||
assert e.value.errno == errno.ESRCH | ||
|
||
# Test order of exit of child & parent | ||
assert stdout.decode() == 'handler 0 received 15\n' * len(child_pids) + 'supervisor exiting cleanly\n' | ||
# Test that our supervisor also exited cleanly | ||
assert proc.returncode == 0 |