5050from easybuild .tools .build_log import EasyBuildError , init_logging , stop_logging
5151from easybuild .tools .config import update_build_option
5252from easybuild .tools .filetools import adjust_permissions , change_dir , mkdir , read_file , write_file
53- from easybuild .tools .run import RunShellCmdResult , check_async_cmd , check_log_for_errors , complete_cmd
54- from easybuild .tools .run import get_output_from_process , parse_log_for_error , run_shell_cmd , run_cmd , run_cmd_qa
55- from easybuild .tools .run import subprocess_terminate
53+ from easybuild .tools .run import RunShellCmdResult , RunShellCmdError , check_async_cmd , check_log_for_errors
54+ from easybuild .tools .run import complete_cmd , get_output_from_process , parse_log_for_error
55+ from easybuild .tools .run import print_run_shell_cmd_error , run_cmd , run_cmd_qa , run_shell_cmd , subprocess_terminate
5656from easybuild .tools .config import ERROR , IGNORE , WARN
5757
5858
@@ -311,6 +311,9 @@ def test_run_shell_cmd_fail(self):
311311 def handler (signum , _ ):
312312 raise RuntimeError ("Signal handler called with signal %s" % signum )
313313
314+ # disable trace output for this test (so stdout remains empty)
315+ update_build_option ('trace' , False )
316+
314317 orig_sigalrm_handler = signal .getsignal (signal .SIGALRM )
315318
316319 try :
@@ -321,38 +324,78 @@ def handler(signum, _):
321324 # command to kill parent shell
322325 cmd = "kill -9 $$"
323326
324- workdir = os .path .realpath (self .test_prefix )
325- change_dir (workdir )
327+ work_dir = os .path .realpath (self .test_prefix )
328+ change_dir (work_dir )
326329
327- with self .mocked_stdout_stderr () as (_ , stderr ):
328- self .assertErrorRegex (SystemExit , '.*' , run_shell_cmd , cmd )
329-
330- # check error reporting output
331- stderr = stderr .getvalue ()
332- patterns = [
333- r"^\| full shell command[ ]*\| kill -9 \$\$" ,
334- r"^\| exit code[ ]*\| -9" ,
335- r"^\| working directory[ ]*\| " + workdir ,
336- r"^\| called from[ ]*\| assertErrorRegex function in .*/easybuild/base/testing.py \(line [0-9]+\)" ,
337- r"^ERROR: shell command 'kill' failed!" ,
338- r"^\| output \(stdout \+ stderr\)[ ]*\| .*/shell-cmd-error-.*/kill.out" ,
339- ]
340- for pattern in patterns :
341- regex = re .compile (pattern , re .M )
342- self .assertTrue (regex .search (stderr ), "Pattern '%s' should be found in: %s" % (regex .pattern , stderr ))
330+ try :
331+ run_shell_cmd (cmd )
332+ self .assertFalse ("This should never be reached, RunShellCmdError should occur!" )
333+ except RunShellCmdError as err :
334+ self .assertEqual (str (err ), "Shell command 'kill' failed!" )
335+ self .assertEqual (err .cmd , "kill -9 $$" )
336+ self .assertEqual (err .cmd_name , 'kill' )
337+ self .assertEqual (err .exit_code , - 9 )
338+ self .assertEqual (err .work_dir , work_dir )
339+ self .assertEqual (err .output , '' )
340+ self .assertEqual (err .stderr , None )
341+ self .assertTrue (isinstance (err .caller_info , tuple ))
342+ self .assertEqual (len (err .caller_info ), 3 )
343+ self .assertEqual (err .caller_info [0 ], __file__ )
344+ self .assertTrue (isinstance (err .caller_info [1 ], int )) # line number of calling site
345+ self .assertEqual (err .caller_info [2 ], 'test_run_shell_cmd_fail' )
346+
347+ with self .mocked_stdout_stderr () as (_ , stderr ):
348+ print_run_shell_cmd_error (err )
349+
350+ # check error reporting output
351+ stderr = stderr .getvalue ()
352+ patterns = [
353+ r"^ERROR: Shell command failed!" ,
354+ r"^\s+full command\s* -> kill -9 \$\$" ,
355+ r"^\s+exit code\s* -> -9" ,
356+ r"^\s+working directory\s* -> " + work_dir ,
357+ r"^\s+called from\s* -> 'test_run_shell_cmd_fail' function in .*/test/.*/run.py \(line [0-9]+\)" ,
358+ r"^\s+output \(stdout \+ stderr\)\s* -> .*/shell-cmd-error-.*/kill.out" ,
359+ ]
360+ for pattern in patterns :
361+ regex = re .compile (pattern , re .M )
362+ self .assertTrue (regex .search (stderr ), "Pattern '%s' should be found in: %s" % (pattern , stderr ))
343363
344364 # check error reporting output when stdout/stderr are collected separately
345- with self .mocked_stdout_stderr () as (_ , stderr ):
346- self .assertErrorRegex (SystemExit , '.*' , run_shell_cmd , cmd , split_stderr = True )
347- stderr = stderr .getvalue ()
348- patterns .pop (- 1 )
349- patterns .extend ([
350- r"^\| output \(stdout\)[ ]*\| .*/shell-cmd-error-.*/kill.out" ,
351- r"^\| error/warnings \(stderr\)[ ]*\| .*/shell-cmd-error-.*/kill.err" ,
352- ])
353- for pattern in patterns :
354- regex = re .compile (pattern , re .M )
355- self .assertTrue (regex .search (stderr ), "Pattern '%s' should be found in: %s" % (regex .pattern , stderr ))
365+ try :
366+ run_shell_cmd (cmd , split_stderr = True )
367+ self .assertFalse ("This should never be reached, RunShellCmdError should occur!" )
368+ except RunShellCmdError as err :
369+ self .assertEqual (str (err ), "Shell command 'kill' failed!" )
370+ self .assertEqual (err .cmd , "kill -9 $$" )
371+ self .assertEqual (err .cmd_name , 'kill' )
372+ self .assertEqual (err .exit_code , - 9 )
373+ self .assertEqual (err .work_dir , work_dir )
374+ self .assertEqual (err .output , '' )
375+ self .assertEqual (err .stderr , '' )
376+ self .assertTrue (isinstance (err .caller_info , tuple ))
377+ self .assertEqual (len (err .caller_info ), 3 )
378+ self .assertEqual (err .caller_info [0 ], __file__ )
379+ self .assertTrue (isinstance (err .caller_info [1 ], int )) # line number of calling site
380+ self .assertEqual (err .caller_info [2 ], 'test_run_shell_cmd_fail' )
381+
382+ with self .mocked_stdout_stderr () as (_ , stderr ):
383+ print_run_shell_cmd_error (err )
384+
385+ # check error reporting output
386+ stderr = stderr .getvalue ()
387+ patterns = [
388+ r"^ERROR: Shell command failed!" ,
389+ r"^\s+full command\s+ -> kill -9 \$\$" ,
390+ r"^\s+exit code\s+ -> -9" ,
391+ r"^\s+working directory\s+ -> " + work_dir ,
392+ r"^\s+called from\s+ -> 'test_run_shell_cmd_fail' function in .*/test/.*/run.py \(line [0-9]+\)" ,
393+ r"^\s+output \(stdout\)\s+ -> .*/shell-cmd-error-.*/kill.out" ,
394+ r"^\s+error/warnings \(stderr\)\s+ -> .*/shell-cmd-error-.*/kill.err" ,
395+ ]
396+ for pattern in patterns :
397+ regex = re .compile (pattern , re .M )
398+ self .assertTrue (regex .search (stderr ), "Pattern '%s' should be found in: %s" % (pattern , stderr ))
356399
357400 # no error reporting when fail_on_error is disabled
358401 with self .mocked_stdout_stderr () as (_ , stderr ):
0 commit comments