blob: 516fc40a61d926983898342e661b776bd5f9345a [file] [log] [blame]
# 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.
"""Base class for using Chrome PyAuto Automation in autotest tests.
This class takes care of getting the automation framework ready for work.
Things this class does:
- Enable automation and restart chrome with appropriate flags
- Log in to default account
The PyAuto framework must be installed on the machine for this to work,
under .../autotest/deps/{pyauto_dep|chrome_test}/test_src/chrome/pyautolib'.
This is built by the chromeos-chrome ebuild.
"""
import logging, os, shutil, subprocess, sys
from optparse import OptionParser
import common, constants, cros_ui, cryptohome
from autotest_lib.client.bin import test, utils
from autotest_lib.client.common_lib import error
class PyAutoTest(test.test):
"""Base autotest class for tests which require the PyAuto framework.
Inherit this class to make calls to the PyUITest framework.
Each test begins with a clean browser profile. (ie clean /home/chronos).
For each test:
- /home/chronos is cleared before firing up chrome
- the default test user's cryptohome vault is cleared
- login as default test user
Beware however that:
- chrome sync is still enabled, so the browser might fetch data/prefs over
the air.
- Settings not stored in /home/chronos might persist across tests
Sample test:
from autotest_lib.client.cros import pyauto_test
class desktopui_UrlFetch(pyauto_test.PyAutoTest):
version = 1
def run_once(self):
self.pyauto.NavigateToURL('http://www.google.com')
self.assertEqual('Google', self.pyauto.GetActiveTabTitle)
This test will login (with the default test account), then navigate to
Google and verify its title.
"""
def __init__(self, *args, **kwargs):
self._dep = 'pyauto_dep'
# Handle to pyauto, for chrome automation.
self.pyauto = None
self.pyauto_suite = None
test.test.__init__(self, *args, **kwargs)
def use_chrome_deps(self):
self._dep = 'chrome_test'
def setup(self):
self.job.setup_dep([self._dep])
def _install_deps(self):
"""Set up deps needed for running pyauto."""
dep_dir = os.path.join(self.autodir, 'deps', self._dep)
self.job.install_pkg(self._dep, 'dep', dep_dir)
# Make pyauto importable.
# This can be done only after chrome_test/pyauto_dep dependency has been
# installed.
pyautolib_dir = os.path.join(
dep_dir, 'test_src', 'chrome', 'test', 'pyautolib')
if not os.path.isdir(pyautolib_dir):
raise error.TestError('%s missing.' % pyautolib_dir)
sys.path.append(pyautolib_dir)
# TODO(frankf): This should be done automatically by setup_dep.
# Create symlinks to chrome
test_binary_dir = os.path.join(
dep_dir, 'test_src', 'out', 'Release')
try:
setup_cmd = '/bin/bash %s/%s' % (test_binary_dir,
'setup_test_links.sh')
utils.system(setup_cmd) # this might raise an exception
except error.CmdError, e:
raise error.TestError(e)
self._setup_suid_python(test_binary_dir)
def _setup_suid_python(self, test_binary_dir):
"""Setup suid python which can enable chrome testing interface.
This is required when running pyauto as non-privileged user (chronos).
"""
suid_python = os.path.join(test_binary_dir, 'suid-python')
py_path = subprocess.Popen(['which', 'python'],
stdout=subprocess.PIPE).communicate()[0]
py_path = py_path.strip()
assert os.path.exists(py_path), 'Could not find python'
if os.path.islink(py_path):
linkto = os.readlink(py_path)
py_path = os.path.join(os.path.dirname(py_path), linkto)
shutil.copy(py_path, suid_python)
os.chown(suid_python, 0, 0)
os.chmod(suid_python, 04755)
def _get_pyuitest_class(self, class_name):
"""Obtains a object reference of a class with the indicated name.
Assumes pyauto deps has already been installed.
Args:
class_name: string in <package>.<class> format that represents
the PYUITest to be used (eg. 'policy_base.PolicyBaseTest')
Returns:
An instance of pyauto.PyUITest.
"""
import pyauto
module, _, name = class_name.rpartition('.')
mod = getattr(__import__(module), name)
assert issubclass(mod, pyauto.PyUITest), '%s is not a subclass of ' \
'PyUITest' % name
return mod
def initialize(self, auto_login=True, extra_chrome_flags=[],
subtract_extra_chrome_flags=[],
pyuitest_class='pyauto.PyUITest', *args, **kwargs):
"""Initialize.
Expects session_manager to be alive.
Args:
auto_login: should we auto login using $default account?
extra_chrome_flags: Extra chrome flags to pass to chrome, if any.
subtract_extra_chrome_flags: Remove default flags passed to chrome
by pyauto, if any.
"""
assert os.geteuid() == 0, 'Need superuser privileges'
self._install_deps()
import pyauto
pyauto_class = self._get_pyuitest_class(pyuitest_class)
class PyUITestInAutotest(pyauto_class):
"""Adaptation of PyUITest for use in Autotest."""
def runTest(self):
# unittest framework expects runTest.
pass
def ShouldOOBESkipToLogin(self):
return False
def ShouldAutoLogin(self):
# Do not auto login
return False
def ExtraChromeFlags(self):
args = pyauto_class.ExtraChromeFlags(self)
return list((set(args) - set(subtract_extra_chrome_flags))
| set(extra_chrome_flags))
parser = OptionParser()
pyauto._OPTIONS, args = parser.parse_args([])
pyauto._OPTIONS.channel_id = ''
pyauto._OPTIONS.no_http_server = True
pyauto._OPTIONS.remote_host = None
self.pyauto_suite = pyauto.PyUITestSuite(
['--ui-test-action-timeout=60000',
'--ui-test-action-max-timeout=60000'])
self.pyauto = PyUITestInAutotest()
# Enable chrome testing interface and log in to default account
self.pyauto.setUp() # connects to pyauto automation
if auto_login:
self.pyauto.SkipToLogin()
self.LoginToDefaultAccount()
def LoginToDefaultAccount(self):
"""Login to ChromeOS using $default testing account."""
creds = constants.CREDENTIALS['$default']
username = cryptohome.canonicalize(creds[0])
passwd = creds[1]
err_mesg = self.pyauto.Login(username, passwd)
if err_mesg or not self.pyauto.GetLoginInfo()['is_logged_in']:
raise error.TestError(
'Error during Login(%s): %s' % (username, err_mesg))
logging.info('Logged in as %s' % username)
def cleanup(self):
"""Clean up after running the test.
We restart chrome and restart the login manager
"""
if self.pyauto:
self.pyauto.tearDown()
del self.pyauto
if self.pyauto_suite:
del self.pyauto_suite
# Reset the UI.
cros_ui.restart()
test.test.cleanup(self)