Bug 1400380 - start integrating debugger r?jmaher draft
authorIonut Goldan <igoldan@mozilla.com>
Tue, 31 Oct 2017 16:05:10 +0200
changeset 698341 d5f775f4ff41b3e915f3cfdeb86fe28cc9bc0239
parent 698340 3e3fa007d5942720b2c51fdfff2ba885a07d52ee
child 698342 a4525e9b2189b7acccc5a14bd075c4cc52c8291e
push id89257
push userbmo:igoldan@mozilla.com
push dateWed, 15 Nov 2017 15:09:44 +0000
reviewersjmaher
bugs1400380
milestone59.0a1
Bug 1400380 - start integrating debugger r?jmaher MozReview-Commit-ID: G1Shyyvc90G
testing/talos/talos/ttest.py
testing/talos/talos/utils.py
--- a/testing/talos/talos/ttest.py
+++ b/testing/talos/talos/ttest.py
@@ -37,17 +37,17 @@ class TTest(object):
     def check_for_crashes(self, browser_config, minidump_dir, test_name):
         # check for minidumps
         found = mozcrash.check_for_crashes(minidump_dir,
                                            browser_config['symbols_path'],
                                            test_name=test_name)
         mozfile.remove(minidump_dir)
 
         if found:
-            raise TalosCrash("Found crashes after test run, terminating test")
+            raise TalosCrash('Found crashes after test run, terminating test')
 
     def runTest(self, browser_config, test_config):
         """
             Runs an url based test on the browser as specified in the
             browser_config dictionary
 
         Args:
             browser_config:  Dictionary of configuration options for the
@@ -57,51 +57,51 @@ class TTest(object):
 
         """
 
         with FFSetup(browser_config, test_config) as setup:
             return self._runTest(browser_config, test_config, setup)
 
     @staticmethod
     def _get_counter_prefix():
-        if platform.system() == "Linux":
+        if platform.system() == 'Linux':
             return 'linux'
-        elif platform.system() in ("Windows", "Microsoft"):
+        elif platform.system() in ('Windows', 'Microsoft'):
             if '6.1' in platform.version():  # w7
                 return 'w7'
             elif '6.2' in platform.version():  # w8
                 return 'w8'
             # Bug 1264325 - FIXME: with python 2.7.11: reports win8 instead of 8.1
             elif '6.3' in platform.version():
                 return 'w8'
             # Bug 1264325 - FIXME: with python 2.7.11: reports win8 instead of 10
             elif '10.0' in platform.version():
                 return 'w8'
             else:
                 raise TalosError('unsupported windows version')
-        elif platform.system() == "Darwin":
+        elif platform.system() == 'Darwin':
             return 'mac'
 
     def _runTest(self, browser_config, test_config, setup):
         minidump_dir = os.path.join(setup.profile_dir, 'minidumps')
         counters = test_config.get('%s_counters' % self._get_counter_prefix(), [])
         resolution = test_config['resolution']
 
         # add the mainthread_io to the environment variable, as defined
         # in test.py configs
         here = os.path.dirname(os.path.realpath(__file__))
         if test_config['mainthread']:
-            mainthread_io = os.path.join(here, "mainthread_io.log")
+            mainthread_io = os.path.join(here, 'mainthread_io.log')
             setup.env['MOZ_MAIN_THREAD_IO_LOG'] = mainthread_io
 
         if browser_config['disable_stylo']:
             if browser_config['stylothreads']:
-                raise TalosError("--disable-stylo conflicts with --stylo-threads")
+                raise TalosError('--disable-stylo conflicts with --stylo-threads')
             if browser_config['enable_stylo']:
-                raise TalosError("--disable-stylo conflicts with --enable-stylo")
+                raise TalosError('--disable-stylo conflicts with --enable-stylo')
 
         # As we transition to Stylo, we need to set env vars and output data properly
         if browser_config['enable_stylo']:
             setup.env['STYLO_FORCE_ENABLED'] = '1'
         if browser_config['disable_stylo']:
             setup.env['STYLO_FORCE_DISABLED'] = '1'
 
         # During the Stylo transition, measure different number of threads
@@ -119,68 +119,71 @@ class TTest(object):
         global_counters = {}
         if browser_config.get('xperf_path'):
             for c in test_config.get('xperf_counters', []):
                 global_counters[c] = []
 
         if test_config['shutdown']:
             global_counters['shutdown'] = []
         if test_config.get('responsiveness') and \
-           platform.system() != "Darwin":
+           platform.system() != 'Darwin':
             # ignore osx for now as per bug 1245793
             setup.env['MOZ_INSTRUMENT_EVENT_LOOP'] = '1'
             setup.env['MOZ_INSTRUMENT_EVENT_LOOP_THRESHOLD'] = '20'
             setup.env['MOZ_INSTRUMENT_EVENT_LOOP_INTERVAL'] = '10'
             global_counters['responsiveness'] = []
 
         setup.env['JSGC_DISABLE_POISONING'] = '1'
         setup.env['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] = '1'
 
         # if using mitmproxy we must allow access to 'external' sites
         if browser_config.get('mitmproxy', False):
-            LOG.info("Using mitmproxy so setting MOZ_DISABLE_NONLOCAL_CONNECTIONS to 0")
+            LOG.info('Using mitmproxy so setting MOZ_DISABLE_NONLOCAL_CONNECTIONS to 0')
             setup.env['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] = '0'
 
         # instantiate an object to hold test results
         test_results = results.TestResults(
             test_config,
             global_counters,
             browser_config.get('framework')
         )
 
         for i in range(test_config['cycles']):
-            LOG.info("Running cycle %d/%d for %s test..."
+            LOG.info('Running cycle %d/%d for %s test...'
                      % (i+1, test_config['cycles'], test_config['name']))
 
             # remove the browser  error file
             mozfile.remove(browser_config['error_filename'])
 
             # reinstall any file whose stability we need to ensure across
             # the cycles
             if test_config.get('reinstall', ''):
                 for keep in test_config['reinstall']:
                     origin = os.path.join(test_config['profile_path'],
                                           keep)
                     dest = os.path.join(setup.profile_dir, keep)
-                    LOG.debug("Reinstalling %s on top of %s"
+                    LOG.debug('Reinstalling %s on top of %s'
                               % (origin, dest))
                     shutil.copy(origin, dest)
 
             # Run the test
             timeout = test_config.get('timeout', 7200)  # 2 hours default
             if setup.gecko_profile:
                 # When profiling, give the browser some extra time
                 # to dump the profile.
                 timeout += 5 * 60
 
             command_args = utils.GenerateBrowserCommandLine(
-                browser_config["browser_path"],
-                browser_config["extra_args"],
+                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,
@@ -212,31 +215,31 @@ class TTest(object):
                 self.check_for_crashes(browser_config, minidump_dir,
                                        test_config['name'])
                 raise
             finally:
                 if counter_management:
                     counter_management.stop()
 
             if test_config['mainthread']:
-                rawlog = os.path.join(here, "mainthread_io.log")
+                rawlog = os.path.join(here, 'mainthread_io.log')
                 if os.path.exists(rawlog):
                     processedlog = \
                         os.path.join(here, 'mainthread_io.json')
                     xre_path = \
                         os.path.dirname(browser_config['browser_path'])
                     mtio_py = os.path.join(here, 'mainthreadio.py')
                     command = ['python', mtio_py, rawlog,
                                processedlog, xre_path]
                     mtio = subprocess.Popen(command,
                                             env=os.environ.copy(),
                                             stdout=subprocess.PIPE)
                     output, stderr = mtio.communicate()
                     for line in output.split('\n'):
-                        if line.strip() == "":
+                        if line.strip() == '':
                             continue
 
                         print(line)
                         mainthread_error_count += 1
                     mozfile.remove(rawlog)
 
             if test_config['cleanup']:
                 # HACK: add the pid to support xperf where we require
@@ -254,18 +257,18 @@ class TTest(object):
             for fname in ('sessionstore.js', '.parentlock',
                           'sessionstore.bak'):
                 mozfile.remove(os.path.join(setup.profile_dir, fname))
 
             # check for xperf errors
             if os.path.exists(browser_config['error_filename']) or \
                mainthread_error_count > 0:
                 raise TalosRegression(
-                    "Talos has found a regression, if you have questions"
-                    " ask for help in irc on #perf"
+                    'Talos has found a regression, if you have questions'
+                    ' ask for help in irc on #perf'
                 )
 
             # add the results from the browser output
             test_results.add(
                 '\n'.join(pcontext.output),
                 counter_results=(counter_management.results()
                                  if counter_management
                                  else None)
@@ -278,12 +281,12 @@ class TTest(object):
                                    test_config['name'])
 
         # include global (cross-cycle) counters
         test_results.all_counter_results.extend(
             [{key: value} for key, value in global_counters.items()]
         )
         for c in test_results.all_counter_results:
             for key, value in c.items():
-                LOG.debug("COUNTER %r: %s" % (key, value))
+                LOG.debug('COUNTER %r: %s' % (key, value))
 
         # return results
         return test_results
--- a/testing/talos/talos/utils.py
+++ b/testing/talos/talos/utils.py
@@ -26,17 +26,17 @@ class Timer(object):
         self._start_time = 0
         self.start()
 
     def start(self):
         self._start_time = time.time()
 
     def elapsed(self):
         seconds = time.time() - self._start_time
-        return time.strftime("%H:%M:%S", time.gmtime(seconds))
+        return time.strftime('%H:%M:%S', time.gmtime(seconds))
 
 
 class TalosError(Exception):
     "Errors found while running the talos harness."
 
 
 class TalosRegression(Exception):
     """When a regression is detected at runtime, report it properly
@@ -113,22 +113,52 @@ 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, profiling_info=None):
+def GenerateBrowserCommandLine(browser_path, extra_args, profile_dir, url,
+                               debug, debugger, debugger_args, profiling_info=None):
     # TODO: allow for spaces in file names on Windows
 
     command_args = [browser_path.strip()]
-    if platform.system() == "Darwin":
+
+    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])