OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # |
| 3 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 |
| 7 """Integration test for breakpad in content shell. |
| 8 |
| 9 This test checks that content shell and breakpad are correctly hooked up, as |
| 10 well as that the tools can symbolize a stack trace.""" |
| 11 |
| 12 |
| 13 import glob |
| 14 import optparse |
| 15 import os |
| 16 import shutil |
| 17 import subprocess |
| 18 import sys |
| 19 import tempfile |
| 20 |
| 21 |
| 22 CONCURRENT_TASKS=4 |
| 23 |
| 24 |
| 25 def main(): |
| 26 parser = optparse.OptionParser() |
| 27 parser.add_option('', '--build-dir', default='', |
| 28 help='The build output directory.') |
| 29 parser.add_option('', '--binary', default='', |
| 30 help='The path of the binary to generate symbols for.') |
| 31 parser.add_option('', '--no-symbols', default=False, action='store_true', |
| 32 help='Symbols are not expected to work.') |
| 33 parser.add_option('-j', '--jobs', default=CONCURRENT_TASKS, action='store', |
| 34 type='int', help='Number of parallel tasks to run.') |
| 35 parser.add_option('-v', '--verbose', action='store_true', |
| 36 help='Print verbose status output.') |
| 37 |
| 38 (options, _) = parser.parse_args() |
| 39 |
| 40 if not options.build_dir: |
| 41 print "Required option --build-dir missing." |
| 42 return 1 |
| 43 |
| 44 if not options.binary: |
| 45 print "Required option --binary missing." |
| 46 return 1 |
| 47 |
| 48 if not os.access(options.binary, os.X_OK): |
| 49 print "Cannot find %s." % options.binary |
| 50 return 1 |
| 51 |
| 52 failure = '' |
| 53 |
| 54 # Create a temporary directory to store the crash dumps and symbols in. |
| 55 crash_dir = tempfile.mkdtemp() |
| 56 |
| 57 try: |
| 58 print "# Generate symbols." |
| 59 breakpad_tools_dir = os.path.join( |
| 60 os.path.dirname(__file__), '..', '..', '..', |
| 61 'components', 'breakpad', 'tools') |
| 62 generate_symbols = os.path.join( |
| 63 breakpad_tools_dir, 'generate_breakpad_symbols.py') |
| 64 symbols_dir = os.path.join(crash_dir, 'symbols') |
| 65 cmd = [generate_symbols, |
| 66 '--build-dir=%s' % options.build_dir, |
| 67 '--binary=%s' % options.binary, |
| 68 '--symbols-dir=%s' % symbols_dir, |
| 69 '--jobs=%d' % options.jobs] |
| 70 if options.verbose: |
| 71 cmd.append('--verbose') |
| 72 print ' '.join(cmd) |
| 73 failure = 'Failed to run generate_breakpad_symbols.py.' |
| 74 subprocess.check_call(cmd) |
| 75 |
| 76 print "# Run content_shell and make it crash." |
| 77 cmd = [options.binary, |
| 78 '--dump-render-tree', |
| 79 'chrome://crash', |
| 80 '--enable-crash-reporter', |
| 81 '--crash-dumps-dir=%s' % crash_dir] |
| 82 if options.verbose: |
| 83 print ' '.join(cmd) |
| 84 failure = 'Failed to run content_shell.' |
| 85 if options.verbose: |
| 86 subprocess.check_call(cmd) |
| 87 else: |
| 88 with open(os.devnull, 'w') as devnull: |
| 89 subprocess.check_call(cmd, stdout=devnull, stderr=devnull) |
| 90 |
| 91 print "# Retrieve crash dump." |
| 92 dmp_files = glob.glob(os.path.join(crash_dir, '*.dmp')) |
| 93 failure = 'Expected 1 crash dump, found %d.' % len(dmp_files) |
| 94 if len(dmp_files) != 1: |
| 95 raise Exception(failure) |
| 96 dmp_file = dmp_files[0] |
| 97 minidump = os.path.join(crash_dir, 'minidump') |
| 98 |
| 99 dmp_to_minidump = os.path.join(breakpad_tools_dir, 'dmp2minidump.py') |
| 100 cmd = [dmp_to_minidump, dmp_file, minidump] |
| 101 if options.verbose: |
| 102 print ' '.join(cmd) |
| 103 failure = 'Failed to run dmp_to_minidump.' |
| 104 subprocess.check_call(cmd) |
| 105 |
| 106 print "# Symbolize crash dump." |
| 107 minidump_stackwalk = os.path.join(options.build_dir, 'minidump_stackwalk') |
| 108 cmd = [minidump_stackwalk, minidump, symbols_dir] |
| 109 if options.verbose: |
| 110 print ' '.join(cmd) |
| 111 failure = 'Failed to run minidump_stackwalk.' |
| 112 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 113 stack = proc.communicate()[0] |
| 114 |
| 115 # Check whether the stack contains a CrashIntentionally symbol. |
| 116 found_symbol = 'CrashIntentionally' in stack |
| 117 |
| 118 if options.no_symbols: |
| 119 if found_symbol: |
| 120 if options.verbose: |
| 121 print stack |
| 122 failure = 'Found unexpected reference to CrashIntentionally in stack' |
| 123 raise Exception(failure) |
| 124 else: |
| 125 if not found_symbol: |
| 126 if options.verbose: |
| 127 print stack |
| 128 failure = 'Could not find reference to CrashIntentionally in stack.' |
| 129 raise Exception(failure) |
| 130 |
| 131 except: |
| 132 print "FAIL: %s" % failure |
| 133 return 1 |
| 134 |
| 135 else: |
| 136 print "PASS: Breakpad integration test ran successfully." |
| 137 return 0 |
| 138 |
| 139 finally: |
| 140 try: |
| 141 shutil.rmtree(crash_dir) |
| 142 except: |
| 143 print 'Failed to delete temp directory "%s".' % crash_dir |
| 144 |
| 145 |
| 146 if '__main__' == __name__: |
| 147 sys.exit(main()) |
OLD | NEW |