def CreateChromedriver(args):
    """Create a webdriver object and close it after."""
    def DeleteWithRetry(path, func):
        # There seems to be a race condition on the bots that causes the paths
        # to not delete because they are being used. This allows up to 4 seconds
        # to delete
        for _ in xrange(8):
            try:
                return func(path)
            except WindowsError:
                time.sleep(0.5)
        raise

    def CollectCrashReports(user_data_dir, output_dir):
        """Searches for Chrome crash reports, collecting them for analysis.

    Args:
      user_data_dir: The full path of the User Data dir.
      output_dir: If not None, a path to which collected crash reports are to be
        moved.

    Returns:
      The number of crash reports found.
    """
        report_dir = os.path.join(user_data_dir, 'Crashpad', 'reports')
        dumps = []
        try:
            dumps = os.listdir(report_dir)
        except OSError:
            # Assume this is file not found, meaning no crash reports.
            return 0
        for dump in dumps:
            dump_path = os.path.join(report_dir, dump)
            if (output_dir):
                target_path = os.path.join(output_dir, dump)
                try:
                    shutil.copyfile(dump_path, target_path)
                    logging.error('Saved Chrome crash dump to %s', target_path)
                except OSError:
                    logging.exception(
                        'Failed to copy Chrome crash dump from %s to %s',
                        dump_path, target_path)
            else:
                logging.error('Found Chrome crash dump at %s', dump_path)
        return len(dumps)

    driver = None
    user_data_dir = tempfile.mkdtemp()
    fd, log_file = tempfile.mkstemp()
    os.close(fd)
    chrome_options = ChromeOptions()
    chrome_options.binary_location = args.chrome_path
    chrome_options.add_argument('user-data-dir=' + user_data_dir)
    chrome_options.add_argument('log-file=' + log_file)
    chrome_options.add_argument('enable-logging')
    chrome_options.add_argument('v=1')
    emit_log = False
    try:
        driver = webdriver.Chrome(args.chromedriver_path,
                                  chrome_options=chrome_options)
        yield driver
    except:
        emit_log = True
        raise
    finally:
        if driver:
            driver.quit()
        chrome_helper.WaitForChromeExit(args.chrome_path)
        report_count = CollectCrashReports(user_data_dir, args.output_dir)
        if report_count:
            emit_log = True
        try:
            DeleteWithRetry(user_data_dir, shutil.rmtree)
        except:
            emit_log = True
            raise
        finally:
            if emit_log:
                with open(log_file) as fh:
                    logging.error(fh.read())
                if args.output_dir:
                    target = os.path.join(args.output_dir,
                                          os.path.basename(log_file))
                    shutil.copyfile(log_file, target)
                    logging.error('Saved Chrome log to %s', target)
            try:
                DeleteWithRetry(log_file, os.remove)
            except WindowsError:
                # Don't fail the test if the log file couldn't be deleted.
                logging.exception('Failed to delete log file %s' % log_file)
        if report_count:
            raise Exception('Failing test due to %s crash reports found' %
                            report_count)
def CreateChromedriver(args):
    """Create a webdriver object ad close it after."""
    def DeleteWithRetry(path, func):
        # There seems to be a race condition on the bots that causes the paths
        # to not delete because they are being used. This allows up to 2 seconds
        # to delete
        for _ in xrange(4):
            try:
                return func(path)
            except WindowsError:
                time.sleep(0.5)
        raise

    def CollectCrashReports(user_data_dir, output_dir):
        """Searches for Chrome crash reports, collecting them for analysis.

    Args:
      user_data_dir: The full path of the User Data dir.
      output_dir: If not None, a path to which collected crash reports are to be
        moved.
    """
        report_dir = os.path.join(user_data_dir, 'Crashpad', 'reports')
        dumps = []
        try:
            dumps = os.listdir(report_dir)
        except OSError:
            # Assume this is file not found, meaning no crash reports.
            return
        for dump in dumps:
            dump_path = os.path.join(report_dir, dump)
            if (output_dir):
                target_path = os.path.join(output_dir, dump)
                try:
                    shutil.copyfile(dump_path, target_path)
                    logging.error('Saved Chrome crash dump to %s', target_path)
                except OSError:
                    logging.exception(
                        'Failed to copy Chrome crash dump from %s to %s',
                        dump_path, target_path)
            else:
                logging.error('Found Chrome crash dump at %s', dump_path)

    driver = None
    user_data_dir = tempfile.mkdtemp()
    fd, log_file = tempfile.mkstemp()
    os.close(fd)
    chrome_options = ChromeOptions()
    chrome_options.binary_location = args.chrome_path
    chrome_options.add_argument('user-data-dir=' + user_data_dir)
    chrome_options.add_argument('log-file=' + log_file)
    chrome_options.add_argument('enable-logging')
    chrome_options.add_argument('v=1')
    try:
        driver = webdriver.Chrome(args.chromedriver_path,
                                  chrome_options=chrome_options)
        yield driver
    except:
        with open(log_file) as fh:
            logging.error(fh.read())
        raise
    finally:
        if driver:
            driver.quit()
        chrome_helper.WaitForChromeExit()
        # To help with local crash analysis, change None to tempfile.gettempdir().
        # TODO(grt): Copy crash dumps into ${ISOLATED_OUTDIR}.
        CollectCrashReports(user_data_dir, None)
        DeleteWithRetry(log_file, os.remove)
        DeleteWithRetry(user_data_dir, shutil.rmtree)