Skip to content

Commit feb5b47

Browse files
authored
Merge pull request #3321 from boegel/fix_test_toy_lock_cleanup_signals
fix broken test_toy_lock_cleanup_signals & properly clean up after using SIGALRM signal in tests
2 parents cf9fd79 + 87168f8 commit feb5b47

File tree

2 files changed

+41
-17
lines changed

2 files changed

+41
-17
lines changed

test/framework/run.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -206,22 +206,27 @@ def test_run_cmd_negative_exit_code(self):
206206
def handler(signum, _):
207207
raise RuntimeError("Signal handler called with signal %s" % signum)
208208

209-
# set the signal handler and a 3-second alarm
210-
signal.signal(signal.SIGALRM, handler)
211-
signal.alarm(3)
209+
orig_sigalrm_handler = signal.getsignal(signal.SIGALRM)
212210

213-
(_, ec) = run_cmd("kill -9 $$", log_ok=False)
214-
self.assertEqual(ec, -9)
211+
try:
212+
# set the signal handler and a 3-second alarm
213+
signal.signal(signal.SIGALRM, handler)
214+
signal.alarm(3)
215215

216-
# reset the alarm
217-
signal.alarm(0)
218-
signal.alarm(3)
216+
(_, ec) = run_cmd("kill -9 $$", log_ok=False)
217+
self.assertEqual(ec, -9)
219218

220-
(_, ec) = run_cmd_qa("kill -9 $$", {}, log_ok=False)
221-
self.assertEqual(ec, -9)
219+
# reset the alarm
220+
signal.alarm(0)
221+
signal.alarm(3)
222222

223-
# disable the alarm
224-
signal.alarm(0)
223+
(_, ec) = run_cmd_qa("kill -9 $$", {}, log_ok=False)
224+
self.assertEqual(ec, -9)
225+
226+
finally:
227+
# cleanup: disable the alarm + reset signal handler for SIGALRM
228+
signal.signal(signal.SIGALRM, orig_sigalrm_handler)
229+
signal.alarm(0)
225230

226231
def test_run_cmd_bis(self):
227232
"""More 'complex' test for run_cmd function."""

test/framework/toy_build.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@
5151
from easybuild.tools.build_log import EasyBuildError
5252
from easybuild.tools.config import get_module_syntax, get_repositorypath
5353
from easybuild.tools.environment import modify_env
54-
from easybuild.tools.filetools import adjust_permissions, mkdir, read_file, remove_dir, remove_file, which, write_file
54+
from easybuild.tools.filetools import adjust_permissions, change_dir, mkdir, read_file, remove_dir, remove_file
55+
from easybuild.tools.filetools import which, write_file
5556
from easybuild.tools.module_generator import ModuleGeneratorTcl
5657
from easybuild.tools.modules import Lmod
5758
from easybuild.tools.py2vs3 import reload, string_type
@@ -2743,8 +2744,10 @@ def test_toy_build_lock(self):
27432744
# also test use of --ignore-locks
27442745
self.test_toy_build(extra_args=extra_args + ['--ignore-locks'], verify=True, raise_error=True)
27452746

2747+
orig_sigalrm_handler = signal.getsignal(signal.SIGALRM)
2748+
27462749
# define a context manager that remove a lock after a while, so we can check the use of --wait-for-lock
2747-
class remove_lock_after:
2750+
class remove_lock_after(object):
27482751
def __init__(self, seconds, lock_fp):
27492752
self.seconds = seconds
27502753
self.lock_fp = lock_fp
@@ -2757,7 +2760,9 @@ def __enter__(self):
27572760
signal.alarm(self.seconds)
27582761

27592762
def __exit__(self, type, value, traceback):
2760-
pass
2763+
# clean up SIGALRM signal handler, and cancel scheduled alarm
2764+
signal.signal(signal.SIGALRM, orig_sigalrm_handler)
2765+
signal.alarm(0)
27612766

27622767
# wait for lock to be removed, with 1 second interval of checking;
27632768
# check with both --wait-on-lock-interval and deprecated --wait-on-lock options
@@ -2850,11 +2855,15 @@ def __exit__(self, type, value, traceback):
28502855
def test_toy_lock_cleanup_signals(self):
28512856
"""Test cleanup of locks after EasyBuild session gets a cancellation signal."""
28522857

2858+
orig_wd = os.getcwd()
2859+
28532860
locks_dir = os.path.join(self.test_installpath, 'software', '.locks')
28542861
self.assertFalse(os.path.exists(locks_dir))
28552862

2863+
orig_sigalrm_handler = signal.getsignal(signal.SIGALRM)
2864+
28562865
# context manager which stops the function being called with the specified signal
2857-
class wait_and_signal:
2866+
class wait_and_signal(object):
28582867
def __init__(self, seconds, signum):
28592868
self.seconds = seconds
28602869
self.signum = signum
@@ -2867,7 +2876,9 @@ def __enter__(self):
28672876
signal.alarm(self.seconds)
28682877

28692878
def __exit__(self, type, value, traceback):
2870-
pass
2879+
# clean up SIGALRM signal handler, and cancel scheduled alarm
2880+
signal.signal(signal.SIGALRM, orig_sigalrm_handler)
2881+
signal.alarm(0)
28712882

28722883
# add extra sleep command to ensure session takes long enough
28732884
test_ecs_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'easyconfigs', 'test_ecs')
@@ -2883,7 +2894,15 @@ def __exit__(self, type, value, traceback):
28832894
(signal.SIGQUIT, SystemExit),
28842895
]
28852896
for (signum, exc) in signums:
2897+
2898+
# avoid recycling stderr of previous test
2899+
stderr = ''
2900+
28862901
with wait_and_signal(1, signum):
2902+
2903+
# change back to original working directory before each test
2904+
change_dir(orig_wd)
2905+
28872906
self.mock_stderr(True)
28882907
self.mock_stdout(True)
28892908
self.assertErrorRegex(exc, '.*', self.test_toy_build, ec_file=test_ec, verify=False,

0 commit comments

Comments
 (0)