Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | #!/usr/bin/env python |
michael@0 | 2 | # |
michael@0 | 3 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | # License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 6 | |
michael@0 | 7 | from __future__ import with_statement |
michael@0 | 8 | import sys, os |
michael@0 | 9 | from optparse import OptionParser |
michael@0 | 10 | import mozprocess, mozinfo, mozlog, mozcrash |
michael@0 | 11 | |
michael@0 | 12 | log = mozlog.getLogger('gtest') |
michael@0 | 13 | |
michael@0 | 14 | class GTests(object): |
michael@0 | 15 | # Time (seconds) to wait for test process to complete |
michael@0 | 16 | TEST_PROC_TIMEOUT = 1200 |
michael@0 | 17 | # Time (seconds) in which process will be killed if it produces no output. |
michael@0 | 18 | TEST_PROC_NO_OUTPUT_TIMEOUT = 300 |
michael@0 | 19 | |
michael@0 | 20 | def run_gtest(self, prog, xre_path, symbols_path=None): |
michael@0 | 21 | """ |
michael@0 | 22 | Run a single C++ unit test program. |
michael@0 | 23 | |
michael@0 | 24 | Arguments: |
michael@0 | 25 | * prog: The path to the test program to run. |
michael@0 | 26 | * env: The environment to use for running the program. |
michael@0 | 27 | * symbols_path: A path to a directory containing Breakpad-formatted |
michael@0 | 28 | symbol files for producing stack traces on crash. |
michael@0 | 29 | |
michael@0 | 30 | Return True if the program exits with a zero status, False otherwise. |
michael@0 | 31 | """ |
michael@0 | 32 | self.xre_path = xre_path |
michael@0 | 33 | env = self.build_environment() |
michael@0 | 34 | log.info("Running gtest") |
michael@0 | 35 | proc = mozprocess.ProcessHandler([prog, "-unittest"], |
michael@0 | 36 | cwd=os.getcwd(), |
michael@0 | 37 | env=env) |
michael@0 | 38 | #TODO: After bug 811320 is fixed, don't let .run() kill the process, |
michael@0 | 39 | # instead use a timeout in .wait() and then kill to get a stack. |
michael@0 | 40 | proc.run(timeout=GTests.TEST_PROC_TIMEOUT, |
michael@0 | 41 | outputTimeout=GTests.TEST_PROC_NO_OUTPUT_TIMEOUT) |
michael@0 | 42 | proc.wait() |
michael@0 | 43 | if proc.timedOut: |
michael@0 | 44 | log.testFail("gtest | timed out after %d seconds", GTests.TEST_PROC_TIMEOUT) |
michael@0 | 45 | return False |
michael@0 | 46 | if mozcrash.check_for_crashes(os.getcwd(), symbols_path, test_name="gtest"): |
michael@0 | 47 | # mozcrash will output the log failure line for us. |
michael@0 | 48 | return False |
michael@0 | 49 | result = proc.proc.returncode == 0 |
michael@0 | 50 | if not result: |
michael@0 | 51 | log.testFail("gtest | test failed with return code %d", proc.proc.returncode) |
michael@0 | 52 | return result |
michael@0 | 53 | |
michael@0 | 54 | def build_core_environment(self, env = {}): |
michael@0 | 55 | """ |
michael@0 | 56 | Add environment variables likely to be used across all platforms, including remote systems. |
michael@0 | 57 | """ |
michael@0 | 58 | env["MOZILLA_FIVE_HOME"] = self.xre_path |
michael@0 | 59 | env["MOZ_XRE_DIR"] = self.xre_path |
michael@0 | 60 | env["XPCOM_DEBUG_BREAK"] = "stack-and-abort" |
michael@0 | 61 | env["MOZ_CRASHREPORTER_NO_REPORT"] = "1" |
michael@0 | 62 | env["MOZ_CRASHREPORTER"] = "1" |
michael@0 | 63 | env["MOZ_RUN_GTEST"] = "1" |
michael@0 | 64 | # Normally we run with GTest default output, override this to use the TBPL test format. |
michael@0 | 65 | env["MOZ_TBPL_PARSER"] = "1" |
michael@0 | 66 | return env |
michael@0 | 67 | |
michael@0 | 68 | def build_environment(self): |
michael@0 | 69 | """ |
michael@0 | 70 | Create and return a dictionary of all the appropriate env variables and values. |
michael@0 | 71 | On a remote system, we overload this to set different values and are missing things like os.environ and PATH. |
michael@0 | 72 | """ |
michael@0 | 73 | if not os.path.isdir(self.xre_path): |
michael@0 | 74 | raise Exception("xre_path does not exist: %s", self.xre_path) |
michael@0 | 75 | env = dict(os.environ) |
michael@0 | 76 | env = self.build_core_environment(env) |
michael@0 | 77 | pathvar = "" |
michael@0 | 78 | if mozinfo.os == "linux": |
michael@0 | 79 | pathvar = "LD_LIBRARY_PATH" |
michael@0 | 80 | elif mozinfo.os == "mac": |
michael@0 | 81 | pathvar = "DYLD_LIBRARY_PATH" |
michael@0 | 82 | elif mozinfo.os == "win": |
michael@0 | 83 | pathvar = "PATH" |
michael@0 | 84 | if pathvar: |
michael@0 | 85 | if pathvar in env: |
michael@0 | 86 | env[pathvar] = "%s%s%s" % (self.xre_path, os.pathsep, env[pathvar]) |
michael@0 | 87 | else: |
michael@0 | 88 | env[pathvar] = self.xre_path |
michael@0 | 89 | return env |
michael@0 | 90 | |
michael@0 | 91 | class gtestOptions(OptionParser): |
michael@0 | 92 | def __init__(self): |
michael@0 | 93 | OptionParser.__init__(self) |
michael@0 | 94 | self.add_option("--xre-path", |
michael@0 | 95 | action = "store", type = "string", dest = "xre_path", |
michael@0 | 96 | default = None, |
michael@0 | 97 | help = "absolute path to directory containing XRE (probably xulrunner)") |
michael@0 | 98 | self.add_option("--symbols-path", |
michael@0 | 99 | action = "store", type = "string", dest = "symbols_path", |
michael@0 | 100 | default = None, |
michael@0 | 101 | help = "absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") |
michael@0 | 102 | |
michael@0 | 103 | def main(): |
michael@0 | 104 | parser = gtestOptions() |
michael@0 | 105 | options, args = parser.parse_args() |
michael@0 | 106 | if not args: |
michael@0 | 107 | print >>sys.stderr, """Usage: %s <binary>""" % sys.argv[0] |
michael@0 | 108 | sys.exit(1) |
michael@0 | 109 | if not options.xre_path: |
michael@0 | 110 | print >>sys.stderr, """Error: --xre-path is required""" |
michael@0 | 111 | sys.exit(1) |
michael@0 | 112 | prog = os.path.abspath(args[0]) |
michael@0 | 113 | options.xre_path = os.path.abspath(options.xre_path) |
michael@0 | 114 | tester = GTests() |
michael@0 | 115 | try: |
michael@0 | 116 | result = tester.run_gtest(prog, options.xre_path, options.symbols_path) |
michael@0 | 117 | except Exception, e: |
michael@0 | 118 | log.error(str(e)) |
michael@0 | 119 | result = False |
michael@0 | 120 | sys.exit(0 if result else 1) |
michael@0 | 121 | |
michael@0 | 122 | if __name__ == '__main__': |
michael@0 | 123 | main() |
michael@0 | 124 |