3939import stat
4040import sys
4141import tempfile
42+ import time
4243from distutils .version import LooseVersion
4344from test .framework .utilities import EnhancedTestCase , TestLoaderFiltered
4445from test .framework .package import mock_fpm
@@ -118,7 +119,8 @@ def check_toy(self, installpath, outtxt, version='0.0', versionprefix='', versio
118119 self .assertTrue (os .path .exists (devel_module_path ))
119120
120121 def test_toy_build (self , extra_args = None , ec_file = None , tmpdir = None , verify = True , fails = False , verbose = True ,
121- raise_error = False , test_report = None , versionsuffix = '' , testing = True ):
122+ raise_error = False , test_report = None , versionsuffix = '' , testing = True ,
123+ raise_systemexit = False ):
122124 """Perform a toy build."""
123125 if extra_args is None :
124126 extra_args = []
@@ -145,7 +147,7 @@ def test_toy_build(self, extra_args=None, ec_file=None, tmpdir=None, verify=True
145147 myerr = None
146148 try :
147149 outtxt = self .eb_main (args , logfile = self .dummylogfn , do_build = True , verbose = verbose ,
148- raise_error = raise_error , testing = testing )
150+ raise_error = raise_error , testing = testing , raise_systemexit = raise_systemexit )
149151 except Exception as err :
150152 myerr = err
151153 if raise_error :
@@ -2607,6 +2609,57 @@ def __exit__(self, type, value, traceback):
26072609 self .assertErrorRegex (EasyBuildError , error_pattern , self .test_toy_build ,
26082610 extra_args = extra_args , raise_error = True , verbose = False )
26092611
2612+ def test_toy_lock_cleanup_signals (self ):
2613+ """Test cleanup of locks after EasyBuild session gets a cancellation signal."""
2614+
2615+ locks_dir = os .path .join (self .test_installpath , 'software' , '.locks' )
2616+ self .assertFalse (os .path .exists (locks_dir ))
2617+
2618+ # context manager which stops the function being called with the specified signal
2619+ class wait_and_signal :
2620+ def __init__ (self , seconds , signum ):
2621+ self .seconds = seconds
2622+ self .signum = signum
2623+
2624+ def send_signal (self , * args ):
2625+ os .kill (os .getpid (), self .signum )
2626+
2627+ def __enter__ (self ):
2628+ signal .signal (signal .SIGALRM , self .send_signal )
2629+ signal .alarm (self .seconds )
2630+
2631+ def __exit__ (self , type , value , traceback ):
2632+ pass
2633+
2634+ # add extra sleep command to ensure session takes long enough
2635+ test_ecs_dir = os .path .join (os .path .dirname (os .path .abspath (__file__ )), 'easyconfigs' , 'test_ecs' )
2636+ toy_ec_txt = read_file (os .path .join (test_ecs_dir , 't' , 'toy' , 'toy-0.0.eb' ))
2637+
2638+ test_ec = os .path .join (self .test_prefix , 'test.eb' )
2639+ write_file (test_ec , toy_ec_txt + '\n postinstallcmds = ["sleep 5"]' )
2640+
2641+ signums = [
2642+ (signal .SIGABRT , SystemExit ),
2643+ (signal .SIGINT , KeyboardInterrupt ),
2644+ (signal .SIGTERM , SystemExit ),
2645+ (signal .SIGQUIT , SystemExit ),
2646+ ]
2647+ for (signum , exc ) in signums :
2648+ with wait_and_signal (1 , signum ):
2649+ self .mock_stderr (True )
2650+ self .mock_stdout (True )
2651+ self .assertErrorRegex (exc , '.*' , self .test_toy_build , ec_file = test_ec , verify = False ,
2652+ raise_error = True , testing = False , raise_systemexit = True )
2653+
2654+ stderr = self .get_stderr ().strip ()
2655+ self .mock_stderr (False )
2656+ self .mock_stdout (False )
2657+
2658+ pattern = r"^WARNING: signal received \(%s\), " % int (signum )
2659+ pattern += r"cleaning up locks \(.*software_toy_0.0\)\.\.\."
2660+ regex = re .compile (pattern )
2661+ self .assertTrue (regex .search (stderr ), "Pattern '%s' found in: %s" % (regex .pattern , stderr ))
2662+
26102663 def test_toy_build_unicode_description (self ):
26112664 """Test installation of easyconfig file that has non-ASCII characters in description."""
26122665 # cfr. https://github.com/easybuilders/easybuild-framework/issues/3284
0 commit comments