15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tempfile
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)script_dir = os.path.dirname(__file__)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sys.path.append(os.path.join(script_dir,
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '../../tools/browser_tester'))
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import browser_tester
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import browsertester.browserlauncher
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This script extends browser_tester to check for the presence of
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Breakpad crash dumps.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This reads a file of lines containing 'key:value' pairs.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The file contains entries like the following:
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   plat:Win32
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   prod:Chromium
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   ptype:nacl-loader
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   rept:crash svc
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ReadDumpTxtFile(filename):
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dump_info = {}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fh = open(filename, 'r')
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in fh:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ':' in line:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key, value = line.rstrip().split(':', 1)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dump_info[key] = value
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fh.close()
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dump_info
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def StartCrashService(browser_path, dumps_dir, windows_pipe_name,
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      cleanup_funcs, crash_service_exe,
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      skip_if_missing=False):
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # Find crash_service.exe relative to chrome.exe.  This is a bit icky.
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  browser_dir = os.path.dirname(browser_path)
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  crash_service_path = os.path.join(browser_dir, crash_service_exe)
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if skip_if_missing and not os.path.exists(crash_service_path):
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  proc = subprocess.Popen([crash_service_path,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           '--v=1',  # Verbose output for debugging failures
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           '--dumps-dir=%s' % dumps_dir,
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           '--pipe-name=%s' % windows_pipe_name])
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Cleanup():
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Note that if the process has already exited, this will raise
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # an 'Access is denied' WindowsError exception, but
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # crash_service.exe is not supposed to do this and such
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # behaviour should make the test fail.
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    proc.terminate()
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    status = proc.wait()
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sys.stdout.write('crash_dump_tester: %s exited with status %s\n'
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     % (crash_service_exe, status))
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cleanup_funcs.append(Cleanup)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def ListPathsInDir(dir_path):
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if os.path.exists(dir_path):
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return [os.path.join(dir_path, name)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            for name in os.listdir(dir_path)]
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return []
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def GetDumpFiles(dumps_dirs):
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  all_files = [filename
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               for dumps_dir in dumps_dirs
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               for filename in ListPathsInDir(dumps_dir)]
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.stdout.write('crash_dump_tester: Found %i files\n' % len(all_files))
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for dump_file in all_files:
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sys.stdout.write('  %s (size %i)\n'
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     % (dump_file, os.stat(dump_file).st_size))
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return [dump_file for dump_file in all_files
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if dump_file.endswith('.dmp')]
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def Main(cleanup_funcs):
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser = browser_tester.BuildArgParser()
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('--expected_crash_dumps', dest='expected_crash_dumps',
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    type=int, default=0,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='The number of crash dumps that we should expect')
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parser.add_option('--expected_process_type_for_crash',
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    dest='expected_process_type_for_crash',
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    type=str, default='nacl-loader',
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    help='The type of Chromium process that we expect the '
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    'crash dump to be for')
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # Ideally we would just query the OS here to find out whether we are
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # running x86-32 or x86-64 Windows, but Python's win32api module
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # does not contain a wrapper for GetNativeSystemInfo(), which is
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # what NaCl uses to check this, or for IsWow64Process(), which is
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # what Chromium uses.  Instead, we just rely on the build system to
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # tell us.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('--win64', dest='win64', action='store_true',
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='Pass this if we are running tests for x86-64 Windows')
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options, args = parser.parse_args()
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  temp_dir = tempfile.mkdtemp(prefix='nacl_crash_dump_tester_')
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def CleanUpTempDir():
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    browsertester.browserlauncher.RemoveDirectory(temp_dir)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cleanup_funcs.append(CleanUpTempDir)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # To get a guaranteed unique pipe name, use the base name of the
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # directory we just created.
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  windows_pipe_name = r'\\.\pipe\%s_crash_service' % os.path.basename(temp_dir)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # This environment variable enables Breakpad crash dumping in
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # non-official builds of Chromium.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  os.environ['CHROME_HEADLESS'] = '1'
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if sys.platform == 'win32':
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dumps_dir = temp_dir
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Override the default (global) Windows pipe name that Chromium will
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # use for out-of-process crash reporting.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.environ['CHROME_BREAKPAD_PIPE_NAME'] = windows_pipe_name
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Launch the x86-32 crash service so that we can handle crashes in
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # the browser process.
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartCrashService(options.browser_path, dumps_dir, windows_pipe_name,
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      cleanup_funcs, 'crash_service.exe')
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if options.win64:
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Launch the x86-64 crash service so that we can handle crashes
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # in the NaCl loader process (nacl64.exe).
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      # Skip if missing, since in win64 builds crash_service.exe is 64-bit
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      # and crash_service64.exe does not exist.
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StartCrashService(options.browser_path, dumps_dir, windows_pipe_name,
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                        cleanup_funcs, 'crash_service64.exe',
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                        skip_if_missing=True)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # We add a delay because there is probably a race condition:
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # crash_service.exe might not have finished doing
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # CreateNamedPipe() before NaCl does a crash dump and tries to
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # connect to that pipe.
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # TODO(mseaborn): We could change crash_service.exe to report when
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # it has successfully created the named pipe.
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    time.sleep(1)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif sys.platform == 'darwin':
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dumps_dir = temp_dir
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.environ['BREAKPAD_DUMP_LOCATION'] = dumps_dir
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  elif sys.platform.startswith('linux'):
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # The "--user-data-dir" option is not effective for the Breakpad
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # setup in Linux Chromium, because Breakpad is initialized before
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # "--user-data-dir" is read.  So we set HOME to redirect the crash
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # dumps to a temporary directory.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    home_dir = temp_dir
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    os.environ['HOME'] = home_dir
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    options.enable_crash_reporter = True
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result = browser_tester.Run(options.url, options)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # Find crash dump results.
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if sys.platform.startswith('linux'):
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Look in "~/.config/*/Crash Reports".  This will find crash
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # reports under ~/.config/chromium or ~/.config/google-chrome, or
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # under other subdirectories in case the branding is changed.
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dumps_dirs = [os.path.join(path, 'Crash Reports')
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  for path in ListPathsInDir(os.path.join(home_dir, '.config'))]
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else:
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dumps_dirs = [dumps_dir]
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dmp_files = GetDumpFiles(dumps_dirs)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  failed = False
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg = ('crash_dump_tester: ERROR: Got %i crash dumps but expected %i\n' %
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (len(dmp_files), options.expected_crash_dumps))
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(dmp_files) != options.expected_crash_dumps:
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stdout.write(msg)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    failed = True
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for dump_file in dmp_files:
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Sanity check: Make sure dumping did not fail after opening the file.
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    msg = 'crash_dump_tester: ERROR: Dump file is empty\n'
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if os.stat(dump_file).st_size == 0:
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sys.stdout.write(msg)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      failed = True
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # On Windows, the crash dumps should come in pairs of a .dmp and
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # .txt file.
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if sys.platform == 'win32':
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      second_file = dump_file[:-4] + '.txt'
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      msg = ('crash_dump_tester: ERROR: File %r is missing a corresponding '
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             '%r file\n' % (dump_file, second_file))
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not os.path.exists(second_file):
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.stdout.write(msg)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        failed = True
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Check that the crash dump comes from the NaCl process.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dump_info = ReadDumpTxtFile(second_file)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'ptype' in dump_info:
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        msg = ('crash_dump_tester: ERROR: Unexpected ptype value: %r != %r\n'
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               % (dump_info['ptype'], options.expected_process_type_for_crash))
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if dump_info['ptype'] != options.expected_process_type_for_crash:
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sys.stdout.write(msg)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          failed = True
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.stdout.write('crash_dump_tester: ERROR: Missing ptype field\n')
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        failed = True
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(mseaborn): Ideally we would also check that a backtrace
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # containing an expected function name can be extracted from the
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # crash dump.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if failed:
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stdout.write('crash_dump_tester: FAILED\n')
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = 1
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stdout.write('crash_dump_tester: PASSED\n')
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def MainWrapper():
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cleanup_funcs = []
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  try:
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return Main(cleanup_funcs)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  finally:
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for func in cleanup_funcs:
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      func()
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sys.exit(MainWrapper())
226