Bug 1400380 - cancel timeout when debugging
MozReview-Commit-ID: 9JJw3tM0FPp
--- a/testing/mozbase/mozprocess/mozprocess/processhandler.py
+++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py
@@ -662,24 +662,29 @@ falling back to not using job objects fo
cwd=None,
env=None,
ignore_children=False,
kill_on_timeout=True,
processOutputLine=(),
processStderrLine=(),
onTimeout=(),
onFinish=(),
+ debuggerInfo=None,
**kwargs):
self.cmd = cmd
self.args = args
self.cwd = cwd
self.didTimeout = False
self._ignore_children = ignore_children
self.keywordargs = kwargs
self.read_buffer = ''
+ self.debuggerInfo = debuggerInfo
+
+ if debuggerInfo is not None:
+ self.cmd = [debuggerInfo.path] + debuggerInfo.args + cmd
if env is None:
env = os.environ.copy()
self.env = env
# handlers
def to_callable_list(arg):
if callable(arg):
@@ -1065,17 +1070,17 @@ class ProcessHandler(ProcessHandlerMixin
If storeOutput==True, the output produced by the process will be saved
as self.output.
If logfile is not None, the output produced by the process will be
appended to the given file.
"""
def __init__(self, cmd, logfile=None, stream=True, storeOutput=True,
- **kwargs):
+ debuggerInfo=None, **kwargs):
kwargs.setdefault('processOutputLine', [])
if callable(kwargs['processOutputLine']):
kwargs['processOutputLine'] = [kwargs['processOutputLine']]
if logfile:
logoutput = LogOutput(logfile)
kwargs['processOutputLine'].append(logoutput)
@@ -1088,9 +1093,9 @@ class ProcessHandler(ProcessHandlerMixin
kwargs['processOutputLine'].append(streamoutput)
self.output = None
if storeOutput:
storeoutput = StoreOutput()
self.output = storeoutput.output
kwargs['processOutputLine'].append(storeoutput)
- ProcessHandlerMixin.__init__(self, cmd, **kwargs)
+ ProcessHandlerMixin.__init__(self, cmd, debuggerInfo=debuggerInfo, **kwargs)
--- a/testing/talos/talos/talos_process.py
+++ b/testing/talos/talos/talos_process.py
@@ -1,14 +1,15 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import
import pprint
+import signal
import time
import traceback
from threading import Event
import mozcrash
import psutil
from mozlog import get_proxy_logger
from mozprocess import ProcessHandler
@@ -73,17 +74,17 @@ class Reader(object):
if not (line.startswith('JavaScript error:') or
line.startswith('JavaScript warning:')):
LOG.process_output(self.proc.pid, line)
self.output.append(line)
def run_browser(command, minidump_dir, timeout=None, on_started=None,
- **kwargs):
+ debug=None, debugger=None, debugger_args=None, **kwargs):
"""
Run the browser using the given `command`.
After the browser prints __endTimestamp, we give it 5
seconds to quit and kill it if it's still alive at that point.
Note that this method ensure that the process is killed at
the end. If this is not possible, an exception will be raised.
@@ -97,30 +98,38 @@ def run_browser(command, minidump_dir, t
:param on_started: a callback that can be used to do things just after
the browser has been started. The callback must takes
an argument, which is the psutil.Process instance
:param kwargs: additional keyword arguments for the :class:`ProcessHandler`
instance
Returns a ProcessContext instance, with available output and pid used.
"""
+
+ debuggerInfo = find_debugger_info(debug, debugger, debugger_args)
+
context = ProcessContext()
first_time = int(time.time()) * 1000
wait_for_quit_timeout = 5
event = Event()
reader = Reader(event)
LOG.info("Using env: %s" % pprint.pformat(kwargs['env']))
kwargs['storeOutput'] = False
kwargs['processOutputLine'] = reader
kwargs['onFinish'] = event.set
- proc = ProcessHandler(command, **kwargs)
+ proc = ProcessHandler(command, debuggerInfo=debuggerInfo, **kwargs)
reader.proc = proc
proc.run()
+
+ if debuggerInfo is not None:
+ timeout = None
+ signal.signal(signal.SIGINT, lambda sigid, frame: None)
+
LOG.process_start(proc.pid, ' '.join(command))
try:
context.process = psutil.Process(proc.pid)
if on_started:
on_started(context.process)
# wait until we saw __endTimestamp in the proc output,
# or the browser just terminated - or we have a timeout
if not event.wait(timeout):
@@ -160,8 +169,38 @@ def run_browser(command, minidump_dir, t
% (int(time.time()) * 1000))
if return_code is not None:
LOG.process_exit(proc.pid, return_code)
else:
LOG.debug("Unable to detect exit code of the process %s." % proc.pid)
context.output = reader.output
return context
+
+
+def find_debugger_info(debug, debugger, debugger_args):
+ debuggerInfo = None
+ if debug or debugger or debugger_args:
+ import mozdebug
+
+ if not debugger:
+ # No debugger name was provided. Look for the default ones on
+ # current OS.
+ debugger = mozdebug.get_default_debugger_name(mozdebug.DebuggerSearch.KeepLooking)
+
+ debuggerInfo = None
+ if debugger:
+ debuggerInfo = mozdebug.get_debugger_info(debugger, debugger_args)
+
+ if debuggerInfo is None:
+ raise TalosError('Could not find a suitable debugger in your PATH.')
+
+ # Parameters come from the CLI. We need to convert them before
+ # their use.
+ if debugger_args:
+ from mozbuild import shellutil
+ try:
+ shellutil.split(debugger_args)
+ except shellutil.MetaCharacterException as e:
+ raise TalosError(
+ "The --debugger_args you passed require a real shell to parse them."
+ "(We can't handle the %r character.)" % e.char)
+ return debuggerInfo
--- a/testing/talos/talos/ttest.py
+++ b/testing/talos/talos/ttest.py
@@ -171,19 +171,16 @@ class TTest(object):
# to dump the profile.
timeout += 5 * 60
command_args = utils.GenerateBrowserCommandLine(
browser_config['browser_path'],
browser_config['extra_args'],
setup.profile_dir,
test_config['url'],
- browser_config['debug'],
- browser_config['debugger'],
- browser_config['debugger_args'],
profiling_info=(setup.gecko_profile.profiling_info
if setup.gecko_profile else None)
)
mainthread_error_count = 0
if test_config['setup']:
# Generate bcontroller.json for xperf
talosconfig.generateTalosConfig(command_args,
@@ -205,16 +202,19 @@ class TTest(object):
pcontext = run_browser(
command_args,
minidump_dir,
timeout=timeout,
env=setup.env,
# start collecting counters as soon as possible
on_started=(counter_management.start
if counter_management else None),
+ debug=browser_config['debug'],
+ debugger=browser_config['debugger'],
+ debugger_args=browser_config['debugger_args']
)
except:
self.check_for_crashes(browser_config, minidump_dir,
test_config['name'])
raise
finally:
if counter_management:
counter_management.stop()
--- a/testing/talos/talos/utils.py
+++ b/testing/talos/talos/utils.py
@@ -113,51 +113,21 @@ def urlsplit(url, default_scheme='file')
def parse_pref(value):
"""parse a preference value from a string"""
from mozprofile.prefs import Preferences
return Preferences.cast(value)
-def GenerateBrowserCommandLine(browser_path, extra_args, profile_dir, url,
- debug, debugger, debugger_args, profiling_info=None):
+def GenerateBrowserCommandLine(browser_path, extra_args, profile_dir, url, profiling_info=None):
# TODO: allow for spaces in file names on Windows
command_args = [browser_path.strip()]
- if debug or debugger or debugger_args:
- import mozdebug
-
- if not debugger:
- # No debugger name was provided. Look for the default ones on
- # current OS.
- debugger = mozdebug.get_default_debugger_name(mozdebug.DebuggerSearch.KeepLooking)
-
- debuggerInfo = None
- if debugger:
- debuggerInfo = mozdebug.get_debugger_info(debugger, debugger_args)
-
- if debuggerInfo is None:
- raise TalosError('Could not find a suitable debugger in your PATH.')
-
- # Parameters come from the CLI. We need to convert them before
- # their use.
- if debugger_args:
- from mozbuild import shellutil
- try:
- debugger_args = shellutil.split(debugger_args)
- except shellutil.MetaCharacterException as e:
- raise TalosError(
- "The --debugger_args you passed require a real shell to parse them."
- "(We can't handle the %r character.)" % e.char)
-
- # Prepend the debugger args.
- command_args = [debuggerInfo.path] + debuggerInfo.args + command_args
-
if platform.system() == 'Darwin':
command_args.extend(['-foreground'])
if isinstance(extra_args, list):
command_args.extend(extra_args)
elif extra_args.strip():
command_args.extend([extra_args])