Home | History | Annotate | Download | only in cros
      1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging, os
      6 
      7 from autotest_lib.client.cros import constants
      8 from autotest_lib.client.bin import utils
      9 from telemetry.core import cros_interface, exceptions, util
     10 from telemetry.internal.browser import browser_finder, browser_options
     11 from telemetry.internal.browser import extension_to_load
     12 
     13 Error = exceptions.Error
     14 
     15 
     16 class Chrome(object):
     17     """Wrapper for creating a telemetry browser instance with extensions."""
     18 
     19 
     20     BROWSER_TYPE_LOGIN = 'system'
     21     BROWSER_TYPE_GUEST = 'system-guest'
     22 
     23 
     24     def __init__(self, logged_in=True, extension_paths=[], autotest_ext=False,
     25                  is_component=True, num_tries=3, extra_browser_args=None,
     26                  clear_enterprise_policy=True, dont_override_profile=False,
     27                  disable_gaia_services=True, disable_default_apps = True,
     28                  auto_login=True, gaia_login=False,
     29                  username=None, password=None, gaia_id=None):
     30         """
     31         Constructor of telemetry wrapper.
     32 
     33         @param logged_in: Regular user (True) or guest user (False).
     34         @param extension_paths: path of unpacked extension to install.
     35         @param autotest_ext: Load a component extension with privileges to
     36                              invoke chrome.autotestPrivate.
     37         @param is_component: Whether extensions should be loaded as component
     38                              extensions.
     39         @param num_tries: Number of attempts to log in.
     40         @param extra_browser_args: Additional argument(s) to pass to the
     41                                    browser. It can be a string or a list.
     42         @param clear_enterprise_policy: Clear enterprise policy before
     43                                         logging in.
     44         @param dont_override_profile: Don't delete cryptohome before login.
     45                                       Telemetry will output a warning with this
     46                                       option.
     47         @param disable_gaia_services: For enterprise autotests, this option may
     48                                       be used to enable policy fetch.
     49         @param disable_default_apps: For tests that exercise default apps.
     50         @param auto_login: Does not login automatically if this is False.
     51                            Useful if you need to examine oobe.
     52         @param gaia_login: Logs in to real gaia.
     53         @param username: Log in using this username instead of the default.
     54         @param password: Log in using this password instead of the default.
     55         @param gaia_id: Log in using this gaia_id instead of the default.
     56         """
     57         self._autotest_ext_path = None
     58         if autotest_ext:
     59             self._autotest_ext_path = os.path.join(os.path.dirname(__file__),
     60                                                    'autotest_private_ext')
     61             extension_paths.append(self._autotest_ext_path)
     62 
     63         finder_options = browser_options.BrowserFinderOptions()
     64         self._browser_type = (self.BROWSER_TYPE_LOGIN
     65                 if logged_in else self.BROWSER_TYPE_GUEST)
     66         finder_options.browser_type = self.browser_type
     67         if extra_browser_args:
     68             finder_options.browser_options.AppendExtraBrowserArgs(
     69                     extra_browser_args)
     70 
     71         if logged_in:
     72             extensions_to_load = finder_options.extensions_to_load
     73             for path in extension_paths:
     74                 extension = extension_to_load.ExtensionToLoad(
     75                         path, self.browser_type, is_component=is_component)
     76                 extensions_to_load.append(extension)
     77             self._extensions_to_load = extensions_to_load
     78 
     79         # finder options must be set before parse_args(), browser options must
     80         # be set before Create().
     81         # TODO(crbug.com/360890) Below MUST be '2' so that it doesn't inhibit
     82         # autotest debug logs
     83         finder_options.verbosity = 2
     84         finder_options.CreateParser().parse_args(args=[])
     85         b_options = finder_options.browser_options
     86         b_options.disable_component_extensions_with_background_pages = False
     87         b_options.create_browser_with_oobe = True
     88         b_options.clear_enterprise_policy = clear_enterprise_policy
     89         b_options.dont_override_profile = dont_override_profile
     90         b_options.disable_gaia_services = disable_gaia_services
     91         b_options.disable_default_apps = disable_default_apps
     92         b_options.disable_component_extensions_with_background_pages = disable_default_apps
     93 
     94         b_options.auto_login = auto_login
     95         b_options.gaia_login = gaia_login
     96         self.username = b_options.username if username is None else username
     97         self.password = b_options.password if password is None else password
     98         b_options.username = self.username
     99         b_options.password = self.password
    100         # gaia_id will be added to telemetry code in chromium repository later
    101         try:
    102             self.gaia_id = b_options.gaia_id if gaia_id is None else gaia_id
    103             b_options.gaia_id = self.gaia_id
    104         except AttributeError:
    105             pass
    106 
    107         # Turn on collection of Chrome coredumps via creation of a magic file.
    108         # (Without this, Chrome coredumps are trashed.)
    109         open(constants.CHROME_CORE_MAGIC_FILE, 'w').close()
    110 
    111         for i in range(num_tries):
    112             try:
    113                 browser_to_create = browser_finder.FindBrowser(finder_options)
    114                 self._browser = browser_to_create.Create(finder_options)
    115                 break
    116             except (exceptions.LoginException) as e:
    117                 logging.error('Timed out logging in, tries=%d, error=%s',
    118                               i, repr(e))
    119                 if i == num_tries-1:
    120                     raise
    121 
    122 
    123     def __enter__(self):
    124         return self
    125 
    126 
    127     def __exit__(self, *args):
    128         self.close()
    129 
    130 
    131     @property
    132     def browser(self):
    133         """Returns a telemetry browser instance."""
    134         return self._browser
    135 
    136 
    137     def get_extension(self, extension_path):
    138         """Fetches a telemetry extension instance given the extension path."""
    139         for ext in self._extensions_to_load:
    140             if extension_path == ext.path:
    141                 return self.browser.extensions[ext]
    142         return None
    143 
    144 
    145     @property
    146     def autotest_ext(self):
    147         """Returns the autotest extension."""
    148         return self.get_extension(self._autotest_ext_path)
    149 
    150 
    151     @property
    152     def login_status(self):
    153         """Returns login status."""
    154         ext = self.autotest_ext
    155         if not ext:
    156             return None
    157 
    158         ext.ExecuteJavaScript('''
    159             window.__login_status = null;
    160             chrome.autotestPrivate.loginStatus(function(s) {
    161               window.__login_status = s;
    162             });
    163         ''')
    164         return ext.EvaluateJavaScript('window.__login_status')
    165 
    166 
    167     @property
    168     def browser_type(self):
    169         """Returns the browser_type."""
    170         return self._browser_type
    171 
    172 
    173     @staticmethod
    174     def did_browser_crash(func):
    175         """Runs func, returns True if the browser crashed, False otherwise.
    176 
    177         @param func: function to run.
    178 
    179         """
    180         try:
    181             func()
    182         except (Error):
    183             return True
    184         return False
    185 
    186 
    187     @staticmethod
    188     def wait_for_browser_restart(func):
    189         """Runs func, and waits for a browser restart.
    190 
    191         @param func: function to run.
    192 
    193         """
    194         _cri = cros_interface.CrOSInterface()
    195         pid = _cri.GetChromePid()
    196         Chrome.did_browser_crash(func)
    197         utils.poll_for_condition(lambda: pid != _cri.GetChromePid(), timeout=60)
    198 
    199 
    200     def wait_for_browser_to_come_up(self):
    201         """Waits for the browser to come up. This should only be called after a
    202         browser crash.
    203         """
    204         def _BrowserReady(cr):
    205             tabs = []  # Wrapper for pass by reference.
    206             if self.did_browser_crash(
    207                     lambda: tabs.append(cr.browser.tabs.New())):
    208                 return False
    209             try:
    210                 tabs[0].Close()
    211             except:
    212                 # crbug.com/350941
    213                 logging.error('Timed out closing tab')
    214             return True
    215         util.WaitFor(lambda: _BrowserReady(self), timeout=10)
    216 
    217 
    218     def close(self):
    219         """Closes the browser."""
    220         self._browser.Close()
    221