Skip to content

Commit

Permalink
🐛 Fix KeyboardInterrupt in wake test multiprocessing
Browse files Browse the repository at this point in the history
  • Loading branch information
MeditationDuck authored and michprev committed Sep 18, 2024
1 parent c2e8c05 commit 2ae57db
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
21 changes: 17 additions & 4 deletions wake/testing/pytest_plugin_multiprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class PytestWakePluginMultiprocess:
_exception_handled: bool

_ctx_managers: List
_keyboard_interrupt: bool

def __init__(
self,
Expand All @@ -62,6 +63,7 @@ def __init__(
self._debug = debug
self._exception_handled = False

self._keyboard_interrupt = False
self._ctx_managers = []

def _setup_stdio(self):
Expand All @@ -86,6 +88,11 @@ def _exception_handler(
e: Optional[BaseException],
tb: Optional[TracebackType],
) -> None:

# After the keyboard interrupt, we do not interested in debugging.
if self._keyboard_interrupt:
return

self._cleanup_stdio()
self._exception_handled = True

Expand Down Expand Up @@ -177,11 +184,14 @@ def coverage_callback() -> None:
except queue.Full:
pass

def signal_handler(sig, frame):
raise KeyboardInterrupt()

pickling_support.install()
signal.signal(signal.SIGTERM, signal_handler)

def sigint_handler(signum, frame):
self._keyboard_interrupt = True
self._queue.put(("keyboard_interrupt", self._index))
pytest.exit("Keyboard interrupt", returncode=0)

signal.signal(signal.SIGINT, sigint_handler)

if self._debug:
set_exception_handler(self._exception_handler)
Expand Down Expand Up @@ -226,6 +236,9 @@ def pytest_runtest_protocol(self, item, nextitem):
# do not forward pytest_runtest_logstart and pytest_runtest_logfinish as they write item location to stdout which may be different for each process

def pytest_runtest_logreport(self, report: pytest.TestReport):
# not sending exception report since the reason of exception is keyboard interrupt or at least triggered by keyboard interrupt
if self._keyboard_interrupt:
return
self._queue.put(("pytest_runtest_logreport", self._index, report))

def pytest_warning_recorded(self, warning_message, when, nodeid, location):
Expand Down
20 changes: 17 additions & 3 deletions wake/testing/pytest_plugin_multiprocess_server.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import multiprocessing
import multiprocessing.connection
import os
import pickle
import shutil
import signal
from contextlib import nullcontext
from pathlib import Path
from typing import Dict, List, Optional, Tuple, Union
Expand Down Expand Up @@ -101,14 +103,15 @@ def pytest_sessionstart(self, session: pytest.Session):
parent_conn,
)
p.start()
signal.signal(signal.SIGINT, signal.SIG_IGN)

def pytest_sessionfinish(self, session: pytest.Session):
self._queue.cancel_join_thread()
for p, conn in self._processes.values():
p.terminate()
if p.pid is not None:
os.kill(p.pid, signal.SIGINT)
p.join()
conn.close()

self._queue.close()

# flush coverage
Expand Down Expand Up @@ -177,6 +180,7 @@ def pytest_runtestloop(self, session: pytest.Session):
)

try:
keyboard_interrupt = [False for _ in range(self._proc_count)]
with ctx as progress:
if progress is not None:
tasks = [
Expand Down Expand Up @@ -268,7 +272,12 @@ def pytest_runtestloop(self, session: pytest.Session):
)
elif msg[0] == "pytest_sessionfinish":
if progress is not None:
text = f"#{index} finished [green]✓[/green]" if msg[2] == 0 else f"#{index} failed [red]✗[/red]"
if keyboard_interrupt[index]:
text = f"#{index} interrupted [yellow]⚠[/yellow]"
elif msg[2] == 0:
text = f"#{index} finished [green]✓[/green]"
else:
text = f"#{index} failed [red]✗[/red]"
progress.update(tasks[index], description=text)

self._processes.pop(index)
Expand All @@ -280,6 +289,11 @@ def pytest_runtestloop(self, session: pytest.Session):
session.config.hook.pytest_internalerror(
excrepr=exc_info.getrepr(style="short"), excinfo=exc_info
)
elif msg[0] == "keyboard_interrupt":
keyboard_interrupt[index] = True

if True in keyboard_interrupt:
raise KeyboardInterrupt
finally:
print("")
for report in reports:
Expand Down

0 comments on commit 2ae57db

Please sign in to comment.