| # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging, os |
| |
| import constants, cros_logging, cros_ui, cryptohome |
| from autotest_lib.client.bin import utils |
| from autotest_lib.client.common_lib import error |
| |
| |
| class CrashError(error.TestError): |
| """Error raised when a pertinent process crashes while waiting on |
| a condition. |
| """ |
| pass |
| |
| |
| class UnexpectedCondition(error.TestError): |
| """Error raised when an expected precondition is not met.""" |
| pass |
| |
| |
| def process_crashed(process, log_reader): |
| """Checks the log watched by |log_reader| to see if a crash was reported |
| for |process|. |
| |
| @param process: process name to look for. |
| @param log_reader: LogReader object set up to watch appropriate log file. |
| |
| @return: True if so, False if not. |
| """ |
| return log_reader.can_find('Received crash notification for %s' % process) |
| |
| |
| def wait_for_condition(condition, timeout_msg, timeout, process, crash_msg): |
| """Wait for callable |condition| to return true, while checking for crashes. |
| |
| Poll for |condition| to become true, for |timeout| seconds. If the timeout |
| is reached, check to see if |process| crashed while we were polling. |
| If so, raise CrashError(crash_msg). If not, raise TimeoutError(timeout_msg). |
| |
| @param condition: a callable to poll on. |
| @param timeout_msg: message to put in TimeoutError before raising. |
| @param timeout: float number of seconds to poll on |condition|. |
| @param process: process name to watch for crashes while polling. |
| @param crash_msg: message to put in CrashError if polling failed and |
| |process| crashed. |
| |
| @raise: TimeoutError if timeout is reached. |
| @raise: CrashError if process crashed and the condition never fired. |
| """ |
| # Mark /var/log/messages now; we'll run through all subsequent log |
| # messages if we couldn't start chrome to see if the browser crashed. |
| log_reader = cros_logging.LogReader() |
| log_reader.set_start_by_current() |
| try: |
| utils.poll_for_condition( |
| condition, |
| utils.TimeoutError(timeout_msg), |
| timeout=timeout) |
| except utils.TimeoutError, e: |
| # We could fail faster if necessary, but it'd be more complicated. |
| if process_crashed(process, log_reader): |
| logging.error(crash_msg) |
| raise CrashError(crash_msg) |
| else: |
| raise e |
| |
| |
| def wait_for_browser(timeout=cros_ui.RESTART_UI_TIMEOUT): |
| """Wait until a Chrome process is running. |
| |
| @param timeout: float number of seconds to wait. |
| |
| @raise: TimeoutError: Chrome didn't start before timeout. |
| """ |
| wait_for_condition( |
| lambda: os.system('pgrep ^%s$ >/dev/null' % constants.BROWSER) == 0, |
| timeout_msg='Timed out waiting for Chrome to start', |
| timeout=timeout, |
| process=constants.BROWSER, |
| crash_msg='Chrome crashed while starting up.') |
| |
| |
| def wait_for_browser_exit(crash_msg, timeout=cros_ui.RESTART_UI_TIMEOUT): |
| """Wait for the Chrome process to exit. |
| |
| @param crash_msg: Error message to include if Chrome crashed. |
| @param timeout: float number of seconds to wait. |
| |
| @return: True if Chrome exited; False otherwise. |
| |
| @raise: CrashError: Chrome crashed while we were waiting. |
| """ |
| try: |
| wait_for_condition( |
| lambda: os.system('pgrep ^%s$ >/dev/null' % constants.BROWSER) != 0, |
| timeout_msg='Timed out waiting for Chrome to exit', |
| timeout=timeout, |
| process=constants.BROWSER, |
| crash_msg=crash_msg) |
| return True |
| except utils.TimeoutError, e: |
| return False |
| |
| |
| def wait_for_cryptohome(user, timeout=cros_ui.RESTART_UI_TIMEOUT): |
| """Wait until cryptohome is mounted. |
| |
| @param user: the user whose cryptohome the caller wants to wait for. |
| @param timeout: float number of seconds to wait. |
| |
| @raise: TimeoutError: cryptohome wasn't mounted before timeout |
| """ |
| wait_for_condition( |
| condition=lambda: cryptohome.is_vault_mounted(user), |
| timeout_msg='Timed out waiting for cryptohome to be mounted', |
| timeout=timeout, |
| process='cryptohomed', |
| crash_msg='cryptohomed crashed during mount attempt') |
| |
| |
| def wait_for_ownership(timeout=constants.DEFAULT_OWNERSHIP_TIMEOUT): |
| """Wait until device owner key file exists on disk. |
| |
| @param timeout: float number of seconds to wait. |
| |
| @raise: TimeoutError: file didn't appear before timeout. |
| """ |
| if os.access(constants.OWNER_KEY_FILE, os.F_OK): |
| raise error.TestError('Device is already owned!') |
| wait_for_condition( |
| condition=lambda: os.access(constants.OWNER_KEY_FILE, os.F_OK), |
| timeout_msg='Timed out waiting for ownership', |
| timeout=timeout, |
| process=constants.BROWSER, |
| crash_msg='Chrome crashed before ownership could be taken.') |