Bug 1238305: Modify cppunittests to look up breakpad symbols for logged stack traces; r=ted
authorAaron Klotz <aklotz@mozilla.com>
Tue, 12 Jan 2016 12:58:59 -0700
changeset 347309 6c32452df00e86d86e65b5097ea253f488816067
parent 347308 cd3745be744588e6cbd802def770a96e425fe6f1
child 347310 eb1336d8898f8b84de79b5a9e152ce82ed4fb3df
push id10298
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:33:03 +0000
treeherdermozilla-aurora@7e29173b1641 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs1238305
milestone52.0a1
Bug 1238305: Modify cppunittests to look up breakpad symbols for logged stack traces; r=ted MozReview-Commit-ID: LnqEVRqYYFZ
testing/mach_commands.py
testing/mozharness/configs/unittests/linux_unittest.py
testing/mozharness/configs/unittests/mac_unittest.py
testing/mozharness/configs/unittests/win_unittest.py
testing/runcppunittests.py
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -371,33 +371,38 @@ class MachCommands(MachCommandBase):
         # If no tests specified, run all tests in main manifest
         tests = params['test_files']
         if len(tests) == 0:
             tests = [os.path.join(self.distdir, 'cppunittests')]
             manifest_path = os.path.join(self.topsrcdir, 'testing', 'cppunittest.ini')
         else:
             manifest_path = None
 
+        utility_path = self.bindir
+
         if conditions.is_android(self):
             from mozrunner.devices.android_device import verify_android_device
             verify_android_device(self, install=False)
             return self.run_android_test(tests, symbols_path, manifest_path, log)
 
-        return self.run_desktop_test(tests, symbols_path, manifest_path, log)
+        return self.run_desktop_test(tests, symbols_path, manifest_path,
+                                     utility_path, log)
 
-    def run_desktop_test(self, tests, symbols_path, manifest_path, log):
+    def run_desktop_test(self, tests, symbols_path, manifest_path, utility_path,
+                         log):
         import runcppunittests as cppunittests
         from mozlog import commandline
 
         parser = cppunittests.CPPUnittestOptions()
         commandline.add_logging_group(parser)
         options, args = parser.parse_args()
 
         options.symbols_path = symbols_path
         options.manifest_path = manifest_path
+        options.utility_path = utility_path
         options.xre_path = self.bindir
 
         try:
             result = cppunittests.run_test_harness(options, tests)
         except Exception as e:
             log.error("Caught exception running cpp unit tests: %s" % str(e))
             result = False
             raise
--- a/testing/mozharness/configs/unittests/linux_unittest.py
+++ b/testing/mozharness/configs/unittests/linux_unittest.py
@@ -75,16 +75,17 @@ config = {
         "jittest": ["jit-test/*"],
         "mozbase": ["mozbase/*"],
         "mozmill": ["mozmill/*"],
     },
     "suite_definitions": {
         "cppunittest": {
             "options": [
                 "--symbols-path=%(symbols_path)s",
+                "--utility-path=tests/bin",
                 "--xre-path=%(abs_app_dir)s"
             ],
             "run_filename": "runcppunittests.py",
             "testsdir": "cppunittest"
         },
         "jittest": {
             "options": [
                 "tests/bin/js",
--- a/testing/mozharness/configs/unittests/mac_unittest.py
+++ b/testing/mozharness/configs/unittests/mac_unittest.py
@@ -52,16 +52,17 @@ config = {
         "jittest": ["jit-test/*"],
         "mozbase": ["mozbase/*"],
         "mozmill": ["mozmill/*"],
     },
     "suite_definitions": {
         "cppunittest": {
             "options": [
                 "--symbols-path=%(symbols_path)s",
+                "--utility-path=tests/bin",
                 "--xre-path=%(abs_res_dir)s"
             ],
             "run_filename": "runcppunittests.py",
             "testsdir": "cppunittest"
         },
         "jittest": {
             "options": [
                 "tests/bin/js",
--- a/testing/mozharness/configs/unittests/win_unittest.py
+++ b/testing/mozharness/configs/unittests/win_unittest.py
@@ -63,16 +63,17 @@ config = {
         "jittest": ["jit-test/*"],
         "mozbase": ["mozbase/*"],
         "mozmill": ["mozmill/*"],
     },
     "suite_definitions": {
         "cppunittest": {
             "options": [
                 "--symbols-path=%(symbols_path)s",
+                "--utility-path=tests/bin",
                 "--xre-path=%(abs_app_dir)s"
             ],
             "run_filename": "runcppunittests.py",
             "testsdir": "cppunittest"
         },
         "jittest": {
             "options": [
                 "tests/bin/js",
--- a/testing/runcppunittests.py
+++ b/testing/runcppunittests.py
@@ -9,16 +9,17 @@ import sys, os, tempfile, shutil
 from optparse import OptionParser
 import manifestparser
 import mozprocess
 import mozinfo
 import mozcrash
 import mozfile
 import mozlog
 from contextlib import contextmanager
+from mozrunner.utils import get_stack_fixer_function
 from subprocess import PIPE
 
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
 
 class CPPUnitTests(object):
     # Time (seconds) to wait for test process to complete
     TEST_PROC_TIMEOUT = 900
     # Time (seconds) in which process will be killed if it produces no output.
@@ -55,17 +56,21 @@ class CPPUnitTests(object):
                                                  processOutputLine=lambda _: None)
             #TODO: After bug 811320 is fixed, don't let .run() kill the process,
             # instead use a timeout in .wait() and then kill to get a stack.
             test_timeout = CPPUnitTests.TEST_PROC_TIMEOUT * timeout_factor
             proc.run(timeout=test_timeout,
                      outputTimeout=CPPUnitTests.TEST_PROC_NO_OUTPUT_TIMEOUT)
             proc.wait()
             if proc.output:
-                output = "\n%s" % "\n".join(proc.output)
+                if self.fix_stack:
+                    procOutput = [self.fix_stack(l) for l in proc.output]
+                else:
+                    procOutput = proc.output
+                output = "\n%s" % "\n".join(procOutput)
                 self.log.process_output(proc.pid, output, command=[prog])
             if proc.timedOut:
                 message = "timed out after %d seconds" % CPPUnitTests.TEST_PROC_TIMEOUT
                 self.log.test_end(basename, status='TIMEOUT', expected='PASS',
                                   message=message)
                 return False
             if mozcrash.check_for_crashes(tempdir, symbols_path,
                                           test_name=basename):
@@ -132,31 +137,35 @@ class CPPUnitTests(object):
 
             # media/mtransport tests statically link in NSS, which
             # causes ODR violations. See bug 1215679.
             assert not 'ASAN_OPTIONS' in env
             env['ASAN_OPTIONS'] = 'detect_leaks=0:detect_odr_violation=0'
 
         return env
 
-    def run_tests(self, programs, xre_path, symbols_path=None, interactive=False):
+    def run_tests(self, programs, xre_path, symbols_path=None, utility_path=None, interactive=False):
         """
         Run a set of C++ unit test programs.
 
         Arguments:
         * programs: An iterable containing (test path, test timeout factor) tuples
         * xre_path: A path to a directory containing a XUL Runtime Environment.
         * symbols_path: A path to a directory containing Breakpad-formatted
                         symbol files for producing stack traces on crash.
+        * utility_path: A path to a directory containing utility programs
+                        (xpcshell et al)
 
         Returns True if all test programs exited with a zero status, False
         otherwise.
         """
         self.xre_path = xre_path
         self.log = mozlog.get_default_logger()
+        if utility_path:
+          self.fix_stack = get_stack_fixer_function(utility_path, symbols_path)
         self.log.suite_start(programs)
         env = self.build_environment()
         pass_count = 0
         fail_count = 0
         for prog in programs:
             test_path = prog[0]
             timeout_factor = prog[1]
             single_result = self.run_one_test(test_path, env, symbols_path,
@@ -183,16 +192,20 @@ class CPPUnittestOptions(OptionParser):
         self.add_option("--symbols-path",
                         action = "store", type = "string", dest = "symbols_path",
                         default = None,
                         help = "absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols")
         self.add_option("--manifest-path",
                         action = "store", type = "string", dest = "manifest_path",
                         default = None,
                         help = "path to test manifest, if different from the path to test binaries")
+        self.add_option("--utility-path",
+                        action = "store", type = "string", dest = "utility_path",
+                        default = None,
+                        help = "path to directory containing utility programs")
 
 def extract_unittests_from_args(args, environ, manifest_path):
     """Extract unittests from args, expanding directories as needed"""
     mp = manifestparser.TestManifest(strict=True)
     tests = []
     binary_path = None
 
     if manifest_path:
@@ -234,18 +247,20 @@ def update_mozinfo():
         dirs.add(path)
         path = os.path.split(path)[0]
     mozinfo.find_and_update_from_json(*dirs)
 
 def run_test_harness(options, args):
     update_mozinfo()
     progs = extract_unittests_from_args(args, mozinfo.info, options.manifest_path)
     options.xre_path = os.path.abspath(options.xre_path)
+    options.utility_path = os.path.abspath(options.utility_path)
     tester = CPPUnitTests()
-    result = tester.run_tests(progs, options.xre_path, options.symbols_path)
+    result = tester.run_tests(progs, options.xre_path, options.symbols_path,
+                              options.utility_path)
 
     return result
 
 def main():
     parser = CPPUnittestOptions()
     mozlog.commandline.add_logging_group(parser)
     options, args = parser.parse_args()
     if not args: