summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coverage/control.py2
-rw-r--r--tests/test_concurrency.py27
2 files changed, 27 insertions, 2 deletions
diff --git a/coverage/control.py b/coverage/control.py
index acce622d..e405a5bf 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -653,7 +653,7 @@ class Coverage(TConfigurable):
self._debug.write(f"{event}: pid: {os.getpid()}, instance: {self!r}")
if self._started:
self.stop()
- if self._auto_save:
+ if self._auto_save or event == "sigterm":
self.save()
def _on_sigterm(self, signum_unused: int, frame_unused: Optional[FrameType]) -> None:
diff --git a/tests/test_concurrency.py b/tests/test_concurrency.py
index 9f12e77e..a9b64d15 100644
--- a/tests/test_concurrency.py
+++ b/tests/test_concurrency.py
@@ -705,7 +705,7 @@ class SigtermTest(CoverageTest):
"""Tests of our handling of SIGTERM."""
@pytest.mark.parametrize("sigterm", [False, True])
- def test_sigterm_saves_data(self, sigterm: bool) -> None:
+ def test_sigterm_multiprocessing_saves_data(self, sigterm: bool) -> None:
# A terminated process should save its coverage data.
self.make_file("clobbered.py", """\
import multiprocessing
@@ -751,6 +751,31 @@ class SigtermTest(CoverageTest):
expected = "clobbered.py 17 5 71% 5-10"
assert self.squeezed_lines(out)[2] == expected
+ def test_sigterm_threading_saves_data(self) -> None:
+ # A terminated process should save its coverage data.
+ self.make_file("handler.py", """\
+ import os, signal
+
+ print("START", flush=True)
+ print("SIGTERM", flush=True)
+ os.kill(os.getpid(), signal.SIGTERM)
+ print("NOT HERE", flush=True)
+ """)
+ self.make_file(".coveragerc", """\
+ [run]
+ # The default concurrency option.
+ concurrency = thread
+ sigterm = true
+ """)
+ out = self.run_command("coverage run handler.py")
+ if env.LINUX:
+ assert out == "START\nSIGTERM\nTerminated\n"
+ else:
+ assert out == "START\nSIGTERM\n"
+ out = self.run_command("coverage report -m")
+ expected = "handler.py 5 1 80% 6"
+ assert self.squeezed_lines(out)[2] == expected
+
def test_sigterm_still_runs(self) -> None:
# A terminated process still runs its own SIGTERM handler.
self.make_file("handler.py", """\