test: add --abort-on-timeout option to test.py
Currently, when a process times out, it is terminated by sending it the SIGTERM signal. Sending SIGBART instead allows the operating system to generate a core file that can be investigated later using post-mortem debuggers such as llnode or mdb_v8. This can be very useful when investigating flaky tests that time out, since in that case the failure is difficult to reproduce, and being able to look at a core file makes a big difference. With these changes, passing the --abort-on-timeout command line option to tools/test.py now sends SIGABRT to processes timing out on all platforms but Windows. PR-URL: https://github.com/nodejs/node/pull/11086 Ref: https://github.com/nodejs/node/issues/11026 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com> Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
3d7ada34e4
commit
3b488eccc1
@ -565,11 +565,11 @@ class TestOutput(object):
|
|||||||
return execution_failed
|
return execution_failed
|
||||||
|
|
||||||
|
|
||||||
def KillProcessWithID(pid):
|
def KillProcessWithID(pid, signal_to_send=signal.SIGTERM):
|
||||||
if utils.IsWindows():
|
if utils.IsWindows():
|
||||||
os.popen('taskkill /T /F /PID %d' % pid)
|
os.popen('taskkill /T /F /PID %d' % pid)
|
||||||
else:
|
else:
|
||||||
os.kill(pid, signal.SIGTERM)
|
os.kill(pid, signal_to_send)
|
||||||
|
|
||||||
|
|
||||||
MAX_SLEEP_TIME = 0.1
|
MAX_SLEEP_TIME = 0.1
|
||||||
@ -588,6 +588,17 @@ def Win32SetErrorMode(mode):
|
|||||||
pass
|
pass
|
||||||
return prev_error_mode
|
return prev_error_mode
|
||||||
|
|
||||||
|
|
||||||
|
def KillTimedOutProcess(context, pid):
|
||||||
|
signal_to_send = signal.SIGTERM
|
||||||
|
if context.abort_on_timeout:
|
||||||
|
# Using SIGABRT here allows the OS to generate a core dump that can be
|
||||||
|
# looked at post-mortem, which helps for investigating failures that are
|
||||||
|
# difficult to reproduce.
|
||||||
|
signal_to_send = signal.SIGABRT
|
||||||
|
KillProcessWithID(pid, signal_to_send)
|
||||||
|
|
||||||
|
|
||||||
def RunProcess(context, timeout, args, **rest):
|
def RunProcess(context, timeout, args, **rest):
|
||||||
if context.verbose: print "#", " ".join(args)
|
if context.verbose: print "#", " ".join(args)
|
||||||
popen_args = args
|
popen_args = args
|
||||||
@ -627,7 +638,7 @@ def RunProcess(context, timeout, args, **rest):
|
|||||||
while True:
|
while True:
|
||||||
if time.time() >= end_time:
|
if time.time() >= end_time:
|
||||||
# Kill the process and wait for it to exit.
|
# Kill the process and wait for it to exit.
|
||||||
KillProcessWithID(process.pid)
|
KillTimedOutProcess(context, process.pid)
|
||||||
exit_code = process.wait()
|
exit_code = process.wait()
|
||||||
timed_out = True
|
timed_out = True
|
||||||
break
|
break
|
||||||
@ -648,7 +659,7 @@ def RunProcess(context, timeout, args, **rest):
|
|||||||
while exit_code is None:
|
while exit_code is None:
|
||||||
if (not end_time is None) and (time.time() >= end_time):
|
if (not end_time is None) and (time.time() >= end_time):
|
||||||
# Kill the process and wait for it to exit.
|
# Kill the process and wait for it to exit.
|
||||||
KillProcessWithID(process.pid)
|
KillTimedOutProcess(context, process.pid)
|
||||||
exit_code = process.wait()
|
exit_code = process.wait()
|
||||||
timed_out = True
|
timed_out = True
|
||||||
else:
|
else:
|
||||||
@ -851,7 +862,7 @@ class Context(object):
|
|||||||
|
|
||||||
def __init__(self, workspace, buildspace, verbose, vm, args, expect_fail,
|
def __init__(self, workspace, buildspace, verbose, vm, args, expect_fail,
|
||||||
timeout, processor, suppress_dialogs,
|
timeout, processor, suppress_dialogs,
|
||||||
store_unexpected_output, repeat):
|
store_unexpected_output, repeat, abort_on_timeout):
|
||||||
self.workspace = workspace
|
self.workspace = workspace
|
||||||
self.buildspace = buildspace
|
self.buildspace = buildspace
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
@ -863,6 +874,7 @@ class Context(object):
|
|||||||
self.suppress_dialogs = suppress_dialogs
|
self.suppress_dialogs = suppress_dialogs
|
||||||
self.store_unexpected_output = store_unexpected_output
|
self.store_unexpected_output = store_unexpected_output
|
||||||
self.repeat = repeat
|
self.repeat = repeat
|
||||||
|
self.abort_on_timeout = abort_on_timeout
|
||||||
|
|
||||||
def GetVm(self, arch, mode):
|
def GetVm(self, arch, mode):
|
||||||
if arch == 'none':
|
if arch == 'none':
|
||||||
@ -1385,6 +1397,9 @@ def BuildOptions():
|
|||||||
result.add_option('--repeat',
|
result.add_option('--repeat',
|
||||||
help='Number of times to repeat given tests',
|
help='Number of times to repeat given tests',
|
||||||
default=1, type="int")
|
default=1, type="int")
|
||||||
|
result.add_option('--abort-on-timeout',
|
||||||
|
help='Send SIGABRT instead of SIGTERM to kill processes that time out',
|
||||||
|
default=False, dest="abort_on_timeout")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@ -1566,7 +1581,8 @@ def Main():
|
|||||||
processor,
|
processor,
|
||||||
options.suppress_dialogs,
|
options.suppress_dialogs,
|
||||||
options.store_unexpected_output,
|
options.store_unexpected_output,
|
||||||
options.repeat)
|
options.repeat,
|
||||||
|
options.abort_on_timeout)
|
||||||
|
|
||||||
# Get status for tests
|
# Get status for tests
|
||||||
sections = [ ]
|
sections = [ ]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user