blob: 15fa7862e7048139cb8748f10c9f31d55dae60ca [file] [log] [blame]
# Copyright (c) 2010 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, utils, signal, subprocess, time
from autotest_lib.client.bin import chromeos_constants, site_cryptohome
from autotest_lib.client.bin import site_utils, test
from autotest_lib.client.common_lib import error, site_ui
class TimeoutError(error.TestError):
"""Error raised when we time out while waiting on a condition."""
pass
class UnexpectedCondition(error.TestError):
"""Error raised when an expected precondition is not met."""
pass
def __get_session_manager_pid():
"""Determine the pid of the session manager.
Returns:
An integer indicating the current session manager pid, or None if
it is not running.
"""
p = subprocess.Popen(["pgrep", "^%s$" % chromeos_constants.SESSION_MANAGER],
stdout=subprocess.PIPE)
ary = p.communicate()[0].split()
return int(ary[0]) if ary else None
def __session_manager_restarted(oldpid):
"""Detect if the session manager has restarted.
Args:
oldpid: Integer indicating the last known pid of the session_manager.
Returns:
True if the session manager is running under a pid other than
'oldpid', X is running, and there is a window displayed.
"""
import autox
newpid = __get_session_manager_pid()
if newpid and newpid != oldpid:
try:
ax = site_ui.get_autox()
except autox.Xlib.error.DisplayConnectionError:
return False
# When the session manager starts up there is a moment where we can
# make a connection with autox, but there is no window displayed. If
# we start sending keystrokes at this point they get lost. If we wait
# for this window to show up, things go much smoother.
wid = ax.get_top_window_id_at_point(0, 0)
if not wid:
return False
# The login manager displays its widgetry in a second window centered
# on the screen. Waiting for this window to show up is also helpful.
# TODO: perhaps the login manager should emit some more trustworthy
# signal when it's ready to accept credentials.
x, y = ax.get_screen_size()
wid2 = ax.get_top_window_id_at_point(x / 2, y / 2)
if wid == wid2:
return False
return True
return False
def logged_in():
# this file is created when the session_manager emits start-user-session
# and removed when the session_manager emits stop-user-session
return os.path.exists(chromeos_constants.LOGGED_IN_MAGIC_FILE)
def attempt_login(username, password, timeout=20):
"""Attempt to log in.
Args:
script: str filename of autox JSON script
timeout: float number of seconds to wait
Raises:
TimeoutError: login didn't complete before timeout
UnexpectedCondition: login manager is not running, or user is already
logged in.
"""
logging.info("Attempting to login using autox.py and (%s, %s)" %
(username, password))
if not __get_session_manager_pid():
raise UnexpectedCondition("Session manager is not running")
if logged_in():
raise UnexpectedCondition("Already logged in")
ax = site_ui.get_autox()
# navigate to login screen
ax.send_hotkey("Ctrl+Alt+L")
# focus username
ax.send_hotkey("Alt+U")
ax.send_text(username)
# TODO(rginda): remove Tab after http://codereview.chromium.org/1390003
ax.send_hotkey("Tab")
# focus password
ax.send_hotkey("Alt+P")
ax.send_text(password)
ax.send_hotkey("Return")
site_utils.poll_for_condition(
logged_in, TimeoutError('Timed out waiting for login'),
timeout=timeout)
def attempt_logout(timeout=20):
"""Attempt to log out by killing Chrome.
Args:
timeout: float number of seconds to wait
Raises:
TimeoutError: logout didn't complete before timeout
UnexpectedCondition: user is not logged in
"""
if not logged_in():
raise UnexpectedCondition('Already logged out')
oldpid = __get_session_manager_pid()
# Gracefully exiting the session manager causes the user's session to end.
utils.system('pkill -TERM -o ^%s$' % chromeos_constants.SESSION_MANAGER)
site_utils.poll_for_condition(
lambda: __session_manager_restarted(oldpid),
TimeoutError('Timed out waiting for logout'),
timeout)
def wait_for_browser(timeout=10):
"""Wait until a Chrome process is running.
Args:
timeout: float number of seconds to wait
Raises:
TimeoutError: Chrome didn't start before timeout
"""
site_utils.poll_for_condition(
lambda: os.system('pgrep ^%s$' % chromeos_constants.BROWSER) == 0,
TimeoutError('Timed out waiting for Chrome to start'),
timeout=timeout)
def wait_for_cryptohome(timeout=10):
"""Wait until cryptohome is mounted.
Args:
timeout: float number of seconds to wait
Raises:
TimeoutError: cryptohome wasn't mounted before timeout
"""
site_utils.poll_for_condition(
lambda: site_cryptohome.is_mounted(),
TimeoutError('Timed out waiting for cryptohome to be mounted'),
timeout=timeout)
def wait_for_screensaver(timeout=10):
"""Wait until xscreensaver is responding.
Args:
timeout: float number of seconds to wait
Raises:
TimeoutError: xscreensaver didn't respond before timeout
"""
site_utils.poll_for_condition(
lambda: site_ui.xsystem('xscreensaver-command -version',
ignore_status=True) == 0,
TimeoutError('Timed out waiting for xscreensaver to respond'),
timeout=timeout)
def wait_for_window_manager(timeout=20):
"""Wait until the window manager is running.
Args:
timeout: float number of seconds to wait
Raises:
TimeoutError: window manager didn't start before timeout
"""
site_utils.poll_for_condition(
lambda: not os.system('pgrep ^%s$' % chromeos_constants.WINDOW_MANAGER),
TimeoutError('Timed out waiting for window manager to start'),
timeout=timeout)
def wait_for_initial_chrome_window(timeout=20):
"""Wait until the initial Chrome window is mapped.
Args:
timeout: float number of seconds to wait
Raises:
TimeoutError: Chrome window wasn't mapped before timeout
"""
site_utils.poll_for_condition(
lambda: os.access(
chromeos_constants.CHROME_WINDOW_MAPPED_MAGIC_FILE, os.F_OK),
TimeoutError('Timed out waiting for initial Chrome window'),
timeout=timeout)
def nuke_login_manager():
nuke_process_by_name('session_manager')
wait_for_browser()
def nuke_process_by_name(name, with_prejudice=False):
pid = int(utils.system_output('pgrep -o ^%s$' % name))
if with_prejudice:
utils.nuke_pid(pid, [signal.SIGKILL])
else:
utils.nuke_pid(pid)